Exemple #1
0
def list_components(*, node, cluster):
    """List the components installed on a node of a specified cluster.

    :param node: Machine name
    :type node: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: [description]
    :return: The list of the components installed on the node
    :rtype: list
    """

    if not nodes.check_node(cluster=cluster, node=node):
        raise ex.LoadError('node', node, 'NotExist')

    if cluster != ss.svars['cluster']:
        try:
            with open(JUMBODIR + cluster + '/jumbo_config', 'r') as clf:
                cluster_conf = json.load(clf)
        except IOError as e:
            raise ex.LoadError('cluster', cluster, e.strerror)
    else:
        cluster_conf = ss.svars

    for m in cluster_conf['nodes']:
        if m['name'] == node:
            m_conf = m
            break

    return m_conf['components']
Exemple #2
0
def remove_component(component, *, node, cluster):
    """Remove a service of a specified node in a specified cluster.

    :param name: Service name
    :type name: str
    :param node: Machine name
    :type node: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: [description]
    :raises ex.CreationError: [description]
    """

    ss.load_config(cluster)

    if not nodes.check_node(cluster=cluster, node=node):
        raise ex.LoadError('node', node, 'NotExist')

    service = check_component(component)
    if not service:
        raise ex.LoadError('component', component, 'NotExist')

    for i, m in enumerate(ss.svars['nodes']):
        if m['name'] == node:
            m_index = i

    if component not in ss.svars['nodes'][m_index]['components']:
        raise ex.CreationError('node', node, 'component', component,
                               'NotInstalled')

    ss.svars['nodes'][m_index]['components'].remove(component)
    ss.dump_config(get_services_components_hosts())
Exemple #3
0
def add_component(name, node, cluster, ha=None):
    """Add a component to a specified node of a specified.

    :param name: Component name
    :type name: str
    :param node: Machine name
    :type node: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: [description]
    :raises ex.CreationError: [description]
    """

    for i, m in enumerate(ss.svars['nodes']):
        if m['name'] == node:
            m_index = i
            break
    else:
        raise ex.LoadError('node', node, 'NotExist')

    service = check_component(name)
    if not service:
        raise ex.LoadError('component', name, 'NotExist')

    if not check_service_cluster(service):
        raise ex.CreationError(
            'cluster', cluster, 'service', service, 'NotInstalled')

    for i, m in enumerate(ss.svars['nodes']):
        if m['name'] == node:
            m_index = i

    if ha is None:
        ha = check_comp_number(service, name)

    missing_serv, missing_comp = check_service_req_service(service, ha)
    if missing_serv:
        raise ex.CreationError('component', name, 'services', missing_serv,
                               'ReqNotMet')
    if missing_comp:
        print_missing = []
        print_missing.append('Default:')
        for k, v in missing_comp['default'].items():
            print_missing.append(' - {} {}'.format(v, k))
        print_missing.append('or High Availability:')
        for k, v in missing_comp['ha'].items():
            print_missing.append(' - {} {}'.format(v, k))
        raise ex.CreationError('service', name, 'components', print_missing,
                               'ReqNotMet')

    if name in ss.svars['nodes'][m_index]['components']:
        raise ex.CreationError('node', node, 'component', name,
                               'Installed')

    ss.svars['nodes'][m_index]['components'].append(name)
    ss.dump_config(get_services_components_hosts())
Exemple #4
0
    def check_and_call(*args, **kwargs):
        if not kwargs['cluster']:
            raise ex.LoadError('cluster', None, 'NoContext')
        elif not check_cluster(kwargs['cluster']):
            raise ex.LoadError('cluster', kwargs['cluster'], 'NotExist')
        elif kwargs['cluster'] != ss.svars['cluster']:
            if ss.svars['cluster']:
                raise ex.LoadError('cluster', ss.svars['cluster'], 'MustExit')

        return func(*args, **kwargs)
Exemple #5
0
def check_comp_number(service, component):
    """Check the maximum number of a component is not already reached.

    :param service: Service name
    :type service: str
    :param component: Component name
    :type component: str
    :return: True if the service is in HA mode, false otherwise
    """

    ha = 'ha' if check_ha(service) else 'default'
    serv_comp_host = get_services_components_hosts()
    number_comp = 1
    if serv_comp_host[service].get(component):
        number_comp = len(serv_comp_host[service][component]) + 1
    for s in config['services']:
        if s['name'] == service:
            for c in s['components']:
                if c['name'] == component:
                    if number_comp > c['number'][ha] \
                            and c['number'][ha] != -1:
                        raise ex.CreationError('cluster',
                                               ss.svars['cluster'],
                                               'components',
                                               component,
                                               'MaxNumber')
                    elif number_comp == c['number']['ha']:
                        to_remove = {}
                        for comp in s['components']:
                            n = 0
                            max_n = comp['number']['ha']
                            if serv_comp_host[service].get(comp['name']):
                                n = len(serv_comp_host[service][comp['name']])
                            if n > max_n and max_n != -1:
                                to_remove[comp['name']] = n - max_n
                        if to_remove:
                            print_remove = []
                            for k, v in to_remove.items():
                                print_remove.append('{} {}'.format(v, k))
                            raise ex.CreationError('service',
                                                   service,
                                                   'components',
                                                   print_remove,
                                                   'TooManyHA')
                        return True
                    return False
            raise ex.LoadError('component', component, 'NotExist')
    raise ex.LoadError('service', service, 'NotExist')
Exemple #6
0
def edit_node(name, ip=None, ram=None, cpus=None, *, cluster):
    """Modify an existing node in a cluster.

    """
    ss.load_config(cluster=cluster)

    if not check_node(cluster=cluster, node=name):
        raise ex.LoadError('node', name, 'NotExist')

    if check_ip(ip, cluster=cluster):
        raise ex.CreationError('node', name, 'IP', ip, 'Exists')

    changed = []

    for i, m in enumerate(ss.svars['nodes']):
        if m['name'] == name:
            if ip:
                changed.append(["IP", ss.svars['nodes'][i]['ip'], ip])
                ss.svars['nodes'][i]['ip'] = ip
            if ram:
                changed.append(["RAM", ss.svars['nodes'][i]['ram'], ram])
                ss.svars['nodes'][i]['ram'] = ram
            if cpus:
                changed.append(["CPUs", ss.svars['nodes'][i]['cpus'], cpus])
                ss.svars['nodes'][i]['cpus'] = cpus

    ss.dump_config()

    return changed
Exemple #7
0
def get_yaml_config(cluster=None):
    """Get the versions to use for each service/platform/ressource

    :raises ex.LoadError: If the file versions.json doesn't exist
    :return: The versions to use
    :rtype: dict
    """

    yaml_versions = {'services': {}, 'platform': {}}

    if not os.path.isfile(JUMBODIR + 'versions.json'):
        raise ex.LoadError('file', JUMBODIR + 'versions.json', 'NotExist')

    # Global versions settings
    with open(JUMBODIR + 'versions.json', 'r') as vs:
        jumbo_versions = json.load(vs)

    yaml_versions = update_yaml_versions(yaml_versions, jumbo_versions)

    if not cluster:
        return yaml_versions

    # Cluster versions settings
    if os.path.isfile(JUMBODIR + cluster + '/versions.json'):
        with open(JUMBODIR + cluster + '/versions.json', 'r') as vs:
            cluster_versions = json.load(vs)

        yaml_versions = update_yaml_versions(yaml_versions, cluster_versions)

    return yaml_versions
Exemple #8
0
def load_config(cluster):
    """Load a cluster in the session.

    :param cluster: Cluster name
    :type cluster: str
    :return: True on success
    """
    global svars

    if not checks.check_cluster(cluster):
        raise ex.LoadError('cluster', cluster, 'NotExist')

    if not clusters.check_config(cluster):
        raise ex.LoadError('cluster', cluster, 'NoConfFile')
    else:
        try:
            with open(JUMBODIR + cluster + '/jumbo_config', 'r') as jc:
                svars = json.load(jc)
        except IOError as e:
            raise ex.LoadError('cluster', cluster, e.strerror)

    vs.update_versions_file()

    return True
Exemple #9
0
def get_abbr(component, service):
    """Return the abbreviation of a component.

    :param component: Component name
    :type component: str
    :param service: Service name of the component
    :type service: str
    """

    if not check_component(component):
        raise ex.LoadError('component', component, 'NotExist')

    for s in config['services']:
        if s['name'] == service:
            for c in s['components']:
                if c['name'] == component:
                    return c['abbr']
Exemple #10
0
def create_cluster(domain, template=None, *, cluster):
    """Create a new cluster and load it in the session.

    :param name: New cluster name
    :type name: str
    :param domain: New cluster domain name
    :type domain: str
    :raises ex.CreationError: If name already used
    :return: True on creation success
    """

    if checks.check_cluster(cluster):
        raise ex.CreationError('cluster', cluster, 'name', cluster, 'Exists')

    allowed_chars = string.ascii_letters + string.digits + '-'
    for l in cluster:
        if l not in allowed_chars:
            raise ex.CreationError('cluster', cluster, 'name',
                                   'Allowed characters: ' + allowed_chars,
                                   'NameNotAllowed')

    ss.clear()
    data_dir = os.path.dirname(os.path.abspath(__file__)) + '/data/'
    config_dir = os.path.dirname(os.path.abspath(__file__)) + '/config/'
    if template:
        try:
            with open(config_dir + 'templates/' + template + '.json') \
                    as template_file:
                ss.svars = json.load(template_file)
        except:
            raise ex.LoadError('template', template, 'NotExist')

    pathlib.Path(JUMBODIR + cluster).mkdir(parents=True)

    dir_util.copy_tree(data_dir, JUMBODIR + cluster)
    dir_util._path_created = {}
    ss.svars['cluster'] = cluster
    ss.svars['domain'] = domain if domain else '%s.local' % cluster

    services_components_hosts = None
    if template:
        services_components_hosts = services.get_services_components_hosts()

    ss.dump_config(services_components_hosts)
    return True
Exemple #11
0
def list_clusters():
    """List all the clusters managed by Jumbo.

    :raises ex.LoadError: If a cluster doesn't have a 'jumbo_config' file
    :return: The list of clusters' configurations
    :rtype: dict
    """
    path_list = [f.path for f in os.scandir(JUMBODIR) if f.is_dir()]
    clusters = []

    for p in path_list:
        if not check_config(p.split('/')[-1]):
            raise ex.LoadError('cluster', p.split('/')[-1], 'NoConfFile')

        with open(p + '/jumbo_config') as cfg:
            clusters += [json.load(cfg)]

    return clusters
Exemple #12
0
def add_service(name, ha=False, *, cluster):
    """Add a service to a specified cluster.

    :param name: Service name
    :type name: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: [description]
    :raises ex.CreationError: [description]
    """

    ss.load_config(cluster)

    if not check_service(name):
        raise ex.LoadError('service', name, 'NotExist')

    if name in ss.svars['services']:
        raise ex.CreationError('cluster', cluster,
                               'service', name,
                               'Installed')

    if check_service_cluster(name):
        raise ex.CreationError(
            'cluster', cluster, 'service', name, 'Installed')

    missing_serv, missing_comp = check_service_req_service(name, ha)
    if missing_serv:
        raise ex.CreationError('service', name, 'services',
                               (' - %s' % s for s in missing_serv),
                               'ReqNotMet')
    if missing_comp:
        print_missing = []
        print_missing.append('Default:')
        for k, v in missing_comp['default'].items():
            print_missing.append(' - {} {}'.format(v, k))
        print_missing.append('or High Availability:')
        for k, v in missing_comp['ha'].items():
            print_missing.append(' - {} {}'.format(v, k))
        raise ex.CreationError('service', name, 'components', print_missing,
                               'ReqNotMet')

    ss.svars['services'].append(name)
    auto_install_service(name, cluster, ha)
    ss.dump_config(get_services_components_hosts())
Exemple #13
0
def check_ha(service):
    """Check if a service is in HA mode.

    :param service: Service name
    :type service: str
    :return: True if the service is in HA mode, False otherwise
    """

    serv_comp_host = get_services_components_hosts()
    for s in config['services']:
        if s['name'] == service:
            for c in s['components']:
                if serv_comp_host[service].get(c['name']):
                    number_comp = len(serv_comp_host[service][c['name']])
                    if number_comp > c['number']['default'] \
                            and c['number']['ha'] > c['number']['default']:
                        return True
            return False
    raise ex.LoadError('service', service, 'NotExist')
Exemple #14
0
def auto_assign(service, ha, *, cluster):
    """Auto-install a service and its components on the best fitting hosts.

    :param service: Service name
    :type service: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: If the cluster doesn't exist
    :raises ex.CreationError: If the requirements are not met to install
    """

    ss.load_config(cluster)

    scfg = check_service(service)
    if not scfg:
        raise ex.LoadError('service', service, 'NotExist')

    # dist is 'default' or 'ha'
    dist = 'ha' if ha else 'default'
    # Check loop for atomicity
    for component in scfg['components']:
        left = auto_assign_service_comp(component, dist, cluster, check=True)
        if left == -1:
            raise ex.CreationError('component', component['name'],
                                   'hosts type (need at least 1 of them)',
                                   (' - %s'
                                    % c for c in component['hosts_types']),
                                   'ReqNotMet')
        elif left > 0:
            raise ex.CreationError('component', component['name'],
                                   'hosts type (need ' + str(left) +
                                   ' of them)',
                                   (' - %s'
                                    % c for c in component['hosts_types']),
                                   'ReqNotMet')

    count = 0
    for component in scfg['components']:
        auto_assign_service_comp(component, dist, cluster, check=False)
        count += 1

    return count
Exemple #15
0
def delete_cluster(*, cluster):
    """Delete a cluster.

    :param name: Cluster name
    :type name: str
    :raises ex.LoadError: If the cluster doesn't exist
    :return: True if the deletion was successfull
    """
    try:
        # Vagrant destroy
        current_dir = os.getcwd()
        os.chdir(JUMBODIR + cluster + '/')
        subprocess.check_output(['vagrant', 'destroy', '-f'])
        os.chdir(current_dir)
        rmtree(JUMBODIR + cluster)
    except IOError as e:
        raise ex.LoadError('cluster', cluster, e.strerror)

    ss.clear()
    return True
Exemple #16
0
def remove_node(*, cluster, node):
    """Remove a node in a cluster.

    :param cluster: Cluster namee
    :type cluster: str
    :param name: Machine name
    :type name: str
    :raises ex.LoadError: If the node or the cluster couldn't be loaded
    :return: True if the session context has changed
    :rtype: bool
    """
    ss.load_config(cluster)

    if not check_node(cluster=cluster, node=node):
        raise ex.LoadError('node', node, 'NotExist')

    for i, m in enumerate(ss.svars['nodes']):
        if m['name'] == node:
            del (ss.svars['nodes'][i])

    ss.dump_config()
Exemple #17
0
def check_service_req_service(name, ha=False):
    """Check if a service requirements are satisfied.

    :param name: Service name
    :type name: str
    :param ha: Weither the service is in HA, defaults to False
    :raises ex.LoadError: If the service doesn't exist
    :return: The misssing services and components needed to install the service
    :rtype: dict
    """

    req = 'ha' if ha else 'default'
    missing_serv = []
    missing_comp = {}
    for s in config['services']:
        if s['name'] == name:
            for req_s in s['requirements']['services'][req]:
                if req_s not in ss.svars['services']:
                    missing_serv.append(req_s)
                missing_comp.update(check_service_req_comp(req_s))
            return missing_serv, missing_comp
    raise ex.LoadError('service', name, 'NotExist')
Exemple #18
0
def remove_service(service, *, cluster):
    """Remove a service of a specified cluster.

    :param name: Service name
    :type name: str
    :param cluster: Cluster name
    :type cluster: str
    :raises ex.LoadError: [description]
    :raises ex.CreationError: [description]
    """

    ss.load_config(cluster)

    if not check_service(service):
        raise ex.LoadError('service', service, 'NotExist')

    if not check_service_cluster(service):
        raise ex.CreationError(
            'cluster', cluster, 'service', service, 'NotInstalled')

    dependent = check_dependent_services(service)
    if dependent:
        raise ex.CreationError(
            'service', service, 'services', dependent, 'Dependency'
        )

    serv_comp = get_service_components(service)
    for m in ss.svars['nodes']:
        to_remove = []
        for c in m['components']:
            if c in serv_comp:
                to_remove.append(c)
        for c in to_remove:
            m['components'].remove(c)

    ss.svars['services'].remove(service)
    ss.dump_config(get_services_components_hosts())
Exemple #19
0
def check_service_req_comp(name):
    """Check if all the components required are installed for a service.

    :param name: Service name
    :type name: str
    :param ha: Weither the service is in HA, defaults to False
    :raises ex.LoadError: If the service doesn't exist
    :return: The missing components needed to install the service
    :rtype: dict
    """

    missing = {
        'default': {},
        'ha': {}
    }
    comp_count = count_components()
    for s in config['services']:
        if s['name'] == name:
            for comp in s['components']:
                req = 'default'
                req_number = comp['number'][req] if comp['number'][req] != -1 \
                    else 1
                missing_count = req_number - comp_count[comp['name']]
                if missing_count > 0:
                    missing['default'][comp['name']] = missing_count
                req = 'ha'
                req_number = comp['number'][req] if comp['number'][req] != -1 \
                    else 1
                missing_count = req_number - comp_count[comp['name']]
                if missing_count > 0:
                    missing['ha'][comp['name']] = missing_count

            if not missing['ha'] or not missing['default']:
                return {}
            return missing
    raise ex.LoadError('service', name, 'NotExist')
Exemple #20
0
def get_component(name):
    for s in config['services']:
        for c in s['components']:
            if c['name'] == name:
                return c
    raise ex.LoadError('component', name, 'NotExist')