def upload_volume(self, volume_id, image_name, disk_format): """Uploads a volume in Glance.""" post_body = 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(Document(post_body)), self.headers) volume = xml_to_json(etree.fromstring(body)) return resp, volume
def update_volume(self, volume_id, **kwargs): """Updates the Specified Volume.""" put_body = Element("volume", xmlns=XMLNS_11, **kwargs) resp, body = self.put("volumes/%s" % volume_id, str(Document(put_body)), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def _parse_array(self, node): array = [] for child in node.getchildren(): tag_list = child.tag.split('}', 1) if tag_list[1] == "endpoint": array.append(xml_to_json(child)) return array
def create_volume(self, size, **kwargs): """Creates a new Volume. :param size: Size of volume in GB. (Required) :param 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 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 = Element("volume", xmlns=XMLNS_11, size=size) if "metadata" in kwargs: _metadata = Element("metadata") volume.append(_metadata) for key, value in kwargs["metadata"].items(): meta = Element("meta") meta.add_attr("key", key) meta.append(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(Document(volume)), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def update_server(self, server_id, name=None, meta=None, accessIPv4=None, accessIPv6=None, disk_config=None): doc = Document() server = 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 = Element("metadata") server.append(metadata) for k, v in meta: meta = Element("meta", key=k) meta.append(Text(v)) metadata.append(meta) resp, body = self.put('servers/%s' % str(server_id), str(doc)) return resp, xml_to_json(etree.fromstring(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 """ volume = Element("volume", xmlns=XMLNS_11, size=size) if 'metadata' in kwargs: _metadata = Element('metadata') volume.append(_metadata) for key, value in kwargs['metadata'].items(): meta = Element('meta') meta.add_attr('key', key) meta.append(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(Document(volume)), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs): """Creates a new flavor or instance type.""" flavor = Element("flavor", xmlns=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(Document(flavor)), self.headers) body = xml_to_json(etree.fromstring(body)) flavor = self._format_flavor(body) return resp, flavor
def shutdown_host(self, hostname): """Shutdown a host.""" resp, body = self.get("os-hosts/%s/shutdown" % str(hostname)) node = etree.fromstring(body) body = [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 = Document('meta', Text(meta), key=key) resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key), post_body, self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body['meta']
def get_console_output(self, server_id, length): post_body = Element("os-getConsoleOutput", length=length) resp, body = self.post("/servers/%s/action" % server_id, headers=self.headers, body=str(Document(post_body))) body = xml_to_json(etree.fromstring(body)) return resp, 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_to_json(x) for x in node.getchildren()] return resp, body
def set_image_metadata_item(self, image_id, key, meta): """Sets the value for a specific image metadata key""" post_body = json.dumps({'meta': meta}) resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key), post_body, self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body['meta']
def set_image_metadata(self, image_id, meta): """Sets the metadata for an image""" post_body = json.dumps({'metadata': meta}) resp, body = self.put('images/%s/metadata' % str(image_id), post_body, self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body['metadata']
def update_server(self, server_id, name=None, meta=None, access_ip_v4=None, access_ip_v6=None, disk_config=None): doc = Document() server = Element("server") doc.append(server) if name is not None: server.add_attr("name", name) if access_ip_v4 or access_ip_v6: server.add_attr('xmlns:os-access-ips', "http://docs.openstack.org/compute/ext/" "os-access-ips/api/v3") if access_ip_v4 is not None: server.add_attr("os-access-ips:access_ip_v4", access_ip_v4) if access_ip_v6 is not None: server.add_attr("os-access-ips:access_ip_v6", access_ip_v6) if disk_config is not None: server.add_attr('xmlns:os-disk-config', "http://docs.openstack.org" "/compute/ext/disk_config/api/v3") server.add_attr("os-disk-config:disk_config", disk_config) if meta is not None: metadata = Element("metadata") server.append(metadata) for k, v in meta: meta = Element("meta", key=k) meta.append(Text(v)) metadata.append(meta) resp, body = self.put('servers/%s' % str(server_id), str(doc), self.headers) return resp, xml_to_json(etree.fromstring(body))
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 = Element("volume_type", xmlns=XMLNS_11) if name: vol_type.add_attr('name', name) extra_specs = kwargs.get('extra_specs') if extra_specs: _extra_specs = Element('extra_specs') vol_type.append(_extra_specs) for key, value in extra_specs.items(): spec = Element('extra_spec') spec.add_attr('key', key) spec.append(Text(value)) _extra_specs.append(spec) resp, body = self.post('types', str(Document(vol_type)), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
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 = Element("volume", xmlns=XMLNS_11, size=size) if display_name: volume.add_attr('display_name', display_name) if metadata: _metadata = Element('metadata') volume.append(_metadata) for key, value in metadata.items(): meta = Element('meta') meta.add_attr('key', key) meta.append(Text(value)) _metadata.append(meta) resp, body = self.post('os-volumes', str(Document(volume)), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def _parse_creds(self, node): array = [] for child in node.getchildren(): tag_list = child.tag.split('}', 1) if tag_list[1] == "credential": array.append(common.xml_to_json(child)) return array
def accept_volume_transfer(self, transfer_id, transfer_auth_key): """Accept a volume transfer.""" post_body = Element("accept", auth_key=transfer_auth_key) url = 'os-volume-transfer/%s/accept' % transfer_id resp, body = self.post(url, str(Document(post_body))) volume = xml_to_json(etree.fromstring(body)) return resp, volume
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 = Element("quota_set", xmlns=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(Document(post_body)), self.headers) body = xml_to_json(etree.fromstring(body)) body = self._format_quota(body) 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_to_json(node)] return resp, body
def _parse_domains(self, node): array = [] for child in node.getchildren(): tag_list = child.tag.split("}", 1) if tag_list[1] == "domain": array.append(xml_to_json(child)) return array
def show_host_detail(self, hostname): """Show detail information for the host.""" resp, body = self.get("os-hosts/%s" % str(hostname), self.headers) node = etree.fromstring(body) body = [xml_to_json(x) for x in node.getchildren()] return resp, body
def action(self, server_id, action_name, response_key, **kwargs): if 'xmlns' not in kwargs: kwargs['xmlns'] = XMLNS_11 doc = Document((Element(action_name, **kwargs))) resp, body = self.post("servers/%s/action" % server_id, str(doc)) if response_key is not None: body = 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] = xml_to_json(child) return vol
def force_delete_volume(self, volume_id): """Force Delete Volume.""" post_body = Element("os-force_delete") url = 'volumes/%s/action' % str(volume_id) resp, body = self.post(url, str(Document(post_body))) if body: body = xml_to_json(etree.fromstring(body)) return resp, body
def volume_roll_detaching(self, volume_id): """Volume Roll Detaching.""" post_body = Element("os-roll_detaching") url = 'volumes/%s/action' % str(volume_id) resp, body = self.post(url, str(Document(post_body))) if body: body = xml_to_json(etree.fromstring(body)) return resp, body
def get_default_quota_set(self, tenant_id): """List the default quota set for a tenant.""" url = 'os-quota-sets/%s/defaults' % str(tenant_id) resp, body = self.get(url, self.headers) body = xml_to_json(etree.fromstring(body)) body = self._format_quota(body) return resp, body
def detach_volume(self, volume_id): """Detaches a volume from an instance.""" post_body = Element("os-detach") url = 'volumes/%s/action' % str(volume_id) resp, body = self.post(url, str(Document(post_body))) if body: body = xml_to_json(etree.fromstring(body)) return resp, body
def unreserve_volume(self, volume_id): """Restore a reserved volume .""" post_body = Element("os-unreserve") url = 'volumes/%s/action' % str(volume_id) resp, body = self.post(url, str(Document(post_body))) if body: body = xml_to_json(etree.fromstring(body)) return resp, body
def get_hypervisor_stats(self): """Get hypervisor statistics over all compute nodes.""" resp, body = self.get('os-hypervisors/statistics', self.headers) stats = xml_to_json(etree.fromstring(body)) return resp, stats
def get_hypervisor_uptime(self, hyper_id): """Display the uptime of the specified hypervisor.""" resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id, self.headers) uptime = xml_to_json(etree.fromstring(body)) return resp, uptime
def _parse_array(self, node): json = xml_to_json(node) return json
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, self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def _parse_array(self, node): return [self._format_flavor(xml_to_json(x)) for x in node]
def _parse_floating_ip(self, body): json = xml_to_json(body) return json
def get_snapshot(self, snapshot_id): """Returns the details of a single snapshot.""" url = "snapshots/%s" % str(snapshot_id) resp, body = self.get(url, self.headers) body = etree.fromstring(body) return resp, xml_to_json(body)
def _process_xml_interface(self, node): iface = xml_to_json(node) # NOTE(danms): if multiple addresses per interface is ever required, # 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_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 = xml_to_json(etree.fromstring(body)) return resp, volume
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), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
def _parse_body(self, body): data = xml_to_json(body) return data
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 = Element("quota_set", xmlns=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(Document(post_body))) body = xml_to_json(etree.fromstring(body)) body = self._format_quota(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), headers=self.headers) return resp, dict([(etree.fromstring(body).attrib['key'], xml_to_json(etree.fromstring(body)))])
def get_keypair(self, key_name): resp, body = self.get("os-keypairs/%s" % str(key_name)) body = xml_to_json(etree.fromstring(body)) return resp, body
def _parse_server(self, node): data = xml_to_json(node) return self._parse_links(node, data)
def list_keypairs(self): resp, body = self.get("os-keypairs") node = etree.fromstring(body) body = [{'keypair': xml_to_json(x)} for x in node.getchildren()] return resp, body
def _parse_resp(self, body): return xml_to_json(etree.fromstring(body))
def get_hypervisor_show_details(self, hyper_id): """Display the details of the specified hypervisor.""" resp, body = self.get('os-hypervisors/%s' % hyper_id, self.headers) hypervisor = xml_to_json(etree.fromstring(body)) return resp, hypervisor
def _parse_array_access(self, node): return [xml_to_json(x) for x in node]
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': 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_to_json(xml_dom) json['addresses'] = json_addresses else: json = 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 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 get_flavor_details(self, flavor_id): resp, body = self.get("flavors/%s" % str(flavor_id), self.headers) body = xml_to_json(etree.fromstring(body)) flavor = self._format_flavor(body) return resp, flavor
def _parse_server(self, node): json = xml_to_json(node) return self._parse_links(node, json)
def list_image_metadata(self, image_id): """Lists all metadata items for an image""" resp, body = self.get("images/%s/metadata" % str(image_id), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body['metadata']
def get_image_metadata_item(self, image_id, key): """Returns the value for a specific image metadata key""" resp, body = self.get( "images/%s/metadata/%s.xml" % (str(image_id), key), self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body['meta']
def get_server_diagnostics(self, server_id): """Get the usage data for a server.""" resp, body = self.get("servers/%s/diagnostics" % server_id, self.headers) body = xml_to_json(etree.fromstring(body)) return resp, body
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_to_json(linknode))
def _parse_array(self, node): array = [] for child in node.getchildren(): array.append(xml_to_json(child)) return array
def _parse_body(self, body): json = xml_to_json(body) return json
def list_services(self): resp, body = self.get("os-services", self.headers) node = etree.fromstring(body) body = [xml_to_json(x) for x in node.getchildren()] return resp, body