Пример #1
0
class Pool(resource.Resource):
    resource_key = 'pool'
    resources_key = 'pools'
    base_path = '/lbaas/pools'
    service = network_service.NetworkService()

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

    _query_mapping = resource.QueryParameters(
        'description',
        'lb_algorithm',
        'name',
        'protocol',
        'provider',
        'subnet_id',
        'virtual_ip_id',
        'listener_id',
        is_admin_state_up='admin_state_up',
        project_id='tenant_id',
        load_balancer_id='loadbalancer_id',
    )

    # Properties
    #: Description for the pool.
    description = resource.Body('description')
    #: The ID of the associated health monitors.
    health_monitor_id = resource.Body('healthmonitor_id')
    #: The ID of the associated health monitors (LBaaS v1).
    health_monitor_ids = resource.Body('health_monitors', type=list)
    #: The statuses of the associated health monitors.
    health_monitor_status = resource.Body('health_monitor_status', type=list)
    #: The administrative state of the pool, which is up ``True`` or down
    #: ``False``. *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: The load-balancer algorithm, which is round-robin, least-connections,
    #: and so on. This value, which must be supported, is dependent on the
    #: load-balancer provider. Round-robin must be supported.
    lb_algorithm = resource.Body('lb_algorithm')
    #: List of associated listeners.
    #: *Type: list of dicts which contain the listener IDs*
    listener_ids = resource.Body('listeners', type=list)
    #: ID of listener associated with this pool
    listener_id = resource.Body('listener_id')
    #: List of associated load balancers.
    #: *Type: list of dicts which contain the load balancer IDs*
    load_balancer_ids = resource.Body('loadbalancers', type=list)
    #: ID of load balancer associated with this pool
    load_balancer_id = resource.Body('loadbalancer_id')
    #: List of members that belong to the pool.
    #: *Type: list of dicts which contain the member IDs*
    member_ids = resource.Body('members', type=list)
    #: Pool name. Does not have to be unique.
    name = resource.Body('name')
    #: The ID of the project this pool is associated with.
    project_id = resource.Body('tenant_id')
    #: The protocol of the pool, which is TCP, HTTP, or HTTPS.
    protocol = resource.Body('protocol')
    #: The provider name of the load balancer service.
    provider = resource.Body('provider')
    #: Human readable description of the status.
    status = resource.Body('status')
    #: The status of the network.
    status_description = resource.Body('status_description')
    #: The subnet on which the members of the pool will be located.
    subnet_id = resource.Body('subnet_id')
    #: Session persistence algorithm that should be used (if any).
    #: *Type: dict with keys ``type`` and ``cookie_name``*
    session_persistence = resource.Body('session_persistence')
    #: The ID of the virtual IP (VIP) address.
    virtual_ip_id = resource.Body('vip_id')
Пример #2
0
class Project(resource.Resource):
    resource_key = 'project'
    resources_key = 'projects'
    base_path = '/projects'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True
    commit_method = 'PATCH'

    _query_mapping = resource.QueryParameters(
        'domain_id',
        'is_domain',
        'name',
        'parent_id',
        is_enabled='enabled',
    )

    # Properties
    #: The description of the project. *Type: string*
    description = resource.Body('description')
    #: References the domain ID which owns the project; if a domain ID is not
    #: specified by the client, the Identity service implementation will
    #: default it to the domain ID to which the client's token is scoped.
    #: *Type: string*
    domain_id = resource.Body('domain_id')
    #: Indicates whether the project also acts as a domain. If set to True,
    #: the project acts as both a project and a domain. Default is False.
    #: New in version 3.6
    is_domain = resource.Body('is_domain', type=bool)
    #: Setting this attribute to ``False`` prevents users from authorizing
    #: against this project. Additionally, all pre-existing tokens authorized
    #: for the project are immediately invalidated. Re-enabling a project
    #: does not re-enable pre-existing tokens. *Type: bool*
    is_enabled = resource.Body('enabled', type=bool)
    #: Unique project name, within the owning domain. *Type: string*
    name = resource.Body('name')
    #: The ID of the parent of the project.
    #: New in version 3.4
    parent_id = resource.Body('parent_id')

    def assign_role_to_user(self, session, user, role):
        """Assign role to user on project"""
        url = utils.urljoin(self.base_path, self.id, 'users', user.id, 'roles',
                            role.id)
        resp = session.put(url, )
        if resp.status_code == 204:
            return True
        return False

    def validate_user_has_role(self, session, user, role):
        """Validates that a user has a role on a project"""
        url = utils.urljoin(self.base_path, self.id, 'users', user.id, 'roles',
                            role.id)
        resp = session.head(url, )
        if resp.status_code == 201:
            return True
        return False

    def unassign_role_from_user(self, session, user, role):
        """Unassigns a role from a user on a project"""
        url = utils.urljoin(self.base_path, self.id, 'users', user.id, 'roles',
                            role.id)
        resp = session.delete(url, )
        if resp.status_code == 204:
            return True
        return False

    def assign_role_to_group(self, session, group, role):
        """Assign role to group on project"""
        url = utils.urljoin(self.base_path, self.id, 'groups', group.id,
                            'roles', role.id)
        resp = session.put(url, )
        if resp.status_code == 204:
            return True
        return False

    def validate_group_has_role(self, session, group, role):
        """Validates that a group has a role on a project"""
        url = utils.urljoin(self.base_path, self.id, 'groups', group.id,
                            'roles', role.id)
        resp = session.head(url, )
        if resp.status_code == 201:
            return True
        return False

    def unassign_role_from_group(self, session, group, role):
        """Unassigns a role from a group on a project"""
        url = utils.urljoin(self.base_path, self.id, 'groups', group.id,
                            'roles', role.id)
        resp = session.delete(url, )
        if resp.status_code == 204:
            return True
        return False
Пример #3
0
class Receiver(resource.Resource):
    resource_key = 'receiver'
    resources_key = 'receivers'
    base_path = '/receivers'
    service = clustering_service.ClusteringService()

    # Capabilities
    allow_list = True
    allow_fetch = True
    allow_create = True
    allow_commit = True
    allow_delete = True

    commit_method = 'PATCH'

    _query_mapping = resource.QueryParameters(
        'name', 'type', 'cluster_id', 'action', 'sort', 'global_project',
        user_id='user')

    # Properties
    #: The name of the receiver.
    name = resource.Body('name')
    #: The type of the receiver.
    type = resource.Body('type')
    #: The ID of the user who created the receiver, thus the owner of it.
    user_id = resource.Body('user')
    #: The ID of the project this receiver belongs to.
    project_id = resource.Body('project')
    #: The domain ID of the receiver.
    domain_id = resource.Body('domain')
    #: The ID of the targeted cluster.
    cluster_id = resource.Body('cluster_id')
    #: The name of the targeted action.
    action = resource.Body('action')
    #: Timestamp of when the receiver was created.
    created_at = resource.Body('created_at')
    #: Timestamp of when the receiver was last updated.
    updated_at = resource.Body('updated_at')
    #: The credential of the impersonated user.
    actor = resource.Body('actor', type=dict)
    #: A dictionary containing key-value pairs that are provided to the
    #: targeted action.
    params = resource.Body('params', type=dict)
    #: The information about the channel through which you can trigger the
    #: receiver hence the associated action.
    channel = resource.Body('channel', type=dict)
Пример #4
0
class FloatingIP(resource.Resource):
    name_attribute = "floating_ip_address"
    resource_name = "floating ip"
    resource_key = 'floatingip'
    resources_key = 'floatingips'
    base_path = '/floatingips'
    service = network_service.NetworkService()

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

    _query_mapping = resource.QueryParameters(
        'description', 'fixed_ip_address',
        'floating_ip_address', 'floating_network_id',
        'port_id', 'router_id', 'status', 'subnet_id',
        project_id='tenant_id')

    # Properties
    #: Timestamp at which the floating IP was created.
    created_at = resource.Body('created_at')
    #: The floating IP description.
    description = resource.Body('description')
    #: The fixed IP address associated with the floating IP. If you
    #: intend to associate the floating IP with a fixed IP at creation
    #: time, then you must indicate the identifier of the internal port.
    #: If an internal port has multiple associated IP addresses, the
    #: service chooses the first IP unless you explicitly specify the
    #: parameter fixed_ip_address to select a specific IP.
    fixed_ip_address = resource.Body('fixed_ip_address')
    #: The floating IP address.
    floating_ip_address = resource.Body('floating_ip_address')
    #: Floating IP object doesn't have name attribute, set ip address to name
    #: so that user could find floating IP by UUID or IP address using find_ip
    name = floating_ip_address
    #: The ID of the network associated with the floating IP.
    floating_network_id = resource.Body('floating_network_id')
    #: The port ID.
    port_id = resource.Body('port_id')
    #: The ID of the QoS policy attached to the floating IP.
    qos_policy_id = resource.Body('qos_policy_id')
    #: The ID of the project this floating IP is associated with.
    project_id = resource.Body('tenant_id')
    #: Revision number of the floating IP. *Type: int*
    revision_number = resource.Body('revision_number', type=int)
    #: The ID of an associated router.
    router_id = resource.Body('router_id')
    #: The floating IP status. Value is ``ACTIVE`` or ``DOWN``.
    status = resource.Body('status')
    #: Timestamp at which the floating IP was last updated.
    updated_at = resource.Body('updated_at')
    #: The Subnet ID associated with the floating IP.
    subnet_id = resource.Body('subnet_id')

    @classmethod
    def find_available(cls, session):
        info = cls.list(session, port_id='')
        try:
            return next(info)
        except StopIteration:
            return None
Пример #5
0
class Flavor(resource.Resource):
    resource_key = 'flavor'
    resources_key = 'flavors'
    base_path = '/flavors'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_delete = True
    allow_list = True
    allow_commit = True

    _query_mapping = resource.QueryParameters(
        "sort_key", "sort_dir", "is_public",
        min_disk="minDisk",
        min_ram="minRam")

    # extra_specs introduced in 2.61
    _max_microversion = '2.61'

    # Properties
    #: Links pertaining to this flavor. This is a list of dictionaries,
    #: each including keys ``href`` and ``rel``.
    links = resource.Body('links')
    #: The name of this flavor.
    name = resource.Body('name')
    #: The description of the flavor.
    description = resource.Body('description')
    #: Size of the disk this flavor offers. *Type: int*
    disk = resource.Body('disk', type=int)
    #: ``True`` if this is a publicly visible flavor. ``False`` if this is
    #: a private image. *Type: bool*
    is_public = resource.Body('os-flavor-access:is_public', type=bool)
    #: The amount of RAM (in MB) this flavor offers. *Type: int*
    ram = resource.Body('ram', type=int)
    #: The number of virtual CPUs this flavor offers. *Type: int*
    vcpus = resource.Body('vcpus', type=int)
    #: Size of the swap partitions.
    swap = resource.Body('swap')
    #: Size of the ephemeral data disk attached to this server. *Type: int*
    ephemeral = resource.Body('OS-FLV-EXT-DATA:ephemeral', type=int)
    #: ``True`` if this flavor is disabled, ``False`` if not. *Type: bool*
    is_disabled = resource.Body('OS-FLV-DISABLED:disabled', type=bool)
    #: The bandwidth scaling factor this flavor receives on the network.
    rxtx_factor = resource.Body('rxtx_factor', type=float)
    # TODO(mordred) extra_specs can historically also come from
    #               OS-FLV-WITH-EXT-SPECS:extra_specs. Do we care?
    #: A dictionary of the flavor's extra-specs key-and-value pairs.
    extra_specs = resource.Body('extra_specs', type=dict, default={})

    @classmethod
    def list(cls, session, paginated=True, base_path='/flavors/detail',
             allow_unknown_params=False, **params):
        # Find will invoke list when name was passed. Since we want to return
        # flavor with details (same as direct get) we need to swap default here
        # and list with "/flavors" if no details explicitely requested
        if 'is_public' not in params or params['is_public'] is None:
            # is_public is ternary - None means give all flavors.
            # Force it to string to avoid requests skipping it.
            params['is_public'] = 'None'
        return super(Flavor, cls).list(
            session, paginated=paginated,
            base_path=base_path,
            allow_unknown_params=allow_unknown_params,
            **params)

    def _action(self, session, body, microversion=None):
        """Preform flavor actions given the message body."""
        url = utils.urljoin(Flavor.base_path, self.id, 'action')
        headers = {'Accept': ''}
        attrs = {}
        if microversion:
            # Do not reset microversion if it is set on a session level
            attrs['microversion'] = microversion
        response = session.post(
            url, json=body, headers=headers, **attrs)
        exceptions.raise_from_response(response)
        return response

    def add_tenant_access(self, session, tenant):
        """Adds flavor access to a tenant and flavor."""
        body = {'addTenantAccess': {'tenant': tenant}}
        self._action(session, body)

    def remove_tenant_access(self, session, tenant):
        """Removes flavor access to a tenant and flavor."""
        body = {'removeTenantAccess': {'tenant': tenant}}
        self._action(session, body)

    def get_access(self, session):
        """Lists tenants who have access to a private flavor

        By default, only administrators can manage private flavor access. A
        private flavor has is_public set to false while a public flavor has
        is_public set to true.

        :return: List of dicts with flavor_id and tenant_id attributes
        """
        url = utils.urljoin(Flavor.base_path, self.id, 'os-flavor-access')
        response = session.get(url)
        exceptions.raise_from_response(response)
        return response.json().get('flavor_access', [])

    def fetch_extra_specs(self, session):
        """Fetch extra_specs of the flavor

        Starting with 2.61 extra_specs are returned with the flavor details,
        before that a separate call is required.
        """
        url = utils.urljoin(Flavor.base_path, self.id, 'os-extra_specs')
        microversion = self._get_microversion_for(session, 'fetch')
        response = session.get(url, microversion=microversion)
        exceptions.raise_from_response(response)
        specs = response.json().get('extra_specs', {})
        self._update(extra_specs=specs)
        return self

    def create_extra_specs(self, session, specs):
        """Creates extra specs for a flavor"""
        url = utils.urljoin(Flavor.base_path, self.id, 'os-extra_specs')
        microversion = self._get_microversion_for(session, 'create')
        response = session.post(
            url,
            json={'extra_specs': specs},
            microversion=microversion)
        exceptions.raise_from_response(response)
        specs = response.json().get('extra_specs', {})
        self._update(extra_specs=specs)
        return self

    def get_extra_specs_property(self, session, prop):
        """Get individual extra_spec property"""
        url = utils.urljoin(Flavor.base_path, self.id,
                            'os-extra_specs', prop)
        microversion = self._get_microversion_for(session, 'fetch')
        response = session.get(url, microversion=microversion)
        exceptions.raise_from_response(response)
        val = response.json().get(prop)
        return val

    def update_extra_specs_property(self, session, prop, val):
        """Update An Extra Spec For A Flavor"""
        url = utils.urljoin(Flavor.base_path, self.id,
                            'os-extra_specs', prop)
        microversion = self._get_microversion_for(session, 'commit')
        response = session.put(
            url,
            json={prop: val},
            microversion=microversion)
        exceptions.raise_from_response(response)
        val = response.json().get(prop)
        return val

    def delete_extra_specs_property(self, session, prop):
        """Delete An Extra Spec For A Flavor"""
        url = utils.urljoin(Flavor.base_path, self.id,
                            'os-extra_specs', prop)
        microversion = self._get_microversion_for(session, 'delete')
        response = session.delete(
            url,
            microversion=microversion)
        exceptions.raise_from_response(response)
class StatusSpec(_base.StatusSpec):
    # Properties
    #: Access address of the kube-apiserver in the cluster.
    endpoints = resource.Body('endpoints', type=dict)
Пример #7
0
class Instance(resource.Resource):
    resource_key = 'instance'
    resources_key = 'instances'
    base_path = '/instances'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True

    # Properties
    #: The flavor of the instance
    flavor = resource.Body('flavor')
    #: Links associated with the instance
    links = resource.Body('links')
    #: The name of the instance
    name = resource.Body('name')
    #: The status of the instance
    status = resource.Body('status')
    #: The size of the volume
    volume = resource.Body('volume')
    #: A dictionary of datastore details, often including 'type' and 'version'
    #: keys
    datastore = resource.Body('datastore', type=dict)
    #: The ID of this instance
    id = resource.Body('id')
    #: The region this instance resides in
    region = resource.Body('region')
    #: The name of the host
    hostname = resource.Body('hostname')
    #: The timestamp when this instance was created
    created_at = resource.Body('created')
    #: The timestamp when this instance was updated
    updated_at = resource.Body('updated')

    def enable_root_user(self, session):
        """Enable login for the root user.

        This operation enables login from any host for the root user
        and provides the user with a generated root password.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :returns: A dictionary with keys ``name`` and ``password`` specifying
            the login credentials.
        """
        url = utils.urljoin(self.base_path, self.id, 'root')
        resp = session.post(url, )
        return resp.json()['user']

    def is_root_enabled(self, session):
        """Determine if root is enabled on an instance.

        Determine if root is enabled on this particular instance.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :returns: ``True`` if root user is enabled for a specified database
            instance or ``False`` otherwise.
        """
        url = utils.urljoin(self.base_path, self.id, 'root')
        resp = session.get(url, )
        return resp.json()['rootEnabled']

    def restart(self, session):
        """Restart the database instance

        :returns: ``None``
        """
        body = {'restart': {}}
        url = utils.urljoin(self.base_path, self.id, 'action')
        session.post(url, json=body)

    def resize(self, session, flavor_reference):
        """Resize the database instance

        :returns: ``None``
        """
        body = {'resize': {'flavorRef': flavor_reference}}
        url = utils.urljoin(self.base_path, self.id, 'action')
        session.post(url, json=body)

    def resize_volume(self, session, volume_size):
        """Resize the volume attached to the instance

        :returns: ``None``
        """
        body = {'resize': {'volume': volume_size}}
        url = utils.urljoin(self.base_path, self.id, 'action')
        session.post(url, json=body)
Пример #8
0
class Group(_base.Resource):
    resource_key = 'scaling_group'
    resources_key = 'scaling_groups'
    base_path = '/scaling_group'
    query_marker_key = 'start_number'
    # service = auto_scaling_service.AutoScalingService()

    # capabilities
    allow_create = True
    allow_list = True
    allow_fetch = True
    allow_delete = True
    allow_commit = True

    _query_mapping = resource.QueryParameters('id',
                                              'name',
                                              'limit',
                                              'marker',
                                              'scaling_configuration_id',
                                              name='scaling_group_name',
                                              status='scaling_group_status',
                                              marker=query_marker_key)

    #: Properties
    #: AutoScaling group ID
    id = resource.Body('scaling_group_id', alternate_id=True)
    #: AutoScaling group name
    name = resource.Body('scaling_group_name')
    #: AutoScaling group status,
    #: valid valus includes: ``INSERVICE``, ``PAUSED``, ``ERROR``
    status = resource.Body('scaling_group_status')
    #: AutoScaling group scaling status, *Type: bool*
    is_scaling = resource.Body('is_scaling', type=bool)
    #: AutoScaling group detail
    detail = resource.Body('detail')
    #: VPC id - (Router Id)
    router_id = resource.Body('vpc_id')
    #: network id list - (Subnet)
    networks = resource.Body('networks', type=list)
    #: security group id list
    security_groups = resource.Body('security_groups', type=list)
    #: Auto Scaling Config ID reference, used for creating instance
    scaling_configuration_id = resource.Body('scaling_configuration_id')
    #: Auto Scaling Config name
    scaling_configuration_name = resource.Body('scaling_configuration_name')
    #: Current alive instance number
    current_instance_number = resource.Body('current_instance_number')
    #: Desire alive instance number
    desire_instance_number = resource.Body('desire_instance_number')
    #: min alive instance number
    min_instance_number = resource.Body('min_instance_number')
    #: max alive instance number
    max_instance_number = resource.Body('max_instance_number')
    #: CoolDown time, only work with `ALARM` policy.
    #: default is 900, valid range is 0-86400
    cool_down_time = resource.Body('cool_down_time')
    #: load balancer listener id reference
    lb_listener_id = resource.Body('lb_listener_id')
    #: Health periodic audit method, Valid values includes: ``ELB_AUDIT``,
    #: ``NOVA_AUDIT``, ELB_AUDIT and lb_listener_id are used in pairs.
    health_periodic_audit_method = resource.Body(
        'health_periodic_audit_method')
    #: Health periodic audit time, valid values includes: ``5``, ``15``,
    #: ``60``, ``180``, default is ``5`` minutes
    health_periodic_audit_time = resource.Body('health_periodic_audit_time')
    #: Instance terminate policy, valid values includes:
    #: ``OLD_CONFIG_OLD_INSTANCE`` (default), ``OLD_CONFIG_NEW_INSTANCE``,
    #: ``OLD_INSTANCE``, ``NEW_INSTANCE``
    instance_terminate_policy = resource.Body('instance_terminate_policy')
    #: notification methods, ``EMAIL``
    notifications = resource.Body('notifications')
    #: Should delete public ip when terminate instance, default ``false``
    delete_publicip = resource.Body('delete_publicip', type=bool)
    #: availability zones
    availability_zones = resource.Body('available_zones')
    #: Create time of the group
    create_time = resource.Body('create_time')

    def resume(self, session):
        '''resume group'''
        body = {'action': 'resume'}
        self._action(session, body)

    def pause(self, session):
        '''pause group'''
        body = {'action': 'pause'}
        self._action(session, body)
Пример #9
0
class Quota(_base.Resource):
    """AutoScaling Quota resource"""
    resources_key = 'quotas.resources'
    base_path = '/quotas'

    # capabilities
    allow_list = True

    #: Properties
    #: Quota of type, current only ``alarm`` is valid
    type = resource.Body('type')
    #: Quota amount has been used
    used = resource.Body('used', type=int)
    #: Quota max amount
    max = resource.Body('max', type=int)
    #: Quota amount
    quota = resource.Body('quota', type=int)

    @staticmethod
    def find_value_by_accessor(input_dict, accessor):
        """Gets value from a dictionary using a dotted accessor"""
        current_data = input_dict
        for chunk in accessor.split('.'):
            if isinstance(current_data, dict):
                current_data = current_data.get(chunk, {})
            else:
                return None
        return current_data

    @classmethod
    def list(cls, session, paginated=False, base_path=None, **params):
        if not cls.allow_list:
            raise exceptions.MethodNotSupported(cls, "list")

        session = cls._get_session(session)

        # pop scaling_group_id, as it should not be also present in the query
        scaling_group_id = params.pop('scaling_group_id', None)
        uri_params = {}

        if scaling_group_id:
            uri_params = {'scaling_group_id': scaling_group_id}

        cls._query_mapping._validate(params, base_path=cls.base_path)
        query_params = cls._query_mapping._transpose(params, cls)
        uri = cls.base_path % uri_params

        limit = query_params.get('limit')

        total_yielded = 0
        while uri:
            response = session.get(uri, params=query_params.copy())
            exceptions.raise_from_response(response)
            data = response.json()

            # Discard any existing pagination keys
            query_params.pop('marker', None)
            query_params.pop('limit', None)

            if cls.resources_key:
                resources = cls.find_value_by_accessor(data, cls.resources_key)
            else:
                resources = data

            if not isinstance(resources, list):
                resources = [resources]

            marker = None
            for raw_resource in resources:
                # Do not allow keys called "self" through. Glance chose
                # to name a key "self", so we need to pop it out because
                # we can't send it through cls.existing and into the
                # Resource initializer. "self" is already the first
                # argument and is practically a reserved word.
                raw_resource.pop("self", None)

                if cls.resource_key and cls.resource_key in raw_resource:
                    raw_resource = raw_resource[cls.resource_key]

                value = cls.existing(**raw_resource)

                marker = value.id
                yield value
                total_yielded += 1

            if resources and paginated:
                uri, next_params = cls._get_next_link(uri, response, data,
                                                      marker, limit,
                                                      total_yielded)
                query_params.update(next_params)
            else:
                return
Пример #10
0
 class Child(resource.Resource):
     something = resource.Body("something")
Пример #11
0
class Domain(_base.Resource):
    """WAF Domain Resource"""
    resources_key = 'items'
    base_path = '/waf/instance'

    # capabilities
    allow_create = True
    allow_list = True
    allow_fetch = True
    allow_delete = True
    allow_commit = True

    _query_mapping = resource.QueryParameters('name',
                                              'hostname',
                                              'policy_name',
                                              'limit',
                                              'offset',
                                              policy_name='policyname',
                                              name='hostname')

    #: Properties
    #: Specifies whether a domain name is connected to WAF
    access_status = resource.Body('access_status', type=int)
    #: Certificate ID.
    #: This parameter is mandatory when client_protocol is set to HTTPS.
    certificate_id = resource.Body('certificate_id')
    #: CNAME
    cname = resource.Body('cname')
    #: domain name
    name = resource.Body('hostname', aka='hostname')
    #: Specifies the policy ID.
    policy_id = resource.Body('policy_id')
    #: protocol type of the client.
    #: The options are HTTP, HTTPS, and HTTP,HTTPS.
    protocol = resource.Body('protocol')
    #: WAF mode.
    protect_status = resource.Body('protect_status', type=int)
    #: Specifies whether a proxy is configured.
    proxy = resource.Body('proxy', type=bool)
    #: Specifies the origin server information, including the client_protocol,
    #: server_protocol, address, and port fields.
    server = resource.Body('server', type=list, list_type=ServerEntry)
    #: source IP header. This parameter is required only when proxy is set
    #: to true.
    #: The options are as follows: default, cloudflare, akamai, and custom.
    sip_header_name = resource.Body('sip_header_name')
    #: Specifies the HTTP request header for identifying the real source IP
    #: address. This parameter is required only when proxy is set to true.
    #: - If sip_header_name is default, sip_header_list is ["X-Forwarded-For"].
    #: - If sip_header_name is cloudflare, sip_header_list is
    #: ["CF-Connecting-IP", "X-Forwarded-For"].
    #: - If sip_header_name is akamai, sip_header_list is ["True-Client-IP"].
    #: - If sip_header_name is custom, you can customize a value.
    sip_header_list = resource.Body('sip_header_list', type=list)
    #: subdomain name.
    #: This parameter is returned only when proxy is set to true.
    subdomain = resource.Body('sub_domain')
    #: Certificate uploading timestamp
    timestamp = resource.Body('timestamp')
    #: TXT record. This parameter is returned only when proxy is set to true.
    txt_record = resource.Body('txt_code')
Пример #12
0
class PortGroup(resource.Resource):

    resources_key = 'portgroups'
    base_path = '/portgroups'
    service = baremetal_service.BaremetalService()

    # capabilities
    allow_create = True
    allow_get = True
    allow_update = True
    allow_delete = True
    allow_list = True
    update_method = 'PATCH'

    _query_mapping = resource.QueryParameters(
        'node',
        'address',
        'fields',
    )

    #: The physical hardware address of the portgroup, typically the hardware
    #: MAC address. Added in API microversion 1.23.
    address = resource.Body('address')
    #: Timestamp at which the portgroup was created.
    created_at = resource.Body('created_at')
    #: A set of one or more arbitrary metadata key and value pairs.
    extra = resource.Body('extra', type=dict)
    #: The name of the portgroup
    name = resource.Body('name')
    #: The UUID for the portgroup
    id = resource.Body('uuid', alternate_id=True)
    #: Internal metadaa set and stored by the portgroup.
    internal_info = resource.Body('internal_info')
    #: Whether ports that are members of this portgroup can be used as
    #: standalone ports. Added in API microversion 1.23.
    is_standalone_ports_supported = resource.Body('standalone_ports_supported',
                                                  type=bool)
    #: A list of relative links, including the self and bookmark links.
    links = resource.Body('links', type=list)
    #: UUID of the node this portgroup belongs to.
    node_id = resource.Body('node_uuid')
    #: A list of links to the collection of ports belonging to this portgroup.
    #: Added in API microversion 1.24.
    ports = resource.Body('ports')
    #: Timestamp at which the portgroup was last updated.
    updated_at = resource.Body('updated_at')
Пример #13
0
class Server(resource.Resource, metadata.MetadataMixin):
    resource_key = 'server'
    resources_key = 'servers'
    base_path = '/servers'
    service = compute_service.ComputeService()

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

    _query_mapping = resource.QueryParameters("image",
                                              "flavor",
                                              "name",
                                              "status",
                                              "host",
                                              "all_tenants",
                                              "sort_key",
                                              "sort_dir",
                                              "reservation_id",
                                              "tags",
                                              "project_id",
                                              tags_any="tags-any",
                                              not_tags="not-tags",
                                              not_tags_any="not-tags-any",
                                              is_deleted="deleted",
                                              ipv4_address="ip",
                                              ipv6_address="ip6",
                                              changes_since="changes-since")

    #: A list of dictionaries holding links relevant to this server.
    links = resource.Body('links')

    access_ipv4 = resource.Body('accessIPv4')
    access_ipv6 = resource.Body('accessIPv6')
    #: A dictionary of addresses this server can be accessed through.
    #: The dictionary contains keys such as ``private`` and ``public``,
    #: each containing a list of dictionaries for addresses of that type.
    #: The addresses are contained in a dictionary with keys ``addr``
    #: and ``version``, which is either 4 or 6 depending on the protocol
    #: of the IP address. *Type: dict*
    addresses = resource.Body('addresses', type=dict)
    #: Timestamp of when the server was created.
    created_at = resource.Body('created')
    #: The flavor reference, as a ID or full URL, for the flavor to use for
    #: this server.
    flavor_id = resource.Body('flavorRef')
    #: The flavor property as returned from server.
    flavor = resource.Body('flavor', type=dict)
    #: An ID representing the host of this server.
    host_id = resource.Body('hostId')
    #: The image reference, as a ID or full URL, for the image to use for
    #: this server.
    image_id = resource.Body('imageRef')
    #: The image property as returned from server.
    image = resource.Body('image', type=dict)
    #: Metadata stored for this server. *Type: dict*
    metadata = resource.Body('metadata', type=dict)
    #: While the server is building, this value represents the percentage
    #: of completion. Once it is completed, it will be 100.  *Type: int*
    progress = resource.Body('progress', type=int)
    #: The ID of the project this server is associated with.
    project_id = resource.Body('tenant_id')
    #: The state this server is in. Valid values include ``ACTIVE``,
    #: ``BUILDING``, ``DELETED``, ``ERROR``, ``HARD_REBOOT``, ``PASSWORD``,
    #: ``PAUSED``, ``REBOOT``, ``REBUILD``, ``RESCUED``, ``RESIZED``,
    #: ``REVERT_RESIZE``, ``SHUTOFF``, ``SOFT_DELETED``, ``STOPPED``,
    #: ``SUSPENDED``, ``UNKNOWN``, or ``VERIFY_RESIZE``.
    status = resource.Body('status')
    #: Timestamp of when this server was last updated.
    updated_at = resource.Body('updated')
    #: The ID of the owners of this server.
    user_id = resource.Body('user_id')
    #: The name of an associated keypair
    key_name = resource.Body('key_name')
    #: The disk configuration. Either AUTO or MANUAL.
    disk_config = resource.Body('OS-DCF:diskConfig')
    #: Indicates whether a configuration drive enables metadata injection.
    #: Not all cloud providers enable this feature.
    has_config_drive = resource.Body('config_drive')
    #: The name of the availability zone this server is a part of.
    availability_zone = resource.Body('OS-EXT-AZ:availability_zone')
    #: The power state of this server.
    power_state = resource.Body('OS-EXT-STS:power_state')
    #: The task state of this server.
    task_state = resource.Body('OS-EXT-STS:task_state')
    #: The VM state of this server.
    vm_state = resource.Body('OS-EXT-STS:vm_state')
    #: A list of an attached volumes. Each item in the list contains at least
    #: an "id" key to identify the specific volumes.
    attached_volumes = resource.Body('os-extended-volumes:volumes_attached')
    #: The timestamp when the server was launched.
    launched_at = resource.Body('OS-SRV-USG:launched_at')
    #: The timestamp when the server was terminated (if it has been).
    terminated_at = resource.Body('OS-SRV-USG:terminated_at')
    #: A list of applicable security groups. Each group contains keys for
    #: description, name, id, and rules.
    security_groups = resource.Body('security_groups')
    #: When a server is first created, it provides the administrator password.
    admin_password = resource.Body('adminPass')
    #: The file path and contents, text only, to inject into the server at
    #: launch. The maximum size of the file path data is 255 bytes.
    #: The maximum limit is The number of allowed bytes in the decoded,
    #: rather than encoded, data.
    personality = resource.Body('personality')
    #: Configuration information or scripts to use upon launch.
    #: Must be Base64 encoded.
    user_data = resource.Body('OS-EXT-SRV-ATTR:user_data')
    #: Enables fine grained control of the block device mapping for an
    #: instance. This is typically used for booting servers from volumes.
    block_device_mapping = resource.Body('block_device_mapping_v2')
    #: The dictionary of data to send to the scheduler.
    scheduler_hints = resource.Body('OS-SCH-HNT:scheduler_hints', type=dict)
    #: A networks object. Required parameter when there are multiple
    #: networks defined for the tenant. When you do not specify the
    #: networks parameter, the server attaches to the only network
    #: created for the current tenant.
    networks = resource.Body('networks')
    #: The hypervisor host name. Appears in the response for administrative
    #: users only.
    hypervisor_hostname = resource.Body('OS-EXT-SRV-ATTR:hypervisor_hostname')
    #: The instance name. The Compute API generates the instance name from the
    #: instance name template. Appears in the response for administrative users
    #: only.
    instance_name = resource.Body('OS-EXT-SRV-ATTR:instance_name')

    def _prepare_request(self, requires_id=True, prepend_key=True):
        request = super(Server, self)._prepare_request(requires_id=requires_id,
                                                       prepend_key=prepend_key)

        server_body = request.body[self.resource_key]

        # Some names exist without prefix on requests but with a prefix
        # on responses. If we find that we've populated one of these
        # attributes with something and then go to make a request, swap out
        # the name to the bare version.

        # Availability Zones exist with a prefix on response, but not request
        az_key = "OS-EXT-AZ:availability_zone"
        if az_key in server_body:
            server_body["availability_zone"] = server_body.pop(az_key)

        # User Data exists with a prefix on response, but not request
        ud_key = "OS-EXT-SRV-ATTR:user_data"
        if ud_key in server_body:
            server_body["user_data"] = server_body.pop(ud_key)

        # Scheduler hints are sent in a top-level scope, not within the
        # resource_key scope like everything else. If we try to send
        # scheduler_hints, pop them out of the resource_key scope and into
        # their own top-level scope.
        hint_key = "OS-SCH-HNT:scheduler_hints"
        if hint_key in server_body:
            request.body[hint_key] = server_body.pop(hint_key)

        return request

    def _action(self, session, body):
        """Preform server actions given the message body."""
        # NOTE: This is using Server.base_path instead of self.base_path
        # as both Server and ServerDetail instances can be acted on, but
        # the URL used is sans any additional /detail/ part.
        url = utils.urljoin(Server.base_path, self.id, 'action')
        headers = {'Accept': ''}
        return session.post(url, json=body, headers=headers)

    def change_password(self, session, new_password):
        """Change the administrator password to the given password."""
        body = {'changePassword': {'adminPass': new_password}}
        self._action(session, body)

    def get_password(self, session):
        """Get the encrypted administrator password."""
        url = utils.urljoin(Server.base_path, self.id, 'os-server-password')
        return session.get(url, endpoint_filter=self.service)

    def reboot(self, session, reboot_type):
        """Reboot server where reboot_type might be 'SOFT' or 'HARD'."""
        body = {'reboot': {'type': reboot_type}}
        self._action(session, body)

    def force_delete(self, session):
        """Force delete a server."""
        body = {'forceDelete': None}
        self._action(session, body)

    def rebuild(self,
                session,
                name,
                admin_password,
                preserve_ephemeral=False,
                image=None,
                access_ipv4=None,
                access_ipv6=None,
                metadata=None,
                personality=None):
        """Rebuild the server with the given arguments."""
        action = {
            'name': name,
            'adminPass': admin_password,
            'preserve_ephemeral': preserve_ephemeral
        }
        if image is not None:
            action['imageRef'] = resource.Resource._get_id(image)
        if access_ipv4 is not None:
            action['accessIPv4'] = access_ipv4
        if access_ipv6 is not None:
            action['accessIPv6'] = access_ipv6
        if metadata is not None:
            action['metadata'] = metadata
        if personality is not None:
            action['personality'] = personality

        body = {'rebuild': action}
        response = self._action(session, body)
        self._translate_response(response)
        return self

    def resize(self, session, flavor):
        """Resize server to flavor reference."""
        body = {'resize': {'flavorRef': flavor}}
        self._action(session, body)

    def confirm_resize(self, session):
        """Confirm the resize of the server."""
        body = {'confirmResize': None}
        self._action(session, body)

    def revert_resize(self, session):
        """Revert the resize of the server."""
        body = {'revertResize': None}
        self._action(session, body)

    def create_image(self, session, name, metadata=None):
        """Create image from server."""
        action = {'name': name}
        if metadata is not None:
            action['metadata'] = metadata
        body = {'createImage': action}
        self._action(session, body)

    def add_security_group(self, session, security_group):
        body = {"addSecurityGroup": {"name": security_group}}
        self._action(session, body)

    def remove_security_group(self, session, security_group):
        body = {"removeSecurityGroup": {"name": security_group}}
        self._action(session, body)

    def reset_state(self, session, state):
        body = {"os-resetState": {"state": state}}
        self._action(session, body)

    def add_fixed_ip(self, session, network_id):
        body = {"addFixedIp": {"networkId": network_id}}
        self._action(session, body)

    def remove_fixed_ip(self, session, address):
        body = {"removeFixedIp": {"address": address}}
        self._action(session, body)

    def add_floating_ip(self, session, address, fixed_address=None):
        body = {"addFloatingIp": {"address": address}}
        if fixed_address is not None:
            body['addFloatingIp']['fixed_address'] = fixed_address
        self._action(session, body)

    def remove_floating_ip(self, session, address):
        body = {"removeFloatingIp": {"address": address}}
        self._action(session, body)

    def backup(self, session, name, backup_type, rotation):
        body = {
            "createBackup": {
                "name": name,
                "backup_type": backup_type,
                "rotation": rotation
            }
        }
        self._action(session, body)

    def pause(self, session):
        body = {"pause": None}
        self._action(session, body)

    def unpause(self, session):
        body = {"unpause": None}
        self._action(session, body)

    def suspend(self, session):
        body = {"suspend": None}
        self._action(session, body)

    def resume(self, session):
        body = {"resume": None}
        self._action(session, body)

    def lock(self, session):
        body = {"lock": None}
        self._action(session, body)

    def unlock(self, session):
        body = {"unlock": None}
        self._action(session, body)

    def rescue(self, session, admin_pass=None, image_ref=None):
        body = {"rescue": {}}
        if admin_pass is not None:
            body["rescue"]["adminPass"] = admin_pass
        if image_ref is not None:
            body["rescue"]["rescue_image_ref"] = image_ref
        self._action(session, body)

    def unrescue(self, session):
        body = {"unrescue": None}
        self._action(session, body)

    def evacuate(self, session, host=None, admin_pass=None, force=None):
        body = {"evacuate": {}}
        if host is not None:
            body["evacuate"]["host"] = host
        if admin_pass is not None:
            body["evacuate"]["adminPass"] = admin_pass
        if force is not None:
            body["evacuate"]["force"] = force
        self._action(session, body)

    def start(self, session):
        body = {"os-start": None}
        self._action(session, body)

    def stop(self, session):
        body = {"os-stop": None}
        self._action(session, body)

    def shelve(self, session):
        body = {"shelve": None}
        self._action(session, body)

    def unshelve(self, session):
        body = {"unshelve": None}
        self._action(session, body)

    def migrate(self, session):
        body = {"migrate": None}
        self._action(session, body)

    def get_console_output(self, session, length=None):
        body = {"os-getConsoleOutput": {}}
        if length is not None:
            body["os-getConsoleOutput"]["length"] = length
        resp = self._action(session, body)
        return resp.json()

    def live_migrate(self, session, host, force):
        body = {
            "os-migrateLive": {
                "host": host,
                "block_migration": "auto",
                "force": force
            }
        }
        self._action(session, body)
Пример #14
0
class PortGroup(_common.ListMixin, resource.Resource):

    resources_key = 'portgroups'
    base_path = '/portgroups'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True
    allow_patch = True
    commit_method = 'PATCH'
    commit_jsonpatch = True

    _query_mapping = resource.QueryParameters(
        'node',
        'address',
        fields={'type': _common.fields_type},
    )

    # The mode and properties field introduced in 1.26.
    _max_microversion = '1.26'

    #: The physical hardware address of the portgroup, typically the hardware
    #: MAC address. Added in API microversion 1.23.
    address = resource.Body('address')
    #: Timestamp at which the portgroup was created.
    created_at = resource.Body('created_at')
    #: A set of one or more arbitrary metadata key and value pairs.
    extra = resource.Body('extra', type=dict)
    #: The name of the portgroup
    name = resource.Body('name')
    #: The UUID for the portgroup
    id = resource.Body('uuid', alternate_id=True)
    #: Internal metadaa set and stored by the portgroup.
    internal_info = resource.Body('internal_info')
    #: Whether ports that are members of this portgroup can be used as
    #: standalone ports. Added in API microversion 1.23.
    is_standalone_ports_supported = resource.Body('standalone_ports_supported',
                                                  type=bool)
    #: A list of relative links, including the self and bookmark links.
    links = resource.Body('links', type=list)
    #: Port bonding mode. Added in API microversion 1.26.
    mode = resource.Body('mode')
    #: UUID of the node this portgroup belongs to.
    node_id = resource.Body('node_uuid')
    #: A list of links to the collection of ports belonging to this portgroup.
    #: Added in API microversion 1.24.
    ports = resource.Body('ports')
    #: Port group properties. Added in API microversion 1.26.
    properties = resource.Body('properties', type=dict)
    #: Timestamp at which the portgroup was last updated.
    updated_at = resource.Body('updated_at')
Пример #15
0
class Router(resource.Resource, resource.TagMixin):
    resource_key = 'router'
    resources_key = 'routers'
    base_path = '/routers'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True

    # NOTE: We don't support query on datetime, list or dict fields
    _query_mapping = resource.QueryParameters(
        'description', 'flavor_id', 'name', 'status',
        is_admin_state_up='admin_state_up',
        is_distributed='distributed',
        is_ha='ha',
        project_id='tenant_id',
        **resource.TagMixin._tag_query_parameters
    )

    # Properties
    #: Availability zone hints to use when scheduling the router.
    #: *Type: list of availability zone names*
    availability_zone_hints = resource.Body('availability_zone_hints',
                                            type=list)
    #: Availability zones for the router.
    #: *Type: list of availability zone names*
    availability_zones = resource.Body('availability_zones', type=list)
    #: Timestamp when the router was created.
    created_at = resource.Body('created_at')
    #: The router description.
    description = resource.Body('description')
    #: The ``network_id``, for the external gateway. *Type: dict*
    external_gateway_info = resource.Body('external_gateway_info', type=dict)
    #: The ID of the flavor.
    flavor_id = resource.Body('flavor_id')
    #: The administrative state of the router, which is up ``True``
    #: or down ``False``. *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: The distributed state of the router, which is distributed ``True``
    #: or not ``False``. *Type: bool*
    is_distributed = resource.Body('distributed', type=bool)
    #: The highly-available state of the router, which is highly available
    #: ``True`` or not ``False``. *Type: bool*
    is_ha = resource.Body('ha', type=bool)
    #: The router name.
    name = resource.Body('name')
    #: The ID of the project this router is associated with.
    project_id = resource.Body('tenant_id')
    #: Revision number of the router. *Type: int*
    revision_number = resource.Body('revision', type=int)
    #: The extra routes configuration for the router.
    routes = resource.Body('routes', type=list)
    #: The router status.
    status = resource.Body('status')
    #: Timestamp when the router was created.
    updated_at = resource.Body('updated_at')

    def _put(self, session, url, body):
        resp = session.put(url, json=body)
        exceptions.raise_from_response(resp)
        return resp

    def add_interface(self, session, **body):
        """Add an internal interface to a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The body requested to be updated on the router

        :returns: The body of the response as a dictionary.

        :raises: :class:`~openstack.exceptions.SDKException` on error.
        """
        url = utils.urljoin(self.base_path, self.id, 'add_router_interface')
        resp = self._put(session, url, body)
        return resp.json()

    def remove_interface(self, session, **body):
        """Remove an internal interface from a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The body requested to be updated on the router

        :returns: The body of the response as a dictionary.

        :raises: :class:`~openstack.exceptions.SDKException` on error.
        """
        url = utils.urljoin(self.base_path, self.id, 'remove_router_interface')
        resp = self._put(session, url, body)
        return resp.json()

    def add_extra_routes(self, session, body):
        """Add extra routes to a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The request body as documented in the api-ref.

        :returns: The response as a Router object with the added extra routes.

        :raises: :class:`~openstack.exceptions.SDKException` on error.
        """
        url = utils.urljoin(self.base_path, self.id, 'add_extraroutes')
        resp = self._put(session, url, body)
        self._translate_response(resp)
        return self

    def remove_extra_routes(self, session, body):
        """Remove extra routes from a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The request body as documented in the api-ref.

        :returns: The response as a Router object with the extra routes left.

        :raises: :class:`~openstack.exceptions.SDKException` on error.
        """
        url = utils.urljoin(self.base_path, self.id, 'remove_extraroutes')
        resp = self._put(session, url, body)
        self._translate_response(resp)
        return self

    def add_gateway(self, session, **body):
        """Add an external gateway to a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The body requested to be updated on the router

        :returns: The body of the response as a dictionary.
        """
        url = utils.urljoin(self.base_path, self.id,
                            'add_gateway_router')
        resp = session.put(url, json=body)
        return resp.json()

    def remove_gateway(self, session, **body):
        """Remove an external gateway from a logical router.

        :param session: The session to communicate through.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param dict body: The body requested to be updated on the router

        :returns: The body of the response as a dictionary.
        """
        url = utils.urljoin(self.base_path, self.id,
                            'remove_gateway_router')
        resp = session.put(url, json=body)
        return resp.json()
Пример #16
0
class Node(_common.ListMixin, resource.Resource):

    resources_key = 'nodes'
    base_path = '/nodes'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True
    commit_method = 'PATCH'
    commit_jsonpatch = True

    _query_mapping = resource.QueryParameters(
        'associated',
        'conductor_group',
        'driver',
        'fault',
        'provision_state',
        'resource_class',
        fields={
            'name': 'fields',
            'type': _common.comma_separated_list
        },
        instance_id='instance_uuid',
        is_maintenance='maintenance',
    )

    # The conductor_group field introduced in 1.46 (Rocky).
    _max_microversion = '1.46'

    # Properties
    #: The UUID of the chassis associated wit this node. Can be empty or None.
    chassis_id = resource.Body("chassis_uuid")
    #: The current clean step.
    clean_step = resource.Body("clean_step")
    #: Conductor group this node is managed by. Added in API microversion 1.46.
    conductor_group = resource.Body("conductor_group")
    #: Timestamp at which the node was last updated.
    created_at = resource.Body("created_at")
    #: The current deploy step. Added in API microversion 1.44.
    deploy_step = resource.Body("deploy_step")
    #: The name of the driver.
    driver = resource.Body("driver")
    #: All the metadata required by the driver to manage this node. List of
    #: fields varies between drivers, and can be retrieved from the
    #: :class:`openstack.baremetal.v1.driver.Driver` resource.
    driver_info = resource.Body("driver_info", type=dict)
    #: Internal metadata set and stored by node's driver. This is read-only.
    driver_internal_info = resource.Body("driver_internal_info", type=dict)
    #: A set of one or more arbitrary metadata key and value pairs.
    extra = resource.Body("extra")
    #: Fault type that caused the node to enter maintenance mode.
    #: Introduced in API microversion 1.42.
    fault = resource.Body("fault")
    #: The UUID of the node resource.
    id = resource.Body("uuid", alternate_id=True)
    #: Information used to customize the deployed image, e.g. size of root
    #: partition, config drive in the form of base64 encoded string and other
    #: metadata.
    instance_info = resource.Body("instance_info")
    #: UUID of the nova instance associated with this node.
    instance_id = resource.Body("instance_uuid")
    #: Whether console access is enabled on this node.
    is_console_enabled = resource.Body("console_enabled", type=bool)
    #: Whether node is currently in "maintenance mode". Nodes put into
    #: maintenance mode are removed from the available resource pool.
    is_maintenance = resource.Body("maintenance", type=bool)
    #: Any error from the most recent transaction that started but failed to
    #: finish.
    last_error = resource.Body("last_error")
    #: A list of relative links, including self and bookmark links.
    links = resource.Body("links", type=list)
    #: user settable description of the reason why the node was placed into
    #: maintenance mode.
    maintenance_reason = resource.Body("maintenance_reason")
    #: Human readable identifier for the node. May be undefined. Certain words
    #: are reserved. Added in API microversion 1.5
    name = resource.Body("name")
    #: Links to the collection of ports on this node.
    ports = resource.Body("ports", type=list)
    #: Links to the collection of portgroups on this node. Available since
    #: API microversion 1.24.
    port_groups = resource.Body("portgroups", type=list)
    #: The current power state. Usually "power on" or "power off", but may be
    #: "None" if service is unable to determine the power state.
    power_state = resource.Body("power_state")
    #: Physical characteristics of the node. Content populated by the service
    #: during inspection.
    properties = resource.Body("properties", type=dict)
    #: The current provisioning state of the node.
    provision_state = resource.Body("provision_state")
    #: The current RAID configuration of the node.
    raid_config = resource.Body("raid_config")
    #: The name of an service conductor host which is holding a lock on this
    #: node, if a lock is held.
    reservation = resource.Body("reservation")
    #: A string to be used by external schedulers to identify this node as a
    #: unit of a specific type of resource. Added in API microversion 1.21.
    resource_class = resource.Body("resource_class")
    #: Links to the collection of states.
    states = resource.Body("states", type=list)
    #: The requested state if a provisioning action has been requested. For
    #: example, ``AVAILABLE``, ``DEPLOYING``, ``DEPLOYWAIT``, ``DEPLOYING``,
    #: ``ACTIVE`` etc.
    target_provision_state = resource.Body("target_provision_state")
    #: The requested state during a state transition.
    target_power_state = resource.Body("target_power_state")
    #: The requested RAID configuration of the node which will be applied when
    #: the node next transitions through the CLEANING state.
    target_raid_config = resource.Body("target_raid_config")
    #: Traits of the node. Introduced in API microversion 1.37.
    traits = resource.Body("traits", type=list)
    #: Timestamp at which the node was last updated.
    updated_at = resource.Body("updated_at")

    # Hardware interfaces grouped together for convenience.

    #: BIOS interface to use when setting BIOS properties of the node.
    #: Introduced in API microversion 1.40.
    bios_interface = resource.Body("bios_interface")
    #: Boot interface to use when configuring boot of the node.
    #: Introduced in API microversion 1.31.
    boot_interface = resource.Body("boot_interface")
    #: Console interface to use when working with serial console.
    #: Introduced in API microversion 1.31.
    console_interface = resource.Body("console_interface")
    #: Deploy interface to use when deploying the node.
    #: Introduced in API microversion 1.31.
    deploy_interface = resource.Body("deploy_interface")
    #: Inspect interface to use when inspecting the node.
    #: Introduced in API microversion 1.31.
    inspect_interface = resource.Body("inspect_interface")
    #: Management interface to use for management actions on the node.
    #: Introduced in API microversion 1.31.
    management_interface = resource.Body("management_interface")
    #: Network interface provider to use when plumbing the network connections
    #: for this node. Introduced in API microversion 1.20.
    network_interface = resource.Body("network_interface")
    #: Power interface to use for power actions on the node.
    #: Introduced in API microversion 1.31.
    power_interface = resource.Body("power_interface")
    #: RAID interface to use for configuring RAID on the node.
    #: Introduced in API microversion 1.31.
    raid_interface = resource.Body("raid_interface")
    #: Rescue interface to use for rescuing of the node.
    #: Introduced in API microversion 1.38.
    rescue_interface = resource.Body("rescue_interface")
    #: Storage interface to use when attaching remote storage.
    #: Introduced in API microversion 1.33.
    storage_interface = resource.Body("storage_interface")
    #: Vendor interface to use for vendor-specific actions on the node.
    #: Introduced in API microversion 1.31.
    vendor_interface = resource.Body("vendor_interface")

    def _consume_body_attrs(self, attrs):
        if 'provision_state' in attrs and attrs['provision_state'] is None:
            # API version 1.1 uses None instead of "available". Make it
            # consistent.
            attrs['provision_state'] = 'available'
        return super(Node, self)._consume_body_attrs(attrs)

    def create(self, session, *args, **kwargs):
        """Create a remote resource based on this instance.

        The overridden version is capable of handling the populated
        ``provision_state`` field of one of three values: ``enroll``,
        ``manageable`` or ``available``. The default is currently
        ``available``, since it's the only state supported by all API versions.

        Note that Bare Metal API 1.4 is required for ``manageable`` and
        1.11 is required for ``enroll``.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`

        :return: This :class:`Resource` instance.
        :raises: ValueError if the Node's ``provision_state`` is not one of
            ``None``, ``enroll``, ``manageable`` or ``available``.
        :raises: :exc:`~openstack.exceptions.NotSupported` if
            the ``provision_state`` cannot be reached with any API version
            supported by the server.
        """
        expected_provision_state = self.provision_state
        if expected_provision_state is None:
            expected_provision_state = 'available'

        if expected_provision_state not in ('enroll', 'manageable',
                                            'available'):
            raise ValueError(
                "Node's provision_state must be one of 'enroll', "
                "'manageable' or 'available' for creation, got %s" %
                expected_provision_state)

        session = self._get_session(session)
        # Verify that the requested provision state is reachable with the API
        # version we are going to use.
        try:
            expected_version = _common.STATE_VERSIONS[expected_provision_state]
        except KeyError:
            pass
        else:
            self._assert_microversion_for(
                session,
                'create',
                expected_version,
                error_message="Cannot create a node with initial provision "
                "state %s" % expected_provision_state)

        # Ironic cannot set provision_state itself, so marking it as unchanged
        self._body.clean(only={'provision_state'})
        super(Node, self).create(session, *args, **kwargs)

        if (self.provision_state == 'enroll'
                and expected_provision_state != 'enroll'):
            self.set_provision_state(session, 'manage', wait=True)

        if (self.provision_state == 'manageable'
                and expected_provision_state == 'available'):
            self.set_provision_state(session, 'provide', wait=True)

        if (self.provision_state == 'available'
                and expected_provision_state == 'manageable'):
            self.set_provision_state(session, 'manage', wait=True)

        return self

    def set_provision_state(self,
                            session,
                            target,
                            config_drive=None,
                            clean_steps=None,
                            rescue_password=None,
                            wait=False,
                            timeout=None):
        """Run an action modifying this node's provision state.

        This call is asynchronous, it will return success as soon as the Bare
        Metal service acknowledges the request.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param target: Provisioning action, e.g. ``active``, ``provide``.
            See the Bare Metal service documentation for available actions.
        :param config_drive: Config drive to pass to the node, only valid
            for ``active` and ``rebuild`` targets. You can use functions from
            :mod:`openstack.baremetal.configdrive` to build it.
        :param clean_steps: Clean steps to execute, only valid for ``clean``
            target.
        :param rescue_password: Password for the rescue operation, only valid
            for ``rescue`` target.
        :param wait: Whether to wait for the target state to be reached.
        :param timeout: Timeout (in seconds) to wait for the target state to be
            reached. If ``None``, wait without timeout.

        :return: This :class:`Node` instance.
        :raises: ValueError if ``config_drive``, ``clean_steps`` or
            ``rescue_password`` are provided with an invalid ``target``.
        """
        session = self._get_session(session)

        if target in _common.PROVISIONING_VERSIONS:
            version = '1.%d' % _common.PROVISIONING_VERSIONS[target]
        else:
            if config_drive and target == 'rebuild':
                version = '1.35'
            else:
                version = None
        version = utils.pick_microversion(session, version)

        body = {'target': target}
        if config_drive:
            if target not in ('active', 'rebuild'):
                raise ValueError('Config drive can only be provided with '
                                 '"active" and "rebuild" targets')
            # Not a typo - ironic accepts "configdrive" (without underscore)
            body['configdrive'] = config_drive

        if clean_steps is not None:
            if target != 'clean':
                raise ValueError('Clean steps can only be provided with '
                                 '"clean" target')
            body['clean_steps'] = clean_steps

        if rescue_password is not None:
            if target != 'rescue':
                raise ValueError('Rescue password can only be provided with '
                                 '"rescue" target')
            body['rescue_password'] = rescue_password

        if wait:
            try:
                expected_state = _common.EXPECTED_STATES[target]
            except KeyError:
                raise ValueError('For target %s the expected state is not '
                                 'known, cannot wait for it' % target)

        request = self._prepare_request(requires_id=True)
        request.url = utils.urljoin(request.url, 'states', 'provision')
        response = session.put(
            request.url,
            json=body,
            headers=request.headers,
            microversion=version,
            retriable_status_codes=_common.RETRIABLE_STATUS_CODES)

        msg = ("Failed to set provision state for bare metal node {node} "
               "to {target}".format(node=self.id, target=target))
        exceptions.raise_from_response(response, error_message=msg)

        if wait:
            return self.wait_for_provision_state(session,
                                                 expected_state,
                                                 timeout=timeout)
        else:
            return self.fetch(session)

    def wait_for_provision_state(self,
                                 session,
                                 expected_state,
                                 timeout=None,
                                 abort_on_failed_state=True):
        """Wait for the node to reach the expected state.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param expected_state: The expected provisioning state to reach.
        :param timeout: If ``wait`` is set to ``True``, specifies how much (in
            seconds) to wait for the expected state to be reached. The value of
            ``None`` (the default) means no client-side timeout.
        :param abort_on_failed_state: If ``True`` (the default), abort waiting
            if the node reaches a failure state which does not match the
            expected one. Note that the failure state for ``enroll`` ->
            ``manageable`` transition is ``enroll`` again.

        :return: This :class:`Node` instance.
        """
        for count in utils.iterate_timeout(
                timeout, "Timeout waiting for node %(node)s to reach "
                "target state '%(state)s'" % {
                    'node': self.id,
                    'state': expected_state
                }):
            self.fetch(session)
            if self._check_state_reached(session, expected_state,
                                         abort_on_failed_state):
                return self

            _logger.debug(
                'Still waiting for node %(node)s to reach state '
                '"%(target)s", the current state is "%(state)s"', {
                    'node': self.id,
                    'target': expected_state,
                    'state': self.provision_state
                })

    def wait_for_reservation(self, session, timeout=None):
        """Wait for a lock on the node to be released.

        Bare metal nodes in ironic have a reservation lock that
        is used to represent that a conductor has locked the node
        while performing some sort of action, such as changing
        configuration as a result of a machine state change.

        This lock can occur during power syncronization, and prevents
        updates to objects attached to the node, such as ports.

        Note that nothing prevents a conductor from acquiring the lock again
        after this call returns, so it should be treated as best effort.

        Returns immediately if there is no reservation on the node.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param timeout: How much (in seconds) to wait for the lock to be
            released. The value of ``None`` (the default) means no timeout.

        :return: This :class:`Node` instance.
        """
        if self.reservation is None:
            return self

        for count in utils.iterate_timeout(
                timeout,
                "Timeout waiting for the lock to be released on node %s" %
                self.id):
            self.fetch(session)
            if self.reservation is None:
                return self

            _logger.debug(
                'Still waiting for the lock to be released on node '
                '%(node)s, currently locked by conductor %(host)s', {
                    'node': self.id,
                    'host': self.reservation
                })

    def _check_state_reached(self,
                             session,
                             expected_state,
                             abort_on_failed_state=True):
        """Wait for the node to reach the expected state.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param expected_state: The expected provisioning state to reach.
        :param abort_on_failed_state: If ``True`` (the default), abort waiting
            if the node reaches a failure state which does not match the
            expected one. Note that the failure state for ``enroll`` ->
            ``manageable`` transition is ``enroll`` again.

        :return: ``True`` if the target state is reached
        :raises: SDKException if ``abort_on_failed_state`` is ``True`` and
            a failure state is reached.
        """
        # NOTE(dtantsur): microversion 1.2 changed None to available
        if (self.provision_state == expected_state or
            (expected_state == 'available' and self.provision_state is None)):
            return True
        elif not abort_on_failed_state:
            return False

        if self.provision_state.endswith(' failed'):
            raise exceptions.SDKException(
                "Node %(node)s reached failure state \"%(state)s\"; "
                "the last error is %(error)s" % {
                    'node': self.id,
                    'state': self.provision_state,
                    'error': self.last_error
                })
        # Special case: a failure state for "manage" transition can be
        # "enroll"
        elif (expected_state == 'manageable'
              and self.provision_state == 'enroll' and self.last_error):
            raise exceptions.SDKException(
                "Node %(node)s could not reach state manageable: "
                "failed to verify management credentials; "
                "the last error is %(error)s" % {
                    'node': self.id,
                    'error': self.last_error
                })

    def attach_vif(self, session, vif_id):
        """Attach a VIF to the node.

        The exact form of the VIF ID depends on the network interface used by
        the node. In the most common case it is a Network service port
        (NOT a Bare Metal port) ID. A VIF can only be attached to one node
        at a time.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param string vif_id: Backend-specific VIF ID.
        :return: ``None``
        :raises: :exc:`~openstack.exceptions.NotSupported` if the server
            does not support the VIF API.
        """
        session = self._get_session(session)
        version = self._assert_microversion_for(
            session,
            'commit',
            _common.VIF_VERSION,
            error_message=("Cannot use VIF attachment API"))

        request = self._prepare_request(requires_id=True)
        request.url = utils.urljoin(request.url, 'vifs')
        body = {'id': vif_id}
        response = session.post(
            request.url,
            json=body,
            headers=request.headers,
            microversion=version,
            # NOTE(dtantsur): do not retry CONFLICT, it's a valid status code
            # in this API when the VIF is already attached to another node.
            retriable_status_codes=[503])

        msg = ("Failed to attach VIF {vif} to bare metal node {node}".format(
            node=self.id, vif=vif_id))
        exceptions.raise_from_response(response, error_message=msg)

    def detach_vif(self, session, vif_id, ignore_missing=True):
        """Detach a VIF from the node.

        The exact form of the VIF ID depends on the network interface used by
        the node. In the most common case it is a Network service port
        (NOT a Bare Metal port) ID.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param string vif_id: Backend-specific VIF ID.
        :param bool ignore_missing: When set to ``False``
                    :class:`~openstack.exceptions.ResourceNotFound` will be
                    raised when the VIF does not exist. Otherwise, ``False``
                    is returned.
        :return: ``True`` if the VIF was detached, otherwise ``False``.
        :raises: :exc:`~openstack.exceptions.NotSupported` if the server
            does not support the VIF API.
        """
        session = self._get_session(session)
        version = self._assert_microversion_for(
            session,
            'commit',
            _common.VIF_VERSION,
            error_message=("Cannot use VIF attachment API"))

        request = self._prepare_request(requires_id=True)
        request.url = utils.urljoin(request.url, 'vifs', vif_id)
        response = session.delete(
            request.url,
            headers=request.headers,
            microversion=version,
            retriable_status_codes=_common.RETRIABLE_STATUS_CODES)

        if ignore_missing and response.status_code == 400:
            _logger.debug('VIF %(vif)s was already removed from node %(node)s',
                          {
                              'vif': vif_id,
                              'node': self.id
                          })
            return False

        msg = ("Failed to detach VIF {vif} from bare metal node {node}".format(
            node=self.id, vif=vif_id))
        exceptions.raise_from_response(response, error_message=msg)
        return True

    def list_vifs(self, session):
        """List IDs of VIFs attached to the node.

        The exact form of the VIF ID depends on the network interface used by
        the node. In the most common case it is a Network service port
        (NOT a Bare Metal port) ID.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :return: List of VIF IDs as strings.
        :raises: :exc:`~openstack.exceptions.NotSupported` if the server
            does not support the VIF API.
        """
        session = self._get_session(session)
        version = self._assert_microversion_for(
            session,
            'fetch',
            _common.VIF_VERSION,
            error_message=("Cannot use VIF attachment API"))

        request = self._prepare_request(requires_id=True)
        request.url = utils.urljoin(request.url, 'vifs')
        response = session.get(request.url,
                               headers=request.headers,
                               microversion=version)

        msg = ("Failed to list VIFs attached to bare metal node {node}".format(
            node=self.id))
        exceptions.raise_from_response(response, error_message=msg)
        return [vif['id'] for vif in response.json()['vifs']]

    def validate(self, session, required=('boot', 'deploy', 'power')):
        """Validate required information on a node.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param required: List of interfaces that are required to pass
            validation. The default value is the list of minimum required
            interfaces for provisioning.

        :return: dict mapping interface names to :class:`ValidationResult`
            objects.
        :raises: :exc:`~openstack.exceptions.ValidationException` if validation
            fails for a required interface.
        """
        session = self._get_session(session)
        version = self._get_microversion_for(session, 'fetch')

        request = self._prepare_request(requires_id=True)
        request.url = utils.urljoin(request.url, 'validate')
        response = session.get(request.url,
                               headers=request.headers,
                               microversion=version)

        msg = ("Failed to validate node {node}".format(node=self.id))
        exceptions.raise_from_response(response, error_message=msg)
        result = response.json()

        if required:
            failed = [
                '%s (%s)' % (key, value.get('reason', 'no reason'))
                for key, value in result.items()
                if key in required and not value.get('result')
            ]

            if failed:
                raise exceptions.ValidationException(
                    'Validation failed for required interfaces of node {node}:'
                    ' {failures}'.format(node=self.id,
                                         failures=', '.join(failed)))

        return {
            key: ValidationResult(value.get('result'), value.get('reason'))
            for key, value in result.items()
        }
class ClusterSpec(resource.Resource):

    #: Authentication
    authentication = resource.Body('authentication', type=dict)
    #: Billing mode of the cluster. Currently, only pay-per-use is supported.
    billing = resource.Body('billingMode')
    #: Container network parameters.
    container_network = resource.Body('containerNetwork', type=dict)
    #: Cluster description.
    description = resource.Body('description')
    #: Extended parameters.
    extended_param = resource.Body('extendParam', type=dict)
    #: Cluster flavors.
    flavor = resource.Body('flavor')
    #: Node network parameters.
    host_network = resource.Body('hostNetwork', type=HostNetworkSpec)
    #: Service forwarding mode
    kube_proxy_mode = resource.Body('kubeProxyMode')
    #: Service CIDR block or the IP address range which the kubernetes
    #: clusterIp must fall within
    service_ip_range = resource.Body('kubernetesSvcIpRange')
    #: Cluster type.
    type = resource.Body('type')
    #: Cluster version ['v1.11.7-r2', 'v1.13.10-r0'].
    version = resource.Body('version')
    #: Eni network parameters.
    eni_network = resource.Body('eniNetwork', type=EniNetworkSpec)
Пример #18
0
class LoadBalancer(resource.Resource):
    resource_key = 'loadbalancer'
    resources_key = 'loadbalancers'
    base_path = '/v2.0/lbaas/loadbalancers'
    service = lb_service.LoadBalancerService()

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

    _query_mapping = resource.QueryParameters(
        'description', 'flavor', 'name', 'project_id', 'provider',
        'vip_address', 'vip_network_id', 'vip_port_id', 'vip_subnet_id',
        'vip_qos_policy_id', 'provisioning_status', 'operating_status',
        is_admin_state_up='admin_state_up'
    )

    #: Properties
    #: The administrative state of the load balancer *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: Timestamp when the load balancer was created
    created_at = resource.Body('created_at')
    #: The load balancer description
    description = resource.Body('description')
    #: The load balancer flavor
    flavor = resource.Body('flavor')
    #: List of listeners associated with this load balancer
    listeners = resource.Body('listeners', type=list)
    #: The load balancer name
    name = resource.Body('name')
    #: Operating status of the load balancer
    operating_status = resource.Body('operating_status')
    #: List of pools associated with this load balancer
    pools = resource.Body('pools', type=list)
    #: The ID of the project this load balancer is associated with.
    project_id = resource.Body('project_id')
    #: Provider name for the load balancer.
    provider = resource.Body('provider')
    #: The provisioning status of this load balancer
    provisioning_status = resource.Body('provisioning_status')
    #: Timestamp when the load balancer was last updated
    updated_at = resource.Body('updated_at')
    #: VIP address of load balancer
    vip_address = resource.Body('vip_address')
    #: VIP netowrk ID
    vip_network_id = resource.Body('vip_network_id')
    #: VIP port ID
    vip_port_id = resource.Body('vip_port_id')
    #: VIP subnet ID
    vip_subnet_id = resource.Body('vip_subnet_id')
    # VIP qos policy id
    vip_qos_policy_id = resource.Body('vip_qos_policy_id')

    def delete(self, session, error_message=None):
        request = self._prepare_request()
        headers = {
            "Accept": ""
        }

        request.headers.update(headers)
        params = {}
        if (hasattr(self, 'cascade') and isinstance(self.cascade, bool)
                and self.cascade):
            params['cascade'] = True
        response = session.delete(request.url,
                                  headers=headers,
                                  params=params)

        self._translate_response(response, has_body=False,
                                 error_message=error_message)
        return self
Пример #19
0
class Network(_base.NetworkResource, resource.TagMixin):
    resource_key = 'network'
    resources_key = 'networks'
    base_path = '/networks'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True

    # NOTE: We don't support query on list or datetime fields yet
    _query_mapping = resource.QueryParameters(
        'description',
        'name',
        'status',
        ipv4_address_scope_id='ipv4_address_scope',
        ipv6_address_scope_id='ipv6_address_scope',
        is_admin_state_up='admin_state_up',
        is_port_security_enabled='port_security_enabled',
        is_router_external='router:external',
        is_shared='shared',
        project_id='tenant_id',
        provider_network_type='provider:network_type',
        provider_physical_network='provider:physical_network',
        provider_segmentation_id='provider:segmentation_id',
        **resource.TagMixin._tag_query_parameters)

    # Properties
    #: Availability zone hints to use when scheduling the network.
    #: *Type: list of availability zone names*
    availability_zone_hints = resource.Body('availability_zone_hints')
    #: Availability zones for the network.
    #: *Type: list of availability zone names*
    availability_zones = resource.Body('availability_zones')
    #: Timestamp when the network was created.
    created_at = resource.Body('created_at')
    #: The network description.
    description = resource.Body('description')
    #: The DNS domain associated.
    dns_domain = resource.Body('dns_domain')
    #: The ID of the IPv4 address scope for the network.
    ipv4_address_scope_id = resource.Body('ipv4_address_scope')
    #: The ID of the IPv6 address scope for the network.
    ipv6_address_scope_id = resource.Body('ipv6_address_scope')
    #: The administrative state of the network, which is up ``True`` or
    #: down ``False``. *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: Whether or not this is the default external network.
    #: *Type: bool*
    is_default = resource.Body('is_default', type=bool)
    #: The port security status, which is enabled ``True`` or disabled
    #: ``False``. *Type: bool* *Default: False*
    #: Available for multiple provider extensions.
    is_port_security_enabled = resource.Body('port_security_enabled',
                                             type=bool,
                                             default=False)
    #: Whether or not the router is external.
    #: *Type: bool* *Default: False*
    is_router_external = resource.Body('router:external',
                                       type=bool,
                                       default=False)
    #: Indicates whether this network is shared across all tenants.
    #: By default, only administrative users can change this value.
    #: *Type: bool*
    is_shared = resource.Body('shared', type=bool)
    #: Read-only. The maximum transmission unit (MTU) of the network resource.
    mtu = resource.Body('mtu', type=int)
    #: The network name.
    name = resource.Body('name')
    #: The ID of the project this network is associated with.
    project_id = resource.Body('project_id')
    #: The type of physical network that maps to this network resource.
    #: For example, ``flat``, ``vlan``, ``vxlan``, or ``gre``.
    #: Available for multiple provider extensions.
    provider_network_type = resource.Body('provider:network_type')
    #: The physical network where this network object is implemented.
    #: Available for multiple provider extensions.
    provider_physical_network = resource.Body('provider:physical_network')
    #: An isolated segment ID on the physical network. The provider
    #: network type defines the segmentation model.
    #: Available for multiple provider extensions.
    provider_segmentation_id = resource.Body('provider:segmentation_id')
    #: The ID of the QoS policy attached to the port.
    qos_policy_id = resource.Body('qos_policy_id')
    #: A list of provider segment objects.
    #: Available for multiple provider extensions.
    segments = resource.Body('segments')
    #: The network status.
    status = resource.Body('status')
    #: The associated subnet IDs.
    #: *Type: list of strs of the subnet IDs*
    subnet_ids = resource.Body('subnets', type=list)
    #: Timestamp when the network was last updated.
    updated_at = resource.Body('updated_at')
    #: Indicates the VLAN transparency mode of the network
    is_vlan_transparent = resource.Body('vlan_transparent', type=bool)
Пример #20
0
class LoadBalancer(resource.Resource):
    resource_key = 'loadbalancer'
    resources_key = 'loadbalancers'
    base_path = '/lbaas/loadbalancers'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True

    # Properties
    #: Description for the load balancer.
    description = resource.Body('description')
    #: The administrative state of the load balancer, which is up
    #: ``True`` or down ``False``. *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: List of listeners associated with this load balancer.
    #: *Type: list of dicts which contain the listener IDs*
    listener_ids = resource.Body('listeners', type=list)
    #: Name of the load balancer
    name = resource.Body('name')
    #: Status of load_balancer operating, e.g. ONLINE, OFFLINE.
    operating_status = resource.Body('operating_status')
    #: List of pools associated with this load balancer.
    #: *Type: list of dicts which contain the pool IDs*
    pool_ids = resource.Body('pools', type=list)
    #: The ID of the project this load balancer is associated with.
    project_id = resource.Body('tenant_id')
    #: The name of the provider.
    provider = resource.Body('provider')
    #: Status of load balancer provisioning, e.g. ACTIVE, INACTIVE.
    provisioning_status = resource.Body('provisioning_status')
    #: The IP address of the VIP.
    vip_address = resource.Body('vip_address')
    #: The ID of the port for the VIP.
    vip_port_id = resource.Body('vip_port_id')
    #: The ID of the subnet on which to allocate the VIP address.
    vip_subnet_id = resource.Body('vip_subnet_id')
Пример #21
0
class Tags(resource.Resource):
    base_path = 'stream/tags'

    # Determine the correct base path by the set flag
    def __init__(self, **params):
        super(Tags, self).__init__(**params)
        self.base_path = "stream/tags"
        if "add_flag" in params or "spec_query_flag" in params:
            self.base_path = f'stream/{params["stream_id"]}/tags'
        elif "delete_flag" in params:
            self.base_path = f'stream/{params["stream_id"]}/tags/{params["key"]}'
        elif "batch_op_flag" in params:
            self.base_path = f'stream/{params["stream_id"]}/tags/action'
        elif "query_by_tag_flag" in params:
            self.base_path = f'stream/resource_instances/action'

    allow_create = True
    allow_list = True
    allow_commit = True
    allow_delete = True
    allow_fetch = True
    allow_patch = True

    # Properties
    #: Tag list
    tags = resource.Body('tags', type=list)
    #: Key.
    # A tag key consists of a maximum of 36 characters, including A-Z, a-z, 0-9, hyphens (-), and underscores (_).
    key = resource.Body('key', type=str)
    # Value.
    # The value consists of a maximum of 43 characters,
    # including A-Z, a-z, 0-9, periods (.), hyphens (-), and underscores (_), and can be an empty string.
    value = resource.Body('value', type=str)
    tag = resource.Body('tag', type=dict)
    action = resource.Body('action', type=str)
    tags_any = resource.Body('tags_any', type=list)
    not_tags = resource.Body('not_tags', type=list)
    not_tags_any = resource.Body('not_tags_any', type=list)
    limit = resource.Body('limit', type=str)
    offset = resource.Body('offset', type=str)
    matches = resource.Body('matches', type=list)
    total_count = resource.Body('total_count', type=int)
    resource_id = resource.Body('resource_id', type=str)
    resource_name = resource.Body('resource_name', type=str)
    resource_detail = resource.Body('resource_detail', type=str)
    resources = resource.Body('resources', type=list())
Пример #22
0
class ZoneImport(resource.Resource):
    """DNS Zone Import Resource"""
    resource_key = ''
    resources_key = 'imports'
    base_path = '/zones/tasks/import'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_delete = True
    allow_list = True

    _query_mapping = resource.QueryParameters(
        'zone_id', 'message', 'status'
    )

    #: Properties
    #: Timestamp when the zone was created
    created_at = resource.Body('created_at')
    #: Links contains a `self` pertaining to this zone or a `next` pertaining
    #: to next page
    links = resource.Body('links', type=dict)
    #: Message
    message = resource.Body('message')
    #: Returns the total_count of resources matching this filter
    metadata = resource.Body('metadata', type=list)
    #: The project id which the zone belongs to
    project_id = resource.Body('project_id')
    #: Current status of the zone import
    status = resource.Body('status')
    #: Timestamp when the zone was last updated
    updated_at = resource.Body('updated_at')
    #: Version of the resource
    version = resource.Body('version', type=int)
    #: ID for the zone that was created by this import
    zone_id = resource.Body('zone_id')

    def create(self, session, prepend_key=True, base_path=None):
        """Create a remote resource based on this instance.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param prepend_key: A boolean indicating whether the resource_key
                            should be prepended in a resource creation
                            request. Default to True.
        :param str base_path: Base part of the URI for creating resources, if
                              different from
                              :data:`~openstack.resource.Resource.base_path`.
        :return: This :class:`Resource` instance.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_create` is not set to ``True``.
        """
        if not self.allow_create:
            raise exceptions.MethodNotSupported(self, "create")

        session = self._get_session(session)
        microversion = self._get_microversion_for(session, 'create')
        # Create ZoneImport requires empty body and 'text/dns' as content-type
        # skip _prepare_request completely, since we need just empty body
        request = resource._Request(
            self.base_path,
            None,
            {'content-type': 'text/dns'}
        )
        response = session.post(request.url,
                                json=request.body, headers=request.headers,
                                microversion=microversion)

        self.microversion = microversion
        self._translate_response(response)
        return self
Пример #23
0
class Listener(resource.Resource, resource.TagMixin):
    resource_key = 'listener'
    resources_key = 'listeners'
    base_path = '/lbaas/listeners'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True

    _query_mapping = resource.QueryParameters(
        'connection_limit', 'default_pool_id', 'default_tls_container_ref',
        'description', 'name', 'project_id', 'protocol', 'protocol_port',
        'created_at', 'updated_at', 'provisioning_status', 'operating_status',
        'sni_container_refs', 'insert_headers', 'load_balancer_id',
        'timeout_client_data', 'timeout_member_connect',
        'timeout_member_data', 'timeout_tcp_inspect',
        is_admin_state_up='admin_state_up',
        **resource.TagMixin._tag_query_parameters
    )

    # Properties
    #: The maximum number of connections permitted for this load balancer.
    #: Default is infinite.
    connection_limit = resource.Body('connection_limit')
    #: Timestamp when the listener was created.
    created_at = resource.Body('created_at')
    #: Default pool to which the requests will be routed.
    default_pool = resource.Body('default_pool')
    #: ID of default pool. Must have compatible protocol with listener.
    default_pool_id = resource.Body('default_pool_id')
    #: A reference to a container of TLS secrets.
    default_tls_container_ref = resource.Body('default_tls_container_ref')
    #: Description for the listener.
    description = resource.Body('description')
    #: Dictionary of additional headers insertion into HTTP header.
    insert_headers = resource.Body('insert_headers', type=dict)
    #: The administrative state of the listener, which is up
    #: ``True`` or down ``False``. *Type: bool*
    is_admin_state_up = resource.Body('admin_state_up', type=bool)
    #: List of l7policies associated with this listener.
    l7_policies = resource.Body('l7policies', type=list)
    #: The ID of the parent load balancer.
    load_balancer_id = resource.Body('loadbalancer_id')
    #: List of load balancers associated with this listener.
    #: *Type: list of dicts which contain the load balancer IDs*
    load_balancers = resource.Body('loadbalancers', type=list)
    #: Name of the listener
    name = resource.Body('name')
    #: Operating status of the listener.
    operating_status = resource.Body('operating_status')
    #: The ID of the project this listener is associated with.
    project_id = resource.Body('project_id')
    #: The protocol of the listener, which is TCP, HTTP, HTTPS
    #: or TERMINATED_HTTPS.
    protocol = resource.Body('protocol')
    #: Port the listener will listen to, e.g. 80.
    protocol_port = resource.Body('protocol_port', type=int)
    #: The provisioning status of this listener.
    provisioning_status = resource.Body('provisioning_status')
    #: A list of references to TLS secrets.
    #: *Type: list*
    sni_container_refs = resource.Body('sni_container_refs')
    #: Timestamp when the listener was last updated.
    updated_at = resource.Body('updated_at')
    #: Frontend client inactivity timeout in milliseconds.
    timeout_client_data = resource.Body('timeout_client_data', type=int)
    #: Backend member connection timeout in milliseconds.
    timeout_member_connect = resource.Body('timeout_member_connect', type=int)
    #: Backend member inactivity timeout in milliseconds.
    timeout_member_data = resource.Body('timeout_member_data', type=int)
    #: Time, in milliseconds, to wait for additional TCP packets for content
    #: inspection.
    timeout_tcp_inspect = resource.Body('timeout_tcp_inspect', type=int)
Пример #24
0
class AppCSpec(resource.Resource):
    app_consistency = resource.Body('app_consistency')
    error_code = resource.Body('app_consistency_error_code')
    error_message = resource.Body('app_consistency_error_message')
    error_status = resource.Body('app_consistency_error_status')
Пример #25
0
class Tracker(resource.Resource):

    base_path = '/tracker'

    _query_mapping = resource.QueryParameters('tracker_name')

    # capabilities
    allow_create = True
    allow_commit = True
    allow_fetch = True
    allow_delete = True

    # Properties
    #: tracker name
    name = resource.Body('tracker_name', alternate_id=True)
    #: bucket name
    bucket_name = resource.Body('bucket_name')
    #: file prefix name in a bucket
    file_prefix_name = resource.Body('file_prefix_name')
    #: Status of the tracker
    #: values: `enabled`, `disabled`, `error`
    status = resource.Body('status')
    #: Detail of the tracker, only validate if exception happens
    detail = resource.Body('detail')
    #: SMN
    smn = resource.Body('smn', type=Smn)

    def _delete_tracker(self, session, tracker):
        """Delete Tracker
        """
        url = self.base_path + '?tracker_name={}'.format(tracker)
        response = session.delete(url)
        exceptions.raise_from_response(response)
        return None

    def _translate_response(self, response, has_body=None, error_message=None):
        """Given a KSA response, inflate this instance with its data

        'DELETE' operations don't return a body, so only try to work
        with a body when has_body is True.

        This method updates attributes that correspond to headers
        and body on this instance and clears the dirty set.
        """
        if has_body is None:
            has_body = self.has_body
        exc.raise_from_response(response, error_message=error_message)
        if has_body:
            if response.status_code == 204:
                # Some bad APIs (i.e. DCS.Backup.List) return emptiness
                self.log.warn('API returned no content, while it was expected')
                return
            # NOTE: in difference to doc "GET" method return list with 1 item
            body = response.json()
            if isinstance(body, list):
                body = body[0]
            if self.resource_key and self.resource_key in body:
                body = body[self.resource_key]

            body = self._consume_body_attrs(body)
            self._body.attributes.update(body)
            self._body.clean()

        headers = self._consume_header_attrs(response.headers)
        self._header.attributes.update(headers)
        self._header.clean()
Пример #26
0
class ExtendInfo(resource.Resource):
    app_consistency = resource.Body('app_consistency', type=AppCSpec)
    architecture = resource.Body('architecture')
    #: Whether the backup is automatically triggered
    auto_trigger = resource.Body('auto_trigger', type=bool)
    #: Whether the backup is a system disk backup
    bootable = resource.Body('bootable', type=bool)
    #: Whether the VM backup data contains system disk data
    contain_system_disk = resource.Body('contain_system_disk', type=bool)
    #: Whether the backup is encrypted
    encrypted = resource.Body('encrypted', type=bool)
    #: Whether the backup is an incremental backup
    incremental = resource.Body('incremental', type=bool)
    #: ID list of images created using backups
    os_images_data = resource.Body('os_images_data')
    progress = resource.Body('progress')
    #: Snapshot ID of the disk backup
    snapshot_id = resource.Body('snapshot_id')
    #: Whether to allow lazyloading for fast restoration
    support_lld = resource.Body('support_lld', type=bool)
    #: Restoration mode
    #: Choices: na, snapshot, backup
    #: Default: na
    #: na indicates the backup cannot be used for restoration
    supported_restore_mode = resource.Body('supported_restore_mode')
    #: Whether the disk is a system disk
    system_disk = resource.Body('system_disk', type=bool)
Пример #27
0
class Image(resource.Resource, resource.TagMixin):
    resources_key = 'images'
    base_path = '/images'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = True
    allow_delete = True
    allow_list = True
    commit_method = 'PATCH'
    commit_jsonpatch = True

    _query_mapping = resource.QueryParameters("name",
                                              "visibility",
                                              "member_status",
                                              "owner",
                                              "status",
                                              "size_min",
                                              "size_max",
                                              "protected",
                                              "is_hidden",
                                              "sort_key",
                                              "sort_dir",
                                              "sort",
                                              "tag",
                                              "created_at",
                                              "updated_at",
                                              is_hidden="os_hidden")

    # NOTE: Do not add "self" support here. If you've used Python before,
    # you know that self, while not being a reserved word, has special
    # meaning. You can't call a class initializer with the self name
    # as the first argument and then additionally in kwargs, as we
    # do when we're constructing instances from the JSON body.
    # Resource.list explicitly pops off any "self" keys from bodies so
    # that we don't end up getting the following:
    # TypeError: __init__() got multiple values for argument 'self'

    # The image data (bytes or a file-like object)
    data = None
    # Properties
    #: Hash of the image data used. The Image service uses this value
    #: for verification.
    checksum = resource.Body('checksum')
    #: The container format refers to whether the VM image is in a file
    #: format that also contains metadata about the actual VM.
    #: Container formats include OVF and Amazon AMI. In addition,
    #: a VM image might not have a container format - instead,
    #: the image is just a blob of unstructured data.
    container_format = resource.Body('container_format')
    #: The date and time when the image was created.
    created_at = resource.Body('created_at')
    #: Valid values are: aki, ari, ami, raw, iso, vhd, vdi, qcow2, or vmdk.
    #: The disk format of a VM image is the format of the underlying
    #: disk image. Virtual appliance vendors have different formats
    #: for laying out the information contained in a VM disk image.
    disk_format = resource.Body('disk_format')
    #: This field controls whether an image is displayed in the default
    #: image-list response
    is_hidden = resource.Body('os_hidden', type=bool)
    #: Defines whether the image can be deleted.
    #: *Type: bool*
    is_protected = resource.Body('protected', type=bool)
    #: The algorithm used to compute a secure hash of the image data
    #: for this image
    hash_algo = resource.Body('os_hash_algo')
    #: The hexdigest of the secure hash of the image data computed using
    #: the algorithm whose name is the value of the os_hash_algo property.
    hash_value = resource.Body('os_hash_value')
    #: The minimum disk size in GB that is required to boot the image.
    min_disk = resource.Body('min_disk')
    #: The minimum amount of RAM in MB that is required to boot the image.
    min_ram = resource.Body('min_ram')
    #: The name of the image.
    name = resource.Body('name')
    #: The ID of the owner, or project, of the image.
    owner_id = resource.Body('owner')
    # TODO(mordred) This is not how this works in v2. I mean, it's how it
    # should work, but it's not. We need to fix properties. They work right
    # in shade, so we can draw some logic from there.
    #: Properties, if any, that are associated with the image.
    properties = resource.Body('properties')
    #: The size of the image data, in bytes.
    size = resource.Body('size', type=int)
    #: When present, Glance will attempt to store the disk image data in the
    #: backing store indicated by the value of the header. When not present,
    #: Glance will store the disk image data in the backing store that is
    #: marked default. Valid values are: file, s3, rbd, swift, cinder,
    #: gridfs, sheepdog, or vsphere.
    store = resource.Body('store')
    #: The image status.
    status = resource.Body('status')
    #: Tags, if any, that are associated with the image.
    tags = resource.Body('tags')
    #: The date and time when the image was updated.
    updated_at = resource.Body('updated_at')
    #: The virtual size of the image.
    virtual_size = resource.Body('virtual_size')
    #: The image visibility.
    visibility = resource.Body('visibility')
    #: The URL for the virtual machine image file.
    file = resource.Body('file')
    #: A list of URLs to access the image file in external store.
    #: This list appears if the show_multiple_locations option is set
    #: to true in the Image service's configuration file.
    locations = resource.Body('locations')
    #: The URL to access the image file kept in external store. It appears
    #: when you set the show_image_direct_url option to true in the
    #: Image service's configuration file.
    direct_url = resource.Body('direct_url')
    #: The URL to access the image file kept in external store.
    url = resource.Body('url')
    #: The location metadata.
    metadata = resource.Body('metadata', type=dict)

    # Additional Image Properties
    # https://docs.openstack.org/glance/latest/user/common-image-properties.html
    # http://docs.openstack.org/cli-reference/glance-property-keys.html
    #: The CPU architecture that must be supported by the hypervisor.
    architecture = resource.Body("architecture")
    #: The hypervisor type. Note that qemu is used for both QEMU and
    #: KVM hypervisor types.
    hypervisor_type = resource.Body("hypervisor-type")
    #: Optional property allows created servers to have a different bandwidth
    #: cap than that defined in the network they are attached to.
    instance_type_rxtx_factor = resource.Body("instance_type_rxtx_factor",
                                              type=float)
    # For snapshot images, this is the UUID of the server used to
    #: create this image.
    instance_uuid = resource.Body('instance_uuid')
    #: Specifies whether the image needs a config drive.
    #: `mandatory` or `optional` (default if property is not used).
    needs_config_drive = resource.Body('img_config_drive')
    #: The ID of an image stored in the Image service that should be used
    #: as the kernel when booting an AMI-style image.
    kernel_id = resource.Body('kernel_id')
    #: The common name of the operating system distribution in lowercase
    os_distro = resource.Body('os_distro')
    #: The operating system version as specified by the distributor.
    os_version = resource.Body('os_version')
    #: Secure Boot is a security standard. When the instance starts,
    #: Secure Boot first examines software such as firmware and OS by
    #: their signature and only allows them to run if the signatures are valid.
    needs_secure_boot = resource.Body('os_secure_boot')
    #: The ID of image stored in the Image service that should be used as
    #: the ramdisk when booting an AMI-style image.
    ramdisk_id = resource.Body('ramdisk_id')
    #: The virtual machine mode. This represents the host/guest ABI
    #: (application binary interface) used for the virtual machine.
    vm_mode = resource.Body('vm_mode')
    #: The preferred number of sockets to expose to the guest.
    hw_cpu_sockets = resource.Body('hw_cpu_sockets', type=int)
    #: The preferred number of cores to expose to the guest.
    hw_cpu_cores = resource.Body('hw_cpu_cores', type=int)
    #: The preferred number of threads to expose to the guest.
    hw_cpu_threads = resource.Body('hw_cpu_threads', type=int)
    #: Specifies the type of disk controller to attach disk devices to.
    #: One of scsi, virtio, uml, xen, ide, or usb.
    hw_disk_bus = resource.Body('hw_disk_bus')
    #: Adds a random-number generator device to the image's instances.
    hw_rng_model = resource.Body('hw_rng_model')
    #: For libvirt: Enables booting an ARM system using the specified
    #: machine type.
    #: For Hyper-V: Specifies whether the Hyper-V instance will be a
    #: generation 1 or generation 2 VM.
    hw_machine_type = resource.Body('hw_machine_type')
    #: Enables the use of VirtIO SCSI (virtio-scsi) to provide block device
    #: access for compute instances; by default, instances use VirtIO Block
    #: (virtio-blk).
    hw_scsi_model = resource.Body('hw_scsi_model')
    #: Specifies the count of serial ports that should be provided.
    hw_serial_port_count = resource.Body('hw_serial_port_count', type=int)
    #: The video image driver used.
    hw_video_model = resource.Body('hw_video_model')
    #: Maximum RAM for the video image.
    hw_video_ram = resource.Body('hw_video_ram', type=int)
    #: Enables a virtual hardware watchdog device that carries out the
    #: specified action if the server hangs.
    hw_watchdog_action = resource.Body('hw_watchdog_action')
    #: The kernel command line to be used by the libvirt driver, instead
    #: of the default.
    os_command_line = resource.Body('os_command_line')
    #: Specifies the model of virtual network interface device to use.
    hw_vif_model = resource.Body('hw_vif_model')
    #: If true, this enables the virtio-net multiqueue feature.
    #: In this case, the driver sets the number of queues equal to the
    #: number of guest vCPUs. This makes the network performance scale
    #: across a number of vCPUs.
    is_hw_vif_multiqueue_enabled = resource.Body('hw_vif_multiqueue_enabled',
                                                 type=bool)
    #: If true, enables the BIOS bootmenu.
    is_hw_boot_menu_enabled = resource.Body('hw_boot_menu', type=bool)
    #: The virtual SCSI or IDE controller used by the hypervisor.
    vmware_adaptertype = resource.Body('vmware_adaptertype')
    #: A VMware GuestID which describes the operating system installed
    #: in the image.
    vmware_ostype = resource.Body('vmware_ostype')
    #: If true, the root partition on the disk is automatically resized
    #: before the instance boots.
    has_auto_disk_config = resource.Body('auto_disk_config', type=bool)
    #: The operating system installed on the image.
    os_type = resource.Body('os_type')
    #: The operating system admin username.
    os_admin_user = resource.Body('os_admin_user')
    #: If true, QEMU guest agent will be exposed to the instance.
    hw_qemu_guest_agent = resource.Body('hw_qemu_guest_agent', type=bool)
    #: If true, require quiesce on snapshot via QEMU guest agent.
    os_require_quiesce = resource.Body('os_require_quiesce', type=bool)

    def _action(self, session, action):
        """Call an action on an image ID."""
        url = utils.urljoin(self.base_path, self.id, 'actions', action)
        return session.post(url, )

    def deactivate(self, session):
        """Deactivate an image

        Note: Only administrative users can view image locations
        for deactivated images.
        """
        self._action(session, "deactivate")

    def reactivate(self, session):
        """Reactivate an image

        Note: The image must exist in order to be reactivated.
        """
        self._action(session, "reactivate")

    def upload(self, session):
        """Upload data into an existing image"""
        url = utils.urljoin(self.base_path, self.id, 'file')
        session.put(url,
                    data=self.data,
                    headers={
                        "Content-Type": "application/octet-stream",
                        "Accept": ""
                    })

    def import_image(self, session, method='glance-direct', uri=None):
        """Import Image via interoperable image import process"""
        url = utils.urljoin(self.base_path, self.id, 'import')
        json = {'method': {'name': method}}
        if uri:
            if method == 'web-download':
                json['method']['uri'] = uri
            else:
                raise exceptions.InvalidRequest('URI is only supported with '
                                                'method: "web-download"')
        session.post(url, json=json)

    def download(self, session, stream=False):
        """Download the data contained in an image"""
        # TODO(briancurtin): This method should probably offload the get
        # operation into another thread or something of that nature.
        url = utils.urljoin(self.base_path, self.id, 'file')
        resp = session.get(url, stream=stream)

        # See the following bug report for details on why the checksum
        # code may sometimes depend on a second GET call.
        # https://storyboard.openstack.org/#!/story/1619675
        checksum = resp.headers.get("Content-MD5")

        if checksum is None:
            # If we don't receive the Content-MD5 header with the download,
            # make an additional call to get the image details and look at
            # the checksum attribute.
            details = self.fetch(session)
            checksum = details.checksum

        # if we are returning the repsonse object, ensure that it
        # has the content-md5 header so that the caller doesn't
        # need to jump through the same hoops through which we
        # just jumped.
        if stream:
            resp.headers['content-md5'] = checksum
            return resp

        if checksum is not None:
            digest = hashlib.md5(resp.content).hexdigest()
            if digest != checksum:
                raise exceptions.InvalidResponse(
                    "checksum mismatch: %s != %s" % (checksum, digest))
        else:
            _logger.warn("Unable to verify the integrity of image %s" %
                         (self.id))

        return resp.content

    def _prepare_request(self,
                         requires_id=None,
                         prepend_key=False,
                         patch=False,
                         base_path=None):
        request = super(Image, self)._prepare_request(requires_id=requires_id,
                                                      prepend_key=prepend_key,
                                                      patch=patch,
                                                      base_path=base_path)
        if patch:
            headers = {
                'Content-Type': 'application/openstack-images-v2.1-json-patch',
                'Accept': ''
            }
            request.headers.update(headers)

        return request

    @classmethod
    def find(cls, session, name_or_id, ignore_missing=True, **params):
        # Do a regular search first (ignoring missing)
        result = super(Image, cls).find(session, name_or_id, True, **params)

        if result:
            return result
        else:
            # Search also in hidden images
            params['is_hidden'] = True
            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))
Пример #28
0
class Backup(resource.Resource):
    """CBR Backup Resource"""
    resource_key = 'backup'
    resources_key = 'backups'
    base_path = '/backups'

    # capabilities
    allow_create = False
    allow_list = True
    allow_fetch = True
    allow_delete = True
    allow_commit = False

    _query_mapping = resource.QueryParameters(
        'checkpoint_id', 'dec', 'end_time', 'enterprise_project_id',
        'image_type', 'limit', 'marker', 'member_status', 'name', 'offset',
        'own_type', 'parent_id', 'resource_az', 'resource_id', 'resource_name',
        'resource_type', 'sort', 'start_time', 'status', 'used_percent',
        'vault_id')

    #: Properties
    #: Restore point ID
    checkpoint_id = resource.Body('checkpoint_id')
    children = resource.Body('children', type=list)
    #: Creation time
    created_at = resource.Body('created_at')
    #: Backup description
    description = resource.Body('description')
    #: Enterprise project ID
    #: default: 0
    enterprise_project_id = resource.Body('enterprise_project_id')
    #: Expiration time
    expired_at = resource.Body('expired_at')
    #: Extended Information
    extend_info = resource.Body('extend_info', type=ExtendInfo)
    #: Backup type
    #: Values: backup or replication
    image_type = resource.Body('image_type')
    #: Backup name
    name = resource.Body('name')
    #: Parent backup ID
    parent_id = resource.Body('parent_id')
    #: Project ID
    project_id = resource.Body('project_id')
    #: Backup time
    protected_at = resource.Body('protected_at')
    provider_id = resource.Body('provider_id')
    replication_records = resource.Body('replication_records', type=list)
    #: Resource availability zone
    resource_az = resource.Body('resource_az')
    #: Resource ID
    resource_id = resource.Body('resource_id')
    #: Resource name
    resource_name = resource.Body('resource_name')
    #: Resource type:
    #: OS::Nova::Server or OS::Cinder::Volume
    resource_type = resource.Body('resource_type')
    #: Resource size in GB
    resource_size = resource.Body('resource_size', type=int)
    #: Backup status
    status = resource.Body('status')
    #: Update time
    updated_at = resource.Body('updated_at')
    #: Vault ID
    vault_id = resource.Body('vault_id')
Пример #29
0
class SecurityGroupRule(_base.NetworkResource, resource.TagMixin):
    resource_key = 'security_group_rule'
    resources_key = 'security_group_rules'
    base_path = '/security-group-rules'

    # capabilities
    allow_create = True
    allow_fetch = True
    allow_commit = False
    allow_delete = True
    allow_list = True

    _query_mapping = resource.QueryParameters(
        'description',
        'direction',
        'protocol',
        'remote_group_id',
        'security_group_id',
        'port_range_max',
        'port_range_min',
        'remote_ip_prefix',
        'revision_number',
        'project_id',
        'tenant_id',
        'sort_dir',
        'sort_key',
        ether_type='ethertype',
        **resource.TagMixin._tag_query_parameters)

    # Properties
    #: Timestamp when the security group rule was created.
    created_at = resource.Body('created_at')
    #: The security group rule description.
    description = resource.Body('description')
    #: ``ingress`` or ``egress``: The direction in which the security group
    #: rule is applied. For a compute instance, an ingress security group
    #: rule is applied to incoming ingress traffic for that instance.
    #: An egress rule is applied to traffic leaving the instance.
    direction = resource.Body('direction')
    #: Must be IPv4 or IPv6, and addresses represented in CIDR must match
    #: the ingress or egress rules.
    ether_type = resource.Body('ethertype')
    #: The maximum port number in the range that is matched by the
    #: security group rule. The port_range_min attribute constrains
    #: the port_range_max attribute. If the protocol is ICMP, this
    #: value must be an ICMP type.
    port_range_max = resource.Body('port_range_max', type=int)
    #: The minimum port number in the range that is matched by the
    #: security group rule. If the protocol is TCP or UDP, this value
    #: must be less than or equal to the value of the port_range_max
    #: attribute. If the protocol is ICMP, this value must be an ICMP type.
    port_range_min = resource.Body('port_range_min', type=int)
    #: The ID of the project this security group rule is associated with.
    project_id = resource.Body('project_id')
    #: The protocol that is matched by the security group rule.
    #: Valid values are ``null``, ``tcp``, ``udp``, and ``icmp``.
    protocol = resource.Body('protocol')
    #: The remote security group ID to be associated with this security
    #: group rule. You can specify either ``remote_group_id`` or
    #: ``remote_ip_prefix`` in the request body.
    remote_group_id = resource.Body('remote_group_id')
    #: The remote IP prefix to be associated with this security group rule.
    #: You can specify either ``remote_group_id`` or ``remote_ip_prefix``
    #: in the request body. This attribute matches the specified IP prefix
    #: as the source IP address of the IP packet.
    remote_ip_prefix = resource.Body('remote_ip_prefix')
    #: The security group ID to associate with this security group rule.
    security_group_id = resource.Body('security_group_id')
    #: The ID of the project this security group rule is associated with.
    tenant_id = resource.Body('tenant_id')
    #: Timestamp when the security group rule was last updated.
    updated_at = resource.Body('updated_at')
Пример #30
0
class ExtendInfoVaultDelete(resource.Resource):
    #: Properties
    #: Number of resources that fail to be deleted
    fail_count = resource.Body('fail_count')
    #: Number of deleted backups
    total_count = resource.Body('total_count')