Exemplo n.º 1
0
 def remove_existing_charms(self, charms):
     existing_charms = [CharmStoreID(s.charm_source).as_str_without_rev()
                        for s in
                        self.placement_controller.bundle.services]
     return [c for c in charms
             if CharmStoreID(c['Id']).as_str_without_rev()
             not in existing_charms]
Exemplo n.º 2
0
 def __init__(self, service_name, charm_source, summary_future,
              constraints, depends, conflicts,
              allowed_assignment_types, num_units, options,
              allow_multi_units, subordinate, required, relations,
              placement_spec):
     self.service_name = service_name
     self.charm_source = charm_source
     self.csid = CharmStoreID(charm_source)
     self.charm_name = self.csid.name
     self.summary_future = summary_future
     self._summary = "Loading summary…"
     self.constraints = constraints
     self.depends = depends
     self.conflicts = conflicts
     self.allowed_assignment_types = allowed_assignment_types
     self.num_units = num_units
     self.orig_num_units = num_units
     self.options = options
     self.allow_multi_units = allow_multi_units
     self.subordinate = subordinate
     self.is_core = required
     self.isolate = True if not subordinate else False
     self.relations = relations
     self.placement_spec = placement_spec
     self.resources = None
Exemplo n.º 3
0
 def services_with_charm_id(self, charm_id):
     l = []
     csid = CharmStoreID(charm_id)
     id_no_rev = csid.as_str_without_rev()
     for service in self.services:
         if service.csid.as_str_without_rev() == id_no_rev:
             l.append(service)
     return l
Exemplo n.º 4
0
 def services_with_charm_id(self, charm_id):
     l = []
     csid = CharmStoreID(charm_id)
     id_no_rev = csid.as_str_without_rev()
     for service in self.services:
         if service.csid.as_str_without_rev() == id_no_rev:
             l.append(service)
     return l
Exemplo n.º 5
0
 def done_cb(f):
     csid = CharmStoreID(charm_dict['Id'])
     id_no_rev = csid.as_str_without_rev()
     info = self.metadata_controller.get_charm_info(id_no_rev)
     is_subordinate = info["Meta"]["charm-metadata"].get(
         "Subordinate", False)
     service_name = self.placement_controller.add_new_service(
         charm_name, charm_dict, is_subordinate=is_subordinate)
     self.frame.focus_position = 'body'
     self.columns.focus_position = 0
     self.update()
     self.services_column.select_service(service_name)
Exemplo n.º 6
0
 def done_cb(f):
     csid = CharmStoreID(charm_dict['Id'])
     id_no_rev = csid.as_str_without_rev()
     info = self.metadata_controller.get_charm_info(id_no_rev)
     is_subordinate = info["Meta"]["charm-metadata"].get(
         "Subordinate", False)
     service_name = self.placement_controller.add_new_service(
         charm_name, charm_dict, is_subordinate=is_subordinate)
     self.frame.focus_position = 'body'
     self.columns.focus_position = 0
     self.update()
     self.services_column.select_service(service_name)
Exemplo n.º 7
0
async def deploy_service(service, default_series, msg_cb):
    """Juju deploy service.

    If the service's charm ID doesn't have a revno, will query charm
    store to get latest revno for the charm.

    If the service's charm ID has a series, use that, otherwise use
    the provided default series.

    Arguments:
    service: Service to deploy
    msg_cb: message callback
    exc_cb: exception handler callback

    Returns a future that will be completed after the deploy has been
    submitted to juju

    """
    name = service.service_name
    if not events.AppMachinesCreated.is_set(name):
        # block until we have machines
        await events.AppMachinesCreated.wait(name)
        app.log.debug('Machines for {} are ready'.format(name))

    if service.csid.rev == "":
        id_no_rev = service.csid.as_str_without_rev()
        mc = app.metadata_controller
        futures.wait([mc.metadata_future])
        info = mc.get_charm_info(id_no_rev, lambda _: None)
        service.csid = CharmStoreID(info["Id"])

    deploy_args = {}
    deploy_args = dict(
        entity_url=service.csid.as_str(),
        application_name=service.service_name,
        num_units=service.num_units,
        constraints=service.constraints,
        to=service.placement_spec,
        config=service.options,
    )

    msg = 'Deploying {}...'.format(service.service_name)
    app.log.info(msg)
    msg_cb(msg)
    from pprint import pformat
    app.log.debug(pformat(deploy_args))

    app_inst = await app.juju.client.deploy(**deploy_args)

    if service.expose:
        msg = 'Exposing {}.'.format(service.service_name)
        app.log.info(msg)
        msg_cb(msg)
        await app_inst.expose()

    msg = '{}: deployed, installing.'.format(service.service_name)
    app.log.info(msg)
    msg_cb(msg)

    events.AppDeployed.set(service.service_name)
Exemplo n.º 8
0
 def __init__(self, service_name, charm_source, summary_future,
              constraints, depends, conflicts,
              allowed_assignment_types, num_units, options,
              allow_multi_units, subordinate, required, relations,
              placement_spec):
     self.service_name = service_name
     self.charm_source = charm_source
     self.csid = CharmStoreID(charm_source)
     self.charm_name = self.csid.name
     self.summary_future = summary_future
     self._summary = "Loading summary…"
     self.constraints = constraints
     self.depends = depends
     self.conflicts = conflicts
     self.allowed_assignment_types = allowed_assignment_types
     self.num_units = num_units
     self.orig_num_units = num_units
     self.options = options
     self.allow_multi_units = allow_multi_units
     self.subordinate = subordinate
     self.is_core = required
     self.isolate = True if not subordinate else False
     self.relations = relations
     self.placement_spec = placement_spec
     self.resources = None
Exemplo n.º 9
0
    def _deploy_async():
        if service.csid.rev == "":
            id_no_rev = service.csid.as_str_without_rev()
            mc = app.metadata_controller
            futures.wait([mc.metadata_future])
            info = mc.get_charm_info(id_no_rev, lambda _: None)
            service.csid = CharmStoreID(info["Id"])

        # Add charm to Juju
        this.CLIENT.Client(request="AddCharm",
                           params={"url": service.csid.as_str()})

        # We must load any resources prior to deploying
        resources = app.metadata_controller.get_resources(
            service.csid.as_str_without_rev())
        app.log.debug("Resources: {}".format(resources))
        if resources:
            params = {
                "tag": "application-{}".format(service.csid.name),
                "url": service.csid.as_str(),
                "resources": resources
            }
            app.log.debug("Adding pending resources: {}".format(params))
            resource_ids = this.CLIENT.Resources(request="AddPendingResources",
                                                 params=params)
            app.log.debug("Pending resources IDs: {}".format(resource_ids))
            application_to_resource_map = {}
            for idx, resource in enumerate(resources):
                pid = resource_ids['pending-ids'][idx]
                application_to_resource_map[resource['Name']] = pid
            service.resources = application_to_resource_map

        app_params = {"applications": [service.as_deployargs()]}

        app.log.debug("Deploying {}: {}".format(service, app_params))

        deploy_message = "Deploying application: {}".format(
            service.service_name)
        if msg_cb:
            msg_cb("{}".format(deploy_message))
        this.CLIENT.Application(request="Deploy", params=app_params)
        if msg_cb:
            msg_cb("{}...done.".format(deploy_message))
Exemplo n.º 10
0
    def _deploy_async():

        if service.csid.rev == "":
            id_no_rev = service.csid.as_str_without_rev()
            mc = app.metadata_controller
            futures.wait([mc.metadata_future])
            info = mc.get_charm_info(id_no_rev, lambda _: None)
            service.csid = CharmStoreID(info["Id"])

        app.log.debug("Adding Charm {}".format(service.csid.as_str()))
        rv = this.CLIENT.Client(request="AddCharm",
                                params={"url": service.csid.as_str()})
        app.log.debug("AddCharm returned {}".format(rv))

        charm_id = service.csid.as_str()
        resources = app.metadata_controller.get_resources(charm_id)

        app.log.debug("Resources for charm id '{}': {}".format(
            charm_id, resources))
        if resources:
            params = {
                "tag": "application-{}".format(service.csid.name),
                "url": service.csid.as_str(),
                "resources": resources
            }
            app.log.debug("AddPendingResources: {}".format(params))
            resource_ids = this.CLIENT.Resources(request="AddPendingResources",
                                                 params=params)
            app.log.debug(
                "AddPendingResources returned: {}".format(resource_ids))
            application_to_resource_map = {}
            for idx, resource in enumerate(resources):
                pid = resource_ids['pending-ids'][idx]
                application_to_resource_map[resource['Name']] = pid
            service.resources = application_to_resource_map

        deploy_args = service.as_deployargs()
        deploy_args['series'] = service.csid.series
        app_params = {"applications": [deploy_args]}

        app.log.debug("Deploying {}: {}".format(service, app_params))

        deploy_message = "Deploying {}... ".format(service.service_name)
        if msg_cb:
            msg_cb("{}".format(deploy_message))
        rv = this.CLIENT.Application(request="Deploy", params=app_params)
        app.log.debug("Deploy returned {}".format(rv))

        for result in rv.get('results', []):
            if 'error' in result:
                raise Exception("Error deploying: {}".format(
                    result['error'].get('message', 'error')))

        if msg_cb:
            msg_cb("{}: deployed, installing.".format(service.service_name))

        if service.expose:
            expose_params = {"application": service.service_name}
            app.log.debug("Expose: {}".format(expose_params))
            rv = this.CLIENT.Application(request="Expose",
                                         params=expose_params)
            app.log.debug("Expose returned: {}".format(rv))
Exemplo n.º 11
0
class Service:

    def __init__(self, service_name, charm_source, summary_future,
                 constraints, depends, conflicts,
                 allowed_assignment_types, num_units, options,
                 allow_multi_units, subordinate, required, relations,
                 placement_spec):
        self.service_name = service_name
        self.charm_source = charm_source
        self.csid = CharmStoreID(charm_source)
        self.charm_name = self.csid.name
        self.summary_future = summary_future
        self._summary = "Loading summary…"
        self.constraints = constraints
        self.depends = depends
        self.conflicts = conflicts
        self.allowed_assignment_types = allowed_assignment_types
        self.num_units = num_units
        self.orig_num_units = num_units
        self.options = options
        self.allow_multi_units = allow_multi_units
        self.subordinate = subordinate
        self.is_core = required
        self.isolate = True if not subordinate else False
        self.relations = relations
        self.placement_spec = placement_spec
        self.resources = None

    @property
    def summary(self):
        if self.summary_future and self.summary_future.done():
            self._summary = self.summary_future.result()
        return self._summary

    @property
    def display_name(self):
        return "{} ({})".format(self.service_name,
                                self.charm_source)

    def _format_scope_directive(self, placement):
        if ':' in placement:
            scope, directive = placement.split(':')
            if scope == 'lxc':
                scope = 'lxd'
            return {"scope": scope, "directive":
                    str(directive)}
        else:
            # Assume that the placement is to a machine number
            scope = '#'
            directive = placement
            return {"scope": scope, "directive":
                    str(directive)}

    def _prepare_placement(self, placement):
        new_placements = []
        if isinstance(placement, list):
            for p in placement:
                new_placements.append(self._format_scope_directive(p))
        else:
            new_placements.append(self._format_scope_directive(placement))

        return new_placements

    def as_deployargs(self):
        rd = {"charm-url": self.csid.as_str(),
              "application": self.service_name,
              "num-units": self.num_units,
              "constraints": self.constraints}

        if self.resources:
            rd['resources'] = self.resources

        if len(self.options) > 0:
            config_dict = {self.service_name: self.options}
            config_yaml = yaml.dump(config_dict, default_flow_style=False)
            rd["config-yaml"] = config_yaml

        if self.placement_spec:
            specs = self._prepare_placement(self.placement_spec)
            rd["placement"] = specs

        return rd

    def required_num_units(self):
        return self.num_units

    def __repr__(self):
        return "<Service {}>".format(self.service_name)

    def __eq__(self, other):
        me = self.charm_source + self.service_name
        them = other.charm_source + other.service_name
        return me == them

    def __hash__(self):
        """We assume that we won't instantiate multiple Charm objects for the
        same class that have different properties.
        """
        return hash(self.charm_source + self.service_name)
Exemplo n.º 12
0
def _graph_string_for_bundle(bundle, mc):
    s = []
    graph = defaultdict(list)
    svc_requires = {}
    svc_provides = {}
    for svc, sd in bundle._bundle['services'].items():

        csid = CharmStoreID(sd['charm'])
        info = mc.get_charm_info(csid.as_str_without_rev())
        if info is None:
            md = {}
        else:
            md = info['Meta']['charm-metadata']
        svc_requires[svc] = md.get("Requires", {})
        svc_provides[svc] = md.get("Provides", {})

    services_seen = set()
    for rel_src, rel_dst in bundle._bundle['relations']:

        def do_split(rel):
            ss = rel.split(":")
            if len(ss) == 1:
                return rel, ""
            else:
                return ss[0], ss[1]

        src, s_relname = do_split(rel_src)
        dst, d_relname = do_split(rel_dst)
        services_seen.add(src)
        services_seen.add(dst)

        if src not in svc_provides or src not in svc_requires or \
           dst not in svc_provides or dst not in svc_requires:
            continue
        src_provides = set(
            [v['Interface'] for v in svc_provides[src].values()])
        src_requires = set(
            [v['Interface'] for v in svc_requires[src].values()])
        dst_provides = set(
            [v['Interface'] for v in svc_provides[dst].values()])
        dst_requires = set(
            [v['Interface'] for v in svc_requires[dst].values()])

        provides_intersection = src_provides.intersection(dst_requires)
        is_provides = len(provides_intersection) == 1

        requires_intersection = src_requires.intersection(dst_provides)
        is_requires = len(requires_intersection) == 1

        srcunits = bundle._bundle['services'][src].get('num_units', 1)
        src_with_units = "{} \N{MULTIPLICATION SIGN} {}".format(src, srcunits)
        dstunits = bundle._bundle['services'][dst].get('num_units', 1)
        dst_with_units = "{} \N{MULTIPLICATION SIGN} {}".format(dst, dstunits)

        if is_provides:
            if s_relname == "":
                s_relname = [
                    k for k, v in svc_provides[src].items()
                    if v['Interface'] == list(provides_intersection)[0]
                ][0]
            if d_relname == "":
                d_relname = [
                    k for k, v in svc_requires[dst].items()
                    if v['Interface'] == list(provides_intersection)[0]
                ][0]

            if s_relname != d_relname:
                relname = s_relname + " \N{RIGHTWARDS ARROW} " + d_relname
            else:
                relname = s_relname
            line = "[{}] - {} -> [{}]".format(src_with_units, relname,
                                              dst_with_units)
            graph[src_with_units].append(dst_with_units)

        elif is_requires:
            if s_relname == "":
                s_relname = [
                    k for k, v in svc_requires[src].items()
                    if v['Interface'] == list(requires_intersection)[0]
                ][0]
            if d_relname == "":
                d_relname = [
                    k for k, v in svc_provides[dst].items()
                    if v['Interface'] == list(requires_intersection)[0]
                ][0]

            if s_relname != d_relname:
                relname = d_relname + " \N{RIGHTWARDS ARROW} " + s_relname
            else:
                relname = s_relname

            line = "[{}] - {} -> [{}]".format(dst_with_units, relname,
                                              src_with_units)
            graph[dst_with_units].append(src_with_units)
        else:
            line = ("[{}] <- {} \N{LEFT RIGHT ARROW} {} -> "
                    "[{}]").format(dst_with_units, s_relname, d_relname,
                                   src_with_units)
            graph[dst_with_units].append(src_with_units)
            graph[src_with_units].append(dst_with_units)
        s.append(line)

    for svc in bundle._bundle['services'].keys():
        if svc not in services_seen:
            s.append("[{}]".format(svc))
    return "\n".join(s), graph
Exemplo n.º 13
0
class Service:

    def __init__(self, service_name, charm_source, summary_future,
                 constraints, depends, conflicts,
                 allowed_assignment_types, num_units, options,
                 allow_multi_units, subordinate, required, relations,
                 placement_spec):
        self.service_name = service_name
        self.charm_source = charm_source
        self.csid = CharmStoreID(charm_source)
        self.charm_name = self.csid.name
        self.summary_future = summary_future
        self._summary = "Loading summary…"
        self.constraints = constraints
        self.depends = depends
        self.conflicts = conflicts
        self.allowed_assignment_types = allowed_assignment_types
        self.num_units = num_units
        self.orig_num_units = num_units
        self.options = options
        self.allow_multi_units = allow_multi_units
        self.subordinate = subordinate
        self.is_core = required
        self.isolate = True if not subordinate else False
        self.relations = relations
        self.placement_spec = placement_spec
        self.resources = None

    @property
    def summary(self):
        if self.summary_future and self.summary_future.done():
            self._summary = self.summary_future.result()
        return self._summary

    @property
    def display_name(self):
        return "{} ({})".format(self.service_name,
                                self.charm_source)

    def _format_scope_directive(self, placement):
        if ':' in placement:
            scope, directive = placement.split(':')
            if scope == 'lxc':
                scope = 'lxd'
            return {"scope": scope, "directive":
                    str(directive)}
        else:
            # Assume that the placement is to a machine number
            scope = '#'
            directive = placement
            return {"scope": scope, "directive":
                    str(directive)}

    def _prepare_placement(self, placement):
        new_placements = []
        if isinstance(placement, list):
            for p in placement:
                new_placements.append(self._format_scope_directive(p))
        else:
            new_placements.append(self._format_scope_directive(placement))

        return new_placements

    def as_deployargs(self):
        rd = {"charm-url": self.csid.as_str(),
              "application": self.service_name,
              "num-units": self.num_units,
              "constraints": self.constraints}

        if self.resources:
            rd['resources'] = self.resources

        if len(self.options) > 0:
            config_dict = {self.service_name: self.options}
            config_yaml = yaml.dump(config_dict, default_flow_style=False)
            rd["config-yaml"] = config_yaml

        if self.placement_spec:
            specs = self._prepare_placement(self.placement_spec)
            rd["placement"] = specs

        return rd

    def required_num_units(self):
        return self.num_units

    def __repr__(self):
        return "<Service {}>".format(self.service_name)

    def __eq__(self, other):
        me = self.charm_source + self.service_name
        them = other.charm_source + other.service_name
        return me == them

    def __hash__(self):
        """We assume that we won't instantiate multiple Charm objects for the
        same class that have different properties.
        """
        return hash(self.charm_source + self.service_name)
Exemplo n.º 14
0
def _graph_string_for_bundle(bundle, mc):
    s = []
    graph = defaultdict(list)
    svc_requires = {}
    svc_provides = {}
    for svc, sd in bundle._bundle['services'].items():

        csid = CharmStoreID(sd['charm'])
        info = mc.get_charm_info(csid.as_str_without_rev())
        if info is None:
            md = {}
        else:
            md = info['Meta']['charm-metadata']
        svc_requires[svc] = md.get("Requires", {})
        svc_provides[svc] = md.get("Provides", {})

    services_seen = set()
    for rel_src, rel_dst in bundle._bundle['relations']:
        def do_split(rel):
            ss = rel.split(":")
            if len(ss) == 1:
                return rel, ""
            else:
                return ss[0], ss[1]

        src, s_relname = do_split(rel_src)
        dst, d_relname = do_split(rel_dst)
        services_seen.add(src)
        services_seen.add(dst)

        if src not in svc_provides or src not in svc_requires or \
           dst not in svc_provides or dst not in svc_requires:
            continue
        src_provides = set([v['Interface'] for v in
                            svc_provides[src].values()])
        src_requires = set([v['Interface'] for v in
                            svc_requires[src].values()])
        dst_provides = set([v['Interface'] for v in
                            svc_provides[dst].values()])
        dst_requires = set([v['Interface'] for v in
                            svc_requires[dst].values()])

        provides_intersection = src_provides.intersection(dst_requires)
        is_provides = len(provides_intersection) == 1

        requires_intersection = src_requires.intersection(dst_provides)
        is_requires = len(requires_intersection) == 1

        srcunits = bundle._bundle['services'][src].get('num_units', 1)
        src_with_units = "{} \N{MULTIPLICATION SIGN} {}".format(src, srcunits)
        dstunits = bundle._bundle['services'][dst].get('num_units', 1)
        dst_with_units = "{} \N{MULTIPLICATION SIGN} {}".format(dst, dstunits)

        if is_provides:
            if s_relname == "":
                s_relname = [k for k, v in svc_provides[src].items() if
                             v['Interface'] ==
                             list(provides_intersection)[0]][0]
            if d_relname == "":
                d_relname = [k for k, v in svc_requires[dst].items() if
                             v['Interface'] ==
                             list(provides_intersection)[0]][0]

            if s_relname != d_relname:
                relname = s_relname + " \N{RIGHTWARDS ARROW} " + d_relname
            else:
                relname = s_relname
            line = "[{}] - {} -> [{}]".format(src_with_units, relname,
                                              dst_with_units)
            graph[src_with_units].append(dst_with_units)

        elif is_requires:
            if s_relname == "":
                s_relname = [k for k, v in svc_requires[src].items() if
                             v['Interface'] ==
                             list(requires_intersection)[0]][0]
            if d_relname == "":
                d_relname = [k for k, v in svc_provides[dst].items() if
                             v['Interface'] ==
                             list(requires_intersection)[0]][0]

            if s_relname != d_relname:
                relname = d_relname + " \N{RIGHTWARDS ARROW} " + s_relname
            else:
                relname = s_relname

            line = "[{}] - {} -> [{}]".format(dst_with_units, relname,
                                              src_with_units)
            graph[dst_with_units].append(src_with_units)
        else:
            line = ("[{}] <- {} \N{LEFT RIGHT ARROW} {} -> "
                    "[{}]").format(dst_with_units, s_relname,
                                   d_relname, src_with_units)
            graph[dst_with_units].append(src_with_units)
            graph[src_with_units].append(dst_with_units)
        s.append(line)

    for svc in bundle._bundle['services'].keys():
        if svc not in services_seen:
            s.append("[{}]".format(svc))
    return "\n".join(s), graph
#!/usr/bin/python3

from bundleplacer.charmstore_api import CharmStoreID

ids = ['mysql',
       'mysql-9',
       'nova-compute',
       'nova-cloud-controller',
       'cs:~adam-stokes/trusty/ghost',
       'cs:~openstack-charmers-next/xenial/lxd',
       'cs:~openstack-charmers-next/xenial/nova-compute-12',
       'cs:~openstack-charmers-next/xenial/nova-compute',
       'cs:bundle/openstack-base-40',
       'cs:~containers/easyrsa-2']

for i in ids:
    print(80*'-')
    print(i)
    csid = CharmStoreID(i)
    print(repr(csid))
    print(csid.as_str_without_rev())
    print(csid.as_str())