Exemple #1
0
    def test_stop(self):
        """Executing the stop transition, results in the workflow going
        to the down state.
        """
        file_path = self.makeFile()
        self.write_hook("install",
                        "#!/bin/bash\necho installed >> %s\n" % file_path)
        self.write_hook("start", "#!/bin/bash\necho start >> %s\n" % file_path)
        self.write_hook("stop", "#!/bin/bash\necho stop >> %s\n" % file_path)
        result = yield self.workflow.fire_transition("install")
        result = yield self.workflow.fire_transition("start")
        result = yield self.workflow.fire_transition("stop")
        self.assertTrue(result)
        current_state = yield self.workflow.get_state()
        self.assertEqual(current_state, "stopped")
        f_state, history, zk_state = yield self.read_persistent_state()
        self.assertEqual(f_state, zk_state)
        self.assertEqual(f_state, {"state": "stopped", "state_variables": {}})

        workflow_client = WorkflowStateClient(self.client, self.states["unit"])
        value = yield workflow_client.get_state()
        self.assertEqual(value, "stopped")

        self.assertEqual(history, [{
            "state": "installed",
            "state_variables": {}
        }, {
            "state": "started",
            "state_variables": {}
        }, {
            "state": "stopped",
            "state_variables": {}
        }])
Exemple #2
0
    def _process_unit_relations(self, service, unit, relations, rel_svc_map):
        """Collect UnitRelationState information per relation and per unit.

        Includes information under each unit for its relations including
        its relation state and information about any possible errors.

        see `_process_relations` for argument information
        """
        u = self.unit_data[unit.unit_name]
        relation_errors = {}

        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.
                # UPDATE: common with subordinate services, and
                # some testing scenarios.
                continue
            relation_workflow_client = WorkflowStateClient(
                self.client, relation_unit)
            workflow_state = yield relation_workflow_client.get_state()

            rel_svc_name = rel_svc_map.get(relation.internal_relation_id)
            if rel_svc_name and workflow_state not in ("up", None):
                relation_errors.setdefault(
                    relation.relation_name, set()).add(rel_svc_name)

        if relation_errors:
            # Normalize sets and store.
            u["relation-errors"] = dict(
                [(r, sorted(relation_errors[r])) for r in relation_errors])
Exemple #3
0
    def test_stop(self):
        """Executing the stop transition, results in the workflow going
        to the down state.
        """
        file_path = self.makeFile()
        self.write_hook(
            "install", "#!/bin/bash\necho installed >> %s\n" % file_path)
        self.write_hook(
            "start", "#!/bin/bash\necho start >> %s\n" % file_path)
        self.write_hook(
            "stop", "#!/bin/bash\necho stop >> %s\n" % file_path)
        result = yield self.workflow.fire_transition("install")
        result = yield self.workflow.fire_transition("start")
        result = yield self.workflow.fire_transition("stop")
        self.assertTrue(result)
        current_state = yield self.workflow.get_state()
        self.assertEqual(current_state, "stopped")
        f_state, history, zk_state = yield self.read_persistent_state()
        self.assertEqual(f_state, zk_state)
        self.assertEqual(f_state,
                         {"state": "stopped", "state_variables": {}})

        workflow_client = WorkflowStateClient(self.client, self.states["unit"])
        value = yield workflow_client.get_state()
        self.assertEqual(value, "stopped")

        self.assertEqual(history,
                         [{"state": "installed", "state_variables": {}},
                          {"state": "started", "state_variables": {}},
                          {"state": "stopped", "state_variables": {}}])
 def test_client_read_only(self):
     workflow_client = WorkflowStateClient(
         self.client, self.states["unit_relation"])
     with (yield workflow_client.lock()):
         yield self.assertFailure(
             workflow_client.set_state("up"),
             NotImplementedError)
Exemple #5
0
    def test_client_readonly(self):
        yield self.workflow.fire_transition("install")
        workflow_client = WorkflowStateClient(self.client, self.states["unit"])

        self.assertEqual((yield workflow_client.get_state()), "installed")
        yield self.assertFailure(workflow_client.set_state("started"),
                                 NotImplementedError)
        self.assertEqual((yield workflow_client.get_state()), "installed")
    def test_client_readonly(self):
        with (yield self.workflow.lock()):
            yield self.workflow.fire_transition("install")
        workflow_client = WorkflowStateClient(
            self.client, self.states["unit"])

        self.assertEqual(
            (yield workflow_client.get_state()), "started")
        with (yield workflow_client.lock()):
            yield self.assertFailure(
                workflow_client.set_state("stopped"), NotImplementedError)
        self.assertEqual(
            (yield workflow_client.get_state()), "started")
Exemple #7
0
    def test_client_read_state(self):
        """The relation workflow client can read the state of a unit
        relation."""
        yield self.workflow.fire_transition("start")
        yield self.assertState(self.workflow, "up")

        self.write_hook("%s-relation-changed" % self.relation_name,
                        "#!/bin/bash\necho hello\n")
        wait_on_hook = self.wait_on_hook("app-relation-changed")
        yield self.add_opposite_service_unit(self.states)
        yield wait_on_hook

        workflow = WorkflowStateClient(
            self.client, self.states["unit_relation"])
        self.assertEqual("up", (yield workflow.get_state()))
Exemple #8
0
    def test_client_read_state(self):
        """The relation workflow client can read the state of a unit
        relation."""
        yield self.workflow.fire_transition("start")
        yield self.assertState(self.workflow, "up")

        self.write_hook("%s-relation-changed" % self.relation_name,
                        "#!/bin/bash\necho hello\n")
        wait_on_hook = self.wait_on_hook("app-relation-changed")
        yield self.add_opposite_service_unit(self.states)
        yield wait_on_hook

        workflow = WorkflowStateClient(self.client,
                                       self.states["unit_relation"])
        self.assertEqual("up", (yield workflow.get_state()))
Exemple #9
0
    def _process_unit(self, service, unit, relations, rel_svc_map):
        """ Generate unit info for a single unit of a single service.

        `unit`: ServiceUnitState
        see `_process_units` for an explanation of other arguments.

        """
        u = self.unit_data[unit.unit_name] = dict()
        container = yield unit.get_container()

        if container:
            u["container"] = container.unit_name
            self.subordinates.setdefault(unit.service_name,
                                    set()).add(container.service_name)

        machine_id = yield unit.get_assigned_machine_id()
        u["machine"] = machine_id
        unit_workflow_client = WorkflowStateClient(self.client, unit)
        unit_state = yield unit_workflow_client.get_state()
        if not unit_state:
            u["agent-state"] = "pending"
        else:
            unit_connected = yield unit.has_agent()
            u["agent-state"] = unit_state.replace("_", "-") \
                               if unit_connected else "down"

        exposed = self.service_data[service.service_name].get("exposed")
        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
        self.seen_machines.add(machine_id)

        # collect info on each relation for the service unit
        yield self._process_unit_relations(service, unit,
                                           relations, rel_svc_map)
Exemple #10
0
    def _process_machine(self, machine_state):
        """
        `machine_state`: MachineState instance
        """
        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 self.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["agent-state"] = "running"
                else:
                    units = (
                        yield machine_state.get_all_service_unit_states())
                    for unit in units:
                        unit_workflow_client = WorkflowStateClient(
                            self.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["agent-state"] = "down"
                            break
                    else:
                        # otherwise we're probably just still waiting
                        m["agent-state"] = "not-started"
            except ProviderError:
                # The provider doesn't have machine information
                self.log.error(
                    "Machine provider information missing: machine %s" % (
                        machine_state.id))

        self.machine_data[machine_state.id] = m
Exemple #11
0
 def test_client_read_only(self):
     workflow_client = WorkflowStateClient(self.client,
                                           self.states["unit_relation"])
     yield self.assertFailure(workflow_client.set_state("up"),
                              NotImplementedError)
Exemple #12
0
 def test_client_read_none(self):
     workflow = WorkflowStateClient(
         self.client, self.states["unit_relation"])
     self.assertEqual(None, (yield workflow.get_state()))
Exemple #13
0
 def test_client_with_state(self):
     with (yield self.workflow.lock()):
         yield self.workflow.fire_transition("install")
     workflow_client = WorkflowStateClient(self.client, self.states["unit"])
     self.assertEqual(
         (yield workflow_client.get_state()), "started")
Exemple #14
0
 def test_client_with_no_state(self):
     workflow_client = WorkflowStateClient(self.client, self.states["unit"])
     state = yield workflow_client.get_state()
     self.assertEqual(state, None)
Exemple #15
0
 def test_client_read_none(self):
     workflow = WorkflowStateClient(self.client,
                                    self.states["unit_relation"])
     self.assertEqual(None, (yield workflow.get_state()))
Exemple #16
0
 def test_client_with_state(self):
     yield self.workflow.fire_transition("install")
     workflow_client = WorkflowStateClient(self.client, self.states["unit"])
     self.assertEqual((yield workflow_client.get_state()), "installed")
Exemple #17
0
 def test_client_with_no_state(self):
     workflow_client = WorkflowStateClient(self.client, self.states["unit"])
     state = yield workflow_client.get_state()
     self.assertEqual(state, None)
Exemple #18
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)
Exemple #19
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)