koris.deploy package¶
Submodules¶
koris.deploy.k8s module¶
deploy cluster service to kubernetes via the API server
-
class
koris.deploy.k8s.
K8S
(config, manifest_path=None)[source]¶ Bases:
koris.deploy.k8s.K8SConfigurator
,koris.deploy.k8s.K8SScaler
Class allowing various interactions with a Kubernets cluster.
-
nginx_ingress_ports
¶ get the ingress-nginx service ports as dictionary
-
-
class
koris.deploy.k8s.
K8SConfigurator
[source]¶ Bases:
object
apply plugins and post install setup
-
add_all_masters_to_loadbalancer
(cluster_name, n_masters, lb_inst)[source]¶ Adds all master nodes to the LoadBalancer listener.
If the number of members in the master listener pool of the LoadBalancer is less than expected number of masters this function will add them to the pool as soon as they have node status “Ready”.
Parameters: - cluster_name (string) – the name of the cluster
- n_master (int) – Number of desired master nodes.
- lb_inst (
cloud.openstack.LoadBalancer
) – A configured LoadBalancer instance.
-
apply_addons
(koris_config, apply_func=<function create_from_yaml>)[source]¶ apply all addons to the cluster
Parameters: koris_config (dict) – koris configuration loaded as dict
-
ca_cert
¶ Returns the API servers CA.
Returns: The CA encoded as base64.
-
ca_info
¶ Return a dict with the read ca and the discovery hash
-
discovery_hash
¶ Calculate and return a discovery_hash.
Based on the cluster CA.
Returns: A discovery hash encoded in Hex.
-
etcd_cluster_status
()[source]¶ Checks the current etcd cluster state.
This function calls etcdctl inside a pod in order to obtain the current state of the etcd cluster before a new member can be added to it.
Right now, etcdctl offers no convenient way to format the output so the URLs from the masters can be extracted, which is why jq is used here.
Parameters: - podname (str) – The name of the pod where the etcdctl command should be sent from. Needs to be inside the kube-system namespace.
- master_ip (str) –
Returns: The status of the etcd as a string (e.g.master-1=192.168.1.102,master-2=192.168.1.103)
-
get_bootstrap_token
()[source]¶ Generate a Bootstrap token
Returns: A string of the form <token id>.<token secret>
.
-
get_random_master
()[source]¶ Returns a name and IP of a random master server in the cluster.
Returns: Tuple of name and IP of a master.
-
host
¶ Retrieve the host or loadbalancer info
-
is_ready
¶ Check if the API server is already available.
Returns: True if it’s reachable.
-
nginx_ingress_ports
¶ get the ingress-nginx service ports as dictionary
-
validate_context
(conn)[source]¶ Validate that server that we are talking to via K8S API is also the cloud context we are using.
This retrieves the project ID of the Kubernetes LoadBalancer, then checks if it finds the same ID in any LoadBalancer of the currently sourced OpenStack project.
In case the IP is not a Floating IP but only a Virtual IP, both IPs are simply compared.
Parameters: conn (obj) – OpenStack connection object. Returns: bool
-
-
class
koris.deploy.k8s.
K8SScaler
[source]¶ Bases:
object
A Mixin to modify the cluster size
-
delete_node
(nodename, grace_period=0, ignore_not_found=True)[source]¶ Delete a node in Kubernetes.
Parameters: - nodename (str) – The name of the node to delete.
- grace_period (int) – Duration in seconds before the node should be delete. Defaults to 0, which means immediately.
- ignore_not_found (bool) – If set to False, will raise a ValueError if node doesn’t exist.
Raises: :class:`kubernetes.client.rest.ApiException` in case the API call – fails.
-
drain_node
(nodename, ignore_not_found=True)[source]¶ Drains a node of pods.
We’re using
kubectl drain
instead of the eviction API, since it’s quicker and we don’t have to get all the Pods of the Node first.Will check if the node exists first.
Parameters: - nodename (str) – Name of the node to drain
- ignore_not_found (bool) – If set to False, will raise a ValueError if the node doesn’t exist.
Raises: RuntimeError if
kubectl drain
fails.
-
etcd_members
(podname, master_ip)[source]¶ Retrieves a dictionary with information about the etcd cluster.
This function uses
etcdctl member list
to retrieve information about the etcd cluster, then parses that response into a dictionary where the keys are the names of the members and the corresponding values hold the rest of the information such as ID, clientURLs and peerURLs.Returns: A dictionary with information about the etcd cluster. Raises: ValueError if master_ip is not valid.
-
node_status
(nodename)[source]¶ Returns the status of a Node.
Parameters: nodename (str) – The name of the node to check. Returns: - The status of the node as string or None if an error was
- encountered.
-
remove_from_etcd
(name, ignore_not_found=True)[source]¶ Removes a member from etcd.
The ‘master-adder’ operator will be used to perform the queries against etcd. The pod will be created if not found.
Parameters: - name (str) – The name of the member to remove.
- ignore_not_found (bool) – If set to False, will raise a ValueError if member is not part of etcd cluster.
-
-
class
koris.deploy.k8s.
KorisAddon
(name, manifest_path='/home/docs/checkouts/readthedocs.org/user_builds/koris/envs/latest/lib/python3.7/site-packages/koris/deploy/manifests')[source]¶ Bases:
object
Naive Addon class. Applies a kubernetes collection of resources from yml.
Parameters: - name (str) – the name of the plugin
- manifest_path (str) – the path where kubernetes resources are saved.
-
apply
(k8s_client, apply_func=<function create_from_yaml>)[source]¶ Apply a plugin to the cluster. Currently we use the Python client to apply a plugin. This might be limited, so we keep the possibilty to use a kubectl shell wrapper by making this an optional argument.
Parameters: - k8s_client – A Kubernet API client
- apply_func – A callable that can apply a plugin to the cluster
-
koris.deploy.k8s.
add_ingress_listeners
(nginx_ingress_ports, lbinst, lb_masters)[source]¶ Reconfigure the Openstack LoadBalancer - add an HTTP and HTTPS listener for nginx ingress controller
Parameters: - lbinst (
cloud.openstack.LoadBalancer
) – A configured LoadBalancer instance. - members (list) – list containining memebr information
- lbinst (
-
koris.deploy.k8s.
get_addons
(config)[source]¶ A prototype for loading addons. There are optional addons, and non-optional addons. Currently, non-optional addons include only the metrics-server.
Parameters: config (dict) – parse yaml with an optional section, list of addons
-
koris.deploy.k8s.
parse_etcd_response
(resp)[source]¶ Takes a response from etcdctl and parses it for its member info.
The response is to be expected in JSON format as obtained by
etcdctl member list -w json
. Right now, the IDs in the JSON response are in uint64 format and will be transformed into hex with this function.Parameters: resp (str) – A JSON response from etcdctl. Returns: A dict containing member information. Raises: ValueError if state could not be extracted.
koris.deploy.dex module¶
The dex module manages a dex (https://github.com/dexidp/dex) installation.
The workflow is the following:
- Create certificates for Dex (via
DexSSL
)
2. In koris.provision.cloud_init.FirstMasterInit
deploy the previously
created CA to the first Master that is created. Additionally, create the extra
arguments for the apiserver as environment variables in the koris.env
file.
3. In koris/provision/userdata/bootstraph-k8s-master-ubuntu-16.04.sh
, take the
variables from koris.env
and add their values as extra arguments to kubeadm’s
init.tmpl
.
4. Take the main LoadBalancer and add two new Listeners to it: one for the Dex service
(via create_dex()
) and one for an OAuth2 client app
(via create_oauth2()
) that will be requesting tokens from Dex.
Example
>>> dex_ssl = DexSSL("certs/", "dex.example.org")
>>> dex_ssl.save_certs()
>>> dex_conf = create_dex_conf(config['addons']['dex'], dex_ssl)
>>> master_tasks = master_builder.create_masters_tasks(..., dex=dex_conf)
>>> # Execute master_tasks
>>> dex_listener = dex_conf['ports']['listener']
>>> dex_service = dex_conf['ports']['service']
>>> dex_members = master_ips
>>> dex_task = loop.create_task(create_dex(NEUTRON, lbinst,
... listener_port=dex_listener,
... pool_port=dex_service,
... members=dex_members))
>>> client_listener = dex_conf['client']['ports']['listener']
>>> client_service = dex_conf['client']['ports']['service']
>>> client_members = node_ips
>>> oauth_task = loop.create_task(create_oauth2(NEUTRON, lbinst,
... listener_port=client_listener,
... pool_port=client_service,
... members=client_members))
>>> tasks = [dex_task, oauth_task]
>>> loop.run_until_complete(asyncio.gather(*tasks))
-
class
koris.deploy.dex.
DexSSL
(cert_dir: str, issuer: str, k8s_ca_path='/etc/ssl/certs/oidc-ca.pem')[source]¶ Bases:
object
Class managing the dex TLS infrastrucutre.
Dex uses a self-signed CA to sign tokens it receives from a OIDC Provider such as Gitlab, GitHub or LDAP. A 3rd Party (such as the Kubernetes apiserver) will then verify the signed token with Dex’s public key. A client certificate, that is signed by the Dex CA, is used to request a token from Dex.
On instantiation, will create the Dex CA and client cert bundles.
Example
>>> dex_ssl = DexSSL("./certs", "dex.example.com") >>> dex_ssl.save_certs()
Parameters: - cert_dir (str) – The directory where the keys and certificates will be saved to.
- issuer (str) – The issuer of the Dex CA. This needs to be an IP or DNS where Dex is reachable from a host and from inside the kube-apiserver.
- k8s_ca_path (str) – This is the location on the Master node(s) where the Dex CA will saved under. Needs to be a full path including file name. This will then be passed as an argument to the kube-apiserver so it can use the certificate’s public key to verify an incoming token.
-
ca_bundle
¶ An SSL Certificate Bundle containing the Dex CA certificate and key pair.
Type: koris.ssl.CertBundle
-
client_bundle
¶ An SSL Certificate Bundle containing the client certificate and key pair.
Type: koris.ssl.CertBundle
-
create_certs
()[source]¶ Create a CA and client cert for Dex.
Will first create a CA bundle, then use this to sign a client certificate. The Client cert will have the following Key Usage parameters: Digital Signature, Content Commitment, Key Encipherment.
Will also set the attributes
ca_bundle
andclient_bundle
.Returns: Tuple consisting of root CA bundle and cert bundle
-
save_certs
(client_prefix='dex-client', ca_prefix='dex-ca')[source]¶ Saves certificate bundles to disc.
This function uses
koris.ssl.CertBundle.save()
to save the certificate bundles to disc.Parameters: - client_prefix (str) – The prefix for the client certificate.
- ca_prefix (str) – The prefix for the Dex CA.
-
class
koris.deploy.dex.
Listener
(lb: koris.cloud.openstack.LoadBalancer, name, port, pool: koris.deploy.dex.Pool, protocol='HTTPS')[source]¶ Bases:
object
A Listener containing a LoadBalancer and Pool.
In future, this should be of the OpenStack scope instead of Dex’s.
When a Listener class gets instantiated, its parameters will be checked for validity. The same is true when functions get executed. Additionally, an instantiated class does not mean the pool is created with OpenStack. Use the
create
function for that.A Pool (see above) is attached to a Listener. This Listener listens on a specific port and forwards traffic to the Pool, on a specific port. A Listener is attached to a LoadBalancer which will forward traffic to a specific Listener, depending on the port.
Example
>>> # Create a Pool with Members >>> members = ["10.0.0.1", 10.0.0.2"] >>> pool = Pool("test-pool", "HTTPS", 32443, "ROUND_ROBIN", members) >>> listener = Listener(LB, "test-listener", 443, pool) >>> # This will create the Pool, add it to the Listener and add it all to a LB >>> listener.all(NEUTRON)
Parameters: - lb (LoadBalancer) – An OpenStack LoadBalancer Object.
- name (str) – The name of the Listener.
- port (int) – The port which will be listened on.
- protocol (str) – The protocol that should be used for listening. Must be part of
allowed_protocols
. - pool (Pool) – A Pool object.
-
allowed_algirthms
¶ A list of strings for the LoadBalancer algorithms that can be used.
Type: list
-
allowed_protocols
¶ A list of string for the LoadBalancer protocols that can be used.
Type: list
-
loadbalancer
¶ An OpenStack LoadBalancer Object
Type: LoadBalancer
-
id
¶ The Listener ID. Will be assigned after
create
gets called.Type: int
-
listener
¶ A LoadBalancer dictionary as received from the OpenStack API. Will be assigned after
create
gets called.Type: dict
-
all
()[source]¶ Convenience function to create a Listener, then Pool.
Will call
create
andcreate_pool
.
-
create
()[source]¶ Creates a new Listener and adds it to the LoadBalancer.
This function will assing the attributes
listener
andid
.
-
class
koris.deploy.dex.
Pool
(name, protocol, port, algorithm, members)[source]¶ Bases:
object
A Pool with Members, Algorithm and Port
In future, this should be of the OpenStack scope instead of Dex’s.
When a Pool class gets instantiated, its parameters will be checked for validity. The same is true when functions get executed. Additionally, an instantiated class does not mean the pool is created with OpenStack. Use the
create
function for that.Members are loadbalanced IP Adresses or DNS Names that belong to a Pool. This Pool is then attached to a Listener.
Example
>>> # Create a Pool with Members >>> members = ["10.0.0.1", 10.0.0.2"] >>> pool = Pool("test-pool", "HTTPS", 32443, "ROUND_ROBIN", members) >>> # Assuming we have a created Listener >>> pool.all(NEUTRON, LB, listener.id)
Parameters: - name (str) – The name of the Pool.
- protocol (str) – The protocol for the Pool. Must be part of
allowed_protocols
. - port (int) – The port for the members.
- algorithm (str) – The loadbalancing algorithm. Must be part of
allowed_algorithms
. - members (list) – A list of members that the Pool contains.
-
allowed_algirthms
¶ A list of strings for the LoadBalancer algorithms that can be used.
Type: list
-
allowed_protocols
¶ A list of string for the LoadBalancer protocols that can be used.
Type: list
-
id
¶ The pool ID. Will be assigned after
create
gets called.Type: int
-
pool
¶ A LoadBalancer dictionary as received from the OpenStack API. Will be assigned after
create
gets called.Type: dict
-
add_health_monitor
(lb: koris.cloud.openstack.LoadBalancer)[source]¶ Adds a Health monitor to a Pool with default settings
Parameters: lb (LoadBalancer) – An OSLoadBalancer instance.
-
add_members
(lb: koris.cloud.openstack.LoadBalancer)[source]¶ Adds Members to a Pool.
Parameters: lb (LoadBalancer) – An OSLoadBalancer instance.
-
all
(lb: koris.cloud.openstack.LoadBalancer, listener_id)[source]¶ Convenience function to create a Pool with Members and Health Monitor.
Will call
create
,add_members
andadd_health_monitor
.Parameters: - lb (LoadBalancer) – An OSLoadBalancer instance.
- listener_id (str) – The Listener ID this pool should be added to.
-
create
(lb: koris.cloud.openstack.LoadBalancer, listener_id)[source]¶ Creates a Pool and adds it to a Listener.
This function will set the attributes
pool
andid
.Parameters: - lb (LoadBalancer) – An OSLoadBalancer instance.
- listener_id (str) – The Listener ID this pool should be added to.
-
exception
koris.deploy.dex.
ValidationError
[source]¶ Bases:
Exception
A custom error if dex is configured inproperly
-
koris.deploy.dex.
create_dex
(lb: koris.cloud.openstack.LoadBalancer, name='dex', listener_port=32000, pool_port=32000, protocol='HTTPS', algo='ROUND_ROBIN', members=None)[source]¶ Convenience function to create a Dex Listener and Pool.
This will take an existing LoadBalancer in OpenStack and adds a new Listener with Pool and members to it, so Dex can be reached inside the cluster.
Will first create a
Pool
, then aListener
from that pool.Parameters: - lb (LoadBalancer) – The used LoadBalancer.
- name (str) – The name of the Dex Listener and Pool.
- listener_port (int) – The port the Listener should listen on.
- pool_port (int) – The exposed port of the Dex service inside the cluster.
- protcol (str) – The protocol to use. Should be HTTPS.
- algo (str) – The loadbalancing algorithm to use.
- members (list) – A list of members to add to the pool. Should be the Masters.
-
koris.deploy.dex.
create_dex_conf
(config, dex_ssl: koris.deploy.dex.DexSSL)[source]¶ Parse the koris config for dex parameters.
The user needs to validate first if dex is wished to be installed. The following config arguments are optional username_claim (default: email), groups_claim (default: group)
Parameters: - config (dict) – The config[‘addons’][‘dex’] part of the config dict.
- dex_ssl (DexSSL) – a DexSSL instance.
Raises: ValidationError if mandatory parts are missing or incorrect information – has been provided.
Returns: A dictionary with the correct config parameters set.
-
koris.deploy.dex.
create_oauth2
(lb: koris.cloud.openstack.LoadBalancer, name='oauth2', listener_port=5556, pool_port=32555, protocol='HTTP', algo='ROUND_ROBIN', members=None)[source]¶ Convenience function to create an OAuth2 Client App Listener and Pool.
Users need to deploy an OAuth2 Client App that talks with Dex to retrieve a token. This function takes an existing LoadBalancer in OpenStack and adds a new Listener with Pool and Members to it. This way, clients and Dex can reach the OAuth2 Client App.
Parameters: - lb (LoadBalancer) – The used LoadBalancer.
- name (str) – The name of the OAuth2 Listener and Pool.
- listener_port (int) – The port the Listener should listen on.
- pool_port (int) – The exposed port of the OAuth2 service inside the cluster.
- protcol (str) – The protocol to use. Should be HTTPS.
- algo (str) – The loadbalancing algorithm to use.
- members (list) – A list of members to add to the pool. Should be the Nodes.