Return OpenStackVolume and OpenStackVolumeType instances from heat.
[snaps.git] / docs / how-to-use / LibraryUsage.rst
1 **********************
2 SNAPS-OO Library Usage
3 **********************
4
5 The pattern used within the SNAPS-OO library for creating OpenStack
6 instances have been made as consistent as possible amongst the different
7 instance types. Each consists of a constructor that takes in a
8 credentials object and generally takes in a single "settings"
9 (configuration) object. The only exception to this rule is with the
10 OpenStackVMInstance (creates an OpenStack Server) where it takes in the
11 additional settings used for the associated image and SSH key-pairs
12 credentials as those objects contain additional attributes required of
13 SNAPS, primarily when one needs to obtain remote access. After
14 instantiation, the create() method must be called to initiate all of the
15 necessary remote API calls to OpenStack required for proper instance
16 creation.
17
18 SNAPS Credentials
19 =================
20
21 As communicating with OpenStack is performed via secure remote RESTful
22 API calls, any function or method performing any type of query or CRUD
23 operation must know how to connect to the NFVI. The class ***OSCreds***
24 defined in *snaps.openstack.os\_credentials.py* contains everything
25 required to connect to any Keystone v2.0 or v3 authorization server. The
26 attributes are listed below:
27
28 -  username
29 -  password
30 -  auth\_url
31 -  project\_name (aka. tenant\_name)
32 -  identity\_api\_version (for obtaining Keystone authorization token.
33    default = 2, Versions 2.0 & v3 only validated.)
34 -  image\_api\_version (default = 2, Glance version 1 & 2 only validated)
35 -  network\_api\_version (Neutron version 2 currently only validated)
36 -  compute\_api\_version (Nova version 2 currently only validated)
37 -  heat\_api\_version (Heat version 1 currently only validated)
38 -  volume\_api\_version (default = 2, Heat versions 2 & 3 currently only validated)
39 -  user\_domain\_id (default='default')
40 -  user\_domain\_name (default='Default')
41 -  project\_domain\_id (default='default')
42 -  project\_domain\_name (default='Default')
43 -  interface (default='admin', used to specify the endpoint type for keystone: public, admin, internal)
44 -  cacert (default=False, expected values T|F to denote server certificate verification, else value contains the path to an HTTPS certificate)
45 -  region_name (The region name default=None)
46 -  proxy\_settings
47
48    -  host (the HTTP proxy host)
49    -  port (the HTTP proxy port)
50    -  https\_host (the HTTPS proxy host, default value of host)
51    -  https\_port (the HTTPS proxy port, default value of port)
52    -  ssh\_proxy\_cmd (same as the value placed into ssh -o
53       ProxyCommand='<this config value>')
54
55 Create OS Credentials Object
56 ----------------------------
57
58 .. code:: python
59
60     from snaps.openstack.os_credentials import OSCreds
61     os_creds=OSCreds(username='admin', password='admin',
62                      auth_url='http://localhost:5000/v3', project_name='admin',
63                      identity_api_version=3)
64
65 SNAPS Object Creators
66 =====================
67
68 Each creator minimally requires an OSCreds object for connecting to the
69 NFVI, associated \*Settings object for instance configuration, create()
70 method to make the necessary remote API calls and create all of the
71 necessary OpenStack instances required, and clean() method that is
72 responsible for deleting all associated OpenStack instances. Please see
73 the class diagram `here </display/SNAP/SNAPS-OO+Classes>`__. Below is a
74 textual representation of the requirements of each creator classes with
75 their associated setting classes and a sample code snippet on how to use
76 the code.
77
78 Create User
79 -----------
80 -  User - snaps.openstack.create\_user.OpenStackUser
81
82    -  snaps.openstack.create\_user.UserSettings
83
84       -  name - the username (required)
85       -  password - the user's password (required)
86       -  project\_name - the name of the project to associated to this
87          user (optional)
88       -  domain\_name - the user's domain (default='default')
89       -  email - the user's email address (optional)
90       -  enabled - flag to determine whether or not the user should be
91          enabled (default=True)
92       -  roles - dict where key is the role's name and value is the name
93          the project to associate with the role (optional)
94
95 .. code:: python
96
97     from snaps.openstack.create_user import UserSettings, OpenStackUser
98     user_settings = UserSettings(name='username', password='password')
99     user_creator = OpenStackUser(os_creds, user_settings)
100     user_creator.create()
101
102     # Retrieve OS creds for new user for creating other OpenStack instance
103     user_creds = user_creator.get_os_creds(os_creds.project_name)
104
105     # Perform logic
106     ...
107
108     # Cleanup
109     user_creator.clean()
110
111 Create Project
112 --------------
113 -  Project - snaps.openstack.create\_project.OpenStackProject
114
115    -  snaps.openstack.create\_project.ProjectSettings
116
117       -  name - the project name (required)
118       -  domain - the project's domain (default='default')
119       -  description - the project's description (optional)
120       -  enabled - flag to determine whether or not the project should
121          be enabled (default=True)
122
123
124 .. code:: python
125
126     from snaps.openstack.create_project import ProjectSettings, OpenStackProject
127     project_settings = ProjectSettings(name='username', password='password')
128     project_creator = OpenStackProject(os_creds, project_settings)
129     project_creator.create()
130
131     # Perform logic
132     ...
133
134     # Cleanup
135     project_creator.clean()
136
137 Create Flavor
138 -------------
139 -  Flavor - snaps.openstack.create\_flavor.OpenStackFlavor
140
141    -  snaps.openstack.create\_flavor.FlavorSettings
142
143       -  name - the flavor name (required)
144       -  flavor\_id - the flavor's string ID (default='auto')
145       -  ram - memory in MB to allocate to VM (required)
146       -  disk - disk storage in GB (required)
147       -  vcpus - the number of CPUs to allocate to VM (required)
148       -  ephemeral - the size of the ephemeral disk in GB (default=0)
149       -  swap - the size of the swap disk in GB (default=0)
150       -  rxtx\_factor - the receive/transmit factor to be set on ports
151          if backend supports QoS extension (default=1.0)
152       -  is\_public - flag that denotes whether or not other projects
153          can access image (default=True)
154       -  metadata - freeform dict() for special metadata (optional)
155
156 .. code:: python
157
158     from snaps.openstack.create_flavor import FlavorSettings, OpenStackFlavor
159     flavor_settings = FlavorSettings(name='flavor-name', ram=4, disk=10, vcpus=2)
160     flavor_creator = OpenStackFlavor(os_creds, flavor_settings)
161     flavor_creator.create()
162
163     # Perform logic
164     ...
165
166     # Cleanup
167     flavor_creator.clean()
168
169 Create Image
170 ------------
171 -  Image - snaps.openstack.create\_image.OpenStackImage
172
173    -  snaps.openstack.create\_image.ImageSettings
174
175       -  name - the image name (required)
176       -  image\_user - the default image user generally used by
177          OpenStackVMInstance class for obtaining an SSH connection
178          (required)
179       -  img\_format or format - the image's format (i.e. qcow2) (required)
180       -  url - the download URL to obtain the image file (this or
181          image\_file must be configured, not both)
182       -  image\_file - the location of the file to be sourced from the
183          local filesystem (this or url must be configured, not both)
184       -  extra\_properties - dict() object containing extra parameters to
185          pass when loading the image (i.e. ids of kernel and initramfs images)
186       -  nic\_config\_pb\_loc - the location of the ansible playbook
187          that can configure additional NICs. Floating IPs are required
188          to perform this operation. (optional and deprecated)
189       -  kernel\_image\_settings - the image settings for a kernel image (optional)
190       -  ramdisk\_image\_settings - the image settings for a ramdisk image (optional)
191       -  public - image will be created with public visibility when True (default = False)
192
193
194 .. code:: python
195
196     from snaps.openstack.create_image import ImageSettings, OpenStackImage
197     image_settings = ImageSettings(name='image-name', image_user='ubuntu', img_format='qcow2',
198                                    url='http://uec-images.ubuntu.com/releases/trusty/14.04/ubuntu-14.04-server-cloudimg-amd64-disk1.img')
199     image_creator = OpenStackImage(os_creds, image_settings)
200     image_creator.create()
201
202     # Perform logic
203     ...
204
205     # Cleanup
206     image_creator.clean()
207
208 Create Keypair
209 --------------
210 -  Keypair - snaps.openstack.create\_keypair.OpenStackKeypair
211
212    -  snaps.openstack.create\_keypair.KeypairSettings
213
214       -  name - the keypair name (required)
215       -  public\_filepath - the file location to where the public key is
216          to be written or currently resides (optional)
217       -  private\_filepath - the file location to where the private key
218          file is to be written or currently resides (optional but highly
219          recommended to leverage or the private key will be lost
220          forever)
221       -  key\_size - The number of bytes for the key size when it needs to
222          be generated (value must be >=512, default = 1024)
223       -  delete\_on\_clean - when True, the key files will be deleted when
224          OpenStackKeypair#clean() is called (default = False)
225
226 .. code:: python
227
228     from snaps.openstack.create_keypairs import KeypairSettings, OpenStackKeypair
229     keypair_settings = KeypairSettings(name='kepair-name', private_filepath='/tmp/priv-kp')
230     keypair_creator = OpenStackKeypair(os_creds, keypair_settings)
231     keypair_creator.create()
232
233     # Perform logic
234     ...
235
236     # Cleanup
237     keypair_creator.clean()
238
239 Create Network
240 --------------
241
242 -  Network - snaps.openstack.create\_network.OpenStackNetwork
243
244    -  snaps.openstack.create\_network.NetworkSettings
245
246       -  name - the name of the network (required)
247       -  admin\_state\_up - flag denoting the administrative status of
248          the network (True = up, False = down)
249       -  shared - flag indicating whether the network can be shared
250          across projects/tenants (default=True)
251       -  project\_name - the name of the project (optional - can only be
252          set by admin users)
253       -  external - flag determining if network has external access
254          (default=False)
255       -  network\_type - the type of network (i.e. vlan\|vxlan\|flat)
256       -  physical\_network - the name of the physical network (required
257          when network\_type is 'flat')
258       -  segmentation\_id - the id of the segmentation (required
259          when network\_type is 'vlan')
260       -  subnet\_settings (list of optional
261          snaps.openstack.create\_network.SubnetSettings objects)
262
263          -  cidr - the subnet's CIDR (required)
264          -  ip\_version - 4 or 6 (default=4)
265          -  name - the subnet name (required)
266          -  project\_name - the name of the project (optional - can only
267             be set by admin users)
268          -  start - the start address for the allocation pools
269          -  end - the end address for the allocation pools
270          -  gateway\_ip - the gateway IP
271          -  enable\_dhcp - flag to determine whether or not to enable
272             DHCP (optional)
273          -  dns\_nameservers - a list of DNS nameservers
274          -  host\_routes - list of host route dictionaries for subnet
275             (optional, see pydoc and Neutron API for more details)
276          -  destination - the destination for static route (optional)
277          -  nexthop - the next hop for the destination (optional)
278          -  ipv6\_ra\_mode - valid values include: 'dhcpv6-stateful',
279             'dhcp6v-stateless', 'slaac' (optional)
280          -  ipvc\_address\_mode - valid values include:
281             'dhcpv6-stateful', 'dhcp6v-stateless', 'slaac' (optional)
282
283 .. code:: python
284
285     from snaps.openstack.create_network import NetworkSettings, SubnetSettings, OpenStackNetwork
286
287     subnet_settings = SubnetSettings(name='subnet-name', cidr='10.0.0.0/24')
288     network_settings = NetworkSettings(name='network-name', subnet_settings=[subnet_settings])
289
290     network_creator = OpenStackNetwork(os_creds, network_settings)
291     network_creator.create()
292
293     # Perform logic
294     ...
295
296     # Cleanup
297     network_creator.clean()
298
299 Create Security Group
300 ---------------------
301
302 -  Security Group -
303    snaps.openstack.create\_security\_group.OpenStackSecurityGroup
304
305    -  snaps.openstack.create\_security\_group.SecurityGroupSettings
306
307       -  name - the security group's name (required)
308       -  description - the description (optional)
309       -  project\_name - the name of the project (optional - can only be
310          set by admin users)
311       -  rule\_settings (list of
312          optional snaps.openstack.create\_security\_group.SecurityGroupRuleSettings
313          objects)
314
315          -  sec\_grp\_name - the name of the associated security group
316             (required)
317          -  description - the description (optional)
318          -  direction - enum
319             snaps.openstack.create\_security\_group.Direction (required)
320          -  remote\_group\_id - the group ID to associate with this rule
321          -  protocol -
322             enum snaps.openstack.create\_security\_group.Protocol
323             (optional)
324          -  ethertype -
325             enum snaps.openstack.create\_security\_group.Ethertype
326             (optional)
327          -  port\_range\_min - the max port number in the range that is
328             matched by the security group rule (optional)
329          -  port\_range\_max - the min port number in the range that is
330             matched by the security group rule (optional)
331          -  sec\_grp\_rule - the rule object to a security group rule
332             object to associate (note: does not work currently)
333          -  remote\_ip\_prefix - the remote IP prefix to associate with
334             this metering rule packet (optional)
335
336 .. code:: python
337
338     from snaps.openstack.create_security_group import SecurityGroupSettings, SecurityGroupRuleSettings, Direction, OpenStackSecurityGroup
339
340     rule_settings = SubnetSettings(name='subnet-name', cidr='10.0.0.0/24')
341     network_settings = NetworkSettings(name='network-name', subnet_settings=[subnet_settings])
342
343     sec_grp_name = 'sec-grp-name'
344     rule_settings = SecurityGroupRuleSettings(name=sec_grp_name, direction=Direction.ingress)
345     security_group_settings = SecurityGroupSettings(name=sec_grp_name, rule_settings=[rule_settings])
346
347     security_group_creator = OpenStackSecurityGroup(os_creds, security_group_settings)
348     security_group_creator.create()
349
350     # Perform logic
351     ...
352
353     # Cleanup
354     security_group_creator.clean()
355
356 Create Router
357 -------------
358
359 -  Router - snaps.openstack.create\_router.OpenStackRouter
360
361    -  snaps.openstack.create\_router.RouterSettings
362
363       -  name - the router name (required)
364       -  project\_name - the name of the project (optional - can only be
365          set by admin users)
366       -  external\_gateway - the name of the external network (optional)
367       -  admin\_state\_up - flag to denote the administrative status of
368          the router (default=True)
369       -  external\_fixed\_ips - dictionary containing the IP address
370          parameters (parameter not tested)
371       -  internal\_subnets - list of subnet names to which this router
372          will connect (optional)
373       -  port\_settings (list of optional
374          snaps.openstack.create\_router.PortSettings objects) - creates
375          custom ports to internal subnets (similar to internal\_subnets
376          with more control)
377
378          -  name - the port's display name
379          -  network\_name - the name of the network on which to create the port
380          -  admin\_state\_up - A boolean value denoting the administrative
381             status of the port (default = True)
382          -  project\_name - the name of the project (optional - can only
383             be set by admin users)
384          -  mac\_address - the port's MAC address to set (optional and
385             recommended not to set this configuration value)
386          -  ip\_addrs - list of dict() objects containing two keys 'subnet_name'
387             and 'ip' where the value of the 'ip' entry is the expected IP
388             address assigned. This value gets mapped to the fixed\_ips
389             attribute (optional)
390          -  fixed\_ips - dict() where the key is the subnet ID and value is the
391             associated IP address to assign to the port (optional)
392          -  security\_groups - list of security group IDs (not tested)
393          -  allowed\_address\_pairs - A dictionary containing a set of zero or
394             more allowed address pairs. An address pair contains an IP address
395             and MAC address (optional)
396          -  opt\_value - the extra DHCP option value (optional)
397          -  opt\_name - the extra DHCP option name (optional)
398          -  device\_owner - The ID of the entity that uses this port.
399             For example, a DHCP agent (optional)
400          -  device\_id - The ID of the device that uses this port.
401             For example, a virtual server (optional)
402
403 .. code:: python
404
405     from snaps.openstack.create_router import RouterSettings, OpenStackRouter
406
407     router_settings = RouterSettings(name='router-name', external_gateway='external')
408     router_creator = OpenStackRouter(os_creds, router_settings)
409     router_creator.create()
410
411     # Perform logic
412     ...
413
414     # Cleanup
415     router_creator.clean()
416
417 Create QoS Spec
418 ---------------
419
420 -  Volume Type - snaps.openstack.create\_qos.OpenStackQoS
421
422    -  snaps.openstack.create\_qos.QoSSettings
423
424       -  name - the volume type's name (required)
425       -  consumer - the qos's consumer type of the enum type Consumer (required)
426       -  specs - freeform dict() to be added as 'specs' (optional)
427
428 .. code:: python
429
430     from snaps.openstack.create_qos import QoSSettings, OpenStackQoS
431
432     qos_settings = QoSSettings(name='stack-name', consumer=Consumer.front-end)
433     qos_creator = OpenStackQoS(os_creds, vol_type_settings)
434     qos_creator.create()
435
436     # Perform logic
437     ...
438
439     # Cleanup
440     qos_creator.clean()
441
442 Create Volume Type
443 ------------------
444
445 -  Volume Type - snaps.openstack.create\_volume\_type.OpenStackVolumeType
446
447    -  snaps.openstack.create\_volume\_type.VolumeTypeSettings
448
449       -  name - the volume type's name (required)
450       -  description - the volume type's description (optional)
451       -  encryption - instance or config for VolumeTypeEncryptionSettings (optional)
452       -  qos\_spec\_name - name of the QoS Spec to associate (optional)
453       -  public - instance or config for VolumeTypeEncryptionSettings (optional)
454
455 .. code:: python
456
457     from snaps.openstack.create_volume_type import VolumeTypeSettings, OpenStackVolumeType
458
459     vol_type_settings = VolumeTypeSettings(name='stack-name')
460     vol_type_creator = OpenStackHeatStack(os_creds, vol_type_settings)
461     vol_type_creator.create()
462
463     # Perform logic
464     ...
465
466     # Cleanup
467     vol_type_creator.clean()
468
469 Create Volume
470 -------------
471
472 -  Volume - snaps.openstack.create\_volume.OpenStackVolume
473
474    -  snaps.openstack.create\_volume.VolumeSettings
475
476       -  name - the volume type's name (required)
477       -  description - the volume type's description (optional)
478       -  size - size of volume in GB (default = 1)
479       -  image_name - when a glance image is used for the image source (optional)
480       -  type\_name - the associated volume's type name (optional)
481       -  availability\_zone - the name of the compute server on which to
482          deploy the volume (optional)
483       -  multi_attach - when true, volume can be attached to more than one
484          server (default = False)
485
486 .. code:: python
487
488     from snaps.openstack.create\_volume import VolumeSettings, OpenStackVolume
489
490     vol_settings = VolumeSettings(name='stack-name')
491     vol_creator = OpenStackVolume(os_creds, vol_settings)
492     vol_creator.create()
493
494     # Perform logic
495     ...
496
497     # Cleanup
498     vol_type_creator.clean()
499
500 Create Heat Stack
501 -----------------
502
503 -  Heat Stack - snaps.openstack.create\_stack.OpenStackHeatStack
504
505    -  snaps.openstack.create\_stack.StackSettings
506
507       -  name - the stack's name (required)
508       -  template - the heat template in dict() format (required when
509          template_path is None)
510       -  template\_path - the location of the heat template file (required
511          when template is None)
512       -  env\_values - dict() of strings for substitution of template
513          default values (optional)
514
515 .. code:: python
516
517     from snaps.openstack.create_stack import StackSettings, OpenStackHeatStack
518
519     stack_settings = StackSettings(name='stack-name', template_path='/tmp/template.yaml')
520     stack_creator = OpenStackHeatStack(os_creds, stack_settings)
521     stack_creator.create()
522
523     # Perform logic
524     ...
525
526     # Cleanup
527     stack_creator.clean()
528
529 Create VM Instance
530 ------------------
531
532 -  VM Instances - snaps.openstack.create\_instance.OpenStackVmInstance
533
534    -  snaps.openstack.create\_instance.VmInstanceSettings
535
536       -  name - the name of the VM (required)
537       -  flavor - the name of the flavor (required)
538       -  port\_settings - list of
539          snaps.openstack.create\_network.PortSettings objects where each
540          denote a NIC (see above in create router section for details)
541          API does not require, but newer NFVIs now require VMs have at
542          least one network
543       -  security\_group\_names - a list of security group names to
544          apply to VM
545       -  floating\_ip\_settings (list of
546          snaps.openstack\_create\_instance.FloatingIpSettings objects)
547
548          -  name - a name to a floating IP for easy lookup 
549          -  port\_name - the name of the VM port on which the floating
550             IP should be applied (required)
551          -  router\_name - the name of the router to the external
552             network (required)
553          -  subnet\_name - the name of the subnet on which to attach the
554             floating IP (optional)
555          -  provisioning - when true, this floating IP will be used for
556             provisioning which will come into play once we are able to
557             get multiple floating IPs working.
558
559       -  sudo\_user - overrides the image\_settings.image\_user value
560          when attempting to connect via SSH
561       -  vm\_boot\_timeout - the number of seconds that the thread will
562          block when querying the VM's status when building (default=900)
563       -  vm\_delete\_timeout - the number of seconds that the thread
564          will block when querying the VM's status when deleting
565          (default=300)
566       -  ssh\_connect\_timeout - the number of seconds that the thread
567          will block when attempting to obtain an SSH connection
568          (default=180)
569       -  availability\_zone - the name of the compute server on which to
570          deploy the VM (optional must be admin)
571       -  userdata - the cloud-init script to execute after VM has been
572          started
573
574    -  image\_settings - see snaps.openstack.create\_image.ImageSettings
575       above (required)
576    -  keypair\_settings - see
577       snaps.openstack.create\_keypairs.KeypairSettings above (optional)
578
579 .. code:: python
580
581     from snaps.openstack.create_instance import VmInstanceSettings, FloatingIpSettings, OpenStackVmInstance
582     from snaps.openstack.create_network import PortSettings
583
584     port_settings = PortSettings(name='port-name', network_name=network_settings.name)
585     floating_ip_settings = FloatingIpSettings(name='fip1', port_name=port_settings.name, router_name=router_settings.name)
586     instance_settings = VmInstanceSettings(name='vm-name', flavor='flavor_settings.name', port_settings=[port_settings],
587                                            floating_ip_settings=[floating_ip_settings])
588
589     instance_creator = OpenStackVmInstance(os_creds, instance_settings, image_settings, kepair_settings)
590     instance_creator.create()
591
592     # Perform logic
593     ...
594     ssh_client = instance_creator.ssh_client()
595     ...
596
597     # Cleanup
598     instance_creator.clean()
599
600 Ansible Provisioning
601 ====================
602
603 Being able to easily create OpenStack instances such as virtual networks
604 and VMs is a good start to the problem of NFV; however, an NFVI is
605 useless unless there is some software performing some function. This is
606 why we added Ansible playbook support to SNAPS-OO which can be located
607 in snaps.provisioning.ansible\_utils#apply\_playbook. See below for a
608 description of that function's parameters:
609
610 -  playbook\_path - the file location of the ansible playbook
611 -  hosts\_inv - a list of hosts/IP addresses to which the playbook will
612    be applied
613 -  host\_user - the user (preferably sudo) to use for applying the
614    playbook
615 -  ssh\_priv\_key\_file\_path - the location to the private key file
616    used for SSH
617 -  variables - a dict() of substitution values for Jinga2 templates
618    leveraged by Ansible
619 -  proxy\_setting - used to extract the SSH proxy command (optional)
620
621 Apply Ansible Playbook Utility
622 ------------------------------
623
624 .. code:: python
625
626     from snaps.provisioning import ansible_utils
627
628     ansible_utils.apply_playbook(playbook_path='provisioning/tests/playbooks/simple_playbook.yml',
629                                  hosts_inv=[ip], host_user=user, ssh_priv_key_file_path=priv_key,
630                                  proxy_setting=self.os_creds.proxy_settings)
631
632 OpenStack Utilities
633 ===================
634
635 For those who do like working procedurally, SNAPS-OO also leverages
636 utilitarian functions for nearly every query or request made to
637 OpenStack. This pattern will make it easier to deal with API version
638 changes as they would all be made in one place. (see keystone\_utils for
639 an example of this pattern as this is the only API where SNAPS is
640 supporting more than one version)
641
642 -  snaps.openstack.utils.keystone\_utils - for calls to the Keystone
643    APIs (support for versions 2 & 3)
644 -  snaps.openstack.utils.glance\_utils - for calls to the Glance APIs
645    (support for versions 1 & 2)
646 -  snaps.openstack.utils.neutron\_utils - for calls to the Neutron APIs
647    (version 2)
648 -  snaps.openstack.utils.nova\_utils - for calls to the Nova APIs (version 2)
649 -  snaps.openstack.utils.heat\_utils - for calls to the Heat APIs (version 1)
650 -  snaps.openstack.utils.cinder\_utils - for calls to the Cinder APIs
651    (support for versions 2 & 3)