def update_enabled(self, user, enabled): """ Update enabled-ness """ params = {"user": {"id": base.getid(user), "enabled": enabled}} self._update("/users/%s/enabled" % base.getid(user), params)
def test_getid(self): self.assertEqual(base.getid(4), 4) class TmpObject(object): id = 4 self.assertEqual(base.getid(TmpObject), 4)
def update_password(self, user, password): """ Update password """ params = {"user": {"id": base.getid(user), "password": password}} self._update("/users/%s/password" % base.getid(user), params)
def update_email(self, user, email): """ Update email """ # FIXME(ja): why do we have to send id in params and url? params = {"user": {"id": base.getid(user), "email": email}} self._update("/users/%s" % base.getid(user), params)
def update_tenant(self, user, tenant): """ Update default tenant. """ params = {"user": {"id": base.getid(user), "tenantId": base.getid(tenant)}} # FIXME(ja): seems like a bad url - default tenant is an attribute # not a subresource!??? self._update("/users/%s/tenant" % base.getid(user), params)
def update_tenant(self, user, tenant): """ Update default tenant. """ params = { "user": { "id": base.getid(user), "tenantId": base.getid(tenant) } } # FIXME(ja): seems like a bad url - default tenant is an attribute # not a subresource!??? self._update("/users/%s/tenant" % base.getid(user), params)
def delete(self, floating_ip): """ Delete (deallocate) a floating ip for a tenant :param key: The :class:`Keypair` (or its ID) to delete. """ self._delete("/os-floating-ips/%s" % base.getid(floating_ip))
def delete(self, snapshot): """ Delete a snapshot. :param snapshot: The :class:`Snapshot` to delete. """ self._delete("/os-snapshots/%s" % base.getid(snapshot))
def delete(self, key): """ Delete a keypair :param key: The :class:`Keypair` (or its ID) to delete. """ self._delete('/os-keypairs/%s' % (base.getid(key)))
def update(self, zone, api_url=None, username=None, password=None, weight_offset=None, weight_scale=None): """ Update the name or the api_url for a zone. :param zone: The :class:`Zone` (or its ID) to update. :param api_url: Update the API URL. :param username: Update the username. :param password: Update the password. :param weight_offset: Update the child zone's weight offset. :param weight_scale: Update the child zone's weight scale. """ body = {"zone": {}} if api_url: body["zone"]["api_url"] = api_url if username: body["zone"]["username"] = username if password: body["zone"]["password"] = password if weight_offset: body["zone"]["weight_offset"] = weight_offset if weight_scale: body["zone"]["weight_scale"] = weight_scale if not len(body["zone"]): return self._update("/zones/%s" % base.getid(zone), body)
def migrate(self, server): """ Migrate a server to a new host in the same zone. :param server: The :class:`Server` (or its ID). """ self.api.client.post('/servers/%s/migrate' % base.getid(server))
def delete(self, rule): """ Delete a security group rule :param rule: The security group rule to delete (ID or Class) """ self._delete('/os-security-group-rules/%s' % base.getid(rule))
def delete(self, volume): """ Delete a volume. :param volume: The :class:`Volume` to delete. """ self._delete("/os-volumes/%s" % base.getid(volume))
def get(self, server): """ Get a server. :param server: ID of the :class:`Server` to get. :rtype: :class:`Server` """ return self._get("/servers/%s" % base.getid(server), "server")
def delete_meta(self, server, keys): """ Delete metadata from an server :param server: The :class:`Server` to add metadata to :param keys: A list of metadata keys to delete from the server """ for k in keys: self._delete("/servers/%s/metadata/%s" % (base.getid(server), k))
def get(self, zone): """ Get a child zone. :param server: ID of the :class:`Zone` to get. :rtype: :class:`Zone` """ return self._get("/zones/%s" % base.getid(zone), "zone")
def get(self, flavor): """ Get a specific flavor. :param flavor: The ID of the :class:`Flavor` to get. :rtype: :class:`Flavor` """ return self._get("/flavors/%s" % base.getid(flavor), "flavor")
def delete(self, group): """ Delete a security group :param group: The security group to delete (group or ID) :rtype: None """ self._delete('/os-security-groups/%s' % base.getid(group))
def get(self, image): """ Get an image. :param image: The ID of the image to get. :rtype: :class:`Image` """ return self._get("/images/%s" % base.getid(image), "image")
def set_meta(self, server, metadata): """ Set a servers metadata :param server: The :class:`Server` to add metadata to :param metadata: A dict of metadata to add to the server """ body = {'metadata': metadata} return self._create("/servers/%s/metadata" % base.getid(server), body, "metadata")
def delete_meta(self, image, keys): """ Delete metadata from an image :param image: The :class:`Image` to add metadata to :param keys: A list of metadata keys to delete from the image """ for k in keys: self._delete("/images/%s/metadata/%s" % (base.getid(image), k))
def delete(self, image): """ Delete an image. It should go without saying that you can't delete an image that you didn't create. :param image: The :class:`Image` (or its ID) to delete. """ self._delete("/images/%s" % base.getid(image))
def set_meta(self, image, metadata): """ Set an images metadata :param image: The :class:`Image` to add metadata to :param metadata: A dict of metadata to add to the image """ body = {'metadata': metadata} return self._create("/images/%s/metadata" % base.getid(image), body, "metadata")
def rebuild(self, server, image, password=None): """ Rebuild -- shut down and then re-image -- a server. :param server: The :class:`Server` (or its ID) to share onto. :param image: the :class:`Image` (or its ID) to re-image with. :param password: string to set as password on the rebuilt server. """ body = {'imageRef': base.getid(image)} if password is not None: body['adminPass'] = password resp, body = self._action('rebuild', server, body) return Server(self, body['server'])
def resize(self, server, flavor): """ Resize a server's resources. :param server: The :class:`Server` (or its ID) to share onto. :param flavor: the :class:`Flavor` (or its ID) to resize to. Until a resize event is confirmed with :meth:`confirm_resize`, the old server will be kept around and you'll be able to roll back to the old flavor quickly with :meth:`revert_resize`. All resizes are automatically confirmed after 24 hours. """ self._action('resize', server, {'flavorRef': base.getid(flavor)})
def update(self, server, name=None): """ Update the name or the password for a server. :param server: The :class:`Server` (or its ID) to update. :param name: Update the server's name. """ if name is None: return body = { "server": { "name": name, }, } self._update("/servers/%s" % base.getid(server), body)
def delete(self, tenant): """ Delete a tenant. """ self._delete("/tenants/%s" % (base.getid(tenant)))
def _action(self, action, server, info=None): """ Perform a server "action" -- reboot/rebuild/resize/etc. """ url = '/servers/%s/action' % base.getid(server) return self.api.client.post(url, body={action: info})
def get(self, user): return self._get("/users/%s" % base.getid(user), "user")
def delete(self, server): """ Delete (i.e. shut down and delete the image) this server. """ self._delete("/servers/%s" % base.getid(server))
def diagnostics(self, server): """Retrieve server diagnostics.""" return self.api.client.get("/servers/%s/diagnostics" % base.getid(server))
def actions(self, server): """Retrieve server actions.""" return self._list("/servers/%s/actions" % base.getid(server), "actions")
def delete(self, user): """ Delete a user. """ self._delete("/users/%s" % base.getid(user))
def add_user(self, user): self.manager.add_user_to_tenant(self.id, base.getid(user))
def _boot(self, resource_url, response_key, name, image, flavor, meta=None, files=None, zone_blob=None, userdata=None, reservation_id=None, return_raw=False, min_count=None, max_count=None, security_groups=None, key_name=None, availability_zone=None, block_device_mapping=None, nics=None, **kwargs): """ Create (boot) a new server. :param name: Something to name the server. :param image: The :class:`Image` to boot with. :param flavor: The :class:`Flavor` to boot onto. :param meta: A dict of arbitrary key/value metadata to store for this server. A maximum of five entries is allowed, and both keys and values must be 255 characters or less. :param files: A dict of files to overrwrite on the server upon boot. Keys are file names (i.e. ``/etc/passwd``) and values are the file contents (either as a string or as a file-like object). A maximum of five entries is allowed, and each file must be 10k or less. :param zone_blob: a single (encrypted) string which is used internally by Engine for routing between Zones. Users cannot populate this field. :param reservation_id: a UUID for the set of servers being requested. :param return_raw: If True, don't try to coearse the result into a Resource object. :param security_groups: list of security group names :param key_name: (optional extension) name of keypair to inject into the instance :param availability_zone: The :class:`Zone`. :param block_device_mapping: A dict of block device mappings for this server. :param nics: (optional extension) an ordered list of nics to be added to this server, with information about connected networks, fixed ips, etc. """ body = {"server": { "name": name, "imageRef": base.getid(image), "flavorRef": base.getid(flavor), }} if userdata: if hasattr(userdata, 'read'): userdata = userdata.read() body["server"]["user_data"] = base64.b64encode(userdata) if meta: body["server"]["metadata"] = meta if reservation_id: body["server"]["reservation_id"] = reservation_id if zone_blob: body["server"]["blob"] = zone_blob if key_name: body["server"]["key_name"] = key_name if not min_count: min_count = 1 if not max_count: max_count = min_count body["server"]["min_count"] = min_count body["server"]["max_count"] = max_count if security_groups: body["server"]["security_groups"] =\ [{'name': sg} for sg in security_groups] # Files are a slight bit tricky. They're passed in a "personality" # list to the POST. Each item is a dict giving a file name and the # base64-encoded contents of the file. We want to allow passing # either an open file *or* some contents as files here. if files: personality = body['server']['personality'] = [] for filepath, file_or_string in files.items(): if hasattr(file_or_string, 'read'): data = file_or_string.read() else: data = file_or_string personality.append({ 'path': filepath, 'contents': data.encode('base64'), }) if availability_zone: body["server"]["availability_zone"] = availability_zone # Block device mappings are passed as a list of dictionaries if block_device_mapping: bdm = body['server']['block_device_mapping'] = [] for device_name, mapping in block_device_mapping.items(): # # The mapping is in the format: # <id>:[<type>]:[<size(GB)>]:[<delete_on_terminate>] # bdm_dict = {'device_name': device_name} mapping_parts = mapping.split(':') id = mapping_parts[0] if len(mapping_parts) == 1: bdm_dict['volume_id'] = id if len(mapping_parts) > 1: type = mapping_parts[1] if type.startswith('snap'): bdm_dict['snapshot_id'] = id else: bdm_dict['volume_id'] = id if len(mapping_parts) > 2: bdm_dict['volume_size'] = mapping_parts[2] if len(mapping_parts) > 3: bdm_dict['delete_on_termination'] = mapping_parts[3] bdm.append(bdm_dict) if nics: all_net_data = [] for nic_info in nics: net_data = {} # if value is empty string, do not send value in body if nic_info['net-id']: net_data['uuid'] = nic_info['net-id'] if nic_info['v4-fixed-ip']: net_data['fixed_ip'] = nic_info['v4-fixed-ip'] all_net_data.append(net_data) body['server']['networks'] = all_net_data return self._create(resource_url, body, response_key, return_raw=return_raw, **kwargs)
def _boot(self, resource_url, response_key, name, image, flavor, meta=None, files=None, zone_blob=None, userdata=None, reservation_id=None, return_raw=False, min_count=None, max_count=None, security_groups=None, key_name=None, availability_zone=None, block_device_mapping=None, nics=None, **kwargs): """ Create (boot) a new server. :param name: Something to name the server. :param image: The :class:`Image` to boot with. :param flavor: The :class:`Flavor` to boot onto. :param meta: A dict of arbitrary key/value metadata to store for this server. A maximum of five entries is allowed, and both keys and values must be 255 characters or less. :param files: A dict of files to overrwrite on the server upon boot. Keys are file names (i.e. ``/etc/passwd``) and values are the file contents (either as a string or as a file-like object). A maximum of five entries is allowed, and each file must be 10k or less. :param zone_blob: a single (encrypted) string which is used internally by Engine for routing between Zones. Users cannot populate this field. :param reservation_id: a UUID for the set of servers being requested. :param return_raw: If True, don't try to coearse the result into a Resource object. :param security_groups: list of security group names :param key_name: (optional extension) name of keypair to inject into the instance :param availability_zone: The :class:`Zone`. :param block_device_mapping: A dict of block device mappings for this server. :param nics: (optional extension) an ordered list of nics to be added to this server, with information about connected networks, fixed ips, etc. """ body = { "server": { "name": name, "imageRef": base.getid(image), "flavorRef": base.getid(flavor), } } if userdata: if hasattr(userdata, 'read'): userdata = userdata.read() body["server"]["user_data"] = base64.b64encode(userdata) if meta: body["server"]["metadata"] = meta if reservation_id: body["server"]["reservation_id"] = reservation_id if zone_blob: body["server"]["blob"] = zone_blob if key_name: body["server"]["key_name"] = key_name if not min_count: min_count = 1 if not max_count: max_count = min_count body["server"]["min_count"] = min_count body["server"]["max_count"] = max_count if security_groups: body["server"]["security_groups"] =\ [{'name': sg} for sg in security_groups] # Files are a slight bit tricky. They're passed in a "personality" # list to the POST. Each item is a dict giving a file name and the # base64-encoded contents of the file. We want to allow passing # either an open file *or* some contents as files here. if files: personality = body['server']['personality'] = [] for filepath, file_or_string in files.items(): if hasattr(file_or_string, 'read'): data = file_or_string.read() else: data = file_or_string personality.append({ 'path': filepath, 'contents': data.encode('base64'), }) if availability_zone: body["server"]["availability_zone"] = availability_zone # Block device mappings are passed as a list of dictionaries if block_device_mapping: bdm = body['server']['block_device_mapping'] = [] for device_name, mapping in block_device_mapping.items(): # # The mapping is in the format: # <id>:[<type>]:[<size(GB)>]:[<delete_on_terminate>] # bdm_dict = {'device_name': device_name} mapping_parts = mapping.split(':') id = mapping_parts[0] if len(mapping_parts) == 1: bdm_dict['volume_id'] = id if len(mapping_parts) > 1: type = mapping_parts[1] if type.startswith('snap'): bdm_dict['snapshot_id'] = id else: bdm_dict['volume_id'] = id if len(mapping_parts) > 2: bdm_dict['volume_size'] = mapping_parts[2] if len(mapping_parts) > 3: bdm_dict['delete_on_termination'] = mapping_parts[3] bdm.append(bdm_dict) if nics: all_net_data = [] for nic_info in nics: net_data = {} # if value is empty string, do not send value in body if nic_info['net-id']: net_data['uuid'] = nic_info['net-id'] if nic_info['v4-fixed-ip']: net_data['fixed_ip'] = nic_info['v4-fixed-ip'] all_net_data.append(net_data) body['server']['networks'] = all_net_data return self._create(resource_url, body, response_key, return_raw=return_raw, **kwargs)