Exemplo n.º 1
0
def test_pod_scheduled(init_openshift_deployer, pod_not_deployed):
    od = init_openshift_deployer
    flexmock(od).should_receive("get_pod").and_raise(
        ApiException(status=404, )).and_return(
            V1Pod(status=V1PodStatus(phase="Running"))).and_return(
                V1Pod(status=V1PodStatus(phase="Succeeded")))
    flexmock(od.api).should_receive("create_namespaced_pod").and_raise(
        ApiException(status="403")).and_return(1)
    od.deploy_pod(["false"])
Exemplo n.º 2
0
def _mock_v1_pod(jobId, userName, vcName, nodeName):
    pod = V1Pod()
    pod.metadata = V1ObjectMeta()
    pod.metadata.labels = {
        "jobId": jobId,
        "type": "job",
        "userName": userName,
        "vcName": vcName
    }
    pod.spec = V1PodSpec(containers=[])
    pod.spec.node_name = nodeName
    return pod
Exemplo n.º 3
0
    def test_list_resources(self, mock_pod_list, mock_pod_delete):
        plugin = K8sPodProtectablePlugin(self._context, cfg.CONF)

        pod = V1Pod(api_version="v1",
                    kind="Pod",
                    metadata=V1ObjectMeta(
                        name="busybox-test",
                        namespace="default",
                        uid="dd8236e1-8c6c-11e7-9b7a-fa163e18e097"),
                    status=V1PodStatus(phase="Running"))
        pod_list = V1PodList(items=[pod])
        mock_pod_list.return_value = pod_list
        self.assertEqual([
            Resource('OS::Kubernetes::Pod',
                     uuid.uuid5(uuid.NAMESPACE_OID, "default:busybox-test"),
                     'default:busybox-test')
        ], plugin.list_resources(self._context))
Exemplo n.º 4
0
    def test_show_resource(self, mock_pod_get):
        plugin = K8sPodProtectablePlugin(self._context, cfg.CONF)

        pod = V1Pod(api_version="v1",
                    kind="Pod",
                    metadata=V1ObjectMeta(
                        name="busybox-test",
                        namespace="default",
                        uid="dd8236e1-8c6c-11e7-9b7a-fa163e18e097"),
                    status=V1PodStatus(phase="Running"))
        mock_pod_get.return_value = pod
        self.assertEqual(
            Resource('OS::Kubernetes::Pod',
                     uuid.uuid5(uuid.NAMESPACE_OID, "default:busybox-test"),
                     'default:busybox-test'),
            plugin.show_resource(
                self._context,
                uuid.uuid5(uuid.NAMESPACE_OID, "default:busybox-test"),
                {'name': 'default:busybox-test'}))
    def test_create_backup(self, mock_k8s_create):
        resource = Resource(id="c88b92a8-e8b4-504c-bad4-343d92061871",
                            type=constants.POD_RESOURCE_TYPE,
                            name='default:busybox-test')

        fake_bank_section.update_object = mock.MagicMock()

        protect_operation = self.plugin.get_protect_operation(resource)
        mock_k8s_create.return_value = self.k8s_client

        self.k8s_client.read_namespaced_pod = mock.MagicMock()
        self.k8s_client.read_namespaced_pod.return_value = V1Pod(
            api_version="v1",
            kind="Pod",
            metadata=V1ObjectMeta(name="busybox-test",
                                  namespace="default",
                                  uid="dd8236e1-8c6c-11e7-9b7a-fa163e18e097"),
            spec=V1PodSpec(volumes=[], containers=[]),
            status=V1PodStatus(phase="Running"))
        fake_bank_section.update_object = mock.MagicMock()
        call_hooks(protect_operation, self.checkpoint, resource, self.cntxt,
                   {})
Exemplo n.º 6
0
def mock_k8s_pod(config):
    if not isinstance(config, MockK8sPodConfig):
        raise TypeError("Wrong config type")

    pod = V1Pod()

    pod.metadata = V1ObjectMeta(name=config.name,
                                labels=config.labels,
                                namespace=config.namespace)

    containers = []
    for i, requests in enumerate(config.container_requests):
        r = V1ResourceRequirements(requests=requests)
        c = V1Container(name=config.name + str(i), resources=r)
        containers.append(c)

    pod.spec = V1PodSpec(node_name=config.node_name,
                         containers=containers,
                         node_selector=config.node_selector)

    pod.status = V1PodStatus(phase=config.phase)

    return pod
    def test_get_pod_dependent_resources(self, mock_pod_read, mock_pvc_read,
                                         mock_pv_read, mock_volume_list):
        plugin = VolumeProtectablePlugin(self._context)

        pod = V1Pod(api_version="v1",
                    kind="Pod",
                    metadata=V1ObjectMeta(
                        name="busybox-test",
                        namespace="default",
                        uid="dd8236e1-8c6c-11e7-9b7a-fa163e18e097"),
                    spec=V1PodSpec(volumes=[
                        V1Volume(persistent_volume_claim=(
                            V1PersistentVolumeClaimVolumeSource(
                                claim_name="cinder-claim1'")))
                    ]),
                    status=V1PodStatus(phase="Running"))

        pvc = V1PersistentVolumeClaim(
            api_version="v1",
            kind="PersistentVolumeClaim",
            metadata=V1ObjectMeta(name="cinder-claim1",
                                  namespace="default",
                                  uid="fec036b7-9123-11e7-a930-fa163e18e097"),
            spec=V1PersistentVolumeClaimSpec(
                access_modes=["ReadWriteOnce"],
                volume_name="pvc-fec036b7-9123-11e7-a930-fa163e18e097"),
            status=V1PersistentVolumeClaimStatus(phase="Bound"))

        pv = V1PersistentVolume(
            api_version="v1",
            kind="PersistentVolume",
            metadata=V1ObjectMeta(
                name="pvc-fec036b7-9123-11e7-a930-fa163e18e097",
                namespace="None",
                uid="ff43c217-9123-11e7-a930-fa163e18e097"),
            spec=V1PersistentVolumeSpec(cinder=V1CinderVolumeSource(
                fs_type=None,
                read_only=None,
                volume_id="7daedb1d-fc99-4a35-ab1b-b64971271d17")),
            status=V1PersistentVolumeClaimStatus(phase="Bound"))

        volumes = [
            mock.Mock(name='Volume',
                      id='7daedb1d-fc99-4a35-ab1b-b64971271d17',
                      availability_zone='az1'),
            mock.Mock(name='Volume',
                      id='7daedb1d-fc99-4a35-ab1b-b64922441d17',
                      availability_zone='az1'),
        ]
        setattr(volumes[0], 'name', 'name123')
        setattr(volumes[1], 'name', 'name456')

        mock_pod_read.return_value = pod
        mock_pvc_read.return_value = pvc
        mock_pv_read.return_value = pv
        mock_volume_list.return_value = volumes
        self.assertEqual([
            Resource('OS::Cinder::Volume',
                     '7daedb1d-fc99-4a35-ab1b-b64971271d17', 'name123',
                     {'availability_zone': 'az1'})
        ],
                         plugin.get_dependent_resources(
                             self._context,
                             Resource(
                                 id="c88b92a8-e8b4-504c-bad4-343d92061871",
                                 name="default:busybox-test",
                                 type="OS::Kubernetes::Pod")))
Exemplo n.º 8
0
def make_pod(
    name,
    image_spec,
    image_pull_policy,
    image_pull_secret,
    port,
    cmd,
    node_selector,
    run_as_uid,
    fs_gid,
    env,
    working_dir,
    volumes,
    volume_mounts,
    labels,
    cpu_limit,
    cpu_guarantee,
    mem_limit,
    mem_guarantee,
    nvidia_gpu_limit,
    lifecycle_hooks,
    init_containers,
):
    """
    Make a k8s pod specification for running a user notebook.

    Parameters:
      - name:
        Name of pod. Must be unique within the namespace the object is
        going to be created in. Must be a valid DNS label.
      - image_spec:
        Image specification - usually a image name and tag in the form
        of image_name:tag. Same thing you would use with docker commandline
        arguments
      - image_pull_policy:
        Image pull policy - one of 'Always', 'IfNotPresent' or 'Never'. Decides
        when kubernetes will check for a newer version of image and pull it when
        running a pod.
      - image_pull_secret:
        Image pull secret - Default is None -- set to your secret name to pull
        from private docker registry.
      - port:
        Port the notebook server is going to be listening on
      - cmd:
        The command used to execute the singleuser server.
      - node_selector:
        Dictionary Selector to match nodes where to launch the Pods
      - run_as_uid:
        The UID used to run single-user pods. The default is to run as the user
        specified in the Dockerfile, if this is set to None.
      - fs_gid
        The gid that will own any fresh volumes mounted into this pod, if using
        volume types that support this (such as GCE). This should be a group that
        the uid the process is running as should be a member of, so that it can
        read / write to the volumes mounted.
      - env:
        Dictionary of environment variables.
      - volumes:
        List of dictionaries containing the volumes of various types this pod
        will be using. See k8s documentation about volumes on how to specify
        these
      - volume_mounts:
        List of dictionaries mapping paths in the container and the volume(
        specified in volumes) that should be mounted on them. See the k8s
        documentaiton for more details
      - working_dir:
        String specifying the working directory for the notebook container
      - labels:
        Labels to add to the spawned pod.
      - cpu_limit:
        Float specifying the max number of CPU cores the user's pod is
        allowed to use.
      - cpu_guarentee:
        Float specifying the max number of CPU cores the user's pod is
        guaranteed to have access to, by the scheduler.
      - mem_limit:
        String specifying the max amount of RAM the user's pod is allowed
        to use. String instead of float/int since common suffixes are allowed
      - mem_guarantee:
        String specifying the max amount of RAM the user's pod is guaranteed
        to have access to. String ins loat/int since common suffixes
        are allowed
      - nvidia_gpu_limit:
        Number of Nvidia GPUs to be allocated to user's pod.
      - lifecycle_hooks:
        Dictionary of lifecycle hooks
      - init_containers:
        List of initialization containers belonging to the pod.
    """

    pod = V1Pod()
    pod.kind = "Pod"
    pod.api_version = "v1"

    pod.metadata = V1ObjectMeta()
    pod.metadata.name = name
    pod.metadata.labels = labels.copy()

    pod.spec = V1PodSpec()

    security_context = V1PodSecurityContext()
    if fs_gid is not None:
        security_context.fs_group = int(fs_gid)
    if run_as_uid is not None:
        security_context.run_as_user = int(run_as_uid)
    pod.spec.security_context = security_context

    if image_pull_secret is not None:
        pod.spec.image_pull_secrets = []
        image_secret = V1LocalObjectReference()
        image_secret.name = image_pull_secret
        pod.spec.image_pull_secrets.append(image_secret)

    if node_selector:
        pod.spec.node_selector = node_selector

    pod.spec.containers = []
    notebook_container = V1Container()
    notebook_container.name = "notebook"
    notebook_container.image = image_spec
    notebook_container.working_dir = working_dir
    notebook_container.ports = []
    port_ = V1ContainerPort()
    port_.name = "notebook-port"
    port_.container_port = port
    notebook_container.ports.append(port_)
    notebook_container.env = [V1EnvVar(k, v) for k, v in env.items()]
    notebook_container.args = cmd
    notebook_container.image_pull_policy = image_pull_policy
    notebook_container.lifecycle = lifecycle_hooks
    notebook_container.resources = V1ResourceRequirements()

    notebook_container.resources.requests = {}

    if cpu_guarantee:
        notebook_container.resources.requests['cpu'] = float(cpu_guarantee)
    if mem_guarantee:
        notebook_container.resources.requests['memory'] = mem_guarantee

    notebook_container.resources.limits = {}
    if cpu_limit:
        notebook_container.resources.limits['cpu'] = float(cpu_limit)
    if mem_limit:
        notebook_container.resources.limits['memory'] = mem_limit
    if nvidia_gpu_limit:
        notebook_container.resources.limits[
            'alpha.kubernetes.io/nvidia-gpu'] = nvidia_gpu_limit
    notebook_container.volume_mounts = volume_mounts
    pod.spec.containers.append(notebook_container)

    pod.spec.init_containers = init_containers
    pod.spec.volumes = volumes
    return pod
Exemplo n.º 9
0
def make_pod(name,
             cmd,
             port,
             image_spec,
             image_pull_policy,
             image_pull_secret=None,
             node_selector=None,
             run_as_uid=None,
             fs_gid=None,
             run_privileged=False,
             env={},
             working_dir=None,
             volumes=[],
             volume_mounts=[],
             labels={},
             cpu_limit=None,
             cpu_guarantee=None,
             mem_limit=None,
             mem_guarantee=None,
             lifecycle_hooks=None,
             init_containers=None,
             service_account=None,
             extra_container_config=None,
             extra_pod_config=None,
             extra_containers=None):
    """
    Make a k8s pod specification for running a user notebook.

    Parameters:
      - name:
        Name of pod. Must be unique within the namespace the object is
        going to be created in. Must be a valid DNS label.
      - image_spec:
        Image specification - usually a image name and tag in the form
        of image_name:tag. Same thing you would use with docker commandline
        arguments
      - image_pull_policy:
        Image pull policy - one of 'Always', 'IfNotPresent' or 'Never'. Decides
        when kubernetes will check for a newer version of image and pull it when
        running a pod.
      - image_pull_secret:
        Image pull secret - Default is None -- set to your secret name to pull
        from private docker registry.
      - port:
        Port the notebook server is going to be listening on
      - cmd:
        The command used to execute the singleuser server.
      - node_selector:
        Dictionary Selector to match nodes where to launch the Pods
      - run_as_uid:
        The UID used to run single-user pods. The default is to run as the user
        specified in the Dockerfile, if this is set to None.
      - fs_gid
        The gid that will own any fresh volumes mounted into this pod, if using
        volume types that support this (such as GCE). This should be a group that
        the uid the process is running as should be a member of, so that it can
        read / write to the volumes mounted.
      - run_privileged:
        Whether the container should be run in privileged mode.
      - env:
        Dictionary of environment variables.
      - volumes:
        List of dictionaries containing the volumes of various types this pod
        will be using. See k8s documentation about volumes on how to specify
        these
      - volume_mounts:
        List of dictionaries mapping paths in the container and the volume(
        specified in volumes) that should be mounted on them. See the k8s
        documentaiton for more details
      - working_dir:
        String specifying the working directory for the notebook container
      - labels:
        Labels to add to the spawned pod.
      - cpu_limit:
        Float specifying the max number of CPU cores the user's pod is
        allowed to use.
      - cpu_guarentee:
        Float specifying the max number of CPU cores the user's pod is
        guaranteed to have access to, by the scheduler.
      - mem_limit:
        String specifying the max amount of RAM the user's pod is allowed
        to use. String instead of float/int since common suffixes are allowed
      - mem_guarantee:
        String specifying the max amount of RAM the user's pod is guaranteed
        to have access to. String ins loat/int since common suffixes
        are allowed
      - lifecycle_hooks:
        Dictionary of lifecycle hooks
      - init_containers:
        List of initialization containers belonging to the pod.
      - service_account:
        Service account to mount on the pod. None disables mounting
      - extra_container_config:
        Extra configuration (e.g. envFrom) for notebook container which is not covered by parameters above.
      - extra_pod_config:
        Extra configuration (e.g. tolerations) for pod which is not covered by parameters above.
      - extra_containers:
        Extra containers besides notebook container. Used for some housekeeping jobs (e.g. crontab).
    """

    pod = V1Pod()
    pod.kind = "Pod"
    pod.api_version = "v1"

    pod.metadata = V1ObjectMeta()
    pod.metadata.name = name
    pod.metadata.labels = labels.copy()

    pod.spec = V1PodSpec()

    security_context = V1PodSecurityContext()
    if fs_gid is not None:
        security_context.fs_group = int(fs_gid)
    if run_as_uid is not None:
        security_context.run_as_user = int(run_as_uid)
    pod.spec.security_context = security_context

    if image_pull_secret is not None:
        pod.spec.image_pull_secrets = []
        image_secret = V1LocalObjectReference()
        image_secret.name = image_pull_secret
        pod.spec.image_pull_secrets.append(image_secret)

    if node_selector:
        pod.spec.node_selector = node_selector

    pod.spec.containers = []
    notebook_container = V1Container()
    notebook_container.name = "notebook"
    notebook_container.image = image_spec
    notebook_container.working_dir = working_dir
    notebook_container.ports = []
    port_ = V1ContainerPort()
    port_.name = "notebook-port"
    port_.container_port = port
    notebook_container.ports.append(port_)
    notebook_container.env = [V1EnvVar(k, v) for k, v in env.items()]
    notebook_container.args = cmd
    notebook_container.image_pull_policy = image_pull_policy
    notebook_container.lifecycle = lifecycle_hooks
    notebook_container.resources = V1ResourceRequirements()

    if service_account is None:
        # Add a hack to ensure that no service accounts are mounted in spawned pods
        # This makes sure that we don"t accidentally give access to the whole
        # kubernetes API to the users in the spawned pods.
        # Note: We don't simply use `automountServiceAccountToken` here since we wanna be compatible
        # with older kubernetes versions too for now.
        hack_volume = V1Volume()
        hack_volume.name = "no-api-access-please"
        hack_volume.empty_dir = {}
        hack_volumes = [hack_volume]

        hack_volume_mount = V1VolumeMount()
        hack_volume_mount.name = "no-api-access-please"
        hack_volume_mount.mount_path = "/var/run/secrets/kubernetes.io/serviceaccount"
        hack_volume_mount.read_only = True
        hack_volume_mounts = [hack_volume_mount]
    else:
        hack_volumes = []
        hack_volume_mounts = []

        pod.service_account_name = service_account

    if run_privileged:
        container_security_context = V1SecurityContext()
        container_security_context.privileged = True
        notebook_container.security_context = container_security_context

    notebook_container.resources.requests = {}

    if cpu_guarantee:
        notebook_container.resources.requests['cpu'] = cpu_guarantee
    if mem_guarantee:
        notebook_container.resources.requests['memory'] = mem_guarantee

    notebook_container.resources.limits = {}
    if cpu_limit:
        notebook_container.resources.limits['cpu'] = cpu_limit
    if mem_limit:
        notebook_container.resources.limits['memory'] = mem_limit
    notebook_container.volume_mounts = volume_mounts + hack_volume_mounts
    pod.spec.containers.append(notebook_container)

    if extra_container_config:
        for key, value in extra_container_config.items():
            setattr(notebook_container,
                    _map_attribute(notebook_container.attribute_map, key),
                    value)
    if extra_pod_config:
        for key, value in extra_pod_config.items():
            setattr(pod.spec, _map_attribute(pod.spec.attribute_map, key),
                    value)
    if extra_containers:
        pod.spec.containers.extend(extra_containers)

    pod.spec.init_containers = init_containers
    pod.spec.volumes = volumes + hack_volumes
    return pod