def test_when_set_for_labelling(owner): obj = {} kopf.label(obj) assert obj['metadata']['labels'] == { 'label-1': 'value-1', 'label-2': 'value-2' }
def test_adding_to_pykube_object(pykube_object): del pykube_object.obj['metadata'] kopf.label(pykube_object, {'label-1': 'value-1', 'label-2': 'value-2'}) assert len(pykube_object.labels) == 2 assert 'label-1' in pykube_object.labels assert 'label-2' in pykube_object.labels assert pykube_object.labels['label-1'] == 'value-1' assert pykube_object.labels['label-2'] == 'value-2'
def test_adding_to_kubernetes_model(kubernetes_model): kubernetes_model.metadata = None kopf.label(kubernetes_model, {'label-1': 'value-1', 'label-2': 'value-2'}) assert len(kubernetes_model.metadata.labels) == 2 assert 'label-1' in kubernetes_model.metadata.labels assert 'label-2' in kubernetes_model.metadata.labels assert kubernetes_model.metadata.labels['label-1'] == 'value-1' assert kubernetes_model.metadata.labels['label-2'] == 'value-2'
def test_nested_with_forced_true_to_kubernetes_model(nested, kubernetes_model): kubernetes_model.metadata.labels = {'label': 'old-value'} kopf.label(kubernetes_model, {'label': 'new-value'}, nested=nested, forced=True) assert kubernetes_model.metadata.labels['label'] == 'new-value' assert kubernetes_model.spec.job_template.metadata.labels[ 'label'] == 'new-value' assert not hasattr(kubernetes_model.spec, 'unexistent')
def test_nested_with_forced_false_to_pykube_object(nested, pykube_object): pykube_object.labels.update({'label': 'old-value'}) pykube_object.obj.update({'spec': {'jobTemplate': {}}}) kopf.label(pykube_object, {'label': 'new-value'}, nested=nested, forced=False) assert pykube_object.labels['label'] == 'old-value' assert pykube_object.obj['spec']['jobTemplate']['metadata']['labels'][ 'label'] == 'new-value' assert 'unexistent' not in pykube_object.obj['spec']
def test_adding_to_dict(): obj = {} kopf.label(obj, {'label-1': 'value-1', 'label-2': 'value-2'}) assert 'metadata' in obj assert 'labels' in obj['metadata'] assert isinstance(obj['metadata']['labels'], dict) assert len(obj['metadata']['labels']) == 2 assert 'label-1' in obj['metadata']['labels'] assert 'label-2' in obj['metadata']['labels'] assert obj['metadata']['labels']['label-1'] == 'value-1' assert obj['metadata']['labels']['label-2'] == 'value-2'
def test_nested_with_forced_false_to_dict(nested): obj = { 'metadata': { 'labels': { 'label': 'old-value' } }, 'spec': { 'jobTemplate': {} } } kopf.label(obj, {'label': 'new-value'}, nested=nested, forced=False) assert obj['metadata']['labels']['label'] == 'old-value' assert obj['spec']['jobTemplate']['metadata']['labels'][ 'label'] == 'new-value' assert 'unexistent' not in obj['spec']
def test_nested_with_forced_false(): obj = { 'metadata': { 'labels': { 'label': 'old-value' } }, 'spec': { 'template': {} } } kopf.label(obj, {'label': 'new-value'}, nested=['spec.template'], force=False) assert obj['metadata']['labels']['label'] == 'old-value' assert obj['spec']['template']['metadata']['labels'][ 'label'] == 'new-value'
def test_adding_to_dicts(multicls): obj1 = {} obj2 = {} objs = multicls([obj1, obj2]) kopf.label(objs, {'label-1': 'value-1', 'label-2': 'value-2'}) assert isinstance(obj1['metadata']['labels'], dict) assert len(obj1['metadata']['labels']) == 2 assert 'label-1' in obj1['metadata']['labels'] assert 'label-2' in obj1['metadata']['labels'] assert obj1['metadata']['labels']['label-1'] == 'value-1' assert obj1['metadata']['labels']['label-2'] == 'value-2' assert isinstance(obj2['metadata']['labels'], dict) assert len(obj2['metadata']['labels']) == 2 assert 'label-1' in obj2['metadata']['labels'] assert 'label-2' in obj2['metadata']['labels'] assert obj2['metadata']['labels']['label-1'] == 'value-1' assert obj2['metadata']['labels']['label-2'] == 'value-2'
async def _run_pod(action, pod_name, body, namespace): # Label the pod for filtering in the on.event handler. kopf.label(body, {ACTION_ANNOTATION: action}) event = asyncio.Event() obj = None async with kubernetes_asyncio.client.ApiClient() as api: v1 = kubernetes_asyncio.client.CoreV1Api(api) obj = await v1.create_namespaced_pod( body=body, namespace=namespace, ) EVENTS[action][obj.metadata.uid] = event # TODO: handle timeout and error log.debug('waiting for pod_event: %s', pod_name) await event.wait() log.debug('pod_event has been set: %s', pod_name) return obj
def create_pod(body, **kwargs): # Render the pod yaml with some spec fields used in the template. pod_data = yaml.safe_load(f""" apiVersion: v1 kind: Pod spec: containers: - name: the-only-one image: busybox command: ["sh", "-x", "-c", "sleep 1"] """) # Make it our child: assign the namespace, name, labels, owner references, etc. kopf.adopt(pod_data, owner=body) kopf.label(pod_data, {'application': 'kopf-example-10'}) # Actually create an object by requesting the Kubernetes API. pod = pykube.Pod(api, pod_data) pod.create()
def create_cron_job(api: client.BatchV1beta1Api, configmap: Resource, cro_spec: ResourceChunk, ns: str, name_suffix: str, cro_meta: ResourceChunk, pod_tpl: str): logger = logging.getLogger('kopf.objects') schedule_spec = cro_spec.get("schedule", {}) schedule = schedule_spec.get("value") tpl = yaml.safe_load(configmap.data['chaostoolkit-cronjob.yaml']) set_ns(tpl, ns) set_cron_job_name(tpl, name_suffix=name_suffix) set_cron_job_schedule(tpl, schedule) set_cron_job_template_spec(tpl, pod_tpl.get("spec", {})) experiment_labels = cro_meta.get('labels', {}) kopf.label(tpl, labels=experiment_labels) kopf.label(tpl["spec"]["jobTemplate"], labels=experiment_labels) kopf.label(tpl["spec"]["jobTemplate"]["spec"]["template"], labels=experiment_labels) logger.debug(f"Creating cron job with template:\n{tpl}") cron = api.create_namespaced_cron_job(body=tpl, namespace=ns) logger.info(f"Cron Job '{cron.metadata.self_link}' scheduled with " f"pattern '{schedule}' in ns '{ns}'") return tpl
def test_forcing_default_to_pykube_object(pykube_object): pykube_object.labels['label'] = 'old-value' kopf.label(pykube_object, {'label': 'new-value'}) assert pykube_object.labels['label'] == 'old-value'
def test_forcing_false_to_pykube_object(pykube_object): pykube_object.labels['label'] = 'old-value' kopf.label(pykube_object, {'label': 'new-value'}, forced=False) assert pykube_object.labels['label'] == 'old-value'
def test_forcing_false_to_dict(): obj = {'metadata': {'labels': {'label': 'old-value'}}} kopf.label(obj, {'label': 'new-value'}, forced=False) assert obj['metadata']['labels']['label'] == 'old-value'
def test_forcing_true(): obj = {'metadata': {'labels': {'label': 'old-value'}}} kopf.label(obj, {'label': 'new-value'}, force=True) assert obj['metadata']['labels']['label'] == 'new-value'
def test_in_labelling(): with pytest.raises(TypeError) as e: kopf.label(object(), {}) assert "K8s object class is not supported" in str(e.value)
def test_forcing_false_warns_on_deprecated_option(): obj = {'metadata': {'labels': {'label': 'old-value'}}} with pytest.deprecated_call(match=r"use forced="): kopf.label(obj, {'label': 'new-value'}, force=False) assert obj['metadata']['labels']['label'] == 'old-value'
def test_forcing_false_to_kubernetes_model(kubernetes_model): kubernetes_model.metadata.labels = {'label': 'old-value'} kopf.label(kubernetes_model, {'label': 'new-value'}, forced=False) assert kubernetes_model.metadata.labels['label'] == 'old-value'
def test_forcing_default_to_dict(): obj = {'metadata': {'labels': {'label': 'old-value'}}} kopf.label(obj, {'label': 'new-value'}) assert obj['metadata']['labels']['label'] == 'old-value'
def test_forcing_default_to_kubernetes_model(kubernetes_model): kubernetes_model.metadata.labels = {'label': 'old-value'} kopf.label(kubernetes_model, {'label': 'new-value'}) assert kubernetes_model.metadata.labels['label'] == 'old-value'
def test_when_unset_for_labelling(): with pytest.raises(LookupError) as e: kopf.label([]) assert 'Owner must be set explicitly' in str(e.value)
def create_pod( api: client.CoreV1Api, configmap: Resource, # noqa: C901 cro_spec: ResourceChunk, ns: str, name_suffix: str, cro_meta: ResourceChunk, *, apply: bool = True): logger = logging.getLogger('kopf.objects') pod_spec = cro_spec.get("pod", {}) sa_name = cro_spec.get("serviceaccount", {}).get("name") # did the user supply their own pod spec? tpl = pod_spec.get("template") # if not, let's use the default one if not tpl: tpl = yaml.safe_load(configmap.data['chaostoolkit-pod.yaml']) image_name = pod_spec.get("image") env_cm_name = pod_spec.get("env", {}).get("configMapName", "chaostoolkit-env") env_cm_enabled = pod_spec.get("env", {}).get("enabled", True) # optional support for loading secret keys as env. variables env_secret_name = pod_spec.get("env", {}).get("secretName") settings_secret_enabled = pod_spec.get("settings", {}).get("enabled", False) settings_secret_name = pod_spec.get("settings", {}).get("secretName", "chaostoolkit-settings") experiment_as_file = pod_spec.get("experiment", {}).get("asFile", True) experiment_config_map_name = pod_spec.get("experiment", {}).get( "configMapName", "chaostoolkit-experiment") experiment_config_map_file_name = pod_spec.get("experiment", {}).get( "configMapExperimentFileName", "experiment.json") cmd_args = pod_spec.get("chaosArgs", []) # if image name is not given in CRO, # we keep the one defined by default in pod template from configmap if image_name: set_image_name(tpl, image_name) if not env_cm_enabled: logger.info("Removing default env configmap volume") remove_env_config_map(tpl) elif env_cm_name: logger.info(f"Env config map named '{env_cm_name}'") set_env_config_map_name(tpl, env_cm_name) if env_secret_name and env_cm_enabled: logger.info(f"Adding secret '{env_secret_name}' " f"as environment variables") add_env_secret(tpl, env_secret_name) if not settings_secret_enabled: logger.info("Removing default settings secret volume") remove_settings_secret(tpl) elif settings_secret_name: logger.info( f"Settings secret volume named '{settings_secret_name}'") set_settings_secret_name(tpl, settings_secret_name) if experiment_as_file: logger.info("Experiment config map named " f"'{experiment_config_map_name}'") set_experiment_config_map_name(tpl, experiment_config_map_name, experiment_config_map_file_name) else: logger.info("Removing default experiment config map volume") remove_experiment_volume(tpl) remove_env_path_config_map(tpl) set_chaos_cmd_args(tpl, ["run", "$(EXPERIMENT_URL)"]) if cmd_args: # filter out empty values from command line arguments: None, '' cmd_args = list(filter(None, cmd_args)) logger.info(f"Override default chaos command arguments: " f"$ chaos {' '.join([str(arg) for arg in cmd_args])}") set_chaos_cmd_args(tpl, cmd_args) set_ns(tpl, ns) set_pod_name(tpl, name_suffix=name_suffix) set_sa_name(tpl, name=sa_name, name_suffix=name_suffix) kopf.label(tpl, labels=cro_meta.get('labels', {})) if apply: logger.debug(f"Creating pod with template:\n{tpl}") pod = api.create_namespaced_pod(body=tpl, namespace=ns) logger.info(f"Pod {pod.metadata.self_link} created in ns '{ns}'") return tpl