Exemplo n.º 1
0
class Stock(resource2.Resource):
    resource_key = 'stock'
    base_path = '/stock'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_get = True

    # Properties
    #: Flavor UUID of Baremetal server stock search condition.
    flavor_id = resource2.Body('flavor_id', alternate_id=True)
    #: Availability Zone name of Baremetal server stock search condition.
    availability_zone = resource2.Body('availability_zone')
    #: Baremetal server stock is available or not.
    stock = resource2.Body('stock')

    def get(self, session, flavor_id, availability_zone=None):
        uri = self.base_path + "?flavor_id=%s" % flavor_id
        if availability_zone:
            uri += "&availability_zone=%s" % availability_zone
        resp = session.get(uri,
                           endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        self._translate_response(resp, has_body=True)
        return self
Exemplo n.º 2
0
 def test_service(self):
     sot = baremetal_service.BaremetalService()
     self.assertEqual('baremetal-server', sot.service_type)
     self.assertEqual('public', sot.interface)
     self.assertIsNone(sot.region)
     self.assertIsNone(sot.service_name)
     self.assertEqual(1, len(sot.valid_versions))
     self.assertEqual('v2', sot.valid_versions[0].module)
     self.assertEqual('v2', sot.valid_versions[0].path)
Exemplo n.º 3
0
class AvailabilityZone(resource2.Resource):
    resources_key = 'availabilityZoneInfo'
    base_path = '/os-availability-zone'

    service = baremetal_service.BaremetalService()

    # capabilities
    allow_list = True

    # Properties
    #: name of availability zone
    zoneName = resource2.Body('zoneName', alternate_id=True)
    name = resource2.Body('zoneName', alternate_id=True)
    #: state of availability zone
    zoneState = resource2.Body('zoneState')
    state = resource2.Body('zoneState')
    #: hosts of availability zone
    hosts = resource2.Body('hosts')

    @classmethod
    def find(cls, session, name_or_id, ignore_missing=False, **params):
        """Find a resource by its name or id.

        :param session: The session to use for making this request.
        :type session: :class:`~ecl.session.Session`
        :param name_or_id: This resource's identifier, if needed by
                           the request. The default is ``None``.
        :param bool ignore_missing: When set to ``False``
                    :class:`~ecl.exceptions.ResourceNotFound` will be
                    raised when the resource does not exist.
                    When set to ``True``, None will be returned when
                    attempting to find a nonexistent resource.
        :param dict params: Any additional parameters to be passed into
                            underlying methods, such as to
                            :meth:`~ecl.resource2.Resource.existing`
                            in order to pass on URI parameters.

        :return: The :class:`Resource` object matching the given name or id
                 or None if nothing matches.
        :raises: :class:`ecl.exceptions.DuplicateResource` if more
                 than one resource is found for this request.
        :raises: :class:`ecl.exceptions.ResourceNotFound` if nothing
                 is found and ignore_missing is ``False``.
        """
        # Try to short-circuit by looking directly for a matching ID.

        data = cls.list(session, **params)

        result = cls._get_one_match(name_or_id, data)
        if result is not None:
            return result

        if ignore_missing:
            return None
        raise exceptions.ResourceNotFound("No %s found for %s" %
                                          (cls.__name__, name_or_id))
Exemplo n.º 4
0
    def __init__(self, plugins=None):
        """User preference for each service.

        :param list plugins: List of entry point namespaces to load.

        Create a new :class:`~ecl.profile.Profile`
        object with no preferences defined, but knowledge of the services.
        Services are identified by their service type, e.g.: 'identity',
        'compute', etc.
        """
        self._services = {}
        self._add_service(compute_service.ComputeService(version="v2"))
        self._add_service(
            connectivity_service.ConnectivityService(version="v1"))
        self._add_service(identity_service.IdentityService(version="v3"))
        self._add_service(image_service.ImageService(version="v2"))
        self._add_service(network_service.NetworkService(version="v2"))
        self._add_service(sss_service.SssService(version="v1"))
        self._add_service(
            orchestration_service.OrchestrationService(version="v1"))
        self._add_service(
            provider_connectivity_service.ProviderConnectivityService(
                version="v2"))
        self._add_service(telemetry_service.TelemetryService(version="v2"))
        self._add_service(block_store_service.BlockStoreService(version="v2"))
        self._add_service(storage_service.StorageService(version="v1"))
        self._add_service(
            security_order_service.SecurityOrderService(version="v2"))
        self._add_service(
            security_portal_service.SecurityPortalService(version="v2"))
        ## This section will be deleted if MSS v1 API is not available
        self._add_service(
            security_order_service_v1.SecurityOrderService(version="v1"))
        self._add_service(
            security_portal_service_v1.SecurityPortalService(version="v1"))
        ## end of the section
        self._add_service(rca_service.RcaService(version="v1"))
        self._add_service(baremetal_service.BaremetalService(version="v2"))
        self._add_service(
            dedicated_hypervisor_service.DedicatedHypervisorService(
                version="v1"))
        self._add_service(dns_service.DnsService(version="v2"))
        self._add_service(
            virtual_network_appliance_service.VirtualNetworkApplianceService(
                version="v1"))
        self._add_service(mvna_service.MVNAService(version="v1"))

        # NOTE: The Metric service is not added here as it currently
        # only retrieves the /capabilities API.

        if plugins:
            for plugin in plugins:
                self._load_plugin(plugin)
        self.service_keys = sorted(self._services.keys())
Exemplo n.º 5
0
class NicPhysicalPort(resource2.Resource):
    resource_key = "nic_physical_port"
    resources_key = "nic_physical_ports"
    base_path = '/servers/%(server_id)s/nic_physical_ports'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_get = True
    allow_list = True

    # Properties
    #: ID for the specified server.
    server_id = resource2.Body('server_id')
    #: UUID of the NicPhysicalPort.
    id = resource2.Body('id')
    #: MAC address of the NicPhysicalPort.
    mac_addr = resource2.Body('mac_addr')
    #: Network controller port id of physical leaf switch.
    network_physical_port_id = resource2.Body('network_physical_port_id')
    #: Value = 'data'(default) or 'storage'. Assigning preferentially the
    #: order to the NIC physical port. data plane: all devices cloud be
    #: connected. storage plane: this plane type is only used and optimized
    #: for storages between servers.You can assigning each until 2 planes.
    plane = resource2.Body('plane')
    #: Logical attached ports of host.
    attached_ports = resource2.Body('attached_ports')
    #: ID of hardware attaching the NicPhysicalPort.
    hardware_id = resource2.Body('hardware_id')

    def list(self, session, server_id):
        uri = self.base_path % {"server_id": server_id}
        resp = session.get(uri,
                           endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        resp = resp.json()
        resp = resp[self.resources_key]

        for data in resp:
            value = self.existing(**data)
            yield value

    def get(self, session, server_id, port_id):
        uri = self.base_path + '/%(nic_physical_port_id)s'
        uri = uri % {"server_id": server_id, "nic_physical_port_id": port_id}
        resp = session.get(uri,
                           endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        self._translate_response(resp, has_body=True)
        return self
Exemplo n.º 6
0
class Limits(resource2.Resource):
    base_path = "/limits"
    resource_key = "limits"
    service = baremetal_service.BaremetalService()

    allow_get = True

    absolute = resource2.Body("absolute", type=AbsoluteLimits)
    rate = resource2.Body("rate", type=list)

    def get(self, session, requires_id=False):
        """Get the Limits resource.

        :param session: The session to use for making this request.
        :type session: :class:`~ecl.session.Session`

        :returns: A Baremetal Limits instance
        :rtype: :class:`~ecl.baremetal.v2.limits.Limits`
        """
        request = self._prepare_request(requires_id=False, prepend_key=False)

        response = session.get(request.uri, endpoint_filter=self.service)

        body = response.json()
        body = body[self.resource_key]

        absolute_body = self._filter_component(
            body["absolute"], AbsoluteLimits._body_mapping())
        self.absolute = AbsoluteLimits.existing(**absolute_body)

        rates_body = body["rate"]

        rates = []
        for rate_body in rates_body:
            rate_body = self._filter_component(rate_body,
                                               RateLimit._body_mapping())
            rates.append(RateLimit(**rate_body))

        self.rate = rates

        return self
Exemplo n.º 7
0
class Chassis(resource2.Resource):
    """Chassis Resource"""

    resource_key = 'chassis'
    resources_key = 'chassis'
    base_path = '/chassis'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_get = True
    allow_list = True

    # Properties
    #: The ID for the chassis, which is a unique integer value.
    id = resource2.Body('id')
    #: The name of availability zone where chassis exists.
    availability_zone = resource2.Body('availability_zone')
    #: The name of flavor of chassis.
    flavor_name = resource2.Body('flavor_name')
    #: The object of summarized hardware spec. That has cpus, disks and rams.
    hardware_summary = resource2.Body('hardware_summary', type=dict)
    #: The status of chassis.
    status = resource2.Body('status')
    #: The ID of server attached to chassis. If no server is attached to chassis, the value is null.
    server_id = resource2.Body('server_id')
    #: The name of server attached to chassis. If no server is attached to chassis, the value is null.
    server_name = resource2.Body('server_name')
    #: The minimum contract period of your chassis.
    contract_year = resource2.Body('contract_year', type=int)
    #: The date that you start to use the chassis.
    start_time = resource2.Body('start_time')

    # Properties (for Detail)
    #: The spec of all cpus installed in chassis.
    cpus = resource2.Body('cpus', type=list)
    #: The spec of all disks installed in chassis.
    disks = resource2.Body('disks', type=list)
    #: The spec of all rams installed in chassis.
    rams = resource2.Body('rams', type=list)
Exemplo n.º 8
0
class Version(resource2.Resource):
    resource_key = 'version'
    resources_key = 'versions'
    base_path = '/'
    service = baremetal_service.BaremetalService(
        version=baremetal_service.BaremetalService.UNVERSIONED)

    # Capabilities
    allow_list = True
    allow_get = True

    # Properties
    #: List of API endpoint link.
    links = resource2.Body('links')
    #: Version support status. Valid values are CURRENT or SUPPORTED.
    #: CURRENT is newest stable version. SUPPORTED is old supported version.
    status = resource2.Body('status')
    #: Version identifier included in API URL.
    id = resource2.Body('id')
    updated = resource2.Body('updated')

    def get_version(self, session):
        uri = self.base_path + 'v2'
        resp = session.get(uri,
                           headers={"Accept": "application/json"},
                           endpoint_filter=self.service)
        self._translate_response(resp, has_body=True)
        return self

    def list_version(self, session):
        uri = self.base_path
        resp = session.get(uri,
                           headers={"Accept": "application/json"},
                           endpoint_filter=self.service)
        resp = resp.json()[self.resources_key]

        for data in resp:
            version = self.existing(**data)
            yield version
Exemplo n.º 9
0
class Keypair(resource2.Resource):
    resource_key = 'keypair'
    resources_key = 'keypairs'
    base_path = '/os-keypairs'
    service = baremetal_service.BaremetalService()

    # capabilities
    allow_create = True
    allow_get = True
    allow_delete = True
    allow_list = True

    # Properties
    #: Fingerprint of public key.
    fingerprint = resource2.Body('fingerprint')
    #: The name to associate with the KeyPair. It is a unique name in
    #: the tenant. Available character is 1-255 character of
    #: alphabet(a-zA-Z), number(0-9) and slash(-).
    name = resource2.Body('name', alternate_id=True)
    #: Generated SSH private key.
    #: This parameter is visible only when did not specify public_key
    #: This parameter is only included in the response of Create Keypair.
    private_key = resource2.Body('private_key')
    #: The public RSA or DSA SSH key to import. If not provided,
    #: a key is generated 2048bit RSA key.
    public_key = resource2.Body('public_key')

    def list(self, session, paginated=False):
        resp = session.get(self.base_path,
                           endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        resp = resp.json()
        resp = resp[self.resources_key]

        for data in resp:
            value = self.existing(**data)
            yield value
Exemplo n.º 10
0
class UEFI(resource2.Resource):
    resource_key = 'uefi'
    resources_key = 'uefi'
    base_path = '/servers/%(server_id)s/uefi'
    service = baremetal_service.BaremetalService()

    # capabilities
    allow_update = True
    allow_get = True

    #: Name for the flavor.
    flavor_name = resource2.Body('flavor_name')
    #: The ID for the flavor.
    flavor_id = resource2.Body('flavor_id', alternate_id=True)
    #: Updated time for UEFI
    updated = resource2.Body('updated')
    #: The last result of applying uefi setting.
    status = resource2.Body('status')
    #: Error messages when updating uefi setting is failed.
    message = resource2.Body('message')
    #: UEFI setting.
    setting = resource2.Body('setting', type=dict)

    def get(self, session, server_id):
        uri = self.base_path % {"server_id": server_id}
        resp = session.get(uri, endpoint_filter=self.service)
        self._translate_response(resp, has_body=True)
        return self

    def update(self, session, server_id, has_body=True, **attrs):
        uri = self.base_path % {"server_id": server_id}
        body = attrs
        args = {'json': body}
        resp = session.put(uri, endpoint_filter=self.service, **args)
        self._translate_response(resp, has_body=False)
        return self
Exemplo n.º 11
0
class Flavor(resource2.Resource):
    resource_key = 'flavor'
    resources_key = 'flavors'
    base_path = '/flavors'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_get = True
    allow_list = True

    # Properties
    #: The ID for the flavor, which is a unique integer value.
    id = resource2.Body('id')
    #: List of flavor resource links.
    links = resource2.Body('links')
    #: The amount of RAM, in MBs, for this flavor.
    ram = resource2.Body('ram', type=int)
    #: Name for the flavor.
    name = resource2.Body('name')
    #: The amount of disk space, in GBs.
    disk = resource2.Body('disk', type=int)
    #: The CPUs, in whole integer amount, for the flavor.
    #: In order to maintain compatibility with Nova API,
    #: we put the size of the physical cpu to vcpu.
    vcpus = resource2.Body('vcpus', type=int)

    @classmethod
    def find(cls, session, name_or_id, ignore_missing=False, **params):
        """Find a resource by its name or id.

        :param session: The session to use for making this request.
        :type session: :class:`~ecl.session.Session`
        :param name_or_id: This resource's identifier, if needed by
                           the request. The default is ``None``.
        :param bool ignore_missing: When set to ``False``
                    :class:`~ecl.exceptions.ResourceNotFound` will be
                    raised when the resource does not exist.
                    When set to ``True``, None will be returned when
                    attempting to find a nonexistent resource.
        :param dict params: Any additional parameters to be passed into
                            underlying methods, such as to
                            :meth:`~ecl.resource2.Resource.existing`
                            in order to pass on URI parameters.

        :return: The :class:`Resource` object matching the given name or id
                 or None if nothing matches.
        :raises: :class:`ecl.exceptions.DuplicateResource` if more
                 than one resource is found for this request.
        :raises: :class:`ecl.exceptions.ResourceNotFound` if nothing
                 is found and ignore_missing is ``False``.
        """
        # Try to short-circuit by looking directly for a matching ID.

        data = cls.list(session, **params)

        result = cls._get_one_match(name_or_id, data)
        if result is not None:
            return result

        if ignore_missing:
            return None
        raise exceptions.ResourceNotFound("No %s found for %s" %
                                          (cls.__name__, name_or_id))
Exemplo n.º 12
0
class Server(resource2.Resource):
    resources_key = "servers"
    resource_key = "server"
    base_path = '/servers'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_get = True
    allow_list = True
    allow_create = True
    allow_delete = True
    allow_update = True

    # Properties
    #: UUID of the Baremetal server.
    id = resource2.Body('id')
    #: Link of the Baremetal server.
    links = resource2.Body('links')
    #: Name of the Baremetal server.
    name = resource2.Body('name')
    #: Password for the administrator.
    #: This parameter is shown only once, so you have to memo.
    #: Please refer OS specific limitations adminPass raw to know the
    #: required administrator name for each OS.
    adminPass = resource2.Body('adminPass')
    admin_pass = resource2.Body('adminPass')
    #: SSH Keypair name you created on KeyPairs API.
    key_name = resource2.Body('key_name')
    #: Power state: {"RUNNING":"The server is running.",
    #: "SHUTDOWN":"The server was shut down.",
    #: "CRASHED":"The server lost powor controll information temporary.
    #: Status transfer RUNNING/SHUTDOWN Automatically."}
    OS_EXT_STS_power_state = resource2.Body('OS-EXT-STS:power_state')
    power_state = resource2.Body('OS-EXT-STS:power_state')
    #: Task state: {None:"There are no tasks. Only this status can be
    #: received API requests.", "BUILDING":"The task is building the
    #: Baremetal Server. This status is transfered by Create Server.",
    #: "DELETING":"The task is deleting the Baremetal Server. This status
    #: is transfered by Delete Server.", "STOPPING":"The task is stopping
    #: the Baremetal Server. This status is transfered by Stop Server.",
    #: "STARTING":"The task is starting the Baremetal Server. This status
    #: is transfered by Start Server.", "REBOOTING":"The task is rebooting
    #: the Baremetal Server. This status is transfered by Reboot Server."}
    OS_EXT_STS_task_state = resource2.Body('OS-EXT-STS:task_state')
    task_state = resource2.Body('OS-EXT-STS:task_state')
    #: VM state: {"ACTIVE":"The Baremetal server is active.
    #: This status is target of billing.", "BUILD":"The Baremetal server
    #: is built.", "ERROR": "The Baremetal server is outputing a error.
    #: There is necessity to report to our support.", "DELETED":"The
    #: Baremetal server is deleted."}
    OS_EXT_STS_vm_state = resource2.Body('OS-EXT-STS:vm_state')
    vm_state = resource2.Body('OS-EXT-STS:vm_state')
    #: Server's availability zone.
    OS_EXT_AZ_availability_zone = resource2.Body('OS-EXT-AZ:availability_zone')
    availability_zone = resource2.Body('OS-EXT-AZ:availability_zone')
    #: Sever's created time.
    created = resource2.Body('created')
    #: Server's flavor information.
    flavor = resource2.Body('flavor')
    #: Server's host ID.
    hostId = resource2.Body('hostId')
    #: Server's ID.
    image = resource2.Body('image')
    #: Server's image information.
    metadata = resource2.Body('metadata')
    #: Server's links information.
    progress = resource2.Body('progress')
    #: Server's metadata information.
    status = resource2.Body('status')
    #: Server's tenant id.
    tenant_id = resource2.Body('tenant_id')
    #: Server's updated time.
    updated = resource2.Body('updated')
    #: Server's user id.
    user_id = resource2.Body('user_id')
    #: Server's raid arrays information.
    raid_arrays = resource2.Body('raid_arrays')
    #: Server's lvm volume groups information.
    lvm_volume_groups = resource2.Body('lvm_volume_groups')
    #: Server's file system information.
    filesystems = resource2.Body('filesystems')
    #: Server's nic physical ports information.
    nic_physical_ports = resource2.Body('nic_physical_ports')
    #: Server's chassis status information.
    chassis_status = resource2.Body('chassis-status')
    #: managed_by_service
    managed_by_service = resource2.Body('managed_by_service')
    media_attachments = resource2.Body('media_attachments')
    #: key_pair name
    key_name = resource2.Body('key_name')

    def create(self, session, **attrs):
        body = {"server": attrs}
        resp = session.post(
            self.base_path, endpoint_filter=self.service,
            json=body,
            headers={"Accept": "application/json"}
        )
        self._translate_response(resp, has_body=True)
        return self

    def update(self, session, server_id, **attrs):
        url = "%s/%s" % (self.base_path, server_id)
        body = {"server": attrs}
        resp = session.put(url,
                           endpoint_filter=self.service,
                           json=body,
                           headers={"Accept": "application/json"})
        self._translate_response(resp, has_body=True)
        return self
Exemplo n.º 13
0
class ServerAction(resource2.Resource):
    resource_key = "console"
    resources_key = None
    base_path = '/servers/%s/action'
    service = baremetal_service.BaremetalService()

    # Properties
    #: Type of the remote console. Valid values are IPMI or IMM.
    type = resource2.Body('type')
    #: URL to access the remote console.
    url = resource2.Body('url')
    #: User ID for sign in to the remote console.
    user_id = resource2.Body('user_id')
    #: Password for sign in to the remote console.
    password = resource2.Body('password')

    def start(self, session, server_id):
        uri = self.base_path % server_id
        body = {"os-start": None}
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def stop(self, session, server_id, shutdown_type):
        uri = self.base_path % server_id
        if shutdown_type is None:
            body = {"os-stop": None}
        else:
            body = {"os-stop": {"type": shutdown_type}}
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def reboot(self, session, server_id, shutdown_type):
        uri = self.base_path % server_id
        body = {
            "reboot": {
                "type": shutdown_type,
            }
        }
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def change_boot_mode(self, session, server_id, shutdown_type, boot_mode):
        uri = self.base_path % server_id
        body = {
            "boot_mode": {
                "type": shutdown_type,
                "boot_mode": boot_mode
            }
        }
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def media_attach(self, session, server_id, image):
        uri = self.base_path % server_id
        body = {
            "media-attach": {
                "imageRef": image
            }
        }
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def media_detach(self, session, server_id, image):
        uri = self.base_path % server_id
        body = {
            "media-detach": {
                "imageRef": image
            }
        }
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body
        )
        self._translate_response(resp, has_body=False)
        return self

    def get_management_console(self, session, server_id):
        uri = self.base_path % server_id
        body = {
            "os-getManagementConsole": None
        }
        resp = session.post(
            uri,
            endpoint_filter=self.service,
            json=body,
            headers={"Accept": "application/json"}
        )
        self._translate_response(resp, has_body=True)
        return self

    @classmethod
    def find(cls, session, name_or_id, ignore_missing=False, **params):
        """Find a resource by its name or id.

        :param session: The session to use for making this request.
        :type session: :class:`~ecl.session.Session`
        :param name_or_id: This resource's identifier, if needed by
                           the request. The default is ``None``.
        :param bool ignore_missing: When set to ``False``
                    :class:`~ecl.exceptions.ResourceNotFound` will be
                    raised when the resource does not exist.
                    When set to ``True``, None will be returned when
                    attempting to find a nonexistent resource.
        :param dict params: Any additional parameters to be passed into
                            underlying methods, such as to
                            :meth:`~ecl.resource2.Resource.existing`
                            in order to pass on URI parameters.

        :return: The :class:`Resource` object matching the given name or id
                 or None if nothing matches.
        :raises: :class:`ecl.exceptions.DuplicateResource` if more
                 than one resource is found for this request.
        :raises: :class:`ecl.exceptions.ResourceNotFound` if nothing
                 is found and ignore_missing is ``False``.
        """
        # Try to short-circuit by looking directly for a matching ID.

        data = cls.list(session, **params)

        result = cls._get_one_match(name_or_id, data)
        if result is not None:
            return result

        if ignore_missing:
            return None
        raise exceptions.ResourceNotFound(
            "No %s found for %s" % (cls.__name__, name_or_id))
Exemplo n.º 14
0
class Metadata(resource2.Resource):
    resource_key = None
    resources_key = None
    base_path = '/servers/%(server_id)s/metadata'
    service = baremetal_service.BaremetalService()

    # Capabilities
    allow_list = True
    allow_show = True
    allow_create = True
    allow_delete = True

    # Properties
    #: Metadata of the server.
    metadata = resource2.Body("metadata")

    def list(self, session, server_id):

        uri = self.base_path % {"server_id" : server_id}
        resp = session.get(uri, endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        self._translate_response(resp, has_body=True)
        return self

    def get(self, session, server_id, key):
        uri = self.base_path + '/%(key)s'
        uri = uri % {"server_id":server_id, "key":key}
        resp = session.get(uri, endpoint_filter=self.service,
                           headers={"Accept": "application/json"})
        self._translate_response(resp, has_body=True)
        return self

    def delete(self, session, server_id, key):
        uri = self.base_path + '/%(key)s'
        uri = uri % {"server_id": server_id, "key": key}
        resp = session.delete(uri, endpoint_filter=self.service,
                              headers={"Accept": ""})
        self._translate_response(resp, has_body=False)
        return self

    def merge(self, session, server_id, **attrs):
        uri = self.base_path % {"server_id" : server_id}
        body = {"metadata": attrs}
        resp = session.post(
            uri, endpoint_filter=self.service,
            json=body,
            headers={"Accept": "application/json"}
        )
        self._translate_response(resp, has_body=True)
        return self

    def replace(self, session, server_id, **attrs):
        uri = self.base_path % {"server_id" : server_id}
        body = attrs
        resp = session.put(
            uri, endpoint_filter=self.service,
            json=body,
            headers={"Accept": "application/json"}
        )
        self._translate_response(resp, has_body=True)
        return self

    def update(self, session, server_id, key, **attrs):
        uri = self.base_path + '/%(key)s'
        uri = uri % {"server_id": server_id, "key": key}
        body = attrs
        resp = session.put(
            uri, endpoint_filter=self.service,
            json=body,
            headers={"Accept": "application/json"}
        )
        self._translate_response(resp, has_body=True)
        return self