All Classes Functions
vnfs_operations.py
1 #!/usr/bin/env python
2 from __future__ import with_statement
3 
4 import os
5 from subprocess import Popen, PIPE
6 import sys
7 import errno
8 import time
9 
10 import logging
11 
12 import getpass
13 import re
14 
15 import errors
16 from hypervisor import hypervisor_factory
17 
18 logger = logging.getLogger(__name__)
19 
20 ##
21 #
22 # Provides a common set of operations for nfio. These operations act as a
23 # helper.
24 #
26 
27 
28  OP_UNDEFINED = 0xFF
29  OP_NF = 0x01
30 
31  def __init__(self, vnfs_root):
32  self.vnfs_root = vnfs_root
33  self._hypervisor = hypervisor_factory.HypervisorFactory.get_hypervisor_instance()
34 
35  def _full_path(self, partial):
36  if partial.startswith("/"):
37  partial = partial[1:]
38  path = os.path.join(self.vnfs_root, partial)
39  return path
40 
41  ##
42  #
43  # Create the file system structure for a VNF.
44  #
45  # Args:
46  # path: path of the new VNF instance.
47  # mode: file creation mode for the new VNF instance directory.
48  #
49  # Returns:
50  # returns the return code of os.mkdir
51  #
52  def vnfs_create_vnf_instance(self, path, mode):
53  logger.info('Creating file/directory structure in ' + path)
54  full_path = self._full_path(path)
55  result = os.mkdir(full_path)
56  default_file_mode = 0o644
57  os.open(
58  full_path +
59  "/status",
60  os.O_WRONLY | os.O_CREAT,
61  default_file_mode)
62 
63  os.mkdir(full_path + "/config", mode)
64  os.open(full_path + "/config/boot.conf", os.O_WRONLY | os.O_CREAT,
65  default_file_mode)
66  os.mkdir(full_path + "/machine", mode)
67  os.open(full_path + "/machine/ip", os.O_WRONLY | os.O_CREAT,
68  default_file_mode)
69  os.open(full_path + "/machine/vm.vcpu", os.O_WRONLY | os.O_CREAT,
70  default_file_mode)
71  os.open(full_path + "/machine/vm.memory", os.O_WRONLY | os.O_CREAT,
72  default_file_mode)
73  os.open(full_path + "/machine/vm.image", os.O_WRONLY | os.O_CREAT,
74  default_file_mode)
75  os.open(full_path + "/machine/vm.ip", os.O_WRONLY | os.O_CREAT,
76  default_file_mode)
77  os.open(full_path + "/action", os.O_WRONLY | os.O_CREAT,
78  default_file_mode)
79 
80  default_file_mode = 0o444
81  os.mkdir(full_path + "/stats", mode)
82  os.open(full_path + "/stats/rx_bytes", os.O_WRONLY | os.O_CREAT,
83  default_file_mode)
84  os.open(full_path + "/stats/tx_bytes", os.O_WRONLY | os.O_CREAT,
85  default_file_mode)
86  os.open(full_path + "/stats/pkt_drops", os.O_WRONLY | os.O_CREAT,
87  default_file_mode)
88  logger.info('Finished creating file/directory structure in ' + path)
89  return result
90 
91  ##
92  #
93  # Determinse the type of operation based on the path.
94  #
95  # Args:
96  # path: path to the file/directory on which the operation is being
97  # performed
98  #
99  # Returns:
100  # If the file is under nf-types subdirectory in the nfio mount, then
101  # returns OP_NF. Otherwise, returns OP_UNDEFINED.
102  #
103  def vnfs_get_opcode(self, path):
104  tokens = self._full_path(path).encode('ascii').split('/')
105  if "nf-types" in tokens:
106  return VNFSOperations.OP_NF
107  return VNFSOperations.OP_UNDEFINED
108 
109  ##
110  #
111  # Parse the type of VNF from path
112  #
113  # Args:
114  # path: the path of the file/directory on which some operation is
115  # being performed.
116  #
117  # Returns:
118  # Returns the type of VNF parsed from the path, e.g., if the path is
119  # /mnt/vnfsroot/nf-types/firewall/fw-alpha/action then returns
120  # firewall.
121  #
122  def vnfs_get_nf_type(self, path):
123  tokens = self._full_path(path).encode('ascii').split('/')
124  try:
125  return tokens[tokens.index("nf-types") + 1]
126  except ValueError:
127  return ""
128  except IndexError:
129  return ""
130 
131  ##
132  #
133  # Return the name of the file represented by a path.
134  #
135  # Args:
136  # path: the path of the file in concern
137  #
138  # Returns:
139  # returns the name of the file, i.e., last token after / in the path.
140  #
141  def vnfs_get_file_name(self, path):
142 
143  return path.split('/')[-1]
144 
145  ##
146  #
147  # Determines if a path represents an nf instance directory.
148  #
149  # Args:
150  # path: path of the file/directory in concern.
151  #
152  # Returns:
153  # True: if path represents an nf instance directory. For example, if
154  # path is /mnt/vnfsmnt/nf-types/firewall/fw-alpha then returns True.
155  #
156  # False: if the path does not represent an nf instance directory. For
157  # example, if path is /mnt/vnfsmnt/nf-types/firewall/fw-alpha/action
158  # then returns False.
159  #
160  def vnfs_is_nf_instance(self, path):
161  tokens = self._full_path(path).encode('ascii').split('/')
162  if ('nf-types' in tokens) and len(tokens) > tokens.index('nf-types') + \
163  1:
164  return True
165  return False
166 
167  ##
168  #
169  # Return the configuration parameters related to a VNF instance.
170  #
171  # Args:
172  # nf_path: path of the VNF instance. e.g.,
173  # /mnt/vnfsmnt/firewall/fw-alpha
174  #
175  # Returns:
176  # A tuple representing the configuration of the VNF instance. The
177  # tuple is organized in the following order:
178  # nf_instance_name: name of the VNF instance.
179  # nf_type: type of the VNF.
180  # ip_address: IP address of the machine where this VNF will be
181  # deployed.
182  # image_name: name of the VM/container image for that VNF.
183  #
185  nf_instance_name = self.vnfs_get_file_name(nf_path)
186  nf_type = self.vnfs_get_nf_type(nf_path)
187  ip_address = ''
188  logger.debug(nf_path + '/machine/ip')
189  with open(nf_path + '/machine/ip') as ip_fd:
190  ip_address = ip_fd.readline().rstrip('\n')
191  image_name = ''
192  with open(nf_path + '/machine/vm.image') as img_fd:
193  image_name = img_fd.readline().rstrip('\n')
194  logger.info("Instance name: " + nf_instance_name + ", type: "
195  + nf_type + ", host-ip: " + ip_address + " VNF image: " + image_name)
196  return nf_instance_name, nf_type, ip_address, image_name
197 
198  ##
199  #
200  # Deploys and STARTS a VNF instance.
201  #
202  # Args:
203  # nf_path: path of the VNF instance.
204  #
205  # @return void
206  #
207  def vnfs_deploy_nf(self, nf_path):
208  logger.info('Deploying new VNF at ' + nf_path)
209  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(nf_path)
210  try:
211  cont_id = self._hypervisor.deploy(
212  ip_address, getpass.getuser(), image_name, nf_instance_name)
213  logger.debug(cont_id)
214  except errors.VNFDeployError:
215  logger.info('Instance: ' + nf_instance_name + ' deployment failed')
216  else:
217  logger.info('Instance: ' + nf_instance_name
218  + ' successfully deployed')
219  try:
220  logger.info('Starting the deployed VNF instance: '
221  + nf_instance_name)
222  self._hypervisor.start(ip_address, cont_id)
223  except errors.VNFStartError:
224  logger.info('Instance: ' + nf_instance_name + ' start failed')
225  # destroy the deployed VNF
226  self._hypervisor.destroy(ip_address, cont_id)
227  logger.info('Instance: ' + nf_instance_name
228  + ' destroyed')
229  else:
230  logger.info('Instance: ' + nf_instance_name
231  + ' successfully deployed and started')
232 
233  ##
234  #
235  # Stops a VNF instance.
236  #
237  # Args:
238  # nf_path: path of the VNF instance.
239  #
240  # @return void
241  #
242  def vnfs_stop_vnf(self, nf_path):
243  logger.info("Stopping VNF at " + nf_path)
244  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
245  nf_path)
246  self._hypervisor.stop(ip_address, getpass.getuser(), nf_instance_name )
247  logger.info('Instance: ' + nf_instance_name + ' successfully stopped')
248 
249  ##
250  #
251  # Starts a deployed VNF instance.
252  #
253  # Args:
254  # nf_path: path of the VNF instance.
255  #
256  # Returns:
257  # return codes are described in hypervisor.hypervisor_return_codes
258  # module.
259  #
260  def vnfs_start_vnf(self, nf_path):
261  logger.info("Starting VNF at " + nf_path)
262  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
263  nf_path)
264  self._hypervisor.start(ip_address, getpass.getuser(), nf_instance_name)
265  logger.info('Instance: ' + nf_instance_name + ' successfully started')
266 
267  ##
268  #
269  # Destroys a deployed VNF instance.
270  #
271  # Args:
272  # nf_path: path of the VNF instance.
273  #
274  # Returns:
275  # return codes are described in hypervisor.hypervisor_return_codes
276  # module.
277  #
278  def vnfs_destroy_vnf(self, nf_path):
279  logger.info("Destroying VNF at " + nf_path)
280  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
281  nf_path)
282  self._hypervisor.destroy(ip_address, getpass.getuser(), nf_instance_name)
283  logger.info('Instance: ' + nf_instance_name + ' successfully destroyed')
284 
285  ##
286  #
287  # Reads the number of bytes received by a VNF instance.
288  #
289  # Args:
290  # nf_path: path of the VNF instance.
291  #
292  # Returns:
293  # returns the number of bytes received by a VNF instance.
294  #
295  def vnfs_get_rx_bytes(self, nf_path):
296  logger.info('Reading rx_bytes at ' + nf_path)
297  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
298  nf_path)
299  command = "ifconfig eth0 | grep -Eo 'RX bytes:[0-9]+' | cut -d':' -f 2"
300  response = self._hypervisor.execute_in_guest(
301  ip_address,
302  getpass.getuser(), nf_instance_name,
303  command)
304  logger.info('Successfully read rx_bytes')
305  return response
306 
307  ##
308  #
309  # Reads the number of bytes sent by a VNF instance.
310  #
311  # Args:
312  # nf_path: path of the VNF instance.
313  #
314  # Returns:
315  # returns the number of bytes sent by a VNF instance.
316  #
317  def vnfs_get_tx_bytes(self, nf_path):
318  logger.info('Reading tx_bytes at ' + nf_path)
319  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
320  nf_path)
321  command = "ifconfig eth0 | grep -Eo 'TX bytes:[0-9]+' | cut -d':' -f 2"
322  response = self._hypervisor.execute_in_guest(
323  ip_address,
324  getpass.getuser(), nf_instance_name,
325  command)
326  logger.info('Successfully read tx_bytes')
327  return response
328 
329  ##
330  #
331  # Reads the number of packets dropped by a VNF instance.
332  #
333  # Args:
334  # nf_path: path of the VNF instance.
335  #
336  # Returns:
337  # returns the number of packets dropped by a VNF instance.
338  #
339  def vnfs_get_pkt_drops(self, nf_path):
340  logger.info('Reading pkt_drops at ' + nf_path)
341  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
342  nf_path)
343  command = "ifconfig eth0 | grep -Eo 'RX .* dropped:[0-9]+' | cut -d':' -f 4"
344  response = self._hypervisor.execute_in_guest(
345  ip_address,
346  getpass.getuser(), nf_instance_name,
347  command)
348  logger.info('Successfully read pkt_drops')
349  return response
350 
351  ##
352  #
353  # Get the status of a VNF instance, e.g., the VNF is
354  # running/suspended/stopped etc.
355  #
356  # Args:
357  # nf_path: path of the VNF instance.
358  #
359  # Returns:
360  # Hypervisor specific status of the VNF. For example, if Docker is
361  # being used for VNF deployment then Docker specific container status
362  # message is returned.
363  #
364  def vnfs_get_status(self, nf_path):
365  logger.info('Reading status at ' + nf_path)
366  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
367  nf_path)
368  response = ''
369  try:
370  response = self._hypervisor.guest_status(ip_address, getpass.getuser(),
371  nf_instance_name)
373  logger.info('Instance: ' + nf_instance_name + ' does not exist')
374  logger.info('Successfully read status')
375  return response
376 
377  ##
378  #
379  # Get the status of a VNF instance, e.g., the VNF is
380  # running/suspended/stopped etc.
381  #
382  # Args:
383  # nf_path: path of the VNF instance.
384  #
385  # Returns:
386  # Hypervisor specific status of the VNF. For example, if Docker is
387  # being used for VNF deployment then Docker specific container status
388  # message is returned.
389  #
390  def vnfs_get_ip(self, nf_path):
391  logger.info('Reading ip at ' + nf_path)
392  nf_instance_name, nf_type, ip_address, image_name = self.vnfs_get_instance_configuration(
393  nf_path)
394  cont_ip = self._hypervisor.get_ip(ip_address, getpass.getuser(), nf_instance_name)
395  logger.debug('cont_ip ' + cont_ip)
396  logger.info('Successfully read ip')
397  return cont_ip
398 
def vnfs_deploy_nf
Deploys and STARTS a VNF instance.
def vnfs_get_opcode
Determinse the type of operation based on the path.
def vnfs_get_rx_bytes
Reads the number of bytes received by a VNF instance.
Provides a common set of operations for nfio.
def vnfs_stop_vnf
Stops a VNF instance.
def vnfs_start_vnf
Starts a deployed VNF instance.
def vnfs_destroy_vnf
Destroys a deployed VNF instance.
def vnfs_get_status
Get the status of a VNF instance, e.g., the VNF is running/suspended/stopped etc. ...
def vnfs_is_nf_instance
Determines if a path represents an nf instance directory.
def vnfs_get_instance_configuration
Return the configuration parameters related to a VNF instance.
def vnfs_get_file_name
Return the name of the file represented by a path.
def vnfs_get_pkt_drops
Reads the number of packets dropped by a VNF instance.
def vnfs_get_ip
Get the status of a VNF instance, e.g., the VNF is running/suspended/stopped etc. ...
def vnfs_get_nf_type
Parse the type of VNF from path.
def vnfs_get_tx_bytes
Reads the number of bytes sent by a VNF instance.
def vnfs_create_vnf_instance
Create the file system structure for a VNF.