def create_volume(self, size, display_name=None, metadata=None): """Creates a new Volume. :param size: Size of volume in GB. (Required) :param display_name: Optional Volume Name. :param metadata: An optional dictionary of values for metadata. """ volume = xml_utils.Element("volume", xmlns=xml_utils.XMLNS_11, size=size) if display_name: volume.add_attr('display_name', display_name) if metadata: _metadata = xml_utils.Element('metadata') volume.append(_metadata) for key, value in metadata.items(): meta = xml_utils.Element('meta') meta.add_attr('key', key) meta.append(xml_utils.Text(value)) _metadata.append(meta) resp, body = self.post('os-volumes', str(xml_utils.Document(volume))) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def shutdown_host(self, hostname): """Shutdown a host.""" resp, body = self.get("os-hosts/%s/shutdown" % str(hostname)) node = etree.fromstring(body) body = [xml_utils.xml_to_json(x) for x in node.getchildren()] return resp, body
def show_host_detail(self, hostname): """Show detail information for the host.""" resp, body = self.get("os-hosts/%s" % str(hostname)) node = etree.fromstring(body) body = [xml_utils.xml_to_json(node)] return resp, body
def update_server(self, server_id, name=None, meta=None, accessIPv4=None, accessIPv6=None, disk_config=None): doc = xml_utils.Document() server = xml_utils.Element("server") doc.append(server) if name is not None: server.add_attr("name", name) if accessIPv4 is not None: server.add_attr("accessIPv4", accessIPv4) if accessIPv6 is not None: server.add_attr("accessIPv6", accessIPv6) if disk_config is not None: server.add_attr('xmlns:OS-DCF', "http://docs.openstack.org/" "compute/ext/disk_config/api/v1.1") server.add_attr("OS-DCF:diskConfig", disk_config) if meta is not None: metadata = xml_utils.Element("metadata") server.append(metadata) for k, v in meta: meta = xml_utils.Element("meta", key=k) meta.append(xml_utils.Text(v)) metadata.append(meta) resp, body = self.put('servers/%s' % str(server_id), str(doc)) return resp, xml_utils.xml_to_json(etree.fromstring(body))
def reboot_host(self, hostname): """Reboot a host.""" resp, body = self.get("os-hosts/%s/reboot" % str(hostname)) node = etree.fromstring(body) body = [xml_utils.xml_to_json(x) for x in node.getchildren()] return resp, body
def update_image_metadata_item(self, image_id, key, meta): """Sets the value for a specific image metadata key.""" post_body = xml_utils.Document('meta', xml_utils.Text(meta), key=key) resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key), post_body) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body['meta']
def get_snapshot(self, snapshot_id): """Returns the details of a single snapshot.""" url = "snapshots/%s" % str(snapshot_id) resp, body = self.get(url) body = etree.fromstring(body) self.expected_success(200, resp.status) return resp, common.xml_to_json(body)
def create_volume(self, size, **kwargs): """Creates a new Volume. :param size: Size of volume in GB. (Required) :param display_name: Optional Volume Name. :param metadata: An optional dictionary of values for metadata. :param volume_type: Optional Name of volume_type for the volume :param snapshot_id: When specified the volume is created from this snapshot :param imageRef: When specified the volume is created from this image """ # NOTE(afazekas): it should use a volume namespace volume = common.Element("volume", xmlns=common.XMLNS_11, size=size) if "metadata" in kwargs: _metadata = common.Element("metadata") volume.append(_metadata) for key, value in kwargs["metadata"].items(): meta = common.Element("meta") meta.add_attr("key", key) meta.append(common.Text(value)) _metadata.append(meta) attr_to_add = kwargs.copy() del attr_to_add["metadata"] else: attr_to_add = kwargs for key, value in attr_to_add.items(): volume.add_attr(key, value) resp, body = self.post("volumes", str(common.Document(volume))) body = common.xml_to_json(etree.fromstring(body)) return resp, body
def _parse_image(self, node): """Parses detailed XML image information into dictionary.""" data = xml_utils.xml_to_json(node) self._parse_links(node, data) # parse all metadata if 'metadata' in data: tag = node.find('{%s}metadata' % xml_utils.XMLNS_11) data['metadata'] = dict((x.get('key'), x.text) for x in tag.getchildren()) # parse server information if 'server' in data: tag = node.find('{%s}server' % xml_utils.XMLNS_11) data['server'] = self._parse_server(tag) # parse extended attributes diskConfig = ('{http://docs.openstack.org' '/compute/ext/disk_config/api/v1.1}diskConfig') image_size = ('{http://docs.openstack.org' '/compute/ext/image_size/api/v1.1}size') if diskConfig in data: data['OS-DCF:diskConfig'] = data.pop(diskConfig) if image_size in data: data['OS-EXT-IMG-SIZE:size'] = data.pop(image_size) return data
def create_volume_type(self, name, **kwargs): """ Creates a new Volume_type. name(Required): Name of volume_type. Following optional keyword arguments are accepted: extra_specs: A dictionary of values to be used as extra_specs. """ vol_type = common.Element("volume_type", xmlns=common.XMLNS_11) if name: vol_type.add_attr("name", name) extra_specs = kwargs.get("extra_specs") if extra_specs: _extra_specs = common.Element("extra_specs") vol_type.append(_extra_specs) for key, value in extra_specs.items(): spec = common.Element("extra_spec") spec.add_attr("key", key) spec.append(common.Text(value)) _extra_specs.append(spec) resp, body = self.post("types", str(common.Document(vol_type))) body = common.xml_to_json(etree.fromstring(body)) self.expected_success(200, resp.status) return resp, body
def update_volume(self, volume_id, **kwargs): """Updates the Specified Volume.""" put_body = common.Element("volume", xmlns=common.XMLNS_11, **kwargs) resp, body = self.put("volumes/%s" % volume_id, str(common.Document(put_body))) body = common.xml_to_json(etree.fromstring(body)) return resp, body
def get_volume_transfer(self, transfer_id): """Returns the details of a volume transfer.""" url = "os-volume-transfer/%s" % str(transfer_id) resp, body = self.get(url) volume = common.xml_to_json(etree.fromstring(body)) self.expected_success(200, resp.status) return resp, volume
def upload_volume(self, volume_id, image_name, disk_format): """Uploads a volume in Glance.""" post_body = common.Element("os-volume_upload_image", image_name=image_name, disk_format=disk_format) url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) volume = common.xml_to_json(etree.fromstring(body)) return resp, volume
def accept_volume_transfer(self, transfer_id, transfer_auth_key): """Accept a volume transfer.""" post_body = common.Element("accept", auth_key=transfer_auth_key) url = "os-volume-transfer/%s/accept" % transfer_id resp, body = self.post(url, str(common.Document(post_body))) volume = common.xml_to_json(etree.fromstring(body)) return resp, volume
def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs): """Creates a new flavor or instance type.""" flavor = xml_utils.Element("flavor", xmlns=xml_utils.XMLNS_11, ram=ram, vcpus=vcpus, disk=disk, id=flavor_id, name=name) if kwargs.get('rxtx'): flavor.add_attr('rxtx_factor', kwargs.get('rxtx')) if kwargs.get('swap'): flavor.add_attr('swap', kwargs.get('swap')) if kwargs.get('ephemeral'): flavor.add_attr('OS-FLV-EXT-DATA:ephemeral', kwargs.get('ephemeral')) if kwargs.get('is_public'): flavor.add_attr('os-flavor-access:is_public', kwargs.get('is_public')) flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA) flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS) resp, body = self.post('flavors', str(xml_utils.Document(flavor))) body = xml_utils.xml_to_json(etree.fromstring(body)) flavor = self._format_flavor(body) return resp, flavor
def _parse_array(self, node): array = [] for child in node.getchildren(): tag_list = child.tag.split('}', 1) if tag_list[1] == "endpoint": array.append(common.xml_to_json(child)) return array
def update_quota_set(self, tenant_id, force=None, injected_file_content_bytes=None, metadata_items=None, ram=None, floating_ips=None, fixed_ips=None, key_pairs=None, instances=None, security_group_rules=None, injected_files=None, cores=None, injected_file_path_bytes=None, security_groups=None): """ Updates the tenant's quota limits for one or more resources """ post_body = xml_utils.Element("quota_set", xmlns=xml_utils.XMLNS_11) if force is not None: post_body.add_attr('force', force) if injected_file_content_bytes is not None: post_body.add_attr('injected_file_content_bytes', injected_file_content_bytes) if metadata_items is not None: post_body.add_attr('metadata_items', metadata_items) if ram is not None: post_body.add_attr('ram', ram) if floating_ips is not None: post_body.add_attr('floating_ips', floating_ips) if fixed_ips is not None: post_body.add_attr('fixed_ips', fixed_ips) if key_pairs is not None: post_body.add_attr('key_pairs', key_pairs) if instances is not None: post_body.add_attr('instances', instances) if security_group_rules is not None: post_body.add_attr('security_group_rules', security_group_rules) if injected_files is not None: post_body.add_attr('injected_files', injected_files) if cores is not None: post_body.add_attr('cores', cores) if injected_file_path_bytes is not None: post_body.add_attr('injected_file_path_bytes', injected_file_path_bytes) if security_groups is not None: post_body.add_attr('security_groups', security_groups) resp, body = self.put('os-quota-sets/%s' % str(tenant_id), str(xml_utils.Document(post_body))) body = xml_utils.xml_to_json(etree.fromstring(body)) body = self._format_quota(body) return resp, body
def action(self, server_id, action_name, response_key, **kwargs): if 'xmlns' not in kwargs: kwargs['xmlns'] = xml_utils.XMLNS_11 doc = xml_utils.Document((xml_utils.Element(action_name, **kwargs))) resp, body = self.post("servers/%s/action" % server_id, str(doc)) if response_key is not None: body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def _parse_volume_transfer(self, body): vol = dict((attr, body.get(attr)) for attr in body.keys()) for child in body.getchildren(): tag = child.tag if tag.startswith("{"): tag = tag.split("}", 1) vol[tag] = common.xml_to_json(child) return vol
def force_delete_volume(self, volume_id): """Force Delete Volume.""" post_body = common.Element("os-force_delete") url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def update_volume_readonly(self, volume_id, readonly): """Update the Specified Volume readonly.""" post_body = common.Element("os-update_readonly_flag", readonly=readonly) url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def reset_volume_status(self, volume_id, status): """Reset the Specified Volume's Status.""" post_body = common.Element("os-reset_status", status=status) url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def unreserve_volume(self, volume_id): """Restore a reserved volume .""" post_body = common.Element("os-unreserve") url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def volume_roll_detaching(self, volume_id): """Volume Roll Detaching.""" post_body = common.Element("os-roll_detaching") url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def create_volume_transfer(self, vol_id, display_name=None): """Create a volume transfer.""" post_body = common.Element("transfer", volume_id=vol_id) if display_name: post_body.add_attr("name", display_name) resp, body = self.post("os-volume-transfer", str(common.Document(post_body))) volume = common.xml_to_json(etree.fromstring(body)) return resp, volume
def attach_volume(self, volume_id, instance_uuid, mountpoint): """Attaches a volume to a given instance on a given mountpoint.""" post_body = common.Element("os-attach", instance_uuid=instance_uuid, mountpoint=mountpoint) url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def detach_volume(self, volume_id): """Detaches a volume from an instance.""" post_body = common.Element("os-detach") url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def extend_volume(self, volume_id, extend_size): """Extend a volume.""" post_body = common.Element("os-extend", new_size=extend_size) url = "volumes/%s/action" % str(volume_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def update_snapshot(self, snapshot_id, **kwargs): """Updates a snapshot.""" put_body = common.Element("snapshot", xmlns=common.XMLNS_11, **kwargs) resp, body = self.put('snapshots/%s' % snapshot_id, str(common.Document(put_body))) body = common.xml_to_json(etree.fromstring(body)) return resp, body
def force_delete_snapshot(self, snapshot_id): """Force Delete Snapshot.""" post_body = common.Element("os-force_delete") url = 'snapshots/%s/action' % str(snapshot_id) resp, body = self.post(url, str(common.Document(post_body))) if body: body = common.xml_to_json(etree.fromstring(body)) return resp, body
def get_keypair(self, key_name): resp, body = self.get("os-keypairs/%s" % str(key_name)) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def update_quota_set(self, tenant_id, user_id=None, force=None, injected_file_content_bytes=None, metadata_items=None, ram=None, floating_ips=None, fixed_ips=None, key_pairs=None, instances=None, security_group_rules=None, injected_files=None, cores=None, injected_file_path_bytes=None, security_groups=None): """ Updates the tenant's quota limits for one or more resources """ post_body = xml_utils.Element("quota_set", xmlns=xml_utils.XMLNS_11) if force is not None: post_body.add_attr('force', force) if injected_file_content_bytes is not None: post_body.add_attr('injected_file_content_bytes', injected_file_content_bytes) if metadata_items is not None: post_body.add_attr('metadata_items', metadata_items) if ram is not None: post_body.add_attr('ram', ram) if floating_ips is not None: post_body.add_attr('floating_ips', floating_ips) if fixed_ips is not None: post_body.add_attr('fixed_ips', fixed_ips) if key_pairs is not None: post_body.add_attr('key_pairs', key_pairs) if instances is not None: post_body.add_attr('instances', instances) if security_group_rules is not None: post_body.add_attr('security_group_rules', security_group_rules) if injected_files is not None: post_body.add_attr('injected_files', injected_files) if cores is not None: post_body.add_attr('cores', cores) if injected_file_path_bytes is not None: post_body.add_attr('injected_file_path_bytes', injected_file_path_bytes) if security_groups is not None: post_body.add_attr('security_groups', security_groups) if user_id: resp, body = self.put( 'os-quota-sets/%s?user_id=%s' % (str(tenant_id), str(user_id)), str(xml_utils.Document(post_body))) else: resp, body = self.put('os-quota-sets/%s' % str(tenant_id), str(xml_utils.Document(post_body))) body = xml_utils.xml_to_json(etree.fromstring(body)) body = format_quota(body) return resp, body
def get_flavor_extra_spec(self, flavor_id): """Gets extra Specs of the mentioned flavor.""" resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def _parse_array(self, node): return [self._format_flavor(xml_utils.xml_to_json(x)) for x in node]
def _parse_body(self, body): _json = common.xml_to_json(body) return _json
def get_volume_transfer(self, transfer_id): """Returns the details of a volume transfer.""" url = "os-volume-transfer/%s" % str(transfer_id) resp, body = self.get(url) volume = common.xml_to_json(etree.fromstring(body)) return resp, volume
def get_password(self, server_id): resp, body = self.get("servers/%s/os-server-password" % str(server_id)) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def get_server_metadata_item(self, server_id, key): resp, body = self.get("servers/%s/metadata/%s" % (str(server_id), key)) return resp, dict([(etree.fromstring(body).attrib['key'], xml_utils.xml_to_json(etree.fromstring(body)))])
def get_server_diagnostics(self, server_id): """Get the usage data for a server.""" resp, body = self.get("servers/%s/diagnostics" % server_id) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def get_instance_action(self, server_id, request_id): """Returns the action details of the provided server.""" resp, body = self.get("servers/%s/os-instance-actions/%s" % (server_id, request_id)) body = xml_utils.xml_to_json(etree.fromstring(body)) return resp, body
def _process_xml_interface(self, node): iface = xml_utils.xml_to_json(node) # NOTE(danms): if multiple addresses per interface is ever required, # xml_utils.xml_to_json will need to be fixed or replaced in this case iface['fixed_ips'] = [dict(iface['fixed_ips']['fixed_ip'].items())] return iface
def get_snapshot(self, snapshot_id): """Returns the details of a single snapshot.""" url = "snapshots/%s" % str(snapshot_id) resp, body = self.get(url) body = etree.fromstring(body) return resp, common.xml_to_json(body)
def _translate_server_xml_to_json(xml_dom): """Convert server XML to server JSON. The addresses collection does not convert well by the dumb xml_to_json. This method does some pre and post-processing to deal with that. Translate XML addresses subtree to JSON. Having xml_doc similar to <api:server xmlns:api="http://docs.openstack.org/compute/api/v1.1"> <api:addresses> <api:network id="foo_novanetwork"> <api:ip version="4" addr="192.168.0.4"/> </api:network> <api:network id="bar_novanetwork"> <api:ip version="4" addr="10.1.0.4"/> <api:ip version="6" addr="2001:0:0:1:2:3:4:5"/> </api:network> </api:addresses> </api:server> the _translate_server_xml_to_json(etree.fromstring(xml_doc)) should produce something like {'addresses': {'bar_novanetwork': [{'addr': '10.1.0.4', 'version': 4}, {'addr': '2001:0:0:1:2:3:4:5', 'version': 6}], 'foo_novanetwork': [{'addr': '192.168.0.4', 'version': 4}]}} """ nsmap = {'api': xml_utils.XMLNS_11} addresses = xml_dom.xpath('/api:server/api:addresses', namespaces=nsmap) if addresses: if len(addresses) > 1: raise ValueError('Expected only single `addresses` element.') json_addresses = _translate_addresses_xml_to_json(addresses[0]) json = xml_utils.xml_to_json(xml_dom) json['addresses'] = json_addresses else: json = xml_utils.xml_to_json(xml_dom) diskConfig = ('{http://docs.openstack.org' '/compute/ext/disk_config/api/v1.1}diskConfig') terminated_at = ('{http://docs.openstack.org/' 'compute/ext/server_usage/api/v1.1}terminated_at') launched_at = ('{http://docs.openstack.org' '/compute/ext/server_usage/api/v1.1}launched_at') power_state = ('{http://docs.openstack.org' '/compute/ext/extended_status/api/v1.1}power_state') availability_zone = ('{http://docs.openstack.org' '/compute/ext/extended_availability_zone/api/v2}' 'availability_zone') vm_state = ('{http://docs.openstack.org' '/compute/ext/extended_status/api/v1.1}vm_state') task_state = ('{http://docs.openstack.org' '/compute/ext/extended_status/api/v1.1}task_state') if 'tenantId' in json: json['tenant_id'] = json.pop('tenantId') if 'userId' in json: json['user_id'] = json.pop('userId') if diskConfig in json: json['OS-DCF:diskConfig'] = json.pop(diskConfig) if terminated_at in json: json['OS-SRV-USG:terminated_at'] = json.pop(terminated_at) if launched_at in json: json['OS-SRV-USG:launched_at'] = json.pop(launched_at) if power_state in json: json['OS-EXT-STS:power_state'] = json.pop(power_state) if availability_zone in json: json['OS-EXT-AZ:availability_zone'] = json.pop(availability_zone) if vm_state in json: json['OS-EXT-STS:vm_state'] = json.pop(vm_state) if task_state in json: json['OS-EXT-STS:task_state'] = json.pop(task_state) return json
def _parse_array(self, node): return [xml_utils.xml_to_json(x) for x in node]
def _parse_server(self, node): data = xml_utils.xml_to_json(node) return self._parse_links(node, data)
def _parse_body(self, body): data = common.xml_to_json(body) return data
def _parse_array(self, node): array = [] for child in node.getchildren(): array.append(common.xml_to_json(child)) return array
def _parse_links(self, node, json): del json['link'] json['links'] = [] for linknode in node.findall('{http://www.w3.org/2005/Atom}link'): json['links'].append(xml_utils.xml_to_json(linknode))
def get_flavor_details(self, flavor_id): resp, body = self.get("flavors/%s" % str(flavor_id)) body = xml_utils.xml_to_json(etree.fromstring(body)) flavor = self._format_flavor(body) return resp, flavor
def _parse_body(self, body): json = xml_utils.xml_to_json(body) return json
def _parse_floating_ip(self, body): json = xml_utils.xml_to_json(body) return json