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, "")
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)
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))
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))
def setUp(self): yield super(CharmStateManagerTest, self).setUp() self.charm_state_manager = CharmStateManager(self.client) self.charm_id = local_charm_id(self.charm)
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 = {}
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)