def get_status(self, context, resource, for_update=False, create_if_absent=True): """Get status of an AIM resource, if any. Values of identity attributes of parameter 'resource' are used to determine the object to get status for; other attributes may be left unspecified. """ with context.store.begin(subtransactions=True): if isinstance(resource, api_res.AciResourceBase): res_type, res_id = self._get_status_params(context, resource) if res_type and res_id is not None: status = self.get(context, api_status.AciStatus( resource_type=res_type, resource_id=res_id, resource_root=resource.root), for_update=for_update) if not status: if not create_if_absent: return # Create one with default values # NOTE(ivar): Sometimes we need the status of an object # even if AID wasn't able to calculate it yet # (eg. storing faults). In this case the status object # will be created with N/A sync_status. return self.update_status( context, resource, api_status.AciStatus( resource_type=res_type, resource_id=res_id, resource_root=resource.root)) status.faults = self.find(context, api_status.AciFault, status_id=status.id) return status return None
def test_leaked_status(self): # Create parentless status object status = aim_status.AciStatus(resource_type='Tenant', resource_id='none', resource_root='tn-1', resource_dn='uni/tn-1') # During creation, the builder will try to delete the parentless status # however, that has not been committed yet to the deletion has no # effect. giving the status another builder round will make sure it is # actually deleted! Note that this only happens for transactional # backends, and it's actually OK since we don't expect Status objects # to be created parentless in a first place. self.mgr.create(self.ctx, status) self.db_l.on_commit(self.ctx.store, [status], [], []) self.db_l.catch_up_with_action_log(self.ctx.store) # status doesn't exist anymore self.assertIsNone(self.mgr.get(self.ctx, status))
def test_process_pod_status_event(self): watcher = k8s_watcher.K8sWatcher() store = self.ctx.store ns = resource.VmmInjectedNamespace(domain_type='Kubernetes', domain_name='kubernetes', controller_name='kube-cluster', name='ns-%s' % self.test_id) pod = resource.VmmInjectedContGroup(domain_type=ns.domain_type, domain_name=ns.domain_name, controller_name=ns.controller_name, namespace_name=ns.name, name='pod1') pod_ht_key = watcher.tt_builder.tt_maker._build_hash_tree_key(pod) self.mgr.create(self.ctx, ns) pod_db_obj = store.make_db_obj(pod) store.add(pod_db_obj) pod_db_obj = store.query(api_v1.Pod, resource.VmmInjectedContGroup, namespace_name=ns.name, name=pod.name)[0] pod.name = 'hidden-pod1' hidden_pod_ht_key = ( watcher.tt_builder.tt_maker._build_hash_tree_key(pod)) hidden_pod_db_obj = store.make_db_obj(pod) hidden_pod_db_obj['spec']['hostNetwork'] = True store.add(hidden_pod_db_obj) hidden_pod_db_obj = store.query(api_v1.Pod, resource.VmmInjectedContGroup, namespace_name=ns.name, name=pod.name)[0] # test pod that is not hidden stat = status.AciStatus(resource_type='VmmInjectedContGroup', resource_id=pod_db_obj.aim_id, resource_root=pod.root) for t in ['ADDED', 'MODIFIED', 'DELETED']: ev = {'event_type': t, 'resource': stat} exp_ev = copy.copy(ev) watcher._process_pod_status_event(ev) self.assertEqual(exp_ev, ev) # seed the hash-tree with the non-hidden pod ev = {'type': 'ADDED', 'object': pod_db_obj} watcher._process_event(ev) cfg_tree = watcher.trees['config'][pod.root] self.assertIsNotNone(cfg_tree.find(pod_ht_key)) # test pod that is hidden stat.resource_id = hidden_pod_db_obj.aim_id for t in ['ADDED', 'MODIFIED', 'DELETED']: ev = {'event_type': t, 'resource': stat} exp_ev = copy.copy(ev) exp_ev['event_type'] = 'DELETED' watcher._process_pod_status_event(ev) self.assertEqual(exp_ev, ev) ev2 = {'type': t, 'object': store.make_db_obj(stat)} watcher._process_event(ev2) self.assertIsNone(cfg_tree.find(hidden_pod_ht_key))