Exemplo n.º 1
0
def test_global_implicit_global_config():
    """ Global config is instantiated from config.json if not explicitly set """
    assert Config.get_instance().api_key == conf_dict.get('apiKey')
    assert Config.get_instance().api_url == conf_dict.get('apiEndpoint')
    assert isinstance(Config.get_instance().products, list)
    assert len(Config.get_instance().products) == 1
    assert Config.get_instance().products[0] == conf_dict.get('products')
Exemplo n.º 2
0
 def __init__(self, config=None):
     self._config = config or Config.get_instance()
     self._tier_account_requests = TierAccountRequestResource(
         config=self._config)
     self._tier_config_requests = TierConfigRequestResource(
         config=self._config)
     self._asset_requests = AssetRequestResource(config=self._config)
Exemplo n.º 3
0
    def collect_usage_records(self, items, project, start_time, end_time):
        """Create UsageRecord object for each type of resources"""

        consumptions = {
            'CPU_consumption': CPU(),
            'Storage_consumption': Storage(),
            'RAM_consumption': RAM(),
            'Floating_IP_consumption': FloatingIP(),
            'LB_consumption': LoadBalancer(),
            'K8S_consumption': K8saas(),
            'Win_VM_consumption': WinVM(),
            'Outgoing_Traffic_consumption': OutgoingTraffic()
        }

        conf = Config.get_instance()
        consumptions.update(
            {mpn: Zero()
             for mpn in conf.misc.get('report_zero_usage', [])})

        def known_resources(item):
            return item in consumptions

        def collect_item_consumption(item):
            return self.create_record(
                project, start_time, end_time, item,
                consumptions.get(item).collect_consumption(
                    project, start_time, end_time))

        return map(collect_item_consumption, filter(known_resources, items))
Exemplo n.º 4
0
 def get_templates(self, config=None):
     """
     :param Config config: Configuration to use, or None for environment config.
     :return: List of all templates associated with the product.
     :rtype: List[Template]
     """
     text, _ = ApiClient(config or Config.get_instance(),
                         'products/' + self.id + '/templates').get()
     return Template.deserialize(text)
Exemplo n.º 5
0
    def keystone_client(self):
        """Create KeystoneClient object using KeystoneSession"""

        c = Config.get_instance()
        return KeystoneClient(
            session=self.keystone_session,
            endpoint_override=c.infra_keystone_endpoint,
            connect_retries=2,
        )
Exemplo n.º 6
0
    def get_answer(self, product, answer):
        """Get template object specified in the Config"""
        c = Config.get_instance()
        line = c.templates.get(product, {}).get(answer)
        if line is None:
            return line

        if line.startswith('TL'):
            return ActivationTemplateResponse(line)
        return ActivationTileResponse(line)
Exemplo n.º 7
0
    def __init__(self, config, base_path):
        # type: (Config, str) -> None

        # Set base URL
        self._base_path = base_path

        # Set passed config or globally configured instance
        self._config = config or Config.get_instance()
        if not isinstance(self._config, Config):
            raise ValueError('A valid Config object must be passed or globally configured.')
Exemplo n.º 8
0
    def get_requests(self, config=None):
        """ Get the requests for this asset.

        :param Config config: Config object or ``None`` to use environment config (default).
        :return: The requests for this asset.
        :rtype: List[Fulfillment]
        """
        from connect.config import Config
        from connect.resources.base import ApiClient
        from .fulfillment import Fulfillment
        text, _ = ApiClient(config or Config.get_instance(),
                            'assets/' + self.id + '/requests').get()
        return Fulfillment.deserialize(text)
Exemplo n.º 9
0
 def get_function_rv():
     if PasswordFilter.is_enabled is None:
         PasswordFilter.is_enabled = Config.get_instance(
         ).misc['hidePasswordsInLog']
     if PasswordFilter.is_enabled and re.search(
             PasswordFilter.type_pattern, record.msg):
         msg = record.msg.replace("\n", "\\n").replace("\\'", "'")
         for pattern in PasswordFilter.password_patterns:
             match = re.search(pattern, msg)
             if match:
                 return match.group(1)
         logger.warning(
             "Message does not match against password patterns")
     return None
Exemplo n.º 10
0
    def keystone_session(self):
        """Create KeystoneSession object using params in the Config"""

        c = Config.get_instance()
        auth = identity.v3.Password(
            auth_url=c.infra_keystone_endpoint,
            username=c.infra_user,
            project_name=c.infra_project,
            password=c.infra_password,
            user_domain_name=c.infra_domain,
            project_domain_name=c.infra_domain,
            reauthenticate=True,
        )
        return KeystoneSession(auth=auth, verify=False)
Exemplo n.º 11
0
 def get_product_configurations(self, filters=None, config=None):
     """
     :param Dict[str, Any] filters: Filters for the requests. Supported filters are:
       - ``parameter.id``
       - ``parameter.title``
       - ``parameter.scope``
       - ``marketplace.id``
       - ``marketplace.name``
       - ``item.id``
       - ``item.name``
       - ``value``
     :param Config config: Configuration to use, or None for environment config.
     :return: A list with the product configuration parameter data.
     :rtype: List[ProductConfigurationParameter]
     """
     text, _ = ApiClient(config or Config.get_instance(), 'products/' +
                         self.id + '/configurations').get(params=filters)
     return ProductConfigurationParameter.deserialize(text)
Exemplo n.º 12
0
 def get_product_configurations(self, filters=None, config=None):
     """
     :param dict|Query filters: Filters for the requests. Supported filters are:
       - ``parameter.id``
       - ``parameter.title``
       - ``parameter.scope``
       - ``marketplace.id``
       - ``marketplace.name``
       - ``item.id``
       - ``item.name``
       - ``value``
     :param Config config: Configuration to use, or None for environment config.
     :return: A list with the product configuration parameter data.
     :rtype: List[ProductConfigurationParameter]
     """
     query = copy(filters) if isinstance(filters, Query) else Query(filters)
     text, _ = ApiClient(
         config or Config.get_instance(),
         'products/' + self.id + '/configurations' + query.compile()).get()
     return ProductConfigurationParameter.deserialize(text)
Exemplo n.º 13
0
 def __init__(self, config=None):
     self._config = config or Config.get_instance()
     self._tier_accounts = TierAccountResource(config=self._config)
Exemplo n.º 14
0
    def process_request(self, request):
        """Each new Fulfillment is processed by this function"""

        conf = Config.get_instance()

        # store all processed request for debug
        self.fulfillments.append(request)

        if request.needs_migration():
            # Skip request if it needs migration
            # (migration is performed by an external service)
            self.logger.info('Skipping request %s because it needs migration.', request.id)
            raise SkipRequest()

        param_partner_id = None
        if not conf.misc['domainCreation']:
            self.logger.info('Request "%s" needs domain that created manually. '
                             'Lookup for domain name in tier1 configuration data...', request.id)
            partner_data = self.get_tier_partner_data(request.asset.tiers.tier1.id)
            if partner_data is None:
                raise SkipRequest('Misconfiguration: there is no "partner_id" parameter in tier1 "%s" config'
                                  % request.asset.tiers.tier1.id)
            elif partner_data.value is None:
                raise SkipRequest(message='Please specify "partner_id" parameter value in tier1 "%s" config'
                                          % request.asset.tiers.tier1.id)
            param_partner_id = partner_data.value
            self.logger.info('Got the following domain data from tier1 config: "%s"' % param_partner_id)

        project = None

        params = {p.id: p for p in request.asset.params}

        # get account parameters from Asset
        param_domain_name = params.get('domain_name')
        param_domain_id = params.get('domain_id')
        param_project_id = params.get('project_id')
        param_user_id = params.get('user_id')

        self.logger.info("param_partner_id: %s, param_domain_name: %s, param_domain_id: %s, "
                         "param_project_id: %s, param_user_id: %s",
                         param_partner_id, param_domain_name and param_domain_name.value,
                         param_domain_id and param_domain_id.value,
                         param_project_id and param_project_id.value, param_user_id and param_user_id.value)

        if request.type in ('purchase', 'resume', 'change'):
            if not conf.misc['domainCreation']:
                # if domain creation is set to manual, needs to check:
                #   - if domain with such description exists in the cloud, go to next steps
                #   - if not - return nice message and set request status
                domain = self.get_existing_domain(partner_id=param_partner_id)
                if domain is None:
                    raise SkipRequest('Request "%s" needs domain that created manually. '
                                      'Cannot find any domain with description "%s"' % (request.id, param_partner_id))
            else:
                # create domain
                customer_id = request.asset.tiers.customer.id
                customer_name = request.asset.tiers.customer.name
                domain = self.create_or_update_domain(
                    name=customer_id, description=customer_name,
                    domain_id=param_domain_id and param_domain_id.value)

            # create project
            project_description = request.asset.id
            project_name = params.get('project') and params['project'].value or project_description
            project = self.create_project(
                project_id=param_project_id and param_project_id.value,
                name=project_name, domain=domain,
                description=project_description, enabled=False)

            # create user
            user_description = request.asset.id
            user_name = params.get('user') and params['user'].value or user_description
            user_password = params.get('password') and params['password'].value or pwgen()
            user = self.create_user(
                user_id=param_user_id and param_user_id.value,
                name=user_name, domain=domain,
                description=user_description,
                password=user_password)

            # check conflicts
            conflicts = []
            if project is None:
                if params.get('project'):
                    params['project'].value_error = 'This project name is already taken, please choose a different name'
                    params['project'].constraints = None
                    conflicts.append(params['project'])

            if user is None:
                if params.get('user'):
                    params['user'].value_error = 'This user name is already taken, please choose a different name'
                    params['user'].constraints = None
                    conflicts.append(params['user'])

            if conflicts:
                if user:
                    user.delete()
                if project:
                    project.delete()
                raise InquireRequest(params=conflicts)
            if user is None:
                raise Exception('Unable to create a user')
            if project is None:
                raise Exception('Unable to create a project')

            # update params (project_id, user_id)
            params_update = []
            if param_domain_name and param_domain_name.value != domain.name:
                param_domain_name.value = domain.name
                param_domain_name.constraints = None
                params_update.append(param_domain_name)
            if param_domain_id and param_domain_id.value != domain.id:
                param_domain_id.value = domain.id
                param_domain_id.constraints = None
                params_update.append(param_domain_id)
            if param_project_id and param_project_id.value != project.id:
                param_project_id.value = project.id
                param_project_id.constraints = None
                params_update.append(param_project_id)
            if param_user_id and param_user_id.value != user.id:
                param_user_id.value = user.id
                param_user_id.constraints = None
                params_update.append(param_user_id)

            self.update_parameters(request.id, params_update)

            # assign roles
            user_roles = ['project_admin']
            if conf.misc['imageUpload']:
                user_roles.append('image_upload')
            self.assign_user_roles(user, project, roles=user_roles)

            # configure quotas
            def get_item_limit(item):
                limit_param = next((p for p in item.params if p.id == 'item_limit'), None)
                try:
                    return int(limit_param.value)
                except Exception:
                    return -1

            def get_quota(item, error=FailRequest("ERROR: REQUESTED LIMITS ARE HIGHER THEN HARD LIMITS")):
                if item is None:
                    return 0
                quantity = item.quantity
                item_limit = get_item_limit(item)
                if item_limit >= 0:
                    if quantity > item_limit:
                        raise error
                if quantity < 0:
                    quantity = item_limit
                return quantity

            items = {item.mpn.lower(): item for item in request.asset.items}
            self.logger.info('VIP requested items %r', items)
            try:
                # get quota limits from Asset parameters
                cpu_quota = get_quota(items.get('cpu_limit', items.get("cpu_consumption", None)))
                ram_quota = get_quota(items.get('ram_limit', items.get("ram_consumption", None)))
                vol_quota = get_quota(items.get('storage_limit', items.get("storage_consumption", None)))

                # fail request if basic limits are missing
                if 0 in (cpu_quota, ram_quota, vol_quota):
                    raise FailRequest("CPU, RAM, and Storage limits cannot be 0")

                fip_quota = get_quota(items.get('floating_ip_limit', items.get("floating_ip_consumption", None)))
                lb_quota = get_quota(items.get('lbaas_limit', items.get("lb_consumption", None)))
                k8s_quota = get_quota(items.get('k8saas_limit', items.get("k8s_consumption", None)))

                errors = []
                updaters = []

                def apply_quota(updater, client, quotas):
                    try:
                        u = updater(client, project.id)
                        u.update(quotas)
                        updaters.append(u)
                    except BadQuota as e:
                        errors.append(e.message)

                try:
                    # update project quotas
                    apply_quota(CinderQuotaUpdater, self.cinder_client, {
                        'gigabytes_default': vol_quota})
                    apply_quota(NovaQuotaUpdater, self.nova_client, {
                        'cores': cpu_quota,
                        'ram': (ram_quota * 1024 if ram_quota > 0 else ram_quota)})
                    apply_quota(NeutronQuotaUpdater, self.neutron_client, {
                        'floatingip': fip_quota})
                    apply_quota(OctaviaQuotaUpdater, self.octavia_client, {
                        'load_balancer': lb_quota})
                    apply_quota(MagnumQuotaUpdater, self.magnum_client, {
                        'hard_limit': k8s_quota})
                    if errors:
                        rollback_error = False
                        for u in updaters:
                            try:
                                u.rollback()
                            except Exception:
                                rollback_error = True
                                self.logger.exception("Unable to rollback quotas")
                        if rollback_error:
                            raise Exception('Unable to setup quotas')
                        raise FailRequest('\n'.join(errors))
                except Exception as e:
                    self.logger.exception("Unable to setup quotas")
                    for u in updaters:
                        try:
                            u.rollback()
                        except Exception:
                            self.logger.exception("Unable to rollback quotas")
                    raise e
            except FailRequest:
                if request.type == 'purchase':
                    # remove project if we fail to process 'purchase' request
                    if project:
                        project.delete()
                        project = None
                raise
            except SkipRequest:
                raise
            except Exception:
                self.logger.exception("Unable to setup quotas")
                raise

            rv = self.get_answer(request.asset.product.id, 'grant')
            if not project.enabled:
                # if project was suspended a long time ago we open new usage
                # reporting interval setting start_usage_report_time. But if
                # stop_report_time is not equal last_report_time then there
                # was no report closing previous usage reporting interval.
                # So the gap between stop and start will be ignored.
                stop_report_time = self.get_stop_report_time(request, project)
                last_report_time, _ = self.get_last_report_time(request, project)
                if stop_report_time != last_report_time:
                    stop_report_time = ''

                report_time = datetime.utcnow().replace(microsecond=0)
                self.keystone_client.projects.update(
                    project, enabled=True,
                    start_usage_report_time=report_time.isoformat()
                    if stop_report_time else '',
                    stop_usage_report_time=stop_report_time)
                project.update(enabled=True)

            if rv:
                return rv
        elif request.type in ('suspend', 'cancel'):
            self.suspend_project(
                request,
                param_domain_id and param_domain_id.value or None,
                param_project_id and param_project_id.value or None,
                param_user_id and param_user_id.value or None,
            )

            # TODO implement automatic cleanup after Asset cancellation
            try:
                pid = param_project_id and param_project_id.value or None
                if request.type == 'cancel' and pid:
                    self.keystone_client.projects.update(
                        pid, description='SCHEDULED FOR DELETE')
            except Exception:
                pass

            return self.get_answer(request.asset.product.id, 'revoke') or ''

        self.logger.warning("Do not know what to do with such request")
        raise SkipRequest()
Exemplo n.º 15
0
 def __init__(self, config=None):
     self._config = config or Config.get_instance()
     self._billing_request = BillingRequestResource(config=self._config)
     self._recurring_asset = RecurringAssetResource(config=self._config)
Exemplo n.º 16
0
 def __init__(self, config=None):
     self._config = config or Config.get_instance()
Exemplo n.º 17
0
def test_global_config_immutable_properties():
    with pytest.raises(AttributeError):
        Config.get_instance().api_key = conf_dict.get('apiKey')
        Config.get_instance().api_url = conf_dict.get('apiEndpoint')
        Config.get_instance().products = [conf_dict.get('products')]