Exemple #1
0
 def setUp(self):
     yield super(MachineStateManagerTest, self).setUp()
     self.charm_state_manager = CharmStateManager(self.client)
     self.machine_state_manager = MachineStateManager(self.client)
     self.service_state_manager = ServiceStateManager(self.client)
     self.charm_state = yield self.charm_state_manager.add_charm_state(
         local_charm_id(self.charm), self.charm, "")
Exemple #2
0
def validate_hooks(client, unit_state, hook_names):

    # Assemble a list of valid hooks for the charm.
    valid_hooks = ["start", "stop", "install", "config-changed"]
    service_manager = ServiceStateManager(client)
    endpoints = yield service_manager.get_relation_endpoints(
        unit_state.service_name)
    endpoint_names = [ep.relation_name for ep in endpoints]
    for endpoint_name in endpoint_names:
        valid_hooks.extend([
            endpoint_name + "-relation-joined",
            endpoint_name + "-relation-changed",
            endpoint_name + "-relation-departed",
            endpoint_name + "-relation-broken",
        ])

    # Verify the debug names.
    for hook_name in hook_names:
        if hook_name in valid_hooks:
            continue
        break
    else:
        returnValue(True)

    # We dereference to the charm to give a fully qualified error
    # message.  I wish this was a little easier to dereference, the
    # service_manager.get_relation_endpoints effectively does this
    # already.
    service_manager = ServiceStateManager(client)
    service_state = yield service_manager.get_service_state(
        unit_state.service_name)
    charm_id = yield service_state.get_charm_id()
    charm_manager = CharmStateManager(client)
    charm = yield charm_manager.get_charm_state(charm_id)
    raise InvalidCharmHook(charm.id, hook_name)
Exemple #3
0
def download_charm(client, charm_id, charms_directory):
    charm_state_manager = CharmStateManager(client)
    charm_state = yield charm_state_manager.get_charm_state(charm_id)

    # Calculate local charm path
    checksum = yield charm_state.get_sha256()
    charm_key = under.quote("%s:%s" % (charm_state.id, checksum))
    local_charm_path = os.path.join(charms_directory, charm_key)

    # Retrieve charm from provider storage link
    if charm_state.bundle_url.startswith("file://"):
        file_path = charm_state.bundle_url[len("file://"):]
        if not os.path.exists(file_path):
            raise FileNotFound(charm_state.bundle_url)
        shutil.copyfileobj(open(file_path), open(local_charm_path, "w"))
    else:
        try:
            yield downloadPage(charm_state.bundle_url, local_charm_path)
        except Error:
            raise FileNotFound(charm_state.bundle_url)
    returnValue(CharmBundle(local_charm_path))
Exemple #4
0
    def start(self):
        """Start the machine agent.

        Creates state directories on the machine, retrieves the machine state,
        and enables watch on assigned units.
        """
        # Initialize directory paths.
        if not os.path.exists(self.charms_directory):
            os.makedirs(self.charms_directory)

        if not os.path.exists(self.units_directory):
            os.makedirs(self.units_directory)

        if not os.path.exists(self.unit_state_directory):
            os.makedirs(self.unit_state_directory)

        # Get state managers we'll be utilizing.
        self.service_state_manager = ServiceStateManager(self.client)
        self.charm_state_manager = CharmStateManager(self.client)

        # Retrieve the machine state for the machine we represent.
        machine_manager = MachineStateManager(self.client)
        self.machine_state = yield machine_manager.get_machine_state(
            self.get_machine_id())

        # Watch assigned units for the machine.
        if self.get_watch_enabled():
            self.machine_state.watch_assigned_units(self.watch_service_units)

        # Find out what provided the machine, and how to deploy units.
        settings = GlobalSettingsStateManager(self.client)
        self.provider_type = yield settings.get_provider_type()
        self.deploy_factory = get_deploy_factory(self.provider_type)

        # Connect the machine agent, broadcasting presence to the world.
        yield self.machine_state.connect_agent()
        log.info(
            "Machine agent started id:%s deploy:%r provider:%r" %
            (self.get_machine_id(), self.deploy_factory, self.provider_type))
Exemple #5
0
 def setUp(self):
     yield super(CharmStateManagerTest, self).setUp()
     self.charm_state_manager = CharmStateManager(self.client)
     self.charm_id = local_charm_id(self.charm)
Exemple #6
0
 def __init__(self, client, storage):
     self._client = client
     self._storage = storage
     self._charm_state_manager = CharmStateManager(self._client)
     self._charm_add_queue = []
     self._charm_state_cache = {}
Exemple #7
0
def collect(scope, machine_provider, client, log):
    """Extract status information into nested dicts for rendering.

       `scope`: an optional list of name specifiers. Globbing based
       wildcards supported. Defaults to all units, services and
       relations.

       `machine_provider`: machine provider for the environment

       `client`: ZK client connection

       `log`: a Python stdlib logger.
    """
    service_manager = ServiceStateManager(client)
    relation_manager = RelationStateManager(client)
    machine_manager = MachineStateManager(client)
    charm_manager = CharmStateManager(client)

    service_data = {}
    machine_data = {}
    state = dict(services=service_data, machines=machine_data)

    seen_machines = set()
    filter_services, filter_units = digest_scope(scope)

    services = yield service_manager.get_all_service_states()
    for service in services:
        if len(filter_services):
            found = False
            for filter_service in filter_services:
                if fnmatch(service.service_name, filter_service):
                    found = True
                    break
            if not found:
                continue

        unit_data = {}
        relation_data = {}

        charm_id = yield service.get_charm_id()
        charm = yield charm_manager.get_charm_state(charm_id)

        service_data[service.service_name] = dict(units=unit_data,
                                                  charm=charm.id,
                                                  relations=relation_data)
        exposed = yield service.get_exposed_flag()
        if exposed:
            service_data[service.service_name].update(exposed=exposed)

        units = yield service.get_all_unit_states()
        unit_matched = False

        relations = yield relation_manager.get_relations_for_service(service)

        for unit in units:
            if len(filter_units):
                found = False
                for filter_unit in filter_units:
                    if fnmatch(unit.unit_name, filter_unit):
                        found = True
                        break
                if not found:
                    continue

            u = unit_data[unit.unit_name] = dict()
            machine_id = yield unit.get_assigned_machine_id()
            u["machine"] = machine_id
            unit_workflow_client = WorkflowStateClient(client, unit)
            unit_state = yield unit_workflow_client.get_state()
            if not unit_state:
                u["state"] = "pending"
            else:
                unit_connected = yield unit.has_agent()
                u["state"] = unit_state if unit_connected else "down"
            if exposed:
                open_ports = yield unit.get_open_ports()
                u["open-ports"] = [
                    "{port}/{proto}".format(**port_info)
                    for port_info in open_ports
                ]

            u["public-address"] = yield unit.get_public_address()

            # indicate we should include information about this
            # machine later
            seen_machines.add(machine_id)
            unit_matched = True

            # collect info on each relation for the service unit
            relation_status = {}
            for relation in relations:
                try:
                    relation_unit = yield relation.get_unit_state(unit)
                except UnitRelationStateNotFound:
                    # This exception will occur when relations are
                    # established between services without service
                    # units, and therefore never have any
                    # corresponding service relation units. This
                    # scenario does not occur in actual deployments,
                    # but can happen in test circumstances. In
                    # particular, it will happen with a misconfigured
                    # provider, which exercises this codepath.
                    continue  # should not occur, but status should not fail
                relation_workflow_client = WorkflowStateClient(
                    client, relation_unit)
                relation_workflow_state = \
                    yield relation_workflow_client.get_state()
                relation_status[relation.relation_name] = dict(
                    state=relation_workflow_state)
            u["relations"] = relation_status

        # after filtering units check if any matched or remove the
        # service from the output
        if filter_units and not unit_matched:
            del service_data[service.service_name]
            continue

        for relation in relations:
            rel_services = yield relation.get_service_states()

            # A single related service implies a peer relation. More
            # imply a bi-directional provides/requires relationship.
            # In the later case we omit the local side of the relation
            # when reporting.
            if len(rel_services) > 1:
                # Filter out self from multi-service relations.
                rel_services = [
                    rsn for rsn in rel_services
                    if rsn.service_name != service.service_name
                ]

            if len(rel_services) > 1:
                raise ValueError("Unexpected relationship with more "
                                 "than 2 endpoints")

            rel_service = rel_services[0]
            relation_data[relation.relation_name] = rel_service.service_name

    machines = yield machine_manager.get_all_machine_states()
    for machine_state in machines:
        if (filter_services or filter_units) and \
                machine_state.id not in seen_machines:
            continue

        instance_id = yield machine_state.get_instance_id()
        m = {"instance-id": instance_id \
             if instance_id is not None else "pending"}
        if instance_id is not None:
            try:
                pm = yield machine_provider.get_machine(instance_id)
                m["dns-name"] = pm.dns_name
                m["instance-state"] = pm.state
                if (yield machine_state.has_agent()):
                    # if the agent's connected, we're fine
                    m["state"] = "running"
                else:
                    units = (yield machine_state.get_all_service_unit_states())
                    for unit in units:
                        unit_workflow_client = WorkflowStateClient(
                            client, unit)
                        if (yield unit_workflow_client.get_state()):
                            # for unit to have a state, its agent must have
                            # run, which implies the machine agent must have
                            # been running correctly at some point in the past
                            m["state"] = "down"
                            break
                    else:
                        # otherwise we're probably just still waiting
                        m["state"] = "not-started"
            except ProviderError:
                # The provider doesn't have machine information
                log.error("Machine provider information missing: machine %s" %
                          (machine_state.id))

        machine_data[machine_state.id] = m

    returnValue(state)