Example #1
0
    def _update(self, application_name, request, infra_type, infra_name):
        check_application_auth(application_name, Authority.WRITE)
        check_infra_type(infra_type)

        scope_type = request.args['scope_type']
        scope_name = request.args['scope_name']
        check_scope(scope_type, scope_name)

        value = request.get_json()
        if not value or not isinstance(value, dict):
            abort(400, 'Unacceptable content type or content body')

        infra_info = InfraInfo(huskar_client.client, application_name,
                               infra_type)
        infra_info.load()
        old_value = infra_info.get_by_name(infra_name, scope_type, scope_name)

        yield application_name, infra_info, scope_type, scope_name, value

        infra_urls = infra_info.extract_urls(value)
        infra_application_names = extract_application_names(infra_urls)
        new_value = infra_info.get_by_name(infra_name, scope_type, scope_name)

        with audit_log(audit_log.types.UPDATE_INFRA_CONFIG,
                       application_name=application_name,
                       infra_type=infra_type,
                       infra_name=infra_name,
                       scope_type=scope_type,
                       scope_name=scope_name,
                       old_value=old_value,
                       new_value=new_value):
            for infra_application_name in infra_application_names:
                check_application(infra_application_name)

            infra_info.save()

            with suppress_exceptions('infra config updating'):
                infra_urls = infra_info.extract_urls(value, as_dict=True)
                infra_applications = extract_application_names(infra_urls)
                for field_name, infra_application_name in \
                        infra_applications.iteritems():
                    InfraDownstream.bind(application_name, infra_type,
                                         infra_name, scope_type, scope_name,
                                         field_name, infra_application_name)
Example #2
0
def _collect_infra_upstream(client, application_name):
    for infra_type in INFRA_CONFIG_KEYS:
        try:
            infra_info = InfraInfo(client, application_name, infra_type)
        except ValueError:
            logger.exception('ValueError with appid: %s type: %s',
                             application_name, infra_type)
            continue
        infra_info.load()
        infra_data = infra_info.data or {}
        for scope_type, scope_data in infra_data.iteritems():
            for scope_name, scope_dict in scope_data.iteritems():
                for infra_name, value in scope_dict.iteritems():
                    infra_urls = infra_info.extract_urls(value, as_dict=True)
                    infra_applications = extract_application_names(infra_urls)
                    for field_name, infra_application_name in \
                            infra_applications.iteritems():
                        yield InfraUpstreamInfo(infra_type, infra_name,
                                                scope_type, scope_name,
                                                field_name,
                                                infra_application_name)
Example #3
0
def test_new_oss_infra_config(
        client, test_application_name, test_application_token,
        test_oss, last_audit_log, mocker):
    major_application_name = test_application_name
    infra_info = InfraInfo(
        huskar_client.client, test_application_name, 'oss')

    logger = mocker.patch(
        'huskar_api.api.middlewares.logger.logger', autospec=True)

    infra_info.set_by_name('r100010', 'idcs', 'alta1', {
        'url': 'http://*****:*****@%s:666/overall.alta' % test_oss
    r = client.patch(
        '/api/infra-config/%s/oss/r100010' % test_application_name,
        query_string={'scope_type': 'idcs', 'scope_name': 'alta1'},
        data=json.dumps({'connect_timeout_ms': 10, 'url': url,
                         'idle_timeout_ms': 5000}),
        headers={'Authorization': test_application_token,
                 'Content-Type': 'application/json'})
    assert_response_ok(r)
    assert r.json['data'] == {'infra_config': [
        {'scope_type': 'idcs', 'scope_name': 'alta1',
         'value': {
             'url': url,
             'max_pool_size': 100,
             'connect_timeout_ms': 10,
             'idle_timeout_ms': 5000,
             'max_error_retry': 3}
         },
    ]}
    request_args = json.loads(logger.mock_calls[0][1][-6])
    assert 'url' not in request_args

    audit_log = last_audit_log()
    assert audit_log and audit_log.action_name == 'UPDATE_INFRA_CONFIG'
    assert audit_log.action_json['application_name'] == major_application_name
    assert audit_log.action_json['infra_type'] == 'oss'
    assert audit_log.action_json['infra_name'] == 'r100010'
    assert audit_log.action_json['scope_type'] == 'idcs'
    assert audit_log.action_json['scope_name'] == 'alta1'
    assert audit_log.action_json['data']['new'] == {
        'url': url,
        'max_pool_size': 100,
        'connect_timeout_ms': 10,
        'idle_timeout_ms': 5000,
        'max_error_retry': 3,
    }
    assert audit_log.action_json['data']['old'] == {
        'url': 'http://localhost:233',
        'max_pool_size': 100,
        'connect_timeout_ms': 5,
        'max_error_retry': 3,
    }
Example #4
0
    def get(self, application_name, infra_type, infra_name):
        """Gets the configuration of infrastructure in specified application.

        The response looks like::

            [{
              "scope_type": "idcs", "scope_name": "alta1",
              "value": {"url": "sam+redis://redis.foobar/overall"}
            }]

        :param application_name: The application which uses infrastructure.
        :param infra_type: ``database``, ``redis`` or ``amqp``.
        :param infra_name: The unique code-reference name of infrastructure.
        :<header Authorization: Huskar Token (See :ref:`token`)
        :status 200: The result is in the response.
        """
        check_application_auth(application_name, Authority.READ)
        check_infra_type(infra_type)
        infra_info = InfraInfo(huskar_client.client, application_name,
                               infra_type)
        infra_info.load()
        infra_config = infra_info.list_by_infra_name(infra_name)
        return api_response({'infra_config': dump_infra_config(infra_config)})
Example #5
0
def test_rollback_infra_config_change(client, db, faker, test_application_name,
                                      admin_token, last_audit_log,
                                      _action_type, _scope_type, _scope_name,
                                      _old_value, _new_value,
                                      _expected_action_type, _expected_value):
    infra_type = 'redis'
    infra_name = 'default'
    infra_info = InfraInfo(huskar_client.client, test_application_name,
                           infra_type)
    infra_info.load()

    action_type = getattr(action_types, _action_type)
    action = action_creator.make_action(
        action_type,
        application_name=test_application_name,
        infra_type=infra_type,
        infra_name=infra_name,
        scope_type=_scope_type,
        scope_name=_scope_name,
        old_value=_old_value,
        new_value=_new_value,
    )
    audit_log = AuditLog.create(0, faker.ipv4(), action)
    db.close()

    r = client.put('/api/audit-rollback/%s/%s' %
                   (test_application_name, audit_log.id),
                   headers={'Authorization': admin_token})
    assert_response_ok(r)

    last_audit = last_audit_log()
    infra_info.load()
    value = infra_info.get_by_name(infra_name, _scope_type, _scope_name)
    assert value == _expected_value
    assert last_audit.action_type == getattr(action_types,
                                             _expected_action_type)
Example #6
0
def rollback_infra_config(action_type, action_data):
    application_name = action_data['application_name']
    infra_type = action_data['infra_type']
    infra_name = action_data['infra_name']
    scope_type = action_data['scope_type']
    scope_name = action_data['scope_name']

    infra_info = InfraInfo(huskar_client.client, application_name, infra_type)
    infra_info.load()
    current = infra_info.get_by_name(infra_name, scope_type, scope_name)
    rollback_to = action_data['data']['old']

    if rollback_to is None:  # new infra config
        infra_info.delete_by_name(infra_name, scope_type, scope_name)
        new_action_type = action_types.DELETE_INFRA_CONFIG
    else:
        infra_info.set_by_name(infra_name, scope_type, scope_name, rollback_to)
        new_action_type = action_types.UPDATE_INFRA_CONFIG
    infra_info.save()

    return new_action_type, {
        'application_name': application_name,
        'infra_type': infra_type,
        'infra_name': infra_name,
        'scope_type': scope_type,
        'scope_name': scope_name,
        'old_value': current,
        'new_value': rollback_to,
    }
Example #7
0
def infra_info(test_application_name):
    return InfraInfo(
        huskar_client.client, test_application_name, 'redis')
Example #8
0
    def delete(self, application_name, infra_type, infra_name):
        """Deletes the infrastructure configuration in specified application.

        :param application_name: The application which uses infrastructure.
        :param infra_type: ``database``, ``redis`` or ``amqp``.
        :param infra_name: The unique code-reference name of infrastructure.
        :query scope_type: ``idcs`` or ``clusters``.
        :query scope_name: The ezone id or clsuter name.
        :<header Authorization: Huskar Token (See :ref:`token`)
        :status 200: The same as ``GET``.
        """
        check_application_auth(application_name, Authority.WRITE)
        check_infra_type(infra_type)

        scope_type = request.args['scope_type']
        scope_name = request.args['scope_name']
        check_scope(scope_type, scope_name)

        infra_info = InfraInfo(huskar_client.client, application_name,
                               infra_type)
        infra_info.load()
        old_value = infra_info.get_by_name(infra_name, scope_type, scope_name)
        infra_info.delete_by_name(infra_name, scope_type, scope_name)
        with audit_log(audit_log.types.DELETE_INFRA_CONFIG,
                       application_name=application_name,
                       infra_type=infra_type,
                       infra_name=infra_name,
                       scope_type=scope_type,
                       scope_name=scope_name,
                       old_value=old_value,
                       new_value=None):
            infra_info.save()

        with suppress_exceptions('infra config deletion'):
            old_urls = infra_info.extract_urls(old_value or {}, as_dict=True)
            for field_name in frozenset(extract_application_names(old_urls)):
                InfraDownstream.unbind(application_name, infra_type,
                                       infra_name, scope_type, scope_name,
                                       field_name)

        infra_config = infra_info.list_by_infra_name(infra_name)
        return api_response({'infra_config': dump_infra_config(infra_config)})
Example #9
0
def test_collect_infra_config(zk, db, faker, test_team):
    prefix = faker.uuid4()[:8]
    for x in 'foo', 'bar':
        x = '%s_%s' % (prefix, x)
        Application.create(x, test_team.id)
        InfraDownstream.bindmany()\
            .bind(x, 'database', 'stale-db', 'idcs', 'altb1', 'master',
                  'dal.foo.master') \
            .bind(x, 'database', 'stale-db', 'idcs', 'altb1', 'slave',
                  'dal.foo.auto') \
            .bind(x, 'redis', 'stale-cache', 'idcs', 'altb1', 'url',
                  'redis.foo') \
            .commit()
        mysql_url = {
            'master': 'sam+mysql://root:[email protected]/%s_db' % x,
            'slave': 'sam+mysql://root:[email protected]/%s_db' % x}
        redis_url = {'url': 'sam+redis://redis.foo'}
        infra_info = InfraInfo(zk, x, 'database')
        infra_info.load()
        infra_info.set_by_name('db', 'idcs', 'altb1', mysql_url)
        infra_info.save()
        infra_info = InfraInfo(zk, x, 'redis')
        infra_info.load()
        infra_info.set_by_name('cache', 'idcs', 'altb1', redis_url)
        infra_info.save()

    InfraDownstream.flush_cache_by_application('dal.foo.auto')
    ds = InfraDownstream.get_multi_by_application('dal.foo.auto')
    assert all(d.user_infra_name == 'stale-db' for d in ds)

    InfraDownstream.flush_cache_by_application('redis.auto')
    ds = InfraDownstream.get_multi_by_application('redis.foo')
    assert all(d.user_infra_name == 'stale-cache' for d in ds)

    list(_collect_infra_upstream(zk, u'error\u00a0'))

    collect_infra_config()

    InfraDownstream.flush_cache_by_application('dal.foo.auto')
    ds = InfraDownstream.get_multi_by_application('dal.foo.auto')
    assert len(ds) == 2
    assert ds[0].user_application_name == '%s_foo' % prefix
    assert ds[0].user_infra_type == 'database'
    assert ds[0].user_infra_name == 'db'
    assert ds[0].user_scope_pair == ('idcs', 'altb1')
    assert ds[0].user_field_name == 'slave'
    assert ds[1].user_application_name == '%s_bar' % prefix
    assert ds[1].user_infra_type == 'database'
    assert ds[1].user_infra_name == 'db'
    assert ds[1].user_scope_pair == ('idcs', 'altb1')
    assert ds[1].user_field_name == 'slave'

    InfraDownstream.flush_cache_by_application('redis.auto')
    ds = InfraDownstream.get_multi_by_application('redis.foo')
    assert len(ds) == 2
    assert ds[0].user_application_name == '%s_foo' % prefix
    assert ds[0].user_infra_type == 'redis'
    assert ds[0].user_infra_name == 'cache'
    assert ds[0].user_scope_pair == ('idcs', 'altb1')
    assert ds[0].user_field_name == 'url'
    assert ds[1].user_application_name == '%s_bar' % prefix
    assert ds[1].user_infra_type == 'redis'
    assert ds[1].user_infra_name == 'cache'
    assert ds[1].user_scope_pair == ('idcs', 'altb1')
    assert ds[1].user_field_name == 'url'