Esempio n. 1
0
    def get_service_status_without_restart(self, ctx, service):
        """
        :param service: instance of type "Service" (module_name - the name of
           the service module, case-insensitive version     - specify the
           service version, which can be either: (1) full git commit hash of
           the module version (2) semantic version or semantic version
           specification Note: semantic version lookup will only work for
           released versions of the module. (3) release tag, which is one of:
           dev | beta | release This information is always fetched from the
           Catalog, so for more details on specifying the version, see the
           Catalog documentation for the get_module_version method.) ->
           structure: parameter "module_name" of String, parameter "version"
           of String
        :returns: instance of type "ServiceStatus" (module_name     - name of
           the service module version         - semantic version number of
           the service module git_commit_hash - git commit hash of the
           service module release_tags    - list of release tags currently
           for this service module (dev/beta/release) url             - the
           url of the service up              - 1 if the service is up, 0
           otherwise status          - status of the service as reported by
           rancher health          - health of the service as reported by
           Rancher TODO: add something to return: string
           last_request_timestamp;) -> structure: parameter "module_name" of
           String, parameter "version" of String, parameter "git_commit_hash"
           of String, parameter "release_tags" of list of String, parameter
           "hash" of String, parameter "url" of String, parameter "up" of
           type "boolean", parameter "status" of String, parameter "health"
           of String
        """
        # ctx is the context object
        # return variables are: status
        #BEGIN get_service_status_without_restart
        cc = Catalog(self.CATALOG_URL, token=ctx['token'])
        mv = cc.get_module_version({
            'module_name': service['module_name'],
            'version': service['version']
        })
        if 'dynamic_service' not in mv:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')
        if mv['dynamic_service'] != 1:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')

        status = self.get_single_service_status(mv)
        #END get_service_status_without_restart

        # At some point might do deeper type checking...
        if not isinstance(status, dict):
            raise ValueError(
                'Method get_service_status_without_restart return value ' +
                'status is not type dict as required.')
        # return the results
        return [status]
Esempio n. 2
0
    def create_stack(self, service):
        cc = Catalog(self.CATALOG_URL, token=self.CATALOG_ADMIN_TOKEN)
        param = {
            'module_name': service['module_name'],
            'version': service['version']
        }
        mv = cc.get_module_version(param)
        if 'dynamic_service' not in mv:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')
        if mv['dynamic_service'] != 1:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')

        secure_param_list = cc.get_secure_config_params({
            'module_name':
            mv['module_name'],
            'version':
            mv['git_commit_hash']
        })
        # Construct the docker compose and rancher compose file
        param['client_group'] = 'service'
        param['function_name'] = 'service'

        mounts = []
        mounts_list = cc.list_volume_mounts(param)
        if len(mounts_list) > 0:
            mounts = mounts_list[0]['volume_mounts']
        docker_compose, rancher_compose, is_new_stack = self.create_compose_files(
            mv, secure_param_list, mounts)

        # To do: try to use API to send docker-compose directly instead of needing to write to disk
        ymlpath = self.SCRATCH_DIR + '/' + mv['module_name'] + '/' + str(
            int(time.time() * 1000))
        os.makedirs(ymlpath)
        docker_compose_path = ymlpath + '/docker-compose.yml'
        rancher_compose_path = ymlpath + '/rancher-compose.yml'

        with open(docker_compose_path, 'w') as outfile:
            outfile.write(
                yaml.safe_dump(docker_compose, default_flow_style=False))
        # can be extended later
        with open(rancher_compose_path, 'w') as outfile:
            outfile.write(
                yaml.safe_dump(rancher_compose, default_flow_style=False))

        return mv, is_new_stack, ymlpath
Esempio n. 3
0
class CatalogCache(object):
    def __init__(self, config):
        self.catalog_url = config.get('catalog-service-url')
        self.catalog = Catalog(self.catalog_url, token=config['admin_token'])
        self.module_cache = dict()

    def get_volume_mounts(self, module, method, cgroup):
        req = {
            'module_name': module,
            'function_name': method,
            'client_group': cgroup
        }
        resp = self.catalog.list_volume_mounts(req)
        if len(resp) > 0:
            return resp[0]['volume_mounts']
        else:
            return []

    def get_module_info(self, module, version):
        # Look up the module info
        if module not in self.module_cache:
            req = {'module_name': module}
            if version is not None:
                req['version'] = version
            # Get the image version from the catalog and cache it
            module_info = self.catalog.get_module_version(req)
            # Lookup secure params
            req['load_all_versions'] = 0
            sp = self.catalog.get_secure_config_params(req)
            module_info['secure_config_params'] = sp
            module_info['cached'] = False
            self.module_cache[module] = module_info
        else:
            # Use the cache
            module_info = self.module_cache[module]
            module_info['cached'] = True

        return module_info
Esempio n. 4
0
 def __init__(self, config):
     self.catalog_url = config.get('catalog-service-url')
     self.catalog = Catalog(self.catalog_url, token=config['admin_token'])
     self.module_cache = dict()
Esempio n. 5
0
    def get_service_log_web_socket(self, ctx, params):
        """
        returns connection info for a websocket connection to get realtime service logs
        :param params: instance of type "GetServiceLogParams" (optional
           instance_id to get logs for a specific instance.  Otherwise logs
           from all instances are returned, TODO: add line number
           constraints.) -> structure: parameter "service" of type "Service"
           (module_name - the name of the service module, case-insensitive
           version     - specify the service version, which can be either:
           (1) full git commit hash of the module version (2) semantic
           version or semantic version specification Note: semantic version
           lookup will only work for released versions of the module. (3)
           release tag, which is one of: dev | beta | release This
           information is always fetched from the Catalog, so for more
           details on specifying the version, see the Catalog documentation
           for the get_module_version method.) -> structure: parameter
           "module_name" of String, parameter "version" of String, parameter
           "instance_id" of String
        :returns: instance of list of type "ServiceLogWebSocket" ->
           structure: parameter "instance_id" of String, parameter
           "socket_url" of String
        """
        # ctx is the context object
        # return variables are: sockets
        #BEGIN get_service_log_web_socket
        service = params['service']
        user_id = ctx['user_id']
        cc = Catalog(self.CATALOG_URL, token=ctx['token'])
        module = cc.get_module_info({'module_name': service['module_name']})
        has_access = False
        for o in module['owners']:
            if o == user_id:
                has_access = True
        if not has_access:
            if cc.is_admin(user_id) == 1:
                has_access = True

        if not has_access:
            raise ValueError(
                'Only module owners and catalog admins can view service logs.')

        mv = cc.get_module_version({
            'module_name': service['module_name'],
            'version': service['version']
        })
        if 'dynamic_service' not in mv:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')
        if mv['dynamic_service'] != 1:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')

        rancher = gdapi.Client(url=self.RANCHER_URL,
                               access_key=self.RANCHER_ACCESS_KEY,
                               secret_key=self.RANCHER_SECRET_KEY)

        #service_info = rancher.list_servicess(name=self.get_service_name(mv))

        GET_SERVICE_URL = self.RANCHER_URL + '/v1/services?name=' + self.get_service_name(
            mv) + '&include=instances'
        service_info = requests.get(GET_SERVICE_URL,
                                    auth=(self.RANCHER_ACCESS_KEY,
                                          self.RANCHER_SECRET_KEY),
                                    verify=False).json()

        if len(service_info['data']) == 0:
            raise ValueError(
                'Unable to fetch service information.  That service version may not be available.'
            )

        if len(service_info['data'][0]['instances']) == 0:
            raise ValueError(
                'The service version specified has no available container instances.'
            )

        instances = service_info['data'][0]['instances']

        #pprint(instances)

        match_instance_id = False
        if 'instance_id' in params:
            match_instance_id = True

        sockets = []
        for i in instances:
            if match_instance_id and params['instance_id'] != i['id']:
                continue
            LOG_URL = i['actions']['logs']
            payload = {'follow': True}
            log_ws = requests.post(LOG_URL,
                                   data=json.dumps(payload),
                                   auth=(self.RANCHER_ACCESS_KEY,
                                         self.RANCHER_SECRET_KEY),
                                   verify=False).json()
            sockets.append({
                'instance_id':
                i['id'],
                'socket_url':
                log_ws['url'] + '?token=' + log_ws['token']
            })

        #END get_service_log_web_socket

        # At some point might do deeper type checking...
        if not isinstance(sockets, list):
            raise ValueError(
                'Method get_service_log_web_socket return value ' +
                'sockets is not type list as required.')
        # return the results
        return [sockets]
Esempio n. 6
0
    def get_service_status(self, ctx, service):
        """
        For a given service, check on the status.  If the service is down or
        not running, this function will attempt to start or restart the
        service once, then return the status.
        This function will throw an error if the specified service cannot be
        found or encountered errors on startup.
        :param service: instance of type "Service" (module_name - the name of
           the service module, case-insensitive version     - specify the
           service version, which can be either: (1) full git commit hash of
           the module version (2) semantic version or semantic version
           specification Note: semantic version lookup will only work for
           released versions of the module. (3) release tag, which is one of:
           dev | beta | release This information is always fetched from the
           Catalog, so for more details on specifying the version, see the
           Catalog documentation for the get_module_version method.) ->
           structure: parameter "module_name" of String, parameter "version"
           of String
        :returns: instance of type "ServiceStatus" (module_name     - name of
           the service module version         - semantic version number of
           the service module git_commit_hash - git commit hash of the
           service module release_tags    - list of release tags currently
           for this service module (dev/beta/release) url             - the
           url of the service up              - 1 if the service is up, 0
           otherwise status          - status of the service as reported by
           rancher health          - health of the service as reported by
           Rancher TODO: add something to return: string
           last_request_timestamp;) -> structure: parameter "module_name" of
           String, parameter "version" of String, parameter "git_commit_hash"
           of String, parameter "release_tags" of list of String, parameter
           "hash" of String, parameter "url" of String, parameter "up" of
           type "boolean", parameter "status" of String, parameter "health"
           of String
        """
        # ctx is the context object
        # return variables are: status
        #BEGIN get_service_status

        # TODO: handle case where version is not registered in the catalog- this may be the case for core services
        #       that were not registered in the usual way.

        # first get infor from the catalog- it must be a dynamic service
        cc = Catalog(self.CATALOG_URL, token=ctx['token'])
        mv = cc.get_module_version({
            'module_name': service['module_name'],
            'version': service['version']
        })
        if 'dynamic_service' not in mv:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')
        if mv['dynamic_service'] != 1:
            raise ValueError(
                'Specified module is not marked as a dynamic service. (' +
                mv['module_name'] + '-' + mv['git_commit_hash'] + ')')

        status = self.get_single_service_status(mv)

        # if we cannot get the status, or it is not up, then try to start it
        if status is None or status['up'] != 1:
            self.start(ctx, service)
            # try to get status
            status = self.get_single_service_status(mv)

        if status is None:
            raise ValueError(
                'Unable to get service status, or service was unable to start properly'
            )

        #END get_service_status

        # At some point might do deeper type checking...
        if not isinstance(status, dict):
            raise ValueError('Method get_service_status return value ' +
                             'status is not type dict as required.')
        # return the results
        return [status]
Esempio n. 7
0
    def list_service_status(self, ctx, params):
        """
        :param params: instance of type "ListServiceStatusParams" (not yet
           implemented funcdef pause(Service service) returns (ServiceStatus
           status);) -> structure: parameter "is_up" of type "boolean",
           parameter "module_names" of list of String
        :returns: instance of list of type "ServiceStatus" (module_name     -
           name of the service module version         - semantic version
           number of the service module git_commit_hash - git commit hash of
           the service module release_tags    - list of release tags
           currently for this service module (dev/beta/release) url          
           - the url of the service up              - 1 if the service is up,
           0 otherwise status          - status of the service as reported by
           rancher health          - health of the service as reported by
           Rancher TODO: add something to return: string
           last_request_timestamp;) -> structure: parameter "module_name" of
           String, parameter "version" of String, parameter "git_commit_hash"
           of String, parameter "release_tags" of list of String, parameter
           "hash" of String, parameter "url" of String, parameter "up" of
           type "boolean", parameter "status" of String, parameter "health"
           of String
        """
        # ctx is the context object
        # return variables are: returnVal
        #BEGIN list_service_status
        rancher = gdapi.Client(url=self.RANCHER_URL,
                               access_key=self.RANCHER_ACCESS_KEY,
                               secret_key=self.RANCHER_SECRET_KEY)

        cc = Catalog(self.CATALOG_URL, token=ctx['token'])

        # first create simple module_name lookup based on hash (TODO: in catalog, allow us to only fetch dynamic service modules)
        modules = cc.list_basic_module_info({
            'include_released': 1,
            'include_unreleased': 1
        })
        module_hash_lookup = {}  # hash => module_name
        for m in modules:
            if 'dynamic_service' not in m or m['dynamic_service'] != 1:
                continue
            module_hash_lookup[self.get_module_name_hash(
                m['module_name'])] = m['module_name']

        # next get environment id (could be a config parameter in the future rather than looping over everything)
        result = []
        # not sure if this is supposed to pass False, or the string 'false'
        slists = rancher.list_environment(system='false')
        if len(slists) == 0: return []  # I shouldn't return
        for slist in slists:
            eid = slist['id']

            # get service info
            entries = rancher.list_service(environmentId=eid)
            if len(entries) == 0: continue

            for entry in entries:
                rs = entry['name'].split('-')
                if len(rs) != 2: continue
                es = {
                    'status': entry['state'],
                    'health': entry['healthState'],
                    'hash': rs[1]
                }
                #if es['health'] == 'healthy' and es['status'] == 'active':
                if es['status'] == 'active':
                    es['up'] = 1
                else:
                    es['up'] = 0
                try:
                    mv = cc.get_module_version({
                        'module_name':
                        module_hash_lookup[rs[0]],
                        'version':
                        rs[1]
                    })
                    es['url'] = self.get_service_url(mv)
                    es['version'] = mv['version']
                    es['module_name'] = mv['module_name']
                    es['release_tags'] = mv['release_tags']
                    es['git_commit_hash'] = mv['git_commit_hash']
                except:
                    # this will occur if the module version is not registered with the catalog, or if the module
                    # was not marked as a service, or if something was started in Rancher directly and pulled
                    # from somewhere else, or an old version of the catalog was used to start this service
                    es['url'] = "https://{0}:{1}/dynserv/{3}.{2}".format(
                        self.SVC_HOSTNAME, self.NGINX_PORT, rs[0], rs[1])
                    es['version'] = ''
                    es['release_tags'] = []
                    es['git_commit_hash'] = ''
                    es['module_name'] = '!' + rs[0] + ''
                result.append(es)

        returnVal = result
        #END list_service_status

        # At some point might do deeper type checking...
        if not isinstance(returnVal, list):
            raise ValueError('Method list_service_status return value ' +
                             'returnVal is not type list as required.')
        # return the results
        return [returnVal]