incubator-airflow/airflow/kubernetes/secret.py

138 строки
5.1 KiB
Python

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""
Classes for interacting with Kubernetes API
"""
import copy
import uuid
from typing import Tuple
from kubernetes.client import models as k8s
from airflow.exceptions import AirflowConfigException
from airflow.kubernetes.k8s_model import K8SModel
class Secret(K8SModel):
"""Defines Kubernetes Secret Volume"""
def __init__(self, deploy_type, deploy_target, secret, key=None):
"""
Initialize a Kubernetes Secret Object. Used to track requested secrets from
the user.
:param deploy_type: The type of secret deploy in Kubernetes, either `env` or
`volume`
:type deploy_type: str
:param deploy_target: (Optional) The environment variable when
`deploy_type` `env` or file path when `deploy_type` `volume` where
expose secret. If `key` is not provided deploy target should be None.
:type deploy_target: str or None
:param secret: Name of the secrets object in Kubernetes
:type secret: str
:param key: (Optional) Key of the secret within the Kubernetes Secret
if not provided in `deploy_type` `env` it will mount all secrets in object
:type key: str or None
"""
if deploy_type not in ('env', 'volume'):
raise AirflowConfigException("deploy_type must be env or volume")
self.deploy_type = deploy_type
self.deploy_target = deploy_target
if deploy_target is not None and deploy_type == 'env':
# if deploying to env, capitalize the deploy target
self.deploy_target = deploy_target.upper()
if key is not None and deploy_target is None:
raise AirflowConfigException(
'If `key` is set, `deploy_target` should not be None'
)
self.secret = secret
self.key = key
def to_env_secret(self) -> k8s.V1EnvVar:
"""Stores es environment secret"""
return k8s.V1EnvVar(
name=self.deploy_target,
value_from=k8s.V1EnvVarSource(
secret_key_ref=k8s.V1SecretKeySelector(
name=self.secret,
key=self.key
)
)
)
def to_env_from_secret(self) -> k8s.V1EnvFromSource:
"""Reads from environment to secret"""
return k8s.V1EnvFromSource(
secret_ref=k8s.V1SecretEnvSource(name=self.secret)
)
def to_volume_secret(self) -> Tuple[k8s.V1Volume, k8s.V1VolumeMount]:
"""Converts to volume secret"""
vol_id = 'secretvol{}'.format(uuid.uuid4())
return (
k8s.V1Volume(
name=vol_id,
secret=k8s.V1SecretVolumeSource(
secret_name=self.secret
)
),
k8s.V1VolumeMount(
mount_path=self.deploy_target,
name=vol_id,
read_only=True
)
)
def attach_to_pod(self, pod: k8s.V1Pod) -> k8s.V1Pod:
"""Attaches to pod"""
cp_pod = copy.deepcopy(pod)
if self.deploy_type == 'volume':
volume, volume_mount = self.to_volume_secret()
cp_pod.spec.volumes = pod.spec.volumes or []
cp_pod.spec.volumes.append(volume)
cp_pod.spec.containers[0].volume_mounts = pod.spec.containers[0].volume_mounts or []
cp_pod.spec.containers[0].volume_mounts.append(volume_mount)
if self.deploy_type == 'env' and self.key is not None:
env = self.to_env_secret()
cp_pod.spec.containers[0].env = cp_pod.spec.containers[0].env or []
cp_pod.spec.containers[0].env.append(env)
if self.deploy_type == 'env' and self.key is None:
env_from = self.to_env_from_secret()
cp_pod.spec.containers[0].env_from = cp_pod.spec.containers[0].env_from or []
cp_pod.spec.containers[0].env_from.append(env_from)
return cp_pod
def __eq__(self, other):
return (
self.deploy_type == other.deploy_type and
self.deploy_target == other.deploy_target and
self.secret == other.secret and
self.key == other.key
)
def __repr__(self):
return 'Secret({}, {}, {}, {})'.format(
self.deploy_type,
self.deploy_target,
self.secret,
self.key
)