Welcome to Krake’s documentation!¶
Quickstart¶
A simple introduction to Krake can be found on the README on the official GitLab repository. You can find there all the requirements and the different steps for the installation, as well as some basic commands and initiatory explanations.
User Documentation¶
Rok documentation¶
The Rok utility has a command line interface with a few specific commands, that can be added one after the other to refer to specific elements. The general syntax is
rok <api> <resource> <operation> <parameters>
The separate elements are:
api
element:- The name of the Krake API used. Different APIs are present to handle different kind of resources. Example:
kube
for the Kubernetes API of Krake. resource
element:- The name of the resource managed. Each API holds one or several resources it can handle. Example:
cluster
for the Krake Clusters, which correspond to Kubernetes clusters. operation
element:- The verb used for the operation to apply. For instance
list
can be used to get all instances of one kind of resource, whiledelete
can be used to remove a resource. parameters
element:- The specific argument for the current operation. For instance, the
-o | --output
argument change the format of the response.
A few examples:
$ rok kube <...> # handle the kubernetes API resources
$ rok kube app <...> # handle the Application resources of the Kubernetes API
# Register a cluster with the Kubernetes API using the minikube.yaml kubeconfig
$ rok kube cluster register --kubeconfig ../minikube.yaml
# Create a cluster with the Kubernetes API using the tosca.yaml manifest
$ rok kube cluster create --file ../tosca.yaml test-cluster
The kube
API¶
This API can be used to manage Kubernetes clusters and start, update and delete applications on them, through Krake.
Base command: rok kube <...>
The Cluster resource: cluster
¶
This resource manages Krake Cluster resources, which needs to be registered or created on Krake to be used. It corresponds to a cluster on Kubernetes.
Base command: rok kube cluster <...>
- register
Add an existing cluster to the Kubernetes clusters registered in Krake on a specified namespace. Example:
rok kube cluster register -k <path_to_kubeconfig_file>
-k | --kubeconfig
: the path to the kubeconfig file that refers to the cluster to register.-n | --namespace
(optional):- The namespace to which the Cluster has to be added. If none is given, the user namespace is selected.
-c | --context
(optional):- The name of the context to use from the kubeconfig file. Only one context can be chosen at a time. If not context is specified, the current context of the kubeconfig file is chosen.
--global-metric
(optional):- The name and weight of of a global cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -m | --metric
(optional):- The name and weight of a cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of a cluster label in the form:
<key>=<value>
. Can be specified multiple times. -R | --custom-resource
(optional):- The name of custom resources definition in the form:
<plural>.<group>
which is supported by the cluster. Can be specified multiple times.
- create
Add a new cluster to the Kubernetes clusters registered in Krake on a specified namespace. Example:
rok kube cluster create <cluster_name> -f <path_to_tosca_template>
name
:- The name of the new Cluster, as stored by Krake (can be arbitrary). The same name cannot be used twice in the same namespace.
-f | --file
:- The path to the TOSCA template file that describes the desired Cluster.
-n | --namespace
(optional):- The namespace to which the Cluster has to be added. If none is given, the user namespace is selected.
--global-metric
(optional):- The name and weight of a global cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -m | --metric
(optional):- The name and weight of a cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of a cluster label in the form:
<key>=<value>
. Can be specified multiple times. -R | --custom-resource
(optional):- The name of custom resources definition in the form:
<plural>.<group>
which is supported by the cluster. Can be specified multiple times. -L | --cloud-label-constraint
(optional):- The name and value of a constraint for labels of the cloud in the form:
<label> expression <value>
. The cluster will be deployed only on the cloud that matches the given label constraint. Can be specified multiple times, see Constraints. -M | --cloud-metric-constraint
(optional):- The name and value of a constraint for metrics of the cloud in the form:
<label> expression <value>
. The cluster will be deployed only on the cloud that matches the given metric constraint. Can be specified multiple times, see Constraints. --backoff
(optional): multiplier applied to backoff_delay between attempts.- default: 1 (no backoff)
backoff_delay
(optional): delay [s] between attempts. default: 1backoff_limit
(optional): a maximal number of attempts. If the attempt to handle the cluster failed, it will transfer to the Cluster State DEGRADED, instead of directly going into the State OFFLINE. Default: -1 (infinite) default: -1 (infinite)- list
List all Cluster of a namespace.
-n | --namespace
(optional):- The namespace from which the Clusters have to be listed. If none is given, the user namespace is selected.
- get
Request information about a specific Cluster.
name
:- The name of the Cluster to fetch.
-n | --namespace
(optional):- The namespace from which the Clusters have to be retrieved. If none is given, the user namespace is selected.
- update
Request a change of the current state of an existing Cluster.
name
:- The name of the Cluster to update.
-k | --kubeconfig
(optional):- The path to the kubeconfig file that describes the Cluster with the updated fields.
-f | --file
(optional):- The path to the TOSCA template file that describes the desired Cluster with the updated fields.
-n | --namespace
(optional):- The namespace from which the Clusters have to be taken. If none is given, the user namespace is selected.
-c | --context
(optional):- The name of the context to use from the kubeconfig file. Only one context can be chosen at a time. If not context is specified, the current context of the kubeconfig file is chosen.
--global-metric
(optional):- The name and weight of a global cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -m | --metric
(optional):- The name and weight of a cluster metric in the form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of a cluster label in the form:
<key>=<value>
. Can be specified multiple times. -R | --custom-resource
(optional):- The name of custom resources definition in the form:
<plural>.<group>
which is supported by the cluster. Can be specified multiple times. -L | --cloud-label-constraint
(optional):- The name and value of a constraint for labels of the cloud in the form:
<label> expression <value>
. The cluster will be deployed only on the cloud that matches the given label constraint. Can be specified multiple times, see Constraints. -M | --cloud-metric-constraint
(optional):- The name and value of a constraint for metrics of the cloud in the form:
<label> expression <value>
. The cluster will be deployed only on the cloud that matches the given metric constraint. Can be specified multiple times, see Constraints. --backoff
(optional): multiplier applied to backoff_delay between attempts.- default: 1 (no backoff)
backoff_delay
(optional): delay [s] between attempts. default: 1backoff_limit
(optional): a maximal number of attempts, default: -1 (infinite)- delete
Request the deletion of a specific Cluster from a namespace.
-n | --namespace
(optional):- The namespace from which the Cluster have to be deleted. If none is given, the user namespace is selected.
--force
(optional):- Force the deletion of resources directly from the Krake Database.
The Application resource: app
¶
This resource manages Krake Applications resources, which need to be registered on Krake to be managed. It corresponds to a Kubernetes resource.
Tip
Krake is able to manage applications that are described by Kubernetes manifests files as well as by TOSCA templates or CSAR archives, see TOSCA.
Base command: rok kube app <...>
- create
Add a new Application to the ones registered on Krake on a specified namespace. Example:
rok kube app create <application_name> -f <path_to_manifest_or_path_to_tosca_template>
name
:- The name of the new Application, as stored by Krake (can be arbitrary). The same name cannot be used twice in the same namespace.
-f | --file
:- The path to the manifest file or the TOSCA template file that describes the new Application.
-u | --url
:- The URL of the TOSCA template file or the CSAR archive that describes the new Application.
-O | --observer_schema
(optional):- The path to the custom observer schema file, specifying the fields of the Kubernetes resources defined in the manifest file which should be observed. If none is given, all fields defined in the manifest file are observed. The custom observer schema could be used even when the application is described by the TOSCA template or CSAR archive.
-n | --namespace
(optional):- The namespace to which the Application has to be added. If none is given, the user namespace is selected.
--hook-complete
(optional):- The complete hook, which allows an Application to send a completion signal to the API.
--hook-shutdown
(optional):- The shutdown hook, which allows the graceful shutdown of the Application. Can have an additional timeout value after the argument.
-R | --cluster-resource-constraint
(optional):- The name of custom resources definition constraint in form:
<plural>.<group>
. The application will be deployed only on the clusters with given custom definition support. Can be specified multiple times. -L | --cluster-label-constraint
(optional):- The name and value of a constraint for labels of the cluster in the form:
<label> expression <value>
. The application will be deployed only on the cluster that matches the given label constraint. Can be specified multiple times, see Constraints. -M | --cluster-metric-constraint
(optional):- The name and value of a constraint for metrics of the cluster in the form:
<label> expression <value>
. The application will be deployed only on the cluster that matches the given metric constraint. Can be specified multiple times, see Constraints. --backoff
(optional): multiplier applied to backoff_delay between attempts to handle the application.- default: 1 (no backoff)
backoff_delay
(optional): delay [s] between attempts to handle the application. default: 1backoff_limit
(optional): a maximal number of attempts to handle the application. If the attempt to handle the application failed, it will transfer to the Application State DEGRADED, instead of directly going into the State FAILED. Default: -1 (infinite)- list
List all Applications of a namespace.
-n | --namespace
(optional):- The namespace from which the Applications have to be listed. If none is given, the user namespace is selected.
- get
Request information about a specific Application.
name
:- The name of the Application to fetch.
-n | --namespace
(optional):- The namespace from which the Applications have to be retrieved. If none is given, the user namespace is selected.
- update
Request a change of the current state of an existing Application.
name
:- The name of the Application to update.
-f | --file
:- The path to the manifest file or TOSCA template file that describes the Application with the updated fields.
-u | --url
:- The URL of the TOSCA template file or the CSAR archive that describes the Application with the updated fields.
-O | --observer_schema
(optional):- The path to the custom observer schema file, specifying the fields of the Kubernetes resources defined in the manifest file which should be observed. If none is given, the observer schema is not udpated. The custom observer schema could be used even when the application is described by the TOSCA template or CSAR archive.
-n | --namespace
(optional):- The namespace from which the Applications have to be taken. If none is given, the user namespace is selected.
--hook-complete
(optional):- The complete hook, which allows an Application to send a completion signal to the API.
--hook-shutdown
(optional):- The shutdown hook, which allows the graceful shutdown of the Application. Can have an additional timeout value after the argument.
-R | --cluster-resource-constraint
(optional):- The name of custom resources definition constraint in form:
<plural>.<group>
. The application will be deployed only on the clusters with given custom definition support. Can be specified multiple times. -L | --cluster-label-constraint
(optional):- The name and value of a constraint for labels of the cluster in the form:
<label> expression <value>
. The application will be deployed only on the cluster that matches the given label constraint. Can be specified multiple times, see Constraints. -M | --cluster-metric-constraint
(optional):- The name and value of a constraint for metrics of the cluster in the form:
<label> expression <value>
. The application will be deployed only on the cluster that matches the given metric constraint. Can be specified multiple times, see Constraints. --backoff
(optional): multiplier applied to backoff_delay between attempts.- default: 1 (no backoff)
backoff_delay
(optional): delay [s] between attempts. default: 1backoff_limit
(optional): a maximal number of attempts, default: -1 (infinite)- delete
Request the deletion of a specific Application from a namespace.
name
:- The name of the Application to delete.
-n | --namespace
(optional):- The namespace from which the Application have to be deleted. If none is given, the user namespace is selected.
--force
(optional):- Force the deletion an Application directly from the Krake Database.
The infra
API¶
This API can be used to manage the following infrastructure resources:
- GlobalInfrastructureProvider
- InfrastructureProvider
- GlobalCloud
- Cloud
Base command: rok infra <...>
The GlobalInfrastructureProvider resource: globalinfrastructureprovider
¶
This resource manages Krake GlobalInfrastructureProvider non-namespaced resources, which needs to be registered on Krake to be used. It corresponds to an infrastructure provider software, that is able to deploy infrastructures (e.g. Virtual machines, Kubernetes clusters, etc.) on IaaS Cloud deployments (e.g. OpenStack, AWS, etc.).
Krake currently supports the following GlobalInfrastructureProvider software (types):
- IM (Infrastructure Manager) tool developed by the GRyCAP research group
Base command: rok infra globalinfrastructureprovider <...>
Available aliases:
- rok infra gprovider <...>
- rok infra gip <...>
Note
The global resource is a non-namespaced resource that could be used by any (even namespaced) Krake resource. For example, the global infrastructure provider resource could be used by any cloud which needs to be managed by the infrastructure provider.
- register
Add a new GlobalInfrastructureProvider to the ones registered on Krake. Example:
rok infra gprovider register <provider_name> \ --type <provider_type> \ --url <provider_api_url> \ --username <provider_api_username> \ --password <provider_api_password>
name
:- The name of the new GlobalInfrastructureProvider, as stored by Krake (can be arbitrary). The same name cannot be used twice.
--type
:- The GlobalInfrastructureProvider type. Type of the infrastructure provider that will be registered on Krake. Currently, only IM infrastructure provider is supported, and valid type is: im.
--url
:- The GlobalInfrastructureProvider API url. Valid together with –type im.
--username
(optional):- The GlobalInfrastructureProvider API username. Valid together with –type im.
--password
(optional):- The GlobalInfrastructureProvider API password. Valid together with –type im.
--token
(optional):- The GlobalInfrastructureProvider API token. Valid together with –type im.
- list
- List all GlobalInfrastructureProviders.
- get
Request information about a specific GlobalInfrastructureProvider.
name
:- The name of the GlobalInfrastructureProvider to fetch.
- update
Request a change of the current state of an existing GlobalInfrastructureProvider.
name
:- The name of the GlobalInfrastructureProvider to update.
--url
(optional):- The GlobalInfrastructureProvider API url to update. Valid together with –type im.
--username
(optional):- The GlobalInfrastructureProvider API username to update. Valid together with –type im.
--password
(optional):- The GlobalInfrastructureProvider API password to update. Valid together with –type im.
--token
(optional):- The GlobalInfrastructureProvider API token to update. Valid together with –type im.
- delete
Request the deletion of a specific GlobalInfrastructureProvider.
name
:- The name of the GlobalInfrastructureProvider to delete.
The InfrastructureProvider resource: infrastructureprovider
¶
This resource manages Krake InfrastructureProvider namespaced resources, which needs to be registered on Krake to be used. It corresponds to an infrastructure provider software, that is able to deploy infrastructures (e.g. Virtual machines, Kubernetes clusters) on IaaS Cloud deployments.
Krake currently supports the following InfrastructureProvider software (types):
- IM (Infrastructure Manager) tool developed by the GRyCAP research group
Base command: rok infra infrastructureprovider <...>
Available aliases:
rok infra provider <...>
rok infra ip <...>
Note
This resource is a namespaced resource that could be used by the Krake resources from the same namespace. For example, the infrastructure provider resource could be used by any cloud which lives in the same namespace as the infrastructure provider.
- register
Add a new InfrastructureProvider to the ones registered on Krake. Example:
rok infra provider register <provider_name> \ --type <provider_type> \ --url <provider_api_url> \ --username <provider_api_username> \ --password <provider_api_password>
name
:- The name of the new InfrastructureProvider, as stored by Krake (can be arbitrary). The same name cannot be used twice in the same namespace.
-n | --namespace
(optional):- The namespace to which the InfrastructureProvider have to be added. If none is given, the user namespace is selected.
--type
:- The InfrastructureProvider type. Type of the infrastructure provider that will be registered on Krake. Currently, only IM infrastructure provider is supported, and valid type is: im.
--url
:- The InfrastructureProvider API url. Valid together with –type im.
--username
(optional):- The InfrastructureProvider API username. Valid together with –type im.
--password
(optional):- The InfrastructureProvider API password. Valid together with –type im.
--token
(optional):- The InfrastructureProvider API token. Valid together with –type im.
- list
List all InfrastructureProviders of a namespace.
-n | --namespace
(optional):- The namespace from which the InfrastructureProvider have to be listed. If none is given, the user namespace is selected.
- get
Request information about a specific InfrastructureProvider.
name
:- The name of the InfrastructureProvider to fetch.
-n | --namespace
(optional):- The namespace from which the InfrastructureProvider have to be retrieved. If none is given, the user namespace is selected.
- update
Request a change of the current state of an existing InfrastructureProvider.
name
:- The name of the InfrastructureProvider to update.
-n | --namespace
(optional):- The namespace from which the InfrastructureProvider have to be taken. If none is given, the user namespace is selected.
--url
(optional):- The InfrastructureProvider API url to update. Valid together with –type im.
--username
(optional):- The InfrastructureProvider API username to update. Valid together with –type im.
--password
(optional):- The InfrastructureProvider API password to update. Valid together with –type im.
--token
(optional):- The InfrastructureProvider API token to update. Valid together with –type im.
- delete
Request the deletion of a specific InfrastructureProvider from a namespace.
name
:- The name of the InfrastructureProvider to delete.
-n | --namespace
(optional):- The namespace from which the InfrastructureProvider have to be deleted. If none is given, the user namespace is selected.
The GlobalCloud resource: globalcloud
¶
This resource manages Krake GlobalCloud non-namespaced resources, which needs to be registered on Krake to be used. It corresponds to an IaaS Cloud deployments (e.g. OpenStack, AWS, etc.) that will be managed by the infrastructure provider software. GlobalCloud resource could contain also metrics and labels, that could be used in cluster scheduling.
Krake currently supports the following GlobalCloud cloud software (types):
Base command: rok infra globalcloud <...>
Available aliases:
rok infra gcloud <...>
rok infra gc <...>
Note
The global resource is a non-namespaced resource that could be used by any (even namespaced) Krake resource. For example, the global cloud resource could be used by any cluster which needs to be scheduled to some cloud.
- register
Add a new GlobalCloud to the ones registered on Krake. Example:
rok infra gcloud register <cloud_name> \ --type <cloud_type> \ --url <cloud_identity_service_url> \ --username <cloud_username> \ --password <cloud_password> \ --project <cloud_project_name> \ --global-infra-provider <global_infra_provider_name>
name
:- The name of the new GlobalCloud, as stored by Krake (can be arbitrary). The same name cannot be used twice.
--type
:- The GlobalCloud type. Type of the cloud that will be registered on Krake. Currently, only OpenStack cloud software is supported, and valid type is: openstack.
--url
:- URL to OpenStack identity service (Keystone). Valid together with –type openstack.
--username
:- Username or UUID of OpenStack user. Valid together with –type openstack.
--password
:- Password of OpenStack user. Valid together with –type openstack.
--project
:- Name or UUID of the OpenStack project. Valid together with –type openstack.
--global-infra-provider
:- Global infrastructure provider name for cloud management. Valid together with –type openstack.
--domain-name
(optional):- Domain name of the OpenStack user. Valid together with –type openstack.
--domain-id
(optional):- Domain ID of the OpenStack project. Valid together with –type openstack.
--global-metric
(optional):- The name and weight of a global cloud metric in form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of cloud label in form:
<key>=<value>
. Can be specified multiple times.
- list
- List all GlobalClouds.
- get
Request information about a specific GlobalCloud.
name
:- The name of the GlobalCloud to fetch.
- update
Request a change of the current state of an existing GlobalCloud.
name
:- The name of the GlobalCloud to update.
--url
(optional):- URL to OpenStack identity service (Keystone) to update. Valid together with –type openstack.
--username
(optional):- Username or UUID of OpenStack user to update. Valid together with –type openstack.
--password
(optional):- Password of OpenStack user to update. Valid together with –type openstack.
--project
(optional):- Name or UUID of the OpenStack project to update. Valid together with –type openstack.
--global-infra-provider
(optional):- Global infrastructure provider name for cloud management to update. Valid together with –type openstack.
--domain-name
(optional):- Domain name of the OpenStack user to update. Valid together with –type openstack.
--domain-id
(optional):- Domain ID of the OpenStack project to update. Valid together with –type openstack.
--global-metric
(optional):- The name and weight of cloud global metric in form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of cloud label in form:
<key>=<value>
. Can be specified multiple times.
- delete
Request the deletion of a specific GlobalCloud.
name
:- The name of the GlobalCloud to delete.
The Cloud resource: cloud
¶
This resource manages Krake Cloud namespaced resources, which needs to be registered on Krake to be used. It corresponds to an IaaS Cloud deployments (e.g. OpenStack, AWS, etc.) that will be managed by the infrastructure provider software. Cloud resource could contain also metrics and labels, that could be used in cluster scheduling.
Krake currently supports the following GlobalCloud cloud software (types):
Base command: rok infra cloud <...>
Note
This resource is a namespaced resource that could be used by the Krake resources from the same namespace. For example, the cloud resource could be used by any cluster which lives in the same namespace as the cloud.
- register
Add a new Cloud to the ones registered on Krake. Example:
rok infra cloud register <cloud_name> \ --type <cloud_type> \ --url <cloud_identity_service_url> \ --username <cloud_username> \ --password <cloud_password> \ --project <cloud_project_name> \ --infra-provider <infra_provider_name>
name
:- The name of the new Cloud, as stored by Krake (can be arbitrary). The same name cannot be used twice in the same namespace.
-n | --namespace
(optional):- The namespace to which the Cloud have to be added. If none is given, the user namespace is selected.
--type
:- The Cloud type. Type of the cloud that will be registered on Krake. Currently, only OpenStack cloud software is supported, and valid type is: openstack.
--url
:- URL to OpenStack identity service (Keystone). Valid together with –type openstack.
--username
:- Username or UUID of OpenStack user. Valid together with –type openstack.
--password
:- Password of OpenStack user. Valid together with –type openstack.
--project
:- Name or UUID of the OpenStack project. Valid together with –type openstack.
--infra-provider
(optional):- Infrastructure provider name for cloud management. Valid together with –type openstack.
--global-infra-provider
(optional):- Global infrastructure provider name for cloud management to update. Valid together with –type openstack.
--domain-name
(optional):- Domain name of the OpenStack user. Valid together with –type openstack.
--domain-id
(optional):- Domain ID of the OpenStack project. Valid together with –type openstack.
--global-metric
(optional):- The name and weight of cloud global metric in form:
<name> <weight>
. Can be specified multiple times. -m | --metric
(optional):- The name and weight of cloud metric in form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of cloud label in form:
<key>=<value>
. Can be specified multiple times.
- list
List all Clouds of a namespace.
-n | --namespace
(optional):- The namespace from which the Cloud have to be listed. If none is given, the user namespace is selected.
- get
Request information about a specific Cloud.
name
:- The name of the Cloud to fetch.
-n | --namespace
(optional):- The namespace from which the Cloud have to be retrieved. If none is given, the user namespace is selected.
- update
Request a change of the current state of an existing Cloud.
name
:- The name of the Cloud to update.
-n | --namespace
(optional):- The namespace from which the Cloud have to be taken. If none is given, the user namespace is selected.
--url
(optional):- URL to OpenStack identity service (Keystone) to update. Valid together with –type openstack.
--username
(optional):- Username or UUID of OpenStack user to update. Valid together with –type openstack.
--password
(optional):- Password of OpenStack user to update. Valid together with –type openstack.
--project
(optional):- Name or UUID of the OpenStack project to update. Valid together with –type openstack.
--infra-provider
(optional):- Infrastructure provider name for cloud management to update. Valid together with –type openstack.
--global-infra-provider
(optional):- Global infrastructure provider name for cloud management to update. Valid together with –type openstack.
--domain-name
(optional):- Domain name of the OpenStack user to update. Valid together with –type openstack.
--domain-id
(optional):- Domain ID of the OpenStack project to update. Valid together with –type openstack.
--global-metric
(optional):- The name and weight of cloud global metric in form:
<name> <weight>
. Can be specified multiple times. -m | --metric
(optional):- The name and weight of cloud metric in form:
<name> <weight>
. Can be specified multiple times. -l | --label
(optional):- The key and the value of cloud label in form:
<key>=<value>
. Can be specified multiple times.
- delete
Request the deletion of a specific Cloud from a namespace.
name
:- The name of the Cloud to delete.
-n | --namespace
(optional):- The namespace from which the Cloud have to be deleted. If none is given, the user namespace is selected.
Common options¶
These options are common to all commands:
-o | --output <format>
(optional):- The format of the displayed response. Three are available: YAML:
yaml
, JSON:json
or table:table
.
Warnings¶
Warning messages are issued in situations where it is useful to alert the user of some
condition in a Krake, which may exhibit errors or unexpected behavior.
Warnings standard library is used, hence the warning messages could be filtered
by PYTHONWARNINGS
environment variable.
An example to disable all warnings:
$ PYTHONWARNINGS=ignore rok kube app create <...>
Configuration¶
This sections describes the configuration of Krake components and Rok. The different parameters, their value and role will be described here
Note
If an example value is specified for a parameter, it means this parameter has no default value in Krake.
Configuration file or command-line options¶
There are two different ways to configure Krake components:
- using the configuration files (also for Rok);
- using command-line options (only for Krake components).
Configuration files¶
There are 7 different configuration files:
api.yaml
for the Krake API;scheduler.yaml
for the Scheduler as controller;kubernetes_application.yaml
for the Kubernetes Application controller;kubernetes_cluster.yaml
for the Kubernetes Cluster controller;garbage_collection.yaml
for the Garbage Collector as controller;infrastructure.yaml
for the Infrastructure controller;rok.yaml
for the Rok utility.
For each one of them except rok.yaml
, a template is present in the
config
directory. They end with the .template
extension. For Rok, the
template configuration file is in the main directory of Krake.
Generate configuration¶
From the templates, actual configuration files can be generated using the
krake_generate_config
script. The templates have parameters that can be
overwritten by the script. It allows setting some parameters using
command-line options. The arguments and available options are:
<src_files> <src_files> ...<src_files>
(list of file paths)- Positional arguments: the list of template files that will be used for generation.
--dst
(path to a directory)- Optional argument: the directory in which the generated files will be
created. Default:
.
(current directory). --tls-enabled
- If used, set the TLS support to enabled between all Krake components. By default, TLS is disabled.
--cert-dir <cert_dir>
(path to a directory)- Set the directory in which the certificates for the TLS communication
should be stored. Default:
"tmp/pki"
. --allow-anonymous
- If enabled, anonymous requests are accepted by the API. See Authentication. Disabled by default for the generation.
--keystone-authentication-enabled
- Enable the Keystone authentication as one of the authentication mechanisms. See Authentication. Disabled by default for the generation.
--keystone-authentication-endpoint
- Endpoint to connect to the keystone service. See
Authentication. Default:
"http://localhost:5000/v3"
. --keycloak-authentication-enabled
- Enable the Keycloak authentication as one of the authentication mechanisms. See Authentication. Disabled by default for the generation.
--keycloak-authentication-endpoint
- Endpoint to connect to the Keycloak service. See
Authentication. Default:
"http://localhost:9080"
. --keycloak-authentication-realm
- Keycloak realm to use on the provided endpoint. See
Authentication. Default:
krake
. --static-authentication-enabled
- Enable the static authentication as one of the authentication mechanisms. See Authentication. Disabled by default.
--static-authentication-username
- Name of the user that will authenticate through static authentication. See
Authentication. Default:
"system:admin"
. --cors-origin
- URL or wildcard for the ‘Access-Control-Allow-Origin’ of the CORS system on the API.
Default:
*
. --authorization-mode
- Authorization mode to use for the requests sent to the API.
Only ‘RBAC’ should be used in production. See Authorization.
Default:
always-allow
. --api-host <api_host>
(Address)- Host that will be used to create the endpoint of the API for the
controllers. Default:
"localhost"
. --api-port <api_port>
(integer)- Port that will be used to create the endpoint of the API for the
controllers.. Default:
8080
. --etcd-version <etcd_version>
(string)- The etcd database version. Default:
v3.3.13
. --etcd-host <etcd_host>
(Address)- Host for the API to use to connect to the etcd database. Default:
127.0.0.1
. --etcd-port <etcd_port>
(integer)- Port for the API to use to connect to the etcd database. Default:
2379
. --etcd-port <etcd_port>
(integer)- Peer port for the etcd endpoint. Default:
2380
. --docs-problem-base-url <docs_problem_base_url>
(string)- URL of the problem documentation. Default:
https://rak-n-rok.readthedocs.io/projects/krake/en/latest/user/problem
. --docker-daemon-mtu <docker_daemon_mtu>
(integer)- The Docker daemon MTU. Default:
1450
. --worker-count <worker_count>
(integer)- Number of worker to start on the controller. Workers are the units that
handle resources. Default:
5
. --debounce <debounce>
(float)- For the controllers: the worker queue has a mechanism to delay a received
state of a resource with a timer. A newer state received will then restart
the timer. If a resource is updated a few times in one second, this
mechanism prevents having to handle it each time by another component, and
wait for the latest value. Default:
1.0
. --reschedule-after
- Time in seconds after which a resource will be rescheduled. See
Scheduling. Default:
60
. --stickiness
- “Stickiness” weight to express migration overhead in the normalized ranking
computation. See Scheduling. Default:
0.1
. --poll-interval
- Time in seconds for the Infrastructure Controller
to ask the infrastructure provider client again after a modification of
a cluster. Default:
30
. --complete-hook-user
- For the complete hook, set the name of the user that will be defined as CN of the
generated certificates. See Complete.
Default:
"system:complete-hook"
. --complete-hook-cert-dest
- For the complete hook, set the path to the mounted directory, in which the
certificates to communicate with the API will be stored. See
Complete. Default:
"/etc/krake_cert"
. --complete-hook-env-token
- For the complete hook, set the name of the environment variable that contain the
value of the token, which will be given to the Application. See
Complete. Default:
"KRAKE_COMPLETE_TOKEN"
. --complete-hook-env-url
- For the complete hook, set the name of the environment variable that contain the
URL of the Krake API, which will be given to the Application. See
Complete. Default:
"KRAKE_COMPLETE_URL"
. --external-endpoint
(str)- If set, replaces the value of the URL host and port of the endpoint given to the Applications which have the ‘complete’ hook enabled. See Complete.
--logging-level
(str)- To set the logging level of a controller.
Default:
INFO
. --logging-handler
(str)- To set the handler to use for logging. This lets one choose whether the
logging messages should be printed to stdout or saved to a file.
Options are ‘console’ and ‘file’.
Default:
console
. -h, --help
- Display the help message and exit the script.
Examples¶
To create default configuration files for Krake, the following command can be used in the main directory:
krake_generate_config config/*template
This will create all Krake configuration files in the main directory of Krake.
To create default configuration files for Rok, the following command can be used in the main directory:
krake_generate_config rok.yaml.template
This will create the Rok configuration file in the main directory of Krake.
The two previous commands can be combined together to generate both Rok and Krake configuration files at the same time:
krake_generate_config config/*template rok.yaml.template
This will create Krake and Rok configuration files in the main directory of Krake.
To create a new configuration for the API on the tmp
directory with a
different etcd database endpoint, the following can be used:
krake_generate_config --dst /tmp config/api.yaml.template --etcd-host newhost.org --etcd-port 1234
Command-line options¶
Apart from the configuration files, specific command-line options are
available for the Krake components. They are created automatically from the
configuration parameters. Nested options are generated by concatenating the
names of section with dashes characters ("-"
). For example, the
authentication.allow_anonymous
YAML element becomes the
--authentication-allow-anonymous
option.
There is one option for each parameter of the configuration, except the elements that are lists for the moment. Booleans are converted into optional flags.
Krake configuration¶
All configuration options for the Krake API are described here.
- port (integer)
- This parameter defines the port to which the Krake API will listen to for incoming requests.
- etcd
This section defines the parameters to let the API communicate with the ETCD database.
- host (string)
- Address of the database. Example:
127.0.0.1
- port (integer), default:
2379
- Port to communicate with the database.
- retry_transactions (int):
- Number of times a database transaction will be attempted again if it failed the first time due to concurrent write on the same resource.
- tls
This section defines the parameters needed for TLS support. If TLS is enabled, all other components and clients need TLS support to communicate with the API.
- enabled (boolean)
- Activate or deactivate the TLS support. Example:
false
- cert (path)
- Set the path to the client certificate authority. Example:
tmp/pki/system:api-server.pem
- key (path)
- Set the path to the client certificate. Example:
tmp/pki/system:api-server-key.pem
- client_ca (path)
- Set the path to the client key. Example:
tmp/pki/ca.pem
Authentication and authorization¶
- authentication
This section defines the method for authenticating users that connect to the API. Three methods are available: keystone, keycloak and static. A user not recognized can still send request if anonymous are allowed.
- allow_anonymous (boolean), default:
false
Enable the “anonymous” user. Any request executed without a user being authenticated will be processed as user
system:anonymous
.- strategy
This section describes the parameters for the methods of authentication.
- keystone
The Keystone service of OpenStack can be used as authentication method.
- enabled (boolean)
- Set Keystone as authentication method. Example:
false
- endpoint (URL)
- Endpoint of the Keystone service. Example:
http://localhost:5000/v3
- keycloak
The Keycloak service can be used as authentication method.
- enabled (boolean)
- Set Keycloak as authentication method. Example:
false
- endpoint (URL)
- Endpoint of the Keycloak service. Example:
http://localhost:9080
- realm (str)
- Keycloak realm to use at the provided endpoint. Example:
krake
- static
The user is set here, and the API will authenticate all requests as being sent by this user.
- enabled (boolean)
- Set the static method as authentication method. Example:
true
- name (string)
- This is the name of the user that will be set as sending all requests. Example:
system
- cors-origin (string), default
*
- For the CORS mechanism of Krake. Set the default allowed URL, which corresponds
to the
Access-Control-Allow-Origin
response header.
- allow_anonymous (boolean), default:
- authorization (enumeration)
- This parameter defines the mode for allowing users to perform specific actions (e.g. “create” or “delete” a resource). Three modes are available:
RBAC
,always-allow
,always-deny
.
Controllers configuration¶
The general configuration is the same for each controller. Additional parameters can be added for specific controllers, depending on the implementation. Here are the common parameters:
- api_endpoint (URL)
Address of the API to be reached by the current controller. Example:
http://localhost:8080
- debounce (float)
- For the worker queue of the controller: set the debounce time
to delay the handling of a resource, and get any updated state
in-between. Example
1.5
- tls
This section defines the parameters needed for TLS support. If TLS support is enabled on the API, it needs to be enabled on the controllers to let them communicate with the API.
- enabled (boolean)
- Activate or deactivate the TLS support. If the API uses only TLS, then this should be set to
true
. This has priority over the scheme given by api_endpoint. Example:false
- client_ca (path)
- Set the path to the client certificate authority. Example:
./tmp/pki/ca.pem
- client_cert (path)
- Set the path to the client certificate. Example:
./tmp/pki/jc.pem
- client_key (path)
- Set the path to the client key. Example:
./tmp/pki/jc-key.pem
Kubernetes application controller¶
Additional parameters, specific for the Kubernetes application controller:
- hooks (string)
All the parameters for the application hooks are described here. See also Complete.
- complete (string)
This section defines the parameters needed for the Application
complete
hook. If is not defined the Applicationcomplete
hook is disabled.- hook_user (string)
- Name of the user that will be set as CN in the certificates generated for
the hook. If RBAC is enabled, should match a
RoleBinding
for theapplications/complete
subresource. Examplesystem:complete-hook
- intermediate_src (path)
- Path to the certificate which will be used to sign new generated
certificates for the hook. Not needed if TLS is not enabled. Example:
/etc/krake/certs/system:complete-signing.pem
- intermediate_key_src (path)
- Path to the key of the certificate which will be used to sign new generated
certificates for the hook. Not needed if TLS is not enabled. Example:
/etc/krake/certs/system:complete-signing-key.pem
- cert_dest (path)
- Set the path to the certificate authority on the deployed Application. Example:
/etc/krake_cert
- env_token (string)
- Name of the environment variable, which stores Krake authentication token. Example:
KRAKE_COMPLETE_TOKEN
- env_url (string)
Name of the environment variable, which stores Krake
complete
hook URL. Example:KRAKE_COMPLETE_URL
- external_endpoint (URL, optional)
- If set, replaces the host and port in the value of environment variable in
the Krake
complete
hook URL (the name of this variable is given by env_url_). By default, the value stored in the variable is the api_endpoint. Example:https://krake.external.host:1234
.
- shutdown (string)
This section defines the parameters needed for the Application
shutdown
hook. If is not defined the Applicationshutdown
hook is disabled.- hook_user (string)
- Name of the user that will be set as CN in the certificates generated for
the hook. If RBAC is enabled, should match a
RoleBinding
for theapplications/shutdown
subresource. Examplesystem:shutdown-hook
- intermediate_src (path)
- Path to the certificate which will be used to sign new generated
certificates for the hook. Not needed if TLS is not enabled. Example:
/etc/krake/certs/system:shutdown-signing.pem
- intermediate_key_src (path)
- Path to the key of the certificate which will be used to sign new generated
certificates for the hook. Not needed if TLS is not enabled. Example:
/etc/krake/certs/system:shutdown-signing-key.pem
- cert_dest (path)
- Set the path to the certificate authority on the deployed Application. Example:
/etc/krake_cert
- env_token (string)
- Name of the environment variable, which stores Krake authentication token. Example:
KRAKE_SHUTDOWN_TOKEN
- env_url (string)
Name of the environment variable, which stores Krake
shutdown
hook URL. Example:KRAKE_SHUTDOWN_URL
- external_endpoint (URL, optional)
- If set, replaces the host and port in the value of environment variable in
the Krake
shutdown
hook URL (the name of this variable is given by env_url_). By default, the value stored in the variable is the api_endpoint. Example:https://krake.external.host:1234
.
Scheduler¶
Additional parameters, specific for the Scheduler:
- reschedule_after (float):
- Number of seconds between the last update or rescheduling of a resource and the
next rescheduling. Example:
60
- stickiness (float):
- Additional weight for the computation of the rank of the scheduler. It is added to
the computation of the rank of the cluster on which a scheduled resource is
actually running. It prevents migration from happening too frequently, and thus,
represents the cost of migration. As the computation is done with normalized
weights, the stickiness is advised to be between 0 and 1. Example:
0.1
.
Infrastructure controller¶
Additional parameters, specific for the Infrastructure controller:
- poll_interval (float):
- Time in seconds for the Infrastructure Controller to ask the infrastructure
provider client again after a modification of a cluster. Example:
30
.
Common configuration:¶
The following elements are common for all components of Krake except Rok.
Rok configuration¶
- api_url (URL)
Address of the Krake API to connect to. If the scheme given is incompatible with the tls.enabled parameter, it will be overwritten to match. Example:
http://localhost:8080
- user (string)
- The name of the user that will access the resources. Example:
john-doe
- tls
This section defines the parameters needed for TLS support, which can be used to communicate with the API.
- enabled (boolean)
Activate or deactivate the TLS support. If the API uses only TLS, then this should be set to
true
. This has priority over the scheme given by api_url. Example:false
- client_ca (path)
- Set the path to the client certificate authority. Example:
./tmp/pki/ca.pem
- client_cert (path)
- Set the path to the client certificate. Example:
./tmp/pki/jc.pem
- client_key (path)
- Set the path to the client key. Example:
./tmp/pki/jc-key.pem
Custom Observer Schema¶
Purpose¶
When a user creates Kubernetes resources on a Kubernetes cluster via Krake, those resources are managed by Krake and should be “observed”. That’s the role of the Kubernetes Observer (see the dev/observers:Observers documentation). But what parts of the Kubernetes resources should be “observed” by Krake? The purpose of the Observer Schema is to provide a flexible mean for the Krake users to define which fields of the Kubernetes resources should be “observed” and which shouldn’t.
When a field is “observed”, every change to the value of this field made outside of Krake is reverted to the last known state of this field. When a field is not “observed”, Krake doesn’t act on external changes made to this field. This is needed to keep a consistent and predictable application state, especially since changes could also be done in the Kubernetes infrastructure or by the Kubernetes plane itself.
Note
The custom observer schema could be used even when the application is described by a TOSCA template or CSAR archive. Both file types are translated to Kubernetes manifests in Krake’s Kubernetes application controller, hence the custom observer schema file will be applied to the Kubernetes resources just like it happens during a “regular” workflow, when a Kubernetes manifest is used, see dev/tosca:TOSCA Workflow.
Note
As Kubernetes manages some fields of a Kubernetes resource (for instance the ResourceVersion), simply observing the entirety of a Kubernetes resource is not possible. This would lead to infinite reconciliation loops between Krake and Kubernetes, which is not a desirable state.
Format¶
Example¶
This basic example will be re-used at different part of this documentation.
Example of manifest file provided by the user:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-demo
namespace: secondary
spec:
selector:
matchLabels:
app: echo
template:
metadata:
labels:
app: echo
spec:
containers:
- name: echo
image: k8s.gcr.io/echoserver:1.10
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: echo-demo
namespace: secondary
spec:
type: NodePort
selector:
app: echo
ports:
- port: 8080
protocol: TCP
targetPort: 8080
Example of custom observer schema provided by the user.
---
apiVersion: v1
kind: Service
metadata:
name: echo-demo
namespace: default
spec:
selector:
app: null
ports:
- port: null
protocol: null
targetPort: null
- port: null
protocol: null
targetPort: null
- observer_schema_list_min_length: 1
observer_schema_list_max_length: 4
sessionAffinity: null
Default observer schema¶
By default, all fields defined in spec.manifest
are observed. All other fields are
not observed. By defining a custom observer schema, the user is able to overwrite the
default behavior and precisely define the observed fields.
In the example above, the user didn’t specify a custom observer schema file for the
Deployment
resource. Therefore Krake will generate a default observer schema, and
observe only the fields which are specified in the manifest file.
The result default observer schema for the Deployment
resource is:
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-demo
namespace: secondary
spec:
selector:
matchLabels:
app: null
template:
metadata:
labels:
app: null
spec:
containers:
- name: null
image: null
ports:
- containerPort: null
- observer_schema_list_min_length: 1
observer_schema_list_max_length: 1
- observer_schema_list_min_length: 1
observer_schema_list_max_length: 1
Resource identification¶
In order to identify which resource a schema is referring to, the apiVersion
,
kind
and name
need to be specified. Those fields are also the minimum fields a
user can specify in order to observe a resource. As a result, and without additional
fields to observe, the Kubernetes Observer will simply check the presence of a
Kubernetes resource with this apiVersion
, kind
and name
.
Example of a minimal observer schema for the Service
resource:
---
apiVersion: v1
kind: Service
metadata:
name: echo-demo
Note
The Kubernetes namespace key metadata.namespace
is not mandatory, as it is not
used in the identification of a resource in Krake. Indeed, its value is not always
known at the creation of the application. It can depend from the Kubernetes cluster
the application is scheduled to.
Please note that not all Kubernetes objects are in a namespace. Most Kubernetes resources (e.g. pods, services, replication controllers, and others) are in some namespaces. However, namespace resources are not themselves in a namespace. And low-level resources, such as nodes and persistentVolumes, are not in any namespace.
Therefore, Krake (by default) does not observe a Kubernetes namespace field.
Users may choose to add the metadata.namespace
key to their custom observer schema,
then the metadata.namespace
field will be observed.
Observed fields¶
A field value will be observed if it is defined in the observer schema. Its value should
be null
(in YAML), except for fields used for the resource identification.
In the example above:
- the
spec.type
of the Service is not observed, as it is not present in the custom observer schema. Its original value is specified in the manifest file, but Krake doesn’t guarantee this value to remain. - the
spec.selector.app
of theService
is observed as it is present in the custom observer schema. Krake guarantee that its original value will remain the same, by observing the value and reverting any changes which were not made through Krake. - the
spec.sessionAffinity
of theService
is observed. As it is not present in the manifest, the Kubernetes API will initialize it. Once it has been initialized by Kubernetes, Krake guarantee that its value will not be modified outside of Krake.
Warning
A non-observed field cannot be updated by Krake. In order to update such a field, one also need to observe it (i.e. update the custom observer schema to add this field).
Note
Except for the fields used for identifying the Kubernetes resource, all fields value
MUST be null
. Otherwise, the custom observer schema is invalid.
List length control¶
A list’s length is controlled though the used of a special control dictionary, added as the last element of a list. The minimum and maximum length of the list must be specified.
In the example Service
’s custom observer schema, the number of ports
must be
between 1 and 4. If the length of the ports
list is below 1 or above 4, Krake
reverts the Service
to its last known value.
For the first port, the value of port
, protocol
, targetPort
are defined in
the manifest file.
The presence of a second element in the ports
list in the custom observer schema
doesn’t guarantee its presence. Krake guarantee that, if a second port is set, its value
won’t be allowed to change outside of Krake. It can be removed and re-added, as long as
its value remains unchanged.
Tip
Krake doesn’t allow to set a minimum list length value below the number of element specified in the manifest file.
Tip
An unlimited list length can be specified by setting
observer_schema_list_max_length
to 0.
Note
A list MUST contain the special control dictionary. Otherwise, the custom observer schema is invalid.
Usage¶
A custom observer schema can be specified in rok
with the argument -O
or
--observer_schema
. If none is provided, a default observer schema is generated and
all fields defined in spec.manifest
are observed
User Stories¶
Introduction¶
This guide¶
This guide aims at providing an introduction in some concepts and mechanisms of Krake. It provides guidances and commands that readers are encouraged to try out by themselves on a demo environment as described in the next section.
It does not aim at providing an exhaustive list of commands nor all the possible ways how to use them.
This guide is structured into independent Scenarios which usually start with a Preparation section, and end with a Cleanup section.
Demo Environment¶
Note
The demo environment described in this section refers to a standard development environment deployed with Ansible. See Set up Krake with Ansible
The demo environment is comprised of 3 virtual machines in the same private network:
- The Krake VM: It runs all the Krake components in docker containers, as well as a Prometheus Server to simulate scheduling data for the backends.
- The two Minikube VMs
minikube-cluster-1
andminikube-cluster-2
: They run an all-in-one Kubernetes “cluster”. They are used as backends by Krake to deploy the users’ applications.
Note
Scenario OpenStack backends additionally requires to have an OpenStack project at hand.
On the Krake VM, the two Kubernetes clusters kubeconfig
files are present:
ll clusters/config/
cat clusters/config/minikube-cluster-1
cat clusters/config/minikube-cluster-2
Note
Unless stated otherwise (generally in the prompt), all commands are run on the Krake VM, with the krake
user.
A simple manifest file will be used as a demo application. It can be found at the following path:
cat git/krake/rak/functionals/echo-demo.yaml
Demonstration of basic commands and workflow¶
Goal: Get familiar with basic rok
commands, and with the associated internal Krake mechanisms.
Introduction to the rok
CLI¶
- Following commands provide basic help on the
rok
CLI and its structure:
rok --help
rok kubernetes --help # Similar to "rok kube --help"
rok kube application --help # Similar to "rok app --help"
rok kube cluster --help
rok infrastructure --help # Similar to "rok infra --help"
Register a cluster¶
- Register a Kubernetes cluster using its associated Kubernetes
kubeconfig
file.
rok kube cluster list # No Cluster resource is present
rok kube cluster register -k clusters/config/minikube-cluster-1
rok kube cluster list # One Cluster resource with name "minikube-cluster-1"
Note
The command register
registers an existing Kubernetes cluster through its
kubeconfig file. Resource called a Cluster
(handled by the
kubernetes
API of Krake) is created by the register
command.
It contains multiple pieces of information, in particular the content
of the kubeconfig file itself. The resource helps to store the information
needed to connect to the actual Kubernetes cluster.
Important
In the following, a Kubernetes cluster refers to an actual cluster, which has been already installed and prepared. This can be the Minikube clusters deployed by the Krake test environment.
A Krake Kubernetes Cluster is a resource in the Krake database, which was created by Krake or registered into Krake and contains the kubeconfig file of the corresponding Kubernetes cluster.
Tip
Krake is able to actually create a Kubernetes cluster by supported infrastructure providers. If you are interested in the topic of Kubernetes cluster life-cycle management by Krake please refer to the Infrastructure providers section.
Spawn the demo application¶
- Spawn a Kubernetes
Application
using its Kubernetes manifest file.
rok kube app list # No Application resource is present
rok kube app create -f git/krake/rak/functionals/echo-demo.yaml echo-demo
rok kube app list # One Application resource with name "echo-demo"
– Alternatively, spawn a Kubernetes Application
using a TOSCA
template file (or URL) or CSAR
archive URL, see Examples.
rok kube app list # No Application resource is present rok kube app create -f git/krake/rak/functionals/echo-demo-tosca.yaml echo-demo rok kube app list # One Application resource with name "echo-demo"
- Check application information:
- Application Status is
RUNNING
. - Application is running on
minikube-cluster-1
.
- Application Status is
rok kube app get echo-demo
rok kube app get echo-demo -o json # Use JSON format, which is also more verbose
- Access the demo application endpoint:
APP_URL=$(rok kube app get echo-demo -o json | jq '.status.services["echo-demo"]'); APP_URL="${APP_URL:1: -1}" # Extract Application endpoint from JSON output and register it in the APP_URL variable
curl $APP_URL
- Check the created resources on the Kubernetes cluster:
kubectl --kubeconfig clusters/config/minikube-cluster-1 get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
echo-demo 1/1 1 1 3h34m
kubectl --kubeconfig clusters/config/minikube-cluster-1 get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
echo-demo NodePort 10.98.78.74 <none> 8080:32235/TCP 3h34m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27h
kubectl --kubeconfig clusters/config/minikube-cluster-1 get po
NAME READY STATUS RESTARTS AGE
echo-demo-6dc5d84869-4hcd8 1/1 Running 0 3h34m
Update resources¶
- Update the manifest file to create a second Pod for the
echo-demo
application.
cat git/krake/rak/functionals/echo-demo-update.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-demo
spec:
replicas: 2
selector:
matchLabels:
app: echo
template:
metadata:
labels:
app: echo
spec:
containers:
- name: echo
image: k8s.gcr.io/echoserver:1.9
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: echo-demo
spec:
type: NodePort
selector:
app: echo
ports:
- port: 8080
protocol: TCP
targetPort: 8080
rok kube app update -f git/krake/rak/functionals/echo-demo-update.yaml echo-demo
– Alternatively, update a TOSCA
template file (or URL) or CSAR
archive URL to create a second Pod for the echo-demo
application, see Examples.
rok kube app update -f git/krake/rak/functionals/echo-demo-update-tosca.yaml echo-demo
- Check the existing resources on the Kubernetes cluster: A second Pod has been spawned.
kubectl --kubeconfig clusters/config/minikube-cluster-1 get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
echo-demo 2/2 2 2 42m
kubectl --kubeconfig clusters/config/minikube-cluster-1 get po
NAME READY STATUS RESTARTS AGE
echo-demo-6dc5d84869-2v6jh 1/1 Running 0 7s
echo-demo-6dc5d84869-l7fm2 1/1 Running 0 42m
Delete resources¶
- Issue the following commands to delete the
echo-demo
KubernetesApplication
and theminikube-cluster-1
KubernetesCluster
.
rok kube app delete echo-demo
rok kube app list # No Application resource is present
rok kube cluster delete minikube-cluster-1
rok kube cluster list # No Cluster resource is present
Scheduling an Application using Labels
and LabelConstraints
¶
Goal: Explore the labels mechanisms and schedule an application based on labels and label constraints
Introduction to Scheduling mechanisms¶
Note
After its initial scheduling, an application location is re-evaluated every 60 seconds by the Scheduler - the so-called “rescheduling”. In the following scenarios, we observe both the initial scheduling of an application, and a migration triggered by the rescheduling. To correctly observe this mechanism, it is recommended to check the Scheduler logs, the Application status, and the resources running on the Kubernetes clusters directly, by running the following commands in separate terminals:
- Watch the
echo-demo
KubernetesApplication
status, and more precisely its current location:
watch "rok kube app get echo-demo -o json | jq .status.running_on"
- Watch Scheduler logs:
docker logs -f krake_krake-ctrl-scheduler_1
- Observe k8s resources on both Minikube clusters:
watch kubectl --kubeconfig clusters/config/minikube-cluster-1 get all
watch kubectl --kubeconfig clusters/config/minikube-cluster-2 get all
Preparation¶
- Register the two clusters with a
location
Label
.
Note
Each label always have a key and a value. We follow the same specifications as Kubernetes.
rok kube cluster register -k clusters/config/minikube-cluster-1 -l location=DE
rok kube cluster register -k clusters/config/minikube-cluster-2 -l location=SK
Spawn the demo application¶
- Create an application with a
location
LabelConstraints
, and observe where it is deployed.
rok kube app create -f git/krake/rak/functionals/echo-demo.yaml echo-demo -L location=DE
rok kube app get echo-demo -o json | jq .status.running_on
Observe a migration¶
- Update an application’s
LabelConstraints
and observe the migration to the second Kubernetes cluster.
rok kube app update echo-demo -L location=SK
rok kube app get echo-demo -o json | jq .status.running_on # The Application is now running on "minikube-cluster-2"
Cleanup¶
- Delete the
echo-demo
KubernetesApplication
and both Krake KubernetesClusters
rok kube app delete echo-demo
rok kube cluster delete minikube-cluster-1
rok kube cluster delete minikube-cluster-2
Scheduling an Application Using Metrics¶
Goal: Explore the metrics mechanisms and schedule an application based on cluster metrics.
Note
Refer to the Introduction to Scheduling mechanisms for useful commands to observe the migration mechanism.
Introduction¶
Metrics in the Krake sense have two meanings. The first one is an actual value for some
parameter, which can be measured or computed in the real world. For instance the current
space available on a data center, its latency, the amount of green energy used by the
data center could all be metrics. This value may be dynamic and change over time.
A GlobalMetric
is also a resource in Krake. It represents an actual metric,
is stored in the database, and defines a few elements, such as the minimum and
maximum values (Krake only considers numbers for the metrics).
The Krake scheduler can use these metrics to compute the score of a Krake Kubernetes
Cluster
. Each cluster is associated with a list of metrics and their respective
weights for this cluster. This list is defined by the user who added the Cluster
resource into Krake. A higher weight means that the metric has a higher influence in the
score: a metrics with a low value, but a high weight may have more impact on the score
than a metric with medium value but low weight. The Cluster
metrics and
the computed score is then used in the Application
scheduling process.
For Krake to fetch the current value of a metric, a user needs to define where and how
it can be requested. GlobalMetricsProvider
resources can be created for this
purpose. They have different types, to support different technologies. There is for
example a support for Prometheus. The GlobalMetricsProvider
resource will define
the URL of the Prometheus instance and some other metadata, and afterwards, Krake’s
scheduler can automatically fetch the current value of the metrics for the score’s
computation.
The static providers are simple metric providers usually only set during tests. They allow a Krake resource to be associated with simple metrics, for which the value can be fetched easily, without having to set up a whole infrastructure.
The static providers thus give values for GlobalMetric
resources. This value is
only defined in the resource (stored in the database). Updating the
GlobalMetricsProvider
resource definition thus implies updating the value of
the metrics.
An example of a static GlobalMetricsProvider
resource is given in the following.
It is used in the next steps of this guide. As explained, the value of the metrics
it provides are directly set inside its definition:
api: core
kind: GlobalMetricsProvider
metadata:
created: '2020-01-21T10:50:11.500376'
deleted: null
finalizers: []
labels: {}
modified: '2020-01-21T10:50:11.500376'
name: static_provider
namespace: null
owners: []
uid: 26ef45e8-e5c8-44fe-8a7f-a3f40944c925
spec:
static:
metrics:
electricity_cost_1: 0.9 # Set the value that will be provided for this metric
green_energy_ratio_1: 0.1 # Set the value that will be provided for this metric
type: static
To get additional information about the metrics and metrics providers, please read the documentation about them, see Metrics and Metrics Providers.
Preparation¶
- Add the
static_provider
metrics provider using the bootstrap script (from the root of the Krake repository):
cd <path_to_krake_root>
krake_bootstrap_db support/static_metrics.yaml
- Check that the
GlobalMetricsProvider
andGlobalMetrics
objects have been successfully added:
rok core globalmetricsprovider get static_provider
+-----------+---------------------------+
| name | static_provider |
| namespace | None |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| type | static |
| metrics | electricity_cost_1: 0.9 |
| | green_energy_ratio_1: 0.1 |
+-----------+---------------------------+
rok core globalmetric get electricity_cost_1
+-----------+---------------------+
| name | electricity_cost_1 |
| namespace | None |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| provider | static_provider |
| min | 0 |
| max | 1 |
+-----------+---------------------+
rok core globalmetric get green_energy_ratio_1
+-----------+----------------------+
| name | green_energy_ratio_1 |
| namespace | None |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| provider | static_provider |
| min | 0 |
| max | 1 |
+-----------+----------------------+
- Register
minikube-cluster-1
andminikube-cluster-2
clusters, and associate theelectricity_cost_1
andgreen_energy_ratio_1
metrics to them using different weights to get different ranking scores:
rok kube cluster register -k clusters/config/minikube-cluster-1 --global-metric electricity_cost_1 10 --global-metric green_energy_ratio_1 1
rok kube cluster register -k clusters/config/minikube-cluster-2 --global-metric electricity_cost_1 1 --global-metric green_energy_ratio_1 10
The clusters
minikube-cluster-1
/-2
have been defined with the following weights for the two static metrics:minikube-cluster-1
minikube-cluster-2
Value electricity_cost_1
Weight: 10 Weight: 1 0.9 green_energy_ratio_1
Weight: 1 Weight: 10 0.1 Score 9.1 1.9 As the score of
minikube-cluster-1
is higher, it will been chosen, and the Application will be deployed on it. The score is computed like the following:\[10 \cdot 0.9 + 1 \cdot 0.1 = 9.1\]
Scheduling of an application¶
- Create the
echo-demo
application and check it is actually deployed on the first cluster:
rok kube app create -f git/krake/rak/functionals/echo-demo.yaml echo-demo
rok kube app get echo-demo # See "running_on": the Application is running on "minikube-cluster-1"
Note
You can observe the scheduler logs in DEBUG
mode to gather additional understanding of the scheduling mechanism.
Observe a migration¶
The Scheduler regularly performs a check, to ensure the current cluster on which an Application is running is the best, depending on its score. This check is done by default every minute (see the configuration of the Scheduler). If an available cluster with a better score than the one of the current cluster is found, the Application is migrated from the current to the better cluster.
As the score is computed using the metrics, we can trigger the migration by updating the exported value of the metrics in the
static_provider
GlobalMetricsProvider
resource. The following command updates the value of the static metrics:electricity_cost_1
: to have a value of 0.1;green_energy_ratio_1
: to have a value of 0.9;
minikube-cluster-1
minikube-cluster-2
New value electricity_cost_1
Weight: 10 Weight: 1 0.1 green_energy_ratio_1
Weight: 1 Weight: 10 0.9 Score 1.9 9.1
Note
This is not the actual score but a simplification, as stickiness is also part of the computation, see Scheduling of Applications
- Update the value of the metrics, by updating the
static_provider
GlobalMetricsProvider:
rok core globalmetricsprovider update static_provider --metric electricity_cost_1 0.1 --metric green_energy_ratio_1 0.9
+-----------+---------------------------+
| name | static_provider |
| namespace | None |
| labels | None |
| created | 2021-04-08 08:04:23 |
| modified | 2021-04-08 08:10:34 |
| deleted | None |
| type | static |
| metrics | electricity_cost_1: 0.1 |
| | green_energy_ratio_1: 0.9 |
+-----------+---------------------------+
- Now, by waiting a bit (maximum 60 seconds if you kept the default configuration), the
Scheduler should have checked the new values of the metrics, and have requested a
migration of the Application onto
minikube-cluster-2
, which has now the better score:
rok kube app get echo-demo # See "running_on": the Application is running on "minikube-cluster-2"
Cleanup¶
- Delete the
echo-demo
KubernetesApplication
and both KubernetesClusters
.
$ rok kube app delete echo-demo
$ rok kube cluster delete minikube-cluster-1
$ rok kube cluster delete minikube-cluster-2
OpenStack backends¶
Warning
Due to stability and development issues on the side of Magnum, this feature isn’t actively developed anymore.
Goal: Demonstrate the use of an OpenStack project as a backend for Krake
Note
Krake supports different kind of backends. In the previous example, we used a Kubernetes cluster (deployed in a single VM via Minikube). In this scenario, we register an existing OpenStack project.
Register an existing OpenStack project to Krake¶
- Gather information about your OpenStack project, for example:
openstack coe cluster template list # Get Template ID
openstack project show my_openstack_project # Get Project ID
openstack user show my_user # Get User ID
grep OS_AUTH_URL ~/openrc # Get Keystone auth URL
- Create a OpenStack
Project
resource in Krake:
rok os project create --template 728f024e-8a88-4971-b79f-151da123f363 --project-id 5bc3bab620bd48b0b9b425ee492050ea --password "password" --user-id 737bbcd2ce264d2fa32fa306ac84e97d --auth-url https://identity.myopenstack.com:5000/v3 myproject
Create a MagnumCluster
¶
rok os cluster list # No Cluster resource is present
rok os cluster create mycluster
rok os cluster list # One Cluster resource with name "mycluster"
Note
The creation of the Magnum cluster can take up to 10 minutes to complete.
- Observe that one Kubernetes
Cluster
is created in association to theMagnumCluster
.
rok kube cluster list
Spawn the demo application¶
- Create the demo Kubernetes
Application
and observe the resource status.
rok kube app create -f git/krake/rak/functionals/echo-demo.yaml echo-demo
rok kube app get echo-demo # See "running_on"
Cleanup¶
- Delete the
echo-demo
KubernetesApplication
and the OpenStackProject
rok kube app delete echo-demo
rok kube os cluster delete mycluster
rok kube project delete myproject
Creation and deployment of a stateful application¶
Goal: Create and deploy a stateful application to Krake.
Note
This feature is still under development in Krake, so new features could be added or removed in the future. Also, some implementation details might change.
Therefore, this page is subject to changes until this note is removed.
Infrastructure providers¶
Goal: Demonstrate the use of an OpenStack based cloud backend for Krake. Krake uses the IM (Infrastructure Manager) provider as a backend for spawning a Kubernetes cluster. A Kubernetes cluster is then automatically registered in Krake and could be used for the application deployment.
This is an advanced user scenario where the user should register the existing infrastructure provider backend (IM) as well as an existing IaaS cloud deployment (OpenStack) before the actual cluster creation. The user is navigated to register those resources to Krake. Please read the brief overview of Krake’s infrastructure provider and cloud resources below:
Krake resources called GlobalInfrastructureProvider and InfrastructureProvider correspond to an infrastructure provider backend, that is able to deploy infrastructures (e.g. Virtual machines, Kubernetes clusters, etc.) on IaaS cloud deployments (e.g. OpenStack, AWS, etc.). Krake currently supports IM (Infrastructure Manager) as an infrastructure provider backend.
Krake resources called GlobalCloud and Cloud correspond to an IaaS cloud deployment (e.g. OpenStack, AWS, etc.) that will be managed by the infrastructure provider backend. GlobalCloud and Cloud resources could contain also metrics and labels, that could be used in Cluster scheduling. Krake currently supports OpenStack as a GlobalCloud or Cloud backend.
Note
The global resource (e.g. GlobalInfrastructureProvider, GlobalCloud) is a non-namespaced resource that could be used by any (even namespaced) Krake resource. For example, the GlobalCloud resource could be used by any Cluster which needs to be scheduled to some cloud.
Note
Note that file paths mentioned in this tutorial are relative to the root of the Krake repository.
Preparation¶
Launch the IM infrastructure provider instance using the support script. Please note that the IM instance is launched in the docker environment, therefore it is mandatory to install docker beforehand.
support/im
Warning
The above support script launches the IM as is described in the IM quick start tutorial, hence with the default configuration and in a non-productive way. Please visit the IM documentation for further information about how to configure, launch and interact with the IM software.
Register an existing infrastructure provider to Krake¶
IM service username
and password
could be arbitrary.
The username
and password
are used for userspace definition.
It means, that anyone can talk with IM but can see only their own userspace.
rok infra provider register --type im --url http://localhost:8800 --username test --password test im-provider
Register an existing OpenStack based cloud to Krake¶
Gather information about your OpenStack project from openrc
file:
- Insert the
OS_AUTH_URL
value (without path) to the--url
argument, e.g. https://identity.cloud.com:5000- Insert the
OS_PROJECT_NAME
value to the--project
argument- Insert the
OS_USERNAME
value to the--username
argument- Insert the
OS_PASSWORD
value to the--password
argument
Use the already registered infrastructure provider called im-provider
as an infrastructure provider for your OpenStack cloud.
Note
If you want to use the C&H F1A OpenStack cloud, please note that it does not assign public IPs to the VMs. C&H F1A requires a private network for all VMs. This private network is connected to the public one via a router. The router should be created beforehand as the IM provider is not able to do this. You can create the requested router in your C&H F1A OpenStack cloud project as follows:
openstack router create --external-gateway shared-public-IPv4 public_router
rok infra cloud register --type openstack --url <os-auth-url> --project <os-project-name> --username <os-username> --password <os-password> --infra-provider im-provider os-cloud
Create a Cluster¶
rok kube cluster list # No Cluster resource is present
rok kube cluster create -f rak/functionals/im-cluster.yaml my-cluster
rok kube cluster list # One Cluster resource with name "my-cluster"
The creation of the cluster can take up to 15 minutes to complete. Observe that Kubernetes Cluster is created.
rok kube cluster list
Spawn the demo application¶
Create the demo Kubernetes Application and observe the resource status.
rok kube app create -f rak/functionals/echo-demo.yaml echo-demo
rok kube app get echo-demo # See "running_on"
Cleanup¶
Delete the Cluster, the Cloud and the InfrastructureProvider:
rok kube cluster delete my-cluster
rok infra cloud delete os-cloud
rok infra provider delete im-provider
Scheduling a Cluster using Labels
and LabelConstraints
¶
Goal: Explore the labels mechanisms and schedule a Cluster based on labels and label constraints.
Introduction¶
Note
Refer to the Label constraints for useful information about label constraints.
Krake allows the user to define a label constraint and restrict the deployment of Cluster resources only to cloud backends that match all defined labels.
Preparation¶
Please go through the Preparation as well as through the Register an existing infrastructure provider to Krake and register an infrastructure provider. Validate the infrastructure provider registration as follows:
rok infra provider list
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
| name | namespace | labels | created | modified | deleted | type | url |
+=============+==============+========+=====================+=====================+=========+======+=======================+
| im-provider | system:admin | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | im | http://localhost:8800 |
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
Register os-cloud-1
and os-cloud-2
Clouds, and associate the location Label.
Each label always has a key and a value. We follow the same specifications as the Kubernetes project.
Note
Refer to the Register an existing OpenStack based cloud to Krake for useful information about Cloud attributes.
rok infra cloud register -l location=DE --type openstack --url <os-auth-url> --project <os-project-name> --username <os-username> --password <os-password> --infra-provider im-provider os-cloud-1
rok infra cloud register -l location=SK --type openstack --url <os-auth-url> --project <os-project-name> --username <os-username> --password <os-password> --infra-provider im-provider os-cloud-2
Tip
You do not need access to the two OpenStack projects for os-cloud-1
and os-cloud-2
registration.
It is possible to register one OpenStack project two times in Krake with different labels. Do not use
this setup in the production environment!
Scheduling of a Cluster¶
Create my-cluster
cluster with a location LabelConstraints, and observe where it is spawned.
rok kube cluster create -f git/krake/rak/functionals/im-cluster.yaml my-cluster -L location=SK
rok kube cluster get my-cluster -o json | jq .status.running_on # Cluster is running on "os-cloud-2"
Note
You can observe the scheduler logs in DEBUG mode to gather additional understanding of the scheduling mechanism.
Cleanup¶
Delete the Cluster, both Clouds and the IM InfrastructureProvider.
rok kube cluster delete my-cluster
rok infra cloud delete os-cloud-1
rok infra cloud delete os-cloud-2
rok infra provider delete im-provider
Scheduling a Cluster using Metrics¶
Goal: Schedule the cluster based on cloud metrics.
Introduction¶
Note
Refer to the Introduction and Metrics and Metrics Providers for useful information about metrics.
The Krake scheduler can use metrics to compute the score of a Krake Cloud resource. Each Cloud is associated with a list of metrics and their respective weights for this Cloud. This list is defined by the user who added the Cloud resource into Krake. A higher weight means that the metric has a higher influence in the score: a metric with a low value, but a high weight may has more impact on the score than a metric with a medium value but low weight. The Cloud metrics and the computed score are then used in the Cluster scheduling process.
Note
Note that file paths mentioned in this tutorial are relative to the root of the Krake repository.
Preparation¶
Add the static_provider
metrics provider using the bootstrap script (from the root of the Krake repository):
cd <path_to_krake_root>
krake_bootstrap_db support/static_metrics.yaml
Check that the GlobalMetricsProvider and GlobalMetrics objects have been successfully added:
rok core globalmetricsprovider list
+-----------------+-----------+--------+---------------------+---------------------+---------+---------+
| name | namespace | labels | created | modified | deleted | mp_type |
+=================+===========+========+=====================+=====================+=========+=========+
| static_provider | None | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | static |
+-----------------+-----------+--------+---------------------+---------------------+---------+---------+
rok core globalmetric list
+----------------------+-----------+--------+---------------------+---------------------+---------+-----------------+-----+-----+
| name | namespace | labels | created | modified | deleted | provider | min | max |
+======================+===========+========+=====================+=====================+=========+=================+=====+=====+
| electricity_cost_1 | None | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | static_provider | 0 | 1 |
| green_energy_ratio_1 | None | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | static_provider | 0 | 1 |
+----------------------+-----------+--------+---------------------+---------------------+---------+-----------------+-----+-----+
Please go through the Preparation as well as through the Register an existing infrastructure provider to Krake and register an infrastructure provider. Validate the infrastructure provider registration as follows:
rok infra provider list
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
| name | namespace | labels | created | modified | deleted | type | url |
+=============+==============+========+=====================+=====================+=========+======+=======================+
| im-provider | system:admin | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | im | http://localhost:8800 |
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
Register os-cloud-1
and os-cloud-2
Clouds, and associate the electricity_cost_1
and green_energy_ratio_1
metrics to them using different weights to get different ranking scores:
Note
Refer to the Register an existing OpenStack based cloud to Krake for useful information about Cloud attributes.
rok infra cloud register --global-metric electricity_cost_1 1 --global-metric green_energy_ratio_1 10 --type openstack --url <os-auth-url> --project <os-project-name> --username <os-username> --password <os-password> --infra-provider im-provider os-cloud-1
rok infra cloud register --global-metric electricity_cost_1 10 --global-metric green_energy_ratio_1 1 --type openstack --url <os-auth-url> --project <os-project-name> --username <os-username> --password <os-password> --infra-provider im-provider os-cloud-2
Tip
You do not need access to the two OpenStack projects for os-cloud-1
and os-cloud-2
registration.
It is possible to register one OpenStack project two times in Krake with different metrics. Do not use
this setup in the production environment!
The clouds os-cloud-1
/-2
have been defined with the following
weights for the two static metrics:
os-cloud-1
os-cloud-2
Value electricity_cost_1
Weight: 1 Weight: 10 0.9 green_energy_ratio_1
Weight: 10 Weight: 1 0.1 Score 1.9 9.1 As the score of
os-cloud-2
is higher, it will been chosen, and the Cluster will be spawned on it. The score is computed like the following:\[10 \cdot 0.9 + 1 \cdot 0.1 = 9.1\]
Scheduling of a Cluster¶
Create the my-cluster
cluster and check it is actually spawned on the second cloud:
rok kube cluster create -f rak/functionals/im-cluster.yaml my-cluster
rok kube cluster get my-cluster -o json | jq .status.running_on # Cluster is running on "os-cloud-2"
Note
You can observe the scheduler logs in DEBUG mode to gather additional understanding of the scheduling mechanism.
Cleanup¶
Delete the Cluster, both Clouds and the InfrastructureProvider.
rok kube cluster delete my-cluster
rok infra cloud delete os-cloud-1
rok infra cloud delete os-cloud-2
rok infra provider delete im-provider
Horizontal Cluster Scaling¶
Goal: Scale up and then down (horizontally) the actual Kubernetes cluster using Krake.
This is an advanced user scenario where the user should register an existing infrastructure provider backend (IM) as well as an existing IaaS cloud deployment (OpenStack) before the actual cluster creation and scaling it horizontally. Horizontal scaling is the act of adding (or removing) nodes of the same size to the cluster.
Note
Keep in mind that Krake is able to actually create and then scale (update) the Kubernetes cluster by supported infrastructure providers. Please refer to the Infrastructure Controller and visit related user stories for more information about how the actual Kubernetes cluster could be managed by Krake.
Note
Note that file paths mentioned in this tutorial are relative to the root of the Krake repository.
Preparation¶
Please go through the Preparation as well as through the Register an existing infrastructure provider to Krake and register an infrastructure provider. Validate the infrastructure provider registration as follows:
rok infra provider list
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
| name | namespace | labels | created | modified | deleted | type | url |
+=============+==============+========+=====================+=====================+=========+======+=======================+
| im-provider | system:admin | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | im | http://localhost:8800 |
+-------------+--------------+--------+---------------------+---------------------+---------+------+-----------------------+
Please go through the Register an existing OpenStack based cloud to Krake and register an existing OpenStack cloud to Krake. Validate the cloud registration as follows:
rok infra cloud list
+----------+--------------+--------+---------------------+---------------------+---------+-----------+---------+----------------+--------+
| name | namespace | labels | created | modified | deleted | type | metrics | infra_provider | state |
+==========+==============+========+=====================+=====================+=========+===========+=========+================+========+
| os-cloud | system:admin | None | 2000-01-01 08:00:00 | 2000-01-01 08:00:00 | None | openstack | [] | im-provider | ONLINE |
+----------+--------------+--------+---------------------+---------------------+---------+-----------+---------+----------------+--------+
Create the Cluster¶
Create the my-cluster
cluster using the example TOSCA template stored in rak/functionals/im-cluster.yaml.
This TOSCA template should create a Kubernetes cluster with one control plane node and one worker node.
rok kube cluster create -f rak/functionals/im-cluster.yaml my-cluster
The creation of the cluster can take up to 15 minutes to complete. The fully created and configured cluster should be in the ONLINE state. You should also see that 2 from 2 nodes total are healthy (nodes: 2/2). Validate them as follows:
rok kube cluster get my-cluster
+-----------------------+---------------------------------------------------------------------------------------------+
| name | my-cluster |
| namespace | system:admin |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| state | ONLINE |
| reason | None |
| custom_resources | [] |
| metrics | [] |
| failing_metrics | None |
| label constraints | [] |
| metric constraints | [] |
| scheduled_to | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| scheduled | 2000-01-01 08:00:00 |
| running_on | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| nodes | 2/2 |
| nodes_pid_pressure | 0/2 |
| nodes_memory_pressure | 0/2 |
| nodes_disk_pressure | 0/2 |
+-----------------------+---------------------------------------------------------------------------------------------+
Optionally, you can export the my-cluster
kubeconfig file and validate the cluster health and nodes count
directly by the kubectl CLI. You can do this as follows (with the help of jq command-line JSON processor):
rok kube cluster get my-cluster -o json | jq .spec.kubeconfig > kubeconfig.json
Access the my-cluster
cluster:
kubectl --kubeconfig=kubeconfig.json get nodes
NAME STATUS ROLES AGE VERSION
kubeserver.localdomain Ready control-plane,master 10m v1.22.9
vnode-1.localdomain Ready <none> 9m46s v1.22.9
Scale up the Cluster¶
Scale the created cluster up using the example TOSCA template stored in rak/functionals/im-cluster-scale-up.yaml. This TOSCA template should add one worker node. Its size (flavor) should be the same as the size of the previously created worker node.
Alternatively, you can adjust the worker node number on your own. In this case, find and adjust the
wn_num
variable count in the TOSCA template:wn_num: type: integer description: Number of WNs in the cluster default: 2 required: yes
Scale up the cluster:
rok kube cluster update -f rak/functionals/im-cluster-scale-up.yaml my-cluster
The scaling of the cluster can take up to 5 minutes to complete. The fully scaled and configured cluster should be in the ONLINE state. You should also see that one node has been successfully added i.e. 3 from 3 nodes total are healthy (nodes: 3/3). Validate them as follows:
rok kube cluster get my-cluster
+-----------------------+---------------------------------------------------------------------------------------------+
| name | my-cluster |
| namespace | system:admin |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| state | ONLINE |
| reason | None |
| custom_resources | [] |
| metrics | [] |
| failing_metrics | None |
| label constraints | [] |
| metric constraints | [] |
| scheduled_to | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| scheduled | 2000-01-01 08:00:00 |
| running_on | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| nodes | 3/3 |
| nodes_pid_pressure | 0/3 |
| nodes_memory_pressure | 0/3 |
| nodes_disk_pressure | 0/3 |
+-----------------------+---------------------------------------------------------------------------------------------+
Access the my-cluster
cluster again and validate the cluster health and nodes count
directly by the kubectl CLI:
kubectl --kubeconfig=kubeconfig.json get nodes
NAME STATUS ROLES AGE VERSION
kubeserver.localdomain Ready control-plane,master 34m v1.22.9
vnode-1.localdomain Ready <none> 32m v1.22.9
vnode-2.localdomain NotReady <none> 9m8s v1.22.9
Scale down the Cluster¶
Scale the created cluster down using the example TOSCA template stored in rak/functionals/im-cluster-scale-down.yaml. This TOSCA template should remove one worker node.
Alternatively, you can adjust the worker node number on your own. In this case, find and adjust the
wn_num
andremoval_list
variables in the TOSCA template:wn_num: type: integer description: Number of WNs in the cluster default: 1 required: yes ... wn: type: tosca.nodes.indigo.Compute capabilities: scalable: properties: count: { get_input: wn_num } removal_list: ['2']The
removal_list
variable should be defined and should contain the ID(s) of the VM(s) which should be removed from the cluster. You can find the VM IDs in thecluster.status.nodes
section of the Krake cluster resource as follows (with the help of jq command-line JSON processor):rok kube cluster get my-cluster -o json | jq .status.nodes[].metadata.name "kubeserver.localdomain" "vnode-1.localdomain" "vnode-2.localdomain"
Find the more detailed description about
removal_list
in the IM documentation.
Scale down the cluster:
rok kube cluster update -f rak/functionals/im-cluster-scale-down.yaml my-cluster
The scaling of the cluster can take up to 5 minutes to complete. The fully scaled and configured cluster should be in the ONLINE state. You should also see that one node has been successfully removed i.e. 2 from 2 nodes total are healthy (nodes: 2/2). Validate them as follows:
rok kube cluster get my-cluster
+-----------------------+---------------------------------------------------------------------------------------------+
| name | my-cluster |
| namespace | system:admin |
| labels | None |
| created | 2000-01-01 08:00:00 |
| modified | 2000-01-01 08:00:00 |
| deleted | None |
| state | ONLINE |
| reason | None |
| custom_resources | [] |
| metrics | [] |
| failing_metrics | None |
| label constraints | [] |
| metric constraints | [] |
| scheduled_to | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| scheduled | 2000-01-01 08:00:00 |
| running_on | {'namespace': 'system:admin', 'kind': 'Cloud', 'name': 'os-cloud', 'api': 'infrastructure'} |
| nodes | 2/2 |
| nodes_pid_pressure | 0/2 |
| nodes_memory_pressure | 0/2 |
| nodes_disk_pressure | 0/2 |
+-----------------------+---------------------------------------------------------------------------------------------+
Access the my-cluster
cluster again and validate the cluster health and nodes count
directly by the kubectl CLI:
kubectl --kubeconfig=kubeconfig.json get nodes
NAME STATUS ROLES AGE VERSION
kubeserver.localdomain Ready control-plane,master 40m v1.22.9
vnode-1.localdomain Ready <none> 38m v1.22.9
Cleanup¶
Delete the Cluster, Cloud and the InfrastructureProvider.
rok kube cluster delete my-cluster
rok infra cloud delete os-cloud
rok infra provider delete im-provider
HTTP Problem documentation¶
The failure reason of the Krake API HTTP layer is stored as an RFC7807 Problem. It is a way to define uniform, machine-readable details of errors in an HTTP response.
In case of a failure on the Krake API HTTP layer, the Krake API responds with a well-formatted RFC7807 Problem message, which could contain the following fields:
type
- A URI reference that identifies the problem type. It should point the Krake API users to the concrete part of the Krake documentation where the problem type is explained in detail. Defaults to about:blank.
title
- A short, human-readable summary of the problem type
status
- The HTTP status code
detail
- A human-readable explanation of the problem
instance
- A URI reference that identifies the specific occurrence of the problem
When RFC7807 Problem type
is defined, it points Krake API clients to the below
list of better-described HTTP problems.
Note
The RFC7807 Problem type
URI is generated based
on --docs-problem-base-url
API configuration parameter (see Krake configuration)
and the value from the list of defined HTTP Problems, see krake.api.helpers.HttpProblemTitle
.
not-found-error¶
A requested resource cannot be found in the database.
transaction-error¶
A database transaction failed.
update-error¶
A update of resource field.
invalid-keystone-token¶
An authentication attempt with a keystone token failed.
invalid-keycloak-token¶
An authentication attempt with a keycloak token failed.
resource-already-exists¶
A resource already defined in the database is requested to be created.
Administrator Documentation¶
This chapter presents the installation of Krake using Ansible.
Set up Krake with Ansible¶
This sections describes prerequisites and deployment of a Krake infrastructure with Ansible.
Prerequisites¶
- Ansible 2.9.x or superior using a Python 3 interpreter
- The full Openstack client python module
- Docker Python module
It is suggested that Ansible is installed inside the virtualenv of Krake.
pip install "ansible>=2.9" docker openstackclient
Check the version and Python executable of the Ansible installation:
ansible --version
ansible 2.9.2
config file = None
configured module search path = ['/path/to/home/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /path/to/virtualenv/lib/python3.6/site-packages/ansible
executable location = /path/to/virtualenv/bin/ansible
python version = 3.6.8 (default, Oct 7 2019, 12:59:55) [GCC 8.3.0]
Krake infrastructure deployment¶
The Krake infrastructure is provisioned by a set of Ansible playbooks. The infrastructure is split into multiple separate OpenStack Heat stacks. Every Heat stack is provisioned by its own Ansible playbook. The complete infrastructure can be created by the top-level site.yml playbook.
Krake YAML inventory file hosts.yml needs to be created. Use the example file and adjust it. The only parameter that needs to be modified is the keypair variable. It should name an existing OpenStack keypair. If the corresponding key file is not ~/.ssh/id_rsa specify it in the key_file parameter.
It is assumed that environmental variables for authentication against OpenStack project exist. They can be set by sourcing the OpenStack RC file.
cd ansible/
cp hosts.yml.example hosts.yml
# Get list of all existing OpenStack keypairs
openstack keypair list
The complete infrastructure can be created by the top-level site.yml playbook.
ansible-playbook -i hosts.yml site.yml
Each infrastructure component can by created separately by corresponding ansible playbook e.g. the Krake application infrastructure can be created by Krake playbook.
ansible-playbook -i hosts.yml krake.yml
Table of available playbooks:
Krake Infrastructure component | Playbook name |
---|---|
Top-level playbook | site.yml |
Krake application | krake.yml |
Central IdP instance | central_idp.yml |
Devstack instance | devstack.yml |
Gateway SSH jump host | gateway.yml |
Network “virtual” host | network.yml |
Prometheus server instance | prometheus.yml |
Minikube cluster | minikube_cluster.yml |
Magnum cluster | magnum_cluster.yml |
Krake Ansible directory structure¶
Ansible related-files are stored in the ansible/ directory of the repository. Each sub-directory groups files based on Ansible best practices recommendations.
Sub-directory / File | Description |
---|---|
ansible.cfg | Local Ansible configuration |
hosts.yml | Krake YAML inventory file |
plugins/ | Custom Ansible plugins |
files/ | Heat stack templates and files |
plugins/ | Custom Ansible plugins |
group_vars/ | Ansible group variables used as default values |
roles/ | Files for reusable Ansible roles |
utils/ | Krake Ansible helper scripts |
Access through the gateway¶
To compartmentalize the infrastructure, all machines deployed by Krake are present on the same OpenStack private network. Only the gateway is associated with a floating IP and can thus be accessed externally. All other machines can be reached through the gateway.
To simplify this process, the wireguard VPN is installed on the gateway when deployed.
After the deployment, for each wireguard peer set for the gateway in the host file (see
Inventory structure), a wireguard configuration file is created
in the etc directory where the inventory files are created (ansible/.etc
by
default). The files names have the following syntax: wg_<peer_name>.conf
.
To use this file you have to:
install wireguard locally. If you are using Ubuntu, you can use the following command:
$ sudo apt install wireguardgenerate a wireguard key:
$ umask 077 $ wg genkey > privatekey $ wg pubkey < privatekey > publickey2.1 open the
wg_<peer_name>.conf
and change theREPLACEME
placeholder with the private key that corresponds to the peer.2.2 Use SSH to connect to the
krake-gateway-server
. Check the gateway server and if necessary adjust to accommodate the correct wireguard keys. Replace theREPLACEME
placeholder with the public key. You can find the public key in the directory under/etc/wireguard
:[Interface] PrivateKey = <INSERT_PRIVATE_WIREGUARD_KEY> Address = 10.9.0.1 [Peer] PublicKey = <INSERT_PUBLIC_KEY_FROM_GATEWAY_SERVER> Endpoint = 185.128.119.165:51820 AllowedIPs = 10.9.0.0/24, 192.168.0.0/24
bring the wireguard interface up by using:
$ wg-quick up <path_to_file>/wg_<peer_name>.conf # Example: $ wg-quick up ansible/.etc/wg_my-peer.confyou can now SSH into the other machines on the private network:
$ ssh ubuntu@<krake_VM_private_ip>
The wireguard interface can be brought down by using:
$ wg-quick down <path_to_file>/wg_<peer_name>.conf
# Example:
$ wg-quick down ansible/.etc/wg_my-peer.conf
Important
If several Krake deployments are managed from a single machine, the peer names should have a different value, to avoid conflicts with the wireguard network interfaces.
If several network interfaces are up at the same time, then the Krake private
networks should not overlap. So if one has for instance the CIDR 192.168.0.0/24
,
another deployment should use something independent, such as 192.168.1.0/24
.
Variables¶
This sections describes Krake Ansible variables definition. Variables are stored in the group_vars/ directory or directly in the inventory file hosts.yml. Inventory file defines variables on global level or on a host group level (see Inventory).
Variables definition¶
Krake Ansible variables stored in group_vars/ directory are structured into files where the filename matches the inventory host group name. Global variables common for all inventory host groups are defined in all.yml variable file. Following section describes files and variables used by Krake Ansible playbooks.
- all.yml
- etc_dir
- The directory of JSON files which store inferred information from hosts by krake_inventory plugin
- central_idps.yml
- keystone_port
- Central IdP keystone port
- secgroup_name
- Security group name
- flavor
- Flavor manages the sizing for the compute, memory and storage capacity of the host
- floating_ip
- Enables the use of public IP address
- git_branch
- Git branch name
- devstack.yml
- prometheus_port
- Prometheus server port
- service_provider_port
- Prometheus clients port
- template_name
- Name of the default kubernetes cluster template
- cluster_keypair
- Name of the default keypair that is used to spawn kubernetes clusters via Magnum
- idp_name
- Central IdP name
- federated_domain_name
- Federated domain name
- federation_protocol_name
- Federation protocol name
- idp_mapping_name
- Central IdP mapping name
- flavor
- Flavor manages the sizing for the compute, memory and storage capacity of the host
- floating_ip
- Enables the use of public IP address
- git_branch
- Git branch name
- gateways.yml
- flavor
- Flavor manage the sizing for the compute, memory and storage capacity of the host
- wireguard_port:
- Port on which the wireguard service will listen to on the gateway.
- krake_apps.yml
- flavor
- Flavor manages the sizing for the compute, memory and storage capacity of the host
- floating_ip
- Enables the use of public IP address
- api_host
- OpenStack Heat template API name
- api_port
- OpenStack Heat template API port
- etcd_host (string)
- Name of the etcd container started using docker-compose.
- etcd_port (int)
- Port of the etcd cluster in the etcd container started using docker-compose.
- etcd_peer_port (int)
- Peer listening port of the etcd cluster in the etcd container started using docker-compose.
- api_host (string)
- Name of the Krake API container started using docker-compose.
- api_port (int)
- Port that can be used to reach the Krake API present in the container started using docker-compose.
- enable_tls (boolean)
- Enable or disable TLS support for communications with the API (for the API, controllers and Rok utility).
The certificates need to be added manually into the
/etc/krake
directory in the Krake VM. - worker_count (integer)
- On each Controller, amount of working units that will handle resources received concurrently.
- debounce (float)
- On each Controller, timeout (in seconds) for the worker queue before handing over a resource, to wait for an updated state.
- complete_hook_user (string)
- Name of the user for the “complete” hook.
- complete_hook_cert_dest (file path)
- Path inside the deployed Application where the certificate and its key will be stored (for the “complete” hook).
- complete_hook_env_token (string)
- Name of the environment variable that will contain the token in the deployed Application.
- complete_hook_env_url (string)
- Name of the environment variable that will contain the URL of the Krake API in the deployed Application.
- external_endpoint (URL, optional)
- URL of the Krake API that will be reachable for any deployed Application.
- use_private_ip (boolean)
- If set to True, and no external endpoint has been set, the URL for the external endpoint (see above) will be computed automatically, using the Krake API private IP, its port and the “http” or “https” scheme depending on the status of TLS on the Krake API (enabled or disabled).
- shutdown_hook_user (string)
- Name of the user for the “shutdown” hook.
- shutdown_hook_cert_dest (file path)
- Path inside the deployed Application where the certificate and its key will be stored (for the “shutdown” hook).
- shutdown_hook_env_token (string)
- Name of the environment variable that will contain the token in the deployed Application.
- shutdown_hook_env_url (string)
- Name of the environment variable that will contain the URL of the Krake API in the deployed Application.
- magnum_clusters.yml
- prometheus_port
- Prometheus server port
- magnum_path
- Magnum path
- kube_api_config
- Path of kubernetes configuration file
- user_role
- Federated user role
- user_project
- Federated project name
- minikube_clusters.yml
- api_port
- OpenStack Heat template api port
- minikube_install_dir
- Minikube installation directory path
- minikube_version
- Minikube version
- kubectl_version
- Kubectl version
- kube_api_config
- Kubectl api configuration file path
- minikube_path
- Minikube keystone path
- user_role
- Federated user role
- user_project
- Federated project name
- flavor
- Flavor manages the sizing for the compute, memory and storage capacity of the host
- floating_ip
- Enables the use of public IP address
- prometheus.yml
- prometheus_admin_pass
- Prometheus server admin password
- grafana_admin_pass
- Grafana server admin password
- ports
- Prometheus server VM open ports
- flavor
- Flavor manages the sizing for the compute, memory and storage capacity of the host
- floating_ip
- Enables the use of public IP address
- git_branch
- Git branch name
Inventory¶
This sections describes the Ansible inventory of the Krake project. Ansible works against multiple infrastructure hosts. Hosts are configured in an inventory file hosts.yml which is a standard Ansible YAML inventory that uses multiple groups structure and a custom krake_inventory plugin (see auto plugin).
Inventory plugin¶
The krake_inventory custom plugin loads the JSON file defined by variable hosts_file and augments the host variables with dynamic variables (e.g. public and private IP addresses) depending on host. The location of JSON file which stores inferred information can be configured by specifying the hosts_file variable in the all group . If it is not specified it defaults to .etc/<inventory-filestem>.json.
Inventory structure¶
Krake inventory file hosts.yml uses Ansible multiple groups structure of inventory.
Global variables for all hosts are defined under the vars
sub-section.
This sub-section defines following:
- keypair
- OpenStack SSH key pair name of public ssh key which will be used for accessing the infrastructure to deploy hosts. Different keys could be defined directly for specific group or host.
- key_file
- SSH private key file path on local computer for corresponding keypair. If key_file is set to null, the default SSH identity (~/.ssh/id_rsa) will be used.
- gateway
- SSH jump host that is used to access the OpenStack instances. By default, no OpenStack server has a floating IP assigned except hosts in the gateways group. All other hosts use the gateway host variable to define a SSH jump host. Wireguard is also installed on the gateway, see Access through the gateway
- authorized_keys - optional
- List of additional authorized SSH keys, which can be used for accessing the hosts.
Each Krake infrastructure host is defined by corresponding host group sub-section in Krake inventory file. The default parameters for every host group are defined in the group_vars/ directory where the filename matches the group name. Krake inventory file defines following host groups and host variables:
- gateways
SSH jump host that is used to access the OpenStack instances.
- network
- Inventory name of the network on which this SSH jump host should be deployed
- vpn_cidr
- VPN Classless Inter-Domain Routing definition (e.g. 10.9.0.0/24). This will define the wireguard network. Each peer on this network (the gateway and users or administrators of the deployment) will have a specific address on this network.
- wireguard_peers
List of all wireguard peer for whom access should be granted on the gateway. Several peers can be added. A wireguard configuration file will be created for each peer.
- name
- The name of the peer. This string is used to differentiate the different peers from each other. It will also be given to the wireguard network interface. The value can be arbitrary, but should be unique per deployment, or over deployment if you plan on managing several ones with the same machine.
- public_key
- The wireguard public key of the peer.
- IP
- Set the IP that will be given to the current peer in the wireguard network.
Each peer should be given a different IP to prevent conflicts. The IP can
be chosen in the
vpn_cidr
network, as long as it is not the IP given to the gateway (which is the first in the network by default).
- networks
Networks group define “virtual” hosts. These hosts exist purely for provisioning purpose. No machines are associated with them.
- subnet_name
- Subnet name
- subnet_cidr
- Subnet Classless Inter-Domain Routing definition (e.g. 192.168.0.0/24)
- public_network
- Public network type (e.g. shared-public-IPv4)
- router_name
- Router name
- common_secgroup_name
- Secure group name
- central_idps
Central IdP host group used for keystone federation of Krake infrastructure.
- network
- Inventory name of the network on which this IdP should be deployed
- devstacks
Devstack host group used for deployment of Krake devstack backends.
- id
- Unique DevStack ID. This ID is also used to define the IP network of the DevStack instance in the private network
- network
- Inventory name of the network on which this DevStack should be deployed
- idp
- Inventory name of the IdP that should be used for federation by this DevStack
- prometheus
- Inventory name of the Prometheus server that should be used for the monitoring of this DevStack backend
- magnum_clusters
Magnum cluster host group used for deployment of magnum clusters on underlying devstack backend.
- name
- Magnum cluster name
- devstack
- Inventory name of underlying devstack backend which hosted the magnum cluster deployment
- prometheus
- Inventory name of the Prometheus server that should be used for the monitoring of this magnum cluster
- use_keystone
- Enables keystone deployment on this magnum cluster
- minikube_clusters
Minikube cluster host group used for deployment of minikube clusters.
- name
- Minikube cluster name
- network
- Inventory name of the network on which this minikube cluster should be deployed
- idp
- Inventory name of the IdP that should be used for federation by this minikube
- use_keystone
- Enables keystone deployment on this minikube cluster
- prometheus
Prometheus host group used for deployment of Prometheus monitoring server.
- hostname
- Prometheus VM host name
- network
- Inventory name of the network on which this minikube cluster should be deployed
- krake_apps
Krake application host group used for deployment Krake infrastructure
- hostname
- Krake VM host name
- network
- Inventory name of the network on which this minikube cluster should be deployed
Bootstrapping¶
After Krake has been installed and runs, the database is still empty. To allow easy
insertion of resources during initialisation, a bootstrap script is present, namely:
krake_bootstrap_db
. It is used along with YAML files in which the resources
are defined.
Requirements for bootstrapping:
- Krake should be installed;
- the database should be started.
Usage¶
Workflow¶
The script is given several files, each with one or several resource definitions.
These definitions should follow the structure of the data defined in krake.data
.
See Structure.
If the insertion of at least one resource fails, all previous insertions are rolled back. This ensures that the database remains in a clean state in all cases.
The insertion will be rolled back in the following cases:
- the structure of a resource was invalid and its deserialization failed;
- a resource belongs to an API or a kind not supported by the bootstrapping script;
- a resource is already present in the database. This can be overridden using the
--force
flag (see the force argument). In this case, a resource already present will be replaced in the database with the currently read definition. In case of rollback, the previous version of the resource will be put back in the database.
Command line¶
The simplest command is to give one or several files as input, for example:
$ krake_bootstrap_db file_1.yaml file_2.yaml
Other arguments can be used:
--db-host
(address):- If the database is not present locally, the host or address can be specified
explicitly. Default:
localhost
. --db-port
(integer):- If the database is not present locally, the port can be specified explicitly.
Default:
2379
. --force
:If set, when the script attempts to insert a resource that is already in the database, the resource will be replaced with its new definition. If not, an error occurs, and a rollback is performed.
The content of the file can alternatively be passed by stdin, using the -
option:
cat file_1.yaml | krake_bootstrap_db -
This can become very useful when starting the command with a container running Krake. If the file is not present in the container, and you do not want to use a volume, you can still execute the following:
docker exec -i <krake_container> krake_bootstrap_db - < file_1.yaml
Structure¶
Only resources defined in krake.data
that are augmented with the
krake.data.persistent
decorator should be inserted with the
krake_bootstrap_db
script.
Each file must have a YAML format, with each resource separated with the ---
separator. The API name, the resource kind and its name must be specified (in the
metadata
for the name).
Thus the minimal resource to add must have the following structure:
api: foo
kind: Bar
metadata:
name: foo_bar
This will add a Bar
object with the name foo_bar
, with Bar
defined in the
API with name foo
.
An actual resource would have more values to fill, see the following example with a
Krake Role
and RoleBinding
definitions:
api: core
kind: Role
metadata:
name: my-role
rules:
- api: 'my-api'
namespaces:
- 'my-namespace'
resources:
- 'my-resource'
verbs:
- list
- get
---
api: core
kind: RoleBinding
metadata:
name: my-rolebinding
roles:
- my-role
users:
- me
Danger
The structure of a resource added in the database is checked against the definition of this resource kind. This means that the attributes’ name and kind are checked. However, the bootstrapping script does not ensure that the relationships between the resources are valid.
For instance, the RoleBinding
my-rolebinding
refers to the Role
my-role
. If this role is not in the database, or its name has been misspelled,
the bootstrapping script will not detect it, and the database will be inconsistent.
Existing definitions¶
Some files are already present in the Krake repository with the definitions of different resources.
Authorization¶
To use the RBAC authorization mode, roles need to be defined, using Role
objects.
They need to be present in the database, and can either be added manually, using the
API, or with the bootstrapping:
$ krake_bootstrap_db bootstrapping/base_roles.yaml
Development and tests¶
To test the migration, support/prometheus
or support/prometheus-mock
script can
be used, or simply static metrics. However, in this case, GlobalMetric
and
GlobalMetricsProvider
objects need to be created. Two bootstrap definition files
are present in support/
for adding Prometheus and static metrics and metrics
provider, respectively prometheus_metrics.yaml
and static_metrics.yaml
.
They can be easily processed using:
$ krake_bootstrap_db support/prometheus_metrics.yaml support/static_metrics.yaml
Security principles¶
This chapter discusses the different security options supported by Krake, and gives explanation on how to set up Krake securely.
Overview¶
When sending a request to the API, Krake uses two mechanisms to limit resource access:
- first the authentication of the user;
- then, using this information, an authorization mechanism describes which resources can be accessed by this user.
Important
There are no user in Krake as actual stored resource. Krake does not manage users, they should be handled by external services (for instance Keystone authentication). Users are identified internally using simple strings. The authentication method ensures that the right string is obtained from a request, and the authorization ensures that the user represented by this string has the right accesses to the resources.
Important
If a Krake component (a controller, or Rok) communicates with the API, the same process is performed. In this case, the user is actually the component itself.
Authentication¶
To authenticate the user, five different mechanisms can be used: static, Keystone, Keycloak, TLS or anonymous. When a request is received by the API, all the mechanisms enabled in this list will attempt to authenticate the user that sent the request. If the first failed, the second will try, and so on, until all failed, and an HTTP error “Unauthorized (401)” will be sent back to the API. The first that succeeds returns the user that has been authenticated. It is then used during the authorization process.
The order of priority between the authentication mechanisms is as follow (if the mechanisms are enabled):
- static:
- This mechanism should never be used in production. When enabled, this mechanism will authenticate any request as coming from a user with a given username. This username needs to be specified in the API configuration.
- Keystone:
- authenticate incoming requests on the API using an OpenStack Keystone server. A
token must first be requested to the Keystone server. This token should then be
sent along with any request to the API as the value of the
Authorization
header in the HTTP request. See Keystone authentication for more information. - Keycloak:
- authenticate incoming requests on the API using a Keycloak server. A token must
first be requested to the Keycloak server. This token should then be sent along with
any request to the API as the value of the
Authorization
header in the HTTP request. See Keycloak authentication for more information. - TLS:
- authenticate incoming requests on the API using the common name attribute of certificates. This name is then used as username. It means TLS needs to be enabled on the API, and thus, on all Krake components. See Certificate authentication for more information.
- Anonymous:
- This mechanism should never be used in production. Set using
allow_anonymous
to true in the configuration. If the user has not been authenticated by any previous mechanism, and if anonymous users are allowed, the user will be authenticated assystem:anonymous
.
The authentication mechanisms can be enabled or disabled in the API configuration file, along their specific parameters (see Authentication and authorization).
Authorization¶
The second phase of security is the authorization of an authenticated user. The user is verified against the chosen authorization policy, called authorization mode in the following. If a user has the right to access and perform the chosen action on the resource currently requested, the request is processed. Otherwise the API returns an HTTP 403 error.
Krake uses three different authorization modes to connect to the API, always-allow
,
always-deny
and RBAC
.
always-allow
- all requests are always accepted, for any user;
always-deny
- all requests are always rejected, for any user;
RBAC
(for Role-Based Access Control)- Krake will use roles to decide the resources that a user can access, and the action that this user can perform on these resources.
Warning
The first two modes are only present for testing purposes and should never be used
in production. Only RBAC
should be used in production.
The authorization mode can be chosen in the configuration file (see Authentication and authorization).
Keystone authentication¶
The Keystone authentication uses the OpenStack Keystone service to obtain the identity of a user. The workflow to send a request to the API is as follow if Keystone authentication is enabled:
- (the user must be registered in Keystone;)
- the user sends a request to the Keystone server to obtain a token;
- an HTTP request is sent to the API, with this token used in the header.
Step 1: Kesytone token request¶
To request a token to the Keystone server, you can use the following example by replacing the values with the corresponding ones for your setup:
$ curl -sD - -o /dev/null -H "Content-Type: application/json" \
http://<keystone_server>/v3/auth/tokens \
-d '{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": "<keystone_user_domain_name>"
},
"name": "<keystone_username>",
"password": "<keystone_password>"
}
}
},
"scope": {
"project": {
"domain": {
"name": "<keystone_project_name>"
},
"name": "<keystone_project_domain_name>"
}
}
}
}'
The following example is for the support/keystone/keystone
script:
$ curl -sD - -o /dev/null -H "Content-Type: application/json" \
http://localhost:5000/v3/auth/tokens \
-d '{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": "Default"
},
"name": "system:admin",
"password": "admin"
}
}
},
"scope": {
"project": {
"domain": {
"name": "Default"
},
"name": "system:admin"
}
}
}
}'
You will get an output close to the following, where you can find the expected token:
HTTP/1.0 201 CREATED
Date: Tue, 42 Dec 2077 10:02:11 GMT
Server: WSGIServer/1.0 CPython/3.8
Content-Type: application/json
Content-Length: 1234
X-Subject-Token: XXXXXXXXXXXXXXXXXXXXXX <--- this is the token
Vary: X-Auth-Token
x-openstack-request-id: xxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
From this output, you can obtain your token. A suggestion is to keep it in your shell as environment variable, for instance:
$ TOKEN=XXXXXXXXXXXXXXXXXXXXXX
Step 2: Keystone token usage¶
Using your token, you can then communicate with the Krake API:
$ curl -k -H "Accept: application/json" -H "Authorization: $TOKEN" \
<scheme>://<krake_api>/<query>
For instance, to get the current authenticated user on Krake installed locally, with TLS support:
$ curl --cacert ./tmp/pki/ca.pem -H "Accept: application/json" -H
"Authorization: $TOKEN" https://localhost:8443/me
Keycloak authentication¶
The Keycloak authentication uses a Keycloak service to obtain the identity of a user. The workflow to send a request to the API is as follow if Keycloak authentication is enabled:
- (the user must be registered in Keycloak;)
- the user sends a request to the Keycloak server to obtain a token;
- an HTTP request is sent to the API, with this token used in the header.
Step 1: Keycloak token request¶
Query¶
To request a token to the server, multiple ways are supported by Keycloak. If the server has been set up for direct access grants, you can use the following example by replacing the values with the corresponding ones for your setup:
$ curl -s http://localhost:9080/auth/realms/krake/protocol/openid-connect/token \
-d 'grant_type=password' \
-d 'username=<username>' \
-d 'password=<password>' \
-d 'client_id=<client_name>' \
-d 'client_secret=<client_secret>'
For the support/keycloak
script, you can use the following command to get a token:
$ support/keycloak token
Internally, something similar to the following is used, with all values set by the script:
$ curl -s http://localhost:9080/auth/realms/krake/protocol/openid-connect/token \
-d 'grant_type=password' \
-d 'username=krake' \
-d 'password=krake' \
-d 'client_id=krake_client' \
-d 'client_secret=AVeryCoolAndSecureSecret'
Response¶
Using the cURL queries, you will get a JSON with the following structure:
{
"access_token":"XXXXXXXXXXXXXXXX",
"expires_in":60,
"refresh_expires_in":1800,
"refresh_token":"<refresh_token>",
"token_type":"bearer",
"not-before-policy":0,
"session_state":"9c22a6df-0997-4d3d-a540-239f85346008",
"scope":"profile email"
}
From this output, you can obtain your token from the access_token
field. A
suggestion is to keep it in your shell as environment variable, for instance:
$ TOKEN=XXXXXXXXXXXXXXXXXXXXXX
With the support/keycloak
direct command, you get the token directly, thus you could
simply use:
$ TOKEN=$(support/keycloak token)
Step 2: Keycloak token usage¶
Using your token, you can then communicate with the Krake API:
$ curl -k -H "Accept: application/json" -H "Authorization: $TOKEN" \
<scheme>://<krake_api>/<query>
For instance, to get the current authenticated user on Krake installed locally, with TLS support:
$ curl --cacert ./tmp/pki/ca.pem -H "Accept: application/json" -H
"Authorization: $TOKEN" https://localhost:8443/me
Certificate authentication¶
With the TLS support enabled on the API configuration, the requests to the API can only be performed using HTTPS. This allows Krake to obtain information about the sender through the certificates. Especially, Krake can use the common name to identify the user that sent the request.
This authentication mechanism should always be used in a production environment. It
also allows the authentication of the Krake components. The scheduler, the garbage
collector or any other controller should have a certificate with a specific common
name. This name can then be used along with the RBAC
mode and a specific
RoleBinding
to allow the controller to access the resources it needs.
Important
With TLS support, all Krake components will use certificates with their corresponding key. All components (API, controllers and rok) must use the same CA, and the certificates they use for communication must also be signed using this CA.
Note
If an external endpoint is specified in the Kubernetes controller configuration for the complete hook, then this host must also be specified in the certificate of the API.
RBAC Authorization¶
The Role-Based Access Control (or RBAC) is a model of resource access. Each user is given one or several roles, and each role has access to one or several resources, and/or actions.
When RBAC is enabled, roles need to be defined and bound to users using respectively
Role
and RoleBinding
core API objects. They have their own endpoints for
creation, update, deletion… (/core/roles
and /core/rolebindings
respectively).
Role bindings¶
The RoleBinding
objects defines a connection between one or several roles to one or
several users.
Roles¶
A Role
defines different rules: each rule describes which resource can be accessed
by a user with this role, and which action can be performed. The Role
can then be
applied to several users, which is the purpose of RoleBinding
objects.
Example¶

In the previous example, the user 1 and 2 have both been given the roles A and C. It means they can both get and list the resources X, Y and Z.
Let’s now say we want to have the following minimal example:

api: core
kind: Role
metadata:
name: my-role
rules:
- api: 'my-api'
resources:
- 'my-resource'
namespaces:
- 'my-namespace'
verbs:
- list
- get
- api: 'my-other-api'
resources:
- 'first'
- 'second'
namespaces:
- 'my-namespace'
verbs:
- update
- delete
In the above example definition of a Role
, a user with this role can:
- list or read the
my-resource
resources defined in themy-api
API, that belong to themy-namespace
namespace (first rule);- update or delete the
first
andsecond
resources defined in themy-other-API
API, also in themy-namespace
namespace (second rule).
api: core
kind: RoleBinding
metadata:
name: my-rolebinding
roles:
- my-role
- my-other-role
users:
- me
- he
- she
In the above example, the RoleBinding
object binds the my-role
and the
my-other-role
to the users me
, he
and she
.
Security Guidelines¶
Warning
DISCLAIMER: The steps described in this chapter do not ensure a fully secure Krake infrastructure. They are the minimal security steps that are recommended. An actual fully secure setup need general security measures on all its components and on the setup itself, not only for the Krake infrastructure
This section is a guide that describes all the steps to create a minimal secure Krake infrastructure.
What you need:
Krake installed;
the Krake repository (optional);
a certificate authority (CA) and at least five certificates and their respective keys (signed with this CA). To follow this guide easily, the common names of the certificates shall be:
system:gc
system:scheduler
system:kubernetes
system:magnum
system:infrastructure
system:admin
system:complete-signing
system:shutdown-signing
- an additional certificate is necessary for the API.
These names are the ones present in the bootstrapping file called
base_roles.yaml
. They can naturally be modified to follow your needs.
The support/pki
script can also generate them for testing purpose, example:
$ support/pki system:admin
The certificate with system:complete-signing
will be used for signing new
certificates, thus would need to be set for signing purposes:
$ support/pki system:complete-signing --intermediate-ca
The certificate with system:shutdown-signing
will be used for signing new
certificates, thus would need to be set for signing purposes:
$ support/pki system:shutdown-signing --intermediate-ca
If Krake is not deployed locally, you also need to set its external endpoint as TLS subject alternative names, for instance:
$ support/pki system:api-server --host 1.2.3.4 --host example.com
Configuration of the API¶
The first step is to configure the API to use the right authentication and authorization modes.
Configuration of the authentication:¶
First, disable the static and anonymous authentications in the API configuration:
authentication:
allow_anonymous: false
#...
static:
enabled: false
name: system:admin
Then, enable the TLS support on the API:
tls:
enabled: true
cert: <path_to_your_certificate>
key: <path_to_your_key>
client_ca: <path_to_your_client_ca>
If you want to use Keystone or Keycloak authentication additionally, you should set the configuration as well:
authentication:
# ...
strategy:
# Keystone authentication
keystone:
enabled: true
endpoint: <your_keystone_endpoint>
# Keycloak authentication
keycloak:
enabled: true
endpoint: <your_keystone_endpoint>
realm: <your_keycloak_realm>
Krake contains an example Keystone server under support/keystone/Dockerfile
.
This is a docker file, which creates an image with a secure Keystone instance, that
can be accessed over HTTPS.
Configuration of the authorization:¶
To set the RBAC
authorization mode, change the following line
in the API configuration:
authorization: RBAC
Configuration of the Controllers¶
You need to enable the TLS support on all controllers:
tls:
enabled: true
client_ca: <path_to_your_client_ca>
client_cert: <path_to_your_client_cert>
client_key: <path_to_your_client_key>
The API endpoint must be modified to use HTTPS:
api_endpoint: https://<endpoint>
This certificate must indicate a common name only used by the current controller. Let’s
refer to it as system:<controller>
as an example. Using TLS authentication,
system:<controller>
will be the username of the Controller every time this
controller will connect to the API, see Authentication
When using bootstrapping, the “username” of the controllers must be adapted to
correspond to the ones in the RoleBinding
objects added in the database. See
Database bootstrapping.
If the bootstrapping file present in the repository is used (base_roles.yaml
), the
common names of the controller certificates must be:
system:gc
for the garbage collector;system:scheduler
for the scheduler;system:kubernetes
for the Kubernetes controller;system:complete-signing
for the signing certificate of the “complete” hook, see Complete.system:shutdown-signing
for the signing certificate of the “shutdown” hook, see Shutdown.system:magnum
for the Magnum controller.
Configuration of rok¶
api_url: https://<endpoint> # must use HTTPS
user: <rok_user>
tls:
enabled: true
client_ca: <path_to_your_client_ca>
client_cert: <path_to_your_client_cert>
client_key: <path_to_your_client_key>
The common name used by the certificate must match the one from <rok_user>
. This
name will be used as username.
If the bootstrapping file present in the repository is used (base_roles.yaml
),
the certificate used by the administrator must have system:admin
as common name,
and <rok_user>
must then match it.
Database bootstrapping¶
For the RBAC authorization mode to work, Role
and RoleBinding
objects need to
be put in the database.
They can be either added manually using the command line, or more simply added by using
bootstrapping (see Bootstrapping). The roles for the Krake
components and the administrator are defined already in
bootstrapping/base_roles.yaml
. Thus they can all be added with:
$ krake_bootstrap_db bootstrapping/base_roles.yaml
When using the base_roles.yaml
, the usernames in the RoleBinding
for the
controllers must match the ones used by the certificates.
For instance for the garbage collector, if the RoleBinding
is defined like this:
api: core
kind: RoleBinding
metadata:
name: rolebinding:system:gc
roles:
- role:system:gc
users:
- system:gc
it means that the certificate common name for the garbage collector must be
system:gc
. It is probably easier to adjust the base_roles.yaml
to match your
needs.
Additional roles and role bindings can also be added to the database using the same
bootstrapping method, by modifying the base_roles.yaml
, or by writing another file
and bootstrapping it into the database.
Administrator¶
The role role:system
added in the base_roles.yaml
corresponds to an
administrator role, and the role binding rolebinding:system
allows a user called
system:admin
full access to all Krake resources from all APIs. These two can
naturally be modified if the administrator should have another name.
Important
Note that if no administrator user is created, Role
and RoleBinding
objects
cannot be created through the API, but must be added to the database directly.
CORS¶
The Cross-origin resource sharing (CORS) mechanism was enabled on Krake but the fields
are set to be quite non-restrictive. By default, the Access-Control-Allow-Origin
is
set to *
. With this setup, sending request through a browser could be dangerous. A
user could first connect to a valid website with some allowed authentication token and
send requests to Krake. Then the user goes on a malicious website, which may be able to
reuse the token, as the default value accepts any origin, so any URL. To prevent this
situation, the value for the Access-Control-Allow-Origin
field can be set for the
Krake API, see the Authentication and authorization part of
the configuration.
Developer Documentation¶
This section of the documentation is dedicated to all contributors of the project. It describes the overall system architecture, explains the core concepts of the system and development principles that should be followed when contributing.
Furthermore, the layout of the repository is explained and a complete Python API reference of all modules is provided.
Architecture¶
This chapters gives a high-level overview about the software architecture of Krake. The following figure gives an overview about the components of Krake. The components are described in more detail in the following sections.

Krake components
API¶
The API is the central component of Krake. It holds the global state of the system. Krake uses an abstraction for real world objects – e.g. Kubernetes clusters or clouds (e.g. OpenStack) – managed or used by it. The objects are represented as RESTful HTTP resources called API resources. These resources are stored in an associated etcd database. Each resource is a nested JSON object following some conventions that can be found in section API Conventions.
The API is declarative: instead of sending commands one-by-one to the infrastructure, the user just defines a desired end state, telling the infrastructure exactly how it should look like. Then, the Control Plane works in sync with the infrastructure to find the best way to get there. This means that the actual control flow is not exposed to the user.
Control Plane¶
The control plane is responsible for bringing the declarative API to life: it synchronizes the declared desired state of a API resource with the managed real world object (see also Control Plane on the concepts chapter).
The control plane consists of a set of controllers. Normally, one controller is responsible for one kind of resource, e.g. the Kubernetes Application controller manages Kubernetes Application resources. Only API resources with a changing state are managed by a controller.
System-level tasks are also handled by controllers:
- Garbage Collector
- Resources can depend on other resources. If an API resource is deleted, dependents of the resource are also deleted automatically. This is called cascading deletion. The garbage collector is the controller responsible for executing the cascading deletion (see Garbage Collection for more details).
- Infrastructure Controller
- The infrastructure controller performs life-cycle management of the real-world Kubernetes clusters. (see Infrastructure Controller for more details).
- Scheduler
The scheduler is a very important controller responsible for binding applications – high-level API resources for executing workloads – to a platform managed by Krake.
Tip
For example, the scheduler binds Kubernetes applications to Kubernetes clusters or selects clouds (e.g. OpenStack) for creating new Kubernetes clusters.
The scheduler makes its decision based on a set of metrics provided by external metrics providers (see Scheduling for more details) as well as the availability of the clusters. The decisions are periodically reevaluated, which could potentially lead to migration of applications.
Control Loop¶
The following figure describes the basic control loop that is executed by any controller.

Operator Pattern
The observation of an API resource is done via watching, a long running HTTP request to the API notifying about changes of resources:
$ curl http://localhost:8080/kubernetes/namespaces/testing/applications?watch
{"type": "UPDATED", "object": {"metadata": …, "spec": …, "status": …}}
{"type": "DELETED", "object": {"metadata": …, "spec": …, "status": …}}
{"type": "UPDATED", "object": {"metadata": …, "spec": …, "status": …}}
…
Controller will read this feed, evaluate differences between the desired state and the state of the managed real world object, act accordingly to this difference and update the status of the resource.
Concepts¶
Krake is heavily inspired by the concepts of Kubernetes. If you are familiar with the internal mechanisms of Kubernetes you should find many similarities within Krake.
Overview¶
The central service of Krake is a RESTful HTTP API. The API is structured in
groups of APIs covering different technologies, e.g. core
for the core
functionalities or kubernetes
for Kubernetes-specific features. Each API
comprises multiple kinds of resources, e.g. the kubernetes
API contains
Application or Cluster resources. The resources are used to describe the
desired state. The user can update the desired state by updating the
resource via simple PUT requests to the API.
In concept, every resource is handled by a Controller. The responsibility of a controller is to bring the described desired state of a resource in sync with the real world state. Some of the resources act as mere data bags, e.g. kubernetes/Cluster resources simply describe how to connect to an existing Kubernetes cluster. These resources do not have a corresponding controller because no logic is needed for syncing desired and real world state.
API Conventions¶
Krake uses abstractions for real world resources managed by Krake, e.g. Kubernetes clusters spawned on top of an OpenStack deployment. These abstractions are represented as API resources encoded as nested JSON objects.
Metadata¶
Every resource MUST have the following metadata in a nested field called
metadata
with the following structure:
- namespace
- A namespace is used to isolate access resources. Normally, a user does only get access to a specific namespace. See Authentication and Authorization for more details. This field is immutable which means a resource cannot be migrated to another namespace.
- name
- A string uniquely identifying a resource in its namespace. This name is used in URLs when operating on an individual resource. This field is immutable.
- uid
- A unique string in time and space used to distinguish between objects of the same name that have been deleted and recreated. This field is immutable.
- finalizers
A list of strings that can be added by controllers to block the deletion of the resource in order to do some clean up work (finalizing). A resource MUST not be deleted if there is at least one finalizer.
Controllers SHOULD process only finalizers that were added by them and that are at the tail of the list. This ensures a strict finalizing order.
- created
- The timestamp when the resource was created. This field is immutable.
- modified
- The timestamp when the
spec
ormetadata
field of the resource was changed. - deleted
- The timestamp when the resource was deleted. If this field is set, the
resource is in the in deletion state. This transition is irreversible.
In this state, no changes to the resource are allowed except removing
items from
finalizers
and updating thestatus
. Iffinalizers
is empty and the resource is in deletion it will be removed from the database. See Garbage Collection for more details.
Spec and Status¶
By convention, the Krake API distinguishes between desired state of a
resource – a nested field called spec
– and its real world state – a
nested field called status
.
Every resource representing a real world object managed by Krake SHOULD have
a field called spec
. If the state of the represented object cannot change,
the resource MAY have a spec
field only which MAY be renamed to a more
appropriate name.
etcd¶
Internally, the Krake API uses etcd – a distributed and reliable key-value store – as persistence layer. But this is considered an implementation detail and no etcd-specific mechanisms are exposed via the REST API. This means that the underlying database could be potentially replaced in the future if the requirements of the project change. The “killer” feature of etcd is the watching of keys and prefixes for changes.
Note
The distributed nature of etcd and its built-in support for observing changes for specific keys were the main motivation why Krake switched from a SQL-based persistence layer to etcd.
Control Plane¶
The API does not implement control logic. The task of reconciling between desired state and real world state is done by so-called controllers. Controllers are independent services watching API resources and reacting on changes. The set of all controllers forms the Control Plane of Krake.
Controllers communicate with the API server: the desired state is fetched from the API and status updates are pushed to the API. In theory, controllers can be programmed with any technology (programming language) capable of communicating with a REST HTTP interface.
Note
The first system architecture of Krake was event-based using message queuing (RabbitMQ). The main issue with event-driven systems is that the they get out-of-sync if a message gets lost. Hence, a lot of effort is involved to make sure that no message loss occurs.
On the other hand, level-based logic operates given a desired state and the current observed state. The functionality is resilient against loss of intermediate state updates. Hence, a component can recover easily from crashes and outages, which makes the overall system more robust. This was the motivation for moving from an event-based system with message queuing to a level-based system with reconciliation.
Authentication and Authorization¶
Access to the API is provided through a two-phased process.
- Authentication
- Each request to the Krake API is authenticated. Authentication verifies the identity of the user. There are multiple authentication providers and the API can be extended by further authentication mechanisms. If no identity is provided, the request is considered to be anonymous. For internal communication between controllers and API, TLS certificates SHOULD be used.
- Authorization
After the identity of a user is verified, it needs to be decided if the user has permission to access a resource.
Krake implements a simple but powerful role-based access control (RBAC) model. The
core
API providesRole
resources describing access to specific operations on specific resources potentially in specific namespaces. A user is assigned to a role by anothercore
resource calledRoleBinding
.Roles in Krake are permissive only. There is no way to deny access to a resource through a role. At least one role a user is bound to needs to allow access to the requested resource and operation. Otherwise access is denied.
Directories¶
The Krake repository contains several main directories, which will be described here.
- ansible
- Contains all the configuration and the playbooks to install Krake using Ansible.
- docker
- Contains all file to start Krake in a Docker infrastructure.
- docs
- Contains the source files for Krake documentation.
- infra
- Contains scripts to deploy Krake. Not up-to-date.
- krake
- Contains the source code and the unit tests for the Krake application. More details are given in the Krake Reference.
- rok
- Contains the source code and the unit tests for the Rok command. More details are given in the Rok Reference.
- support
- Contains the utility scripts to create a simple local test environment.
Design Principles¶
This section contains a number of principles that should be followed when extending Krake. The principles are very similar to the Kubernetes design principles.
API¶
See also API Conventions.
All APIs should be declarative.
API resources should be complementary and composable, not opaque wrappers.
Note
For example, a Kubernetes cluster could be created on top of a managed OpenStack project.
The control plane should be transparent – there are no hidden internal APIs.
Resource status must be completely reconstructable by observation. Any history kept (caching) must be just an optimization and not required for correct operation.
Control Logic¶
Functionality must be level-based, meaning the system must operate correctly given the desired state and the current/observed state, regardless of how many intermediate state updates may have been missed. Event/Edge-triggered behavior must be just an optimization.
Note
There should be a CAP-like theorem regarding the trade-offs between driving control loops via polling or events about simultaneously achieving high performance, reliability, and simplicity – pick any two.
Assume an open world: continually verify assumptions and gracefully adapt to external events and/or actors.
Tip
For example, Krake allows users to kill Kubernetes resources under control of a Kubernetes application controller; the controller just replaces the killed resource.
Do not assume any state transition or state that cannot be determined by observation.
Do not assume a component’s decisions will not be overridden or rejected, nor for the component to always understand why.
Tip
For example, etcd may reject writes. The scheduler may not be able to schedule applications. A Kubernetes cluster may reject requests.
Retry, but back off and/or make alternative decisions.
Components should be self-healing.
Tip
For example, if some state must be kept, e.g. cached, the content needs to be periodically refreshed, so that if an item does get incorrectly stored or a deletion event is missed, the kept state will be soon synchronized, ideally on timescales that are shorter than what will attract attention from humans.
Component behavior should degrade gracefully. Actions should be prioritized such that the most important activities can continue to function even when overloaded and/or in states of partial failure.
Architecture¶
- Only the API server communicate with etcd, and no other components, e.g. scheduler, garbage collector, etc.
- Components should continue to do what they were last told in the absence of new instructions, e.g. due to network partition or component outage.
- All components should keep all relevant state in memory all the time. The API server writes through to etcd, other components write through to the API server, and they watch for updates made by other clients.
- Watch is preferred over polling.
Extensibility¶
All components should be replaceable. This means there is no strong coupling between components.
Tip
For example, the different scheduler should be usable without any changes in another component.
Krake is extended with new technologies/platforms by adding new APIs.
Availability¶
Note
High-availability (HA) is about removing single point of failure (SPOF).
- HA is achieved by service replication.
Todo
It needs to be decided on which level replication is introduced.
- Coarse grained
- Replicate “Krake master” with all included components, e.g. API server, controllers etc.
- Fine grained
- Replicate single components. If a component is stateful – relevant state should be kept in memory as stated in section Architecture – the components should follow an active-passive principle where only one replica of a component is active at the same time. A etcd lease may be a good option for this but only the API should have direct access to etcd. A solution for this would be to introduce special API endpoints for electing a leader across multiple replicas.
Development¶
- Self-hosting of all components is the goal.
- Use standard tooling and de facto standards of the Python ecosystem.
- Keep dependencies as small as possible, but do not reinvent the wheel.
Scheduling¶
This part of the documentation presents the Krake scheduling component and how the Krake resources are handled by the scheduling algorithm.
The Krake scheduler is a standalone controller that processes the following Krake resources:
- Application
- Cluster
- Magnum cluster (Warning: Due to stability and development issues on the side of Magnum, this feature isn’t actively developed anymore.)
The scheduler algorithm selects the “best” backend for each resource based on metrics of the backends and the resource’s constraints and specifications. The following sections describe the application and Magnum cluster handlers of the Krake scheduler.
Application handler¶
The application handler is responsible for scheduling and rescheduling (automatic migration) of the applications with non-deleted and non-failed states. Applications with deleted or failed state are omitted from the scheduling. Currently, the application handler considers every Kubernetes cluster.
Scheduling of Applications¶
At first, the scheduler checks, if the clusters that will be considered and filtered to host the application, are even ONLINE. If a cluster isn’t reachable, it is not considered in the scheduling process.
The application handler evaluates if all constraints of an application match the available Kubernetes cluster resources. The application constraints define restrictions for the scheduling algorithm. Currently, the custom resources constraint, the cluster label constraint and the metric constraint are supported, see Constraints. This is a first filtering step.
Selected Kubernetes clusters could contain metrics definition. If the cluster contains metrics definition, the application handler fetches metric values from the corresponding metrics providers which should be defined in the metric resource specification, see Metrics and Metrics Providers.
Then, the score for each Kubernetes cluster resource is computed. The cluster score is represented by a decimal number and is computed from Kubernetes cluster stickiness and metric values and weights. More information on stickiness in the Stickiness section. The Kubernetes clusters with defined metrics are preferred. It means clusters which are not linked to any metric have a lower priority than the ones with linked metrics:
- If there are no cluster with metrics: the score is only computed using the stickiness;
- If there are clusters with metrics: the clusters without metrics are filtered out and the scores of the ones with metrics are computed and compared.
This step is a ranking step.
The score formula for a cluster without metrics is defined as follows:
\[score = sticky_{value} \cdot sticky_{weight}\]The score formula for a cluster with n metrics is defined as follows:
\[score = \frac{(sticky_{value} \cdot sticky_{weight}) + \sum\limits_{i=1}^n metric_{value_i} \cdot metric_{weight_i}} {sticky_{weight} + \sum\limits_{i=1}^n metric_{weight_i}}\]
The application is scheduled to the cluster with the highest score. If several clusters have the same score, one of them is chosen randomly.
Rescheduling (automatic migration) of Applications¶
- Applications that were already scheduled are put in the scheduler controller queue again, to be rescheduled later on. Applications will go through the scheduling process again after a certain interval, which is defined globally in the scheduler configuration file, see Configuration (defaults to 60s). This parameter is called reschedule_after. It allows an application to be rescheduled to a more suitable cluster if a better one is found.
Stickiness¶
Stickiness is an extra metric for clusters to make the application “stick” to it by increasing its score. Stickiness extra metric is defined by its value and configurable weight. It represents the cost of migration of an Application, as it is added to the score of the cluster on which the Application is currently running.
If the value is high, no migration will be performed, as the updated score of the current cluster of the Application will be too high compared to the score of the other clusters. If this value is too low, or if this mechanism was not present, any application could be migrated from just the slightest change in the clusters score, which could be induced by small changes in the metrics value. Thus the stickiness acts as a threshold: the changes in the metrics values has to be higher than this value to trigger a rescheduling.
The stickiness weight is defined globally in the scheduler configuration file, see Configuration (defaults to 0.1). If the application is already scheduled to the passed cluster, a cluster stickiness is 1.0 multiplied by the weight, otherwise 0.
Application Handler’s workflow:¶
The following figure gives an overview about the application handler of Krake scheduler.

Special note on updates:¶
kube_controller_triggered:¶
This timestamp is used as a flag to trigger the Kubernetes Controller reconciliation.
Together with modified
, it’s allowing correct synchronization between Scheduler and
Controller.
It is updated when the chosen Cluster
has changed, or once after the update of an
Application triggered its rescheduling, even if this did not change the scheduled
cluster. The second case mostly occurs when a user updates it through the API.
This timestamp is used to force an Application
that has been updated by a user to be
rescheduled before the changes are applied by the Kubernetes Controller. Without this
mechanism, the Application
may be updated, but rescheduled somewhere else
afterwards.
The actual workflow is the same as the one explained in the schema above. However, there is an additional interaction with the Kubernetes Controller:
The user updates the
Application
my-app
on the API:my-app
’smodified
timestamp is higher than thekube_controller_triggered
timestamp;The Kubernetes Controller rejects the update on
my-app
in this case;The Scheduler accepts the update on
my-app
and chooses a cluster for the updatedmy-app
;as the cluster changed, the
kube_controller_triggered
timestamp is updated;my-app
’smodified
timestamp is lower than thekube_controller_triggered
timestamp;the updated
my-app
is rejected by the Scheduler because of this comparison;the updated
my-app
is accepted by the Kubernetes Controller;the actual updates of the
Application
are performed by the Kubernetes Controller if needed.
When the Application is rescheduled, if the selected cluster did not change, then the
kube_controller_triggered
timestamp is updated only if the rescheduling was
triggered by an update of the Application. If the Application is rescheduled on the same
cluster automatically, then the timestamp is not updated. This prevents an update of
each Application on each automatic rescheduling, which would need to be handled by the
Kubernetes controller.
To sum up, the kube_controller_triggered
timestamp represent the last time this
version of the Application was scheduled by the Scheduler.
scheduled:¶
The scheduled
timestamp expresses the last time the scheduling decision changed for
the current resource. This timestamp does not correspond to the time where the
Application was deployed on the new cluster, just the time where the scheduler updated,
on the Application, the reference to the cluster where it should be deployed. It is
actually updated during a call from the scheduler to the API to change the binding of
the Application.
This timestamp is however not updated if an update of its Application did not lead to a rescheduling, just a re-deployment.
Cluster handler¶
The Cluster handler is responsible for scheduling Kubernetes Clusters to the best cloud backend (currently Krake supports OpenStack as a cloud backend). The Cluster handler should process only Clusters that are not bound to any Cloud, have non-deleted/non-failed state and also the Clusters should not contain the kubeconfig file in their spec. If the Cluster contains the kubeconfig file in its spec it is considered as an existing cluster which was registered or created by Krake and therefore should be ignored by the Cluster handler.
Scheduling of Clusters¶
The Cluster handler evaluates if all the constraints of a Cluster match the available cloud resources. The Cluster constraints define restrictions for the scheduling algorithm. Currently, Cloud label and metrics constraints are supported, see Constraints.
If the selected Cloud resources contain metric definitions, the Cluster handler fetches metric values from the corresponding metrics providers which should be defined in the metric resource specifications, see Metrics and Metrics Providers.
Then, the score for each Cloud resource is computed. The Cloud score is represented by a decimal number and is computed from metric values and weights. If a given Cloud does not contain any metric definition, its score is set to 0. Therefore, the Clouds with defined metrics are preferred:
- If there are no Clouds with metrics: the score is 0 for all Clouds.
- If there are Clouds with metrics: the Clouds without metrics are filtered out and the scores of the ones with metrics are computed and compared.
This step is a ranking step.
The score formula for a Cloud without metrics is defined as follows:
\[score = 0\]The score formula for a Cloud with n metrics is defined as follows:
\[score = \frac{\sum\limits_{i=1}^n metric_{value_i} \cdot metric_{weight_i}} {\sum\limits_{i=1}^n metric_{weight_i}}\]
The Cluster is scheduled to the Cloud with the highest score. If several Clouds have the same score, one of them is chosen randomly.
The following figure gives an overview about the Cluster handler of the Krake scheduler.

Magnum cluster handler¶
Warning
Due to stability and development issues on the side of Magnum, this feature isn’t actively developed anymore.
The Magnum cluster handler is responsible for scheduling Magnum clusters to the best OpenStack project. The Magnum cluster handler should process only Magnum clusters that are not bound to any OpenStack project and have non-deleted state. Currently, the Magnum cluster handler considers every OpenStack project.
Scheduling of Magnum clusters¶
The Magnum cluster handler evaluates if all the constraints of a Magnum cluster match the available OpenStack project resources. The Magnum cluster constraints define restrictions for the scheduling algorithm. Currently, only the OpenStack project label constraints are supported, see Constraints. This is a first filtering step.
Selected OpenStack project resources could contain metric definitions. If the OpenStack project contains metrics definition, the Magnum cluster handler fetches metric values from the corresponding metrics providers which should be defined in the metric resource specifications, see Metrics and Metrics Providers.
Then, the score for each OpenStack project resource is computed. The OpenStack project score is represented by a decimal number and is computed from metric values and weights. If a given OpenStack project does not contain metric definition, its score is set to 0. Therefore, the OpenStack projects with defined metrics are preferred:
- If there are no project with metrics: the score is 0 for all projects;
- If there are projects with metrics: the projects without metrics are filtered out and the scores of the ones with metrics are computed and compared.
This step is a ranking step.
The score formula for a OpenStack project without metrics is defined as follows:
\[score = 0\]The score formula for a OpenStack project with n metrics is defined as follows:
\[score = \frac{\sum\limits_{i=1}^n metric_{value_i} \cdot metric_{weight_i}} {\sum\limits_{i=1}^n metric_{weight_i}}\]
The Magnum cluster is scheduled to the OpenStack project with the highest score. If several OpenStack projects have the same score, one of them is chosen randomly.
The following figure gives an overview about the Magnum cluster handler of Krake scheduler. “OS project” means “OpenStack project resource” on the figure.

Metrics and Metrics Providers¶
Overview¶
Warning
Due to stability and development issues on the side of Magnum, this feature isn’t actively developed anymore.
This section describes the metrics and their providers used in the Krake scheduling algorithm.
The Krake scheduler filters backends based on defined backend metrics. The appropriate metrics definition can prioritize the backend as a potential destination for a given resource.
Krake provides two kinds of Metrics and MetricsProviders. GlobalMetric
as well as
the GlobalMetricsProvider
can be used throughout the entire Krake infrastructure by
all users, apps and clusters. In contrast, the Metric
and MetricsProvider
object
are bound to a namespace (hence why they’re called ‘namespaced’) and can only be used in
their respective context. In most of the documentation chapters, only GlobalMetrics
are talked about, but namespaced Metrics
can also be used to follow these sections.
The metrics for the Kubernetes clusters, Magnum clusters and OpenStack projects
resources are defined by the -m
or --metric
option in the rok CLI, see
Rok documentation. Multiple metrics can be specified for
one resource with the following syntax: <name> <weight>.
Examples:
# Kubernetes clusters:
rok kube cluster create <kubeconfig> --metric heat_demand_zone_1 0.45
# Magnum clusters:
rok os cluster create <cluster_name> --metric heat_demand_zone_1 54
# OpenStack projects:
rok os project create --user-id $OS_USER_ID --template $TEMPLATE_ID my-project --metric heat_demand_zone_1 3
By design, the general Krake metric resource (called GlobalMetric
) is a core api
object, that contains its value normalization interval (min, max) and metrics provider
name, from which the metric current value should be requested. For the moment, Krake
supports the following types of metrics providers:
- Prometheus metrics provider, which can be used to fetch the current value of a metric from a Prometheus server;
- Kafka metrics provider, which can be used to fetch the current value of a metric from a KSQL database;
- Static metrics provider, which returns always the same value when a metric is fetched. Different metrics can be configured to be given by a Static provider, each with their respective value. The static provider was mostly designed for testing purposes.
The metrics provider is defined as a core api resource (called
GlobalMetricsProvider
) that stores the access information for the case of a
Prometheus metrics provider, or the metrics values for the case of a Static
metrics provider.
Example¶
api: core
kind: GlobalMetric
metadata:
name: heat_demand_zone_1 # name as stored in Krake API (for management purposes)
spec:
max: 5.0
min: 0.0
provider:
metric: heat_demand_zone_1 # name on the provider
name: <metrics provider name> # for instance prometheus or static_provider
---
# Prometheus metrics provider
api: core
kind: GlobalMetricsProvider
metadata:
name: prometheus_provider
spec:
type: prometheus # specify here the type of metrics provider
prometheus:
url: http://localhost:9090
---
# Kafka metrics provider
api: core
kind: GlobalMetricsProvider
metadata:
name: kafka_provider
spec:
type: kafka
kafka:
comparison_column: my_comp_col # Name of the column where the metrics names are stored
table: my_table # Name of the table in which the metrics are stored
url: http://localhost:8080
value_column: my_value_col # Name of the column where the metrics values are stored
---
# Static metrics provider
api: core
kind: GlobalMetricsProvider
metadata:
name: static_provider
spec:
type: static # specify here the type of metrics provider
static:
metrics:
heat_demand_zone_1: 0.9
electricity_cost_1: 0.1
In the example above, all metrics providers could be used to fetch the
heat_demand_zone_1
metric. By specifying a name in spec.provider.name
of the
GlobalMetric
resource, the value would be fetched from a different provider:
prometheus_provider
for the Prometheus provider;kafka_provider
for the Kafka provider;static_provider
for the Static provider (and the metric would always have the value0.9
).
Note
A metric contains two “names”, but they can be different. metadata.name
is the
name of the GlobalMetric resource as stored by the Krake API. In the database,
there can not be two resources of the same kind with the exact same name.
However (if we take for instance the case of Prometheus), two metrics, taken from
two different Prometheus servers could have the exact same name. This name is given
by spec.provider.metric
.
So two Krake GlobalMetric`s resources could be called ``latency_from_A` and
latency_from_B
in the database, but their name could
be latency
in both Prometheus servers.
The Krake metrics and metrics providers definitions can also be added directly to the Krake etcd database using the script krake_bootstrap_db, instead of using the API, see Bootstrapping.
Constraints¶
This section describes the resource constraints definition used in the Krake scheduling algorithm.
The Krake scheduler filters appropriate backends based on defined resource constraints. A backend can be accepted by the scheduler as a potential destination for a given resource only if it matches all defined resource constraints.
The Krake scheduler supports the following resource constraints:
- Label constraints
- Metric constraints
- Custom resources constraints
The Krake users are allowed to define these restrictions for the scheduling algorithm of Krake.
The following sections describe the supported constraints of the Krake scheduler in more detail.
Label constraints¶
Krake allows the user to define a label constraint and to restrict the deployment of resources only to backends that matches all defined labels. Based on the resource, Krake supports the following label constraints:
- The Cluster label constraints for the Application resource
- The Cloud label constraints for the Cluster resource
- The OpenStack project label constraints for the Magnum Cluster resource (Warning: Due to stability and development issues on the side of Magnum, this feature isn’t actively developed anymore.)
A simple language for expressing label constraints is used. The following operations can be expressed:
- equality
The value of a label must be equal to a specific value:
<label> is <value> <label> = <value> <label> == <value>- non-equality
The value of a label must not be equal to a specific value:
<label> is not <value> <label> != <value>- inclusion
The value of a label must be inside a set of values:
<label> in (<value>, <value>, ...)- exclusion
The value of a label must not be inside a set of values:
<label> not in (<value>, <value>, ...)
The Cluster label constraints for the Application and Cluster resources
are defined by -L
(or --cluster-label-constraint
, --cloud-label-constraint
) option in the
rok CLI, see Rok documentation. The constraints can be
specified multiple times with the syntax: <label> expression <value>.
Examples:
# Application
rok kube app create <application_name> -f <path_to_manifest> -L 'location is DE'
# Cluster:
rok kube cluster create <cluster_name> -f <path_to_tosca> -L 'location is DE' ...
Metric constraints¶
Krake allows the user to define a metric constraint and to restrict the deployment of resources only to backends that matches the metric constraint. Based on the resource, Krake supports the following metric constraints:
- The Cluster metric constraints for the Application resource
- The Cloud metric constraints for the Cluster resource
A simple language for expressing metric constraints is used. The following operations can be expressed:
- equality
The value of a label must be equal to a specific value:
<metric> is <value> <metric> = <value> <metric> == <value>- non-equality
The value of a metric must not be equal to a specific value:
<metric> is not <value> <metric> != <value>- greater than
The value of a metric must be greater than a specific value:
<metric> greater than <value> <metric> gt <value> <metric> > <value>- greater than or equal
The value of a metric must be greater or equal than a specific value:
<metric> greater than or equal <value> <metric> gte <value> <metric> >= <value> <metric> => <value>- less than
The value of a metric must be less than a specific value:
<metric> less than <value> <metric> lt <value> <metric> < <value>- less than or equal
The value of a metric must be less or equal than a specific value:
<metric> less than or equal <value> <metric> lte <value> <metric> <= <value> <metric> =< <value>
The metric label constraints for the Application and Cluster resources are defined
by -M
(or --cluster-metric-constraint
, --cloud-metric-constraint
) option in the rok CLI,
see Rok documentation. The constraints can be
specified multiple times with the syntax: <metric> expression <value>.
Examples:
# Application
rok kube app create <application_name> -f <path_to_manifest> -M 'load = 5'
# Cluster
rok kube cluster create <cluster_name> -f <path_to_tosca> -M 'load = 5' ...
Custom resources:¶
Krake allows the user to deploy an application that uses Kubernetes Custom Resources (CR).
The user can define which CRs are available on his cluster. A CR is defined
by the Custom Resource Definition (CRD) and Krake uses this CRD name with the format
<plural>.<group>
as a marker.
The supported CRD names are defined by -R
or --custom-resource
option in rok
CLI. See also Rok documentation.
Example:
rok kube cluster create <kubeconfig> --custom-resource <plural>.<group>
Applications that are based on a CR have to be explicitly labeled with a cluster resource constraint. This is used in the Krake scheduling algorithm to select an appropriate cluster where the CR is supported.
Cluster resource constraints are defined by a CRD name with the
format <plural>.<group>
using -R
or --cluster-resource-constraint
option in
rok CLI. See also Rok documentation.
Example:
rok kube app create <application_name> -f <path_to_manifest> --cluster-resource-constraint <plural>.<group>
Application hooks¶
This section describes Application hooks which are registered and called by the Hook Dispatcher in kubernetes application controller module.
Complete¶
The application complete hook gives the ability to signals job completion.
The Krake Kubernetes controller calls the application complete
hook before the deployment of the application on a Kubernetes
cluster. The hook is disabled by default. The user can enable this hook with the
--hook-complete
argument in rok CLI.
See also Rok documentation.
The complete hook injects the KRAKE_COMPLETE_TOKEN
environment variable, which stores the
Krake authentication token, and the KRAKE_COMPLETE_URL
environment variable, which
stores the Krake complete hook URL for a given application.
By default, this URL is the Krake API endpoint as specified in the Kubernetes Controller
configuration. This endpoint may be only internal and thus not accessible by an
application that runs on a cluster. Thus, the external_endpoint
parameter can be
leveraged. It specifies an endpoint of the Krake API, which can be accessed by the
application. The endpoint is only overridden if the external_endpoint
parameter is set.
Applications signal the job completion by calling the complete hook URL. The token is used for authentication and should be sent in a PUT request body.
Shutdown¶
The application shutdown hook gives the ability to gracefully stop an application before a migration or deletion happens. This in turn allows to save data or bring other important processes to a safe conclusion.
The Krake Kubernetes controller calls the application shutdown
hook before the deployment of the application on a Kubernetes
cluster. The hook is disabled by default. The user can enable this hook with the
--hook-shutdown
argument in rok CLI.
See also Rok documentation.
The shutdown hook injects the KRAKE_SHUTDOWN_TOKEN
and the KRAKE_SHUTDOWN_URL
environment variables, which respectively store the Krake authentication token and the
Krake shutdown hook URL for a given application.
By default, this URL is the Krake API endpoint as specified in the Kubernetes Controller
configuration. This endpoint may be only internal and thus not accessible by an
application that runs on a cluster. Thus, the external_endpoint
parameter can be
leveraged. It specifies an endpoint of the Krake API, which can be accessed by the
application. The endpoint is only overridden if the external_endpoint
parameter is set.
If the application should be migrated or deleted, Krake calls the shutdown
services
URL, which is set via the manifest file of the application.
The integrated service gracefully shuts down the application, preferably via SIGTERM
call, but the exact implementation is up to the individual developer.
After the shutdown process is complete, the service sends a completion signal
to the shutdown hook endpoint of the specific application on the Krake API.
The previously set token is used for authentication and should be sent in a PUT
request body. This requirement prevents the malicious or unintentional deletion of an
application. The workflow of this process can be seen in the following figure:

Shutdown hook workflow in Krake
The shutdown hook was developed especially to enable stateful applications. Since these services generate data or are in specific states, it was difficult to migrate or even delete these applications without disrupting their workflow. The shutdown hook enables these normal Krake features for these applications by allowing saving of the current state. But be aware, that Krake doesn’t implement a specific graceful shutdown for these applications and merely gives them a possibility to be informed about the intentions of Krake.
TLS¶
If TLS is enabled on the Krake API, both hooks need to be authenticated with some certificates signed directly or indirectly by the Krake CA. For that purpose, the hooks inject a Kubernetes ConfigMap for different files and mounts it in a volume:
ca-bundle.pem
- It contains the CA certificate of Krake, and the hook certificate that was used to sign the certificate specific to the Application.
cert.pem
- The certificate signed by the hook. It is generated automatically for each Application. Its CN is set to the hooks user defined in the hook configuration, see Krake configuration.
key.pem
- The key of the certificate signed by the hook. It is generated automatically for each Application.
The certificate added are signed by a specific certificate, defined by the
intermediate_src
field in the configuration
Kubernetes application controller. This certificate needs the
following:
- able to sign other certificates;
- hold the right alternative names to accept the Krake endpoint.
The ConfigMap is mounted by default at: /etc/krake_ca/cert.pem
in the Kubernetes
Deployment resources of the Applications.
The name of the environment variables and the directory where the ConfigMap is mounted are defined in the Kubernetes controller configuration file, see Krake configuration.
Examples¶
cURL¶
Example using cURL:
$ curl -X PUT -d "{\"token\":\"$KRAKE_COMPLETE_TOKEN\"}" $KRAKE_COMPLETE_URL
# If TLS is enabled on the Krake API
$ curl -X PUT -d "{\"token\":\"$KRAKE_COMPLETE_TOKEN\"}" $KRAKE_COMPLETE_URL \
--cacert /etc/krake_cert/ca-bundle.pem \
--cert /etc/krake_cert/cert.pem \
--key /etc/krake_cert/key.pem
By running this command, the Krake API will compare the given token to the one in its database, and if they match, will set the Application to be deleted.
The cURL above may not work with older versions of cURL. You should use versions >= 7.51, otherwise you would get:
curl: (35) gnutls_handshake() failed: The TLS connection was non-properly terminated.
Python requests¶
Example using Python’s requests module:
If TLS is not enabled:
import requests
import os
endpoint = os.getenv("KRAKE_COMPLETE_URL")
token = os.getenv("KRAKE_COMPLETE_TOKEN")
requests.put(endpoint, json={"token": token})
If TLS is enabled, using the default configuration for the certificate directory:
import requests
import os
ca_bundle = "/etc/krake_cert/ca-bundle.pem"
cert_path = "/etc/krake_cert/cert.pem"
key_path = "/etc/krake_cert/key.pem"
cert_and_key = (cert_path, key_path)
endpoint = os.getenv("KRAKE_COMPLETE_URL")
token = os.getenv("KRAKE_COMPLETE_TOKEN")
requests.put(endpoint, verify=ca_bundle, json={"token": token}, cert=cert_and_key)
Kubernetes Application Controller¶
Reconciliation loop¶
In the following section, we describe what happens in the Kubernetes Application controller when receiving a resource, and highlight the role of the observer schema.
In this example, the user provides:
- Two resources (one
Song
and oneArtist
) that should be created. This is provided inspec.manifest
. - A custom observer schema for the
Song
. This is provided inspec.observer_schema
The first resource (Song
) illustrates the use of a custom observer schema
and demonstrates the behavior of list length control. The second resource
(Artist
) highlights the generation of a default observer schema and the
special case of mangled resources.

Step 0 (Optional)¶
If the resource is defined by the TOSCA template file, an URL or a CSAR archive URL, the controller translates the given TOSCA or CSAR file to the Kubernetes manifest file if possible, see TOSCA.
The result of translation is stored in spec.manifest
.
This step is performed by the ApplicationToscaTranslation
hook.
Step 1¶
First, the controller generates the default observer schema for resources,
where none have been provided. In our example, a default observer schema is
created for the Artist
, while the custom observer schema provided by the
user for the Song
is used as-is.
The result is stored in status.mangled_observer_schema
.
This step is performed by the generate_default_observer_schema
function.
Step 2¶
In this step, the controller initializes - or updates if previously
initialized - the status.last_applied_manifest
. This attribute represents
the desired state (i.e. which values should be set for which fields).
If empty (i.e. during the first reconciliation of the resource), it is
initialized as a copy of spec.manifest
. The
status.last_applied_manifest
might be augmented at a later step by
non-initialized observed fields (see Step 6). As a result, if this field has
already been initialized (i.e. during later reconciliation), this step
updates the observed fields present in spec.manifest
.
This the role of the update_last_applied_manifest_from_spec
function.
In the example above, looking at the Song
resource:
key1
is initialized inspec.manifest
and is observed.key2
is initialized inspec.manifest
but is not observed. Its initial value is copied to thestatus.last_applied_manifest
, so that the Kubernetes resource can be created using this value. But as it’s not observed, its value instatus.last_applied_manifest
will never be updated (see Step 6).key3
is observed but is not set inspec.manifest
. Its value instatus.last_applied_manifest
is initialized as part of the Step 6 (see below).
Step 3¶
When an application is mangled, for instance if the Complete Hook has been
enabled for the application, some fields or resources are added to
status.last_applied_manifest
. They should also be observed, so there are
added to status.mangled_observer_schema
.
This steps is performed in the mangle_app
method of the Complete
class.
In the example above, the Artist
resource is mangled. The key
spec.nickname
is added to both spec.last_applied_manifest
and
mangled_observer_schema
.
Step 4¶
The controller compares the desired state
(status.last_applied_manifest
) and the current state (represented in
status.last_observed_manifest
). It creates a set of new
, updated
and deleted
resource, to be used in the next step:
- new
resources are present in the desired state but not in
the current state; they need to be created on the cluster.
updated
resources have a different definition in the desired and in the current state; they need to be updated on the cluster.deleted
resources are not in the desired state anymore, but are in the current state; they need to be deleted from the cluster.
During the first reconciliation of the application, the current state is empty. All resources present in the desired state needs to be created.
This steps occurs in ResourceDelta.calculate()
function.
Note
In order to calculate the “diff” between the desired state and the current state of a resource, the controller: - compares the value of the observed fields only. By definition, the
controller should not act if a non-observed fields value changes.
- checks if the lengths of lists are valid using the list control dictionary.
Step 5¶
The controller acts on the result of the comparison by either creating, patching, or deleting resources on the cluster. In particular:
- A resource is created using the whole
status.last_applied_manifest
. This ensures that all initialized fields (set by the user inspec.manifest
), are set on the selected cluster, regardless of whether they are observed. In the example above, this is especially the case forkey2
in theSong
. - Only the observed fields of a resource are used in order to patch that resource.
In other words, the non-observed initialized fields (i.e. set by the user in
spec.manifest
, however not in spec.observer_schema
):
- are used for the creation of the resource.
- are not used for patching the resource.
This reflects the fact that if a non-observed fields value changes on the Kubernetes cluster, this update should not be reverted by the Kubernetes Application controller, while providing the user with the ability to set the initial value of a non-observed field.
Step 6¶
Using the Kubernetes response, the status.last_applied_manifest
is
updated. It is augmented with observed fields which value was not yet known.
In the example above, this is the case of key3
in the Song
. It is
observed (present in spec.observer_schema
) but not initialized
(not present in spec.manifest
). Its value in
status.last_applied_manifest
couldn’t be initialized during Step 2. Its
value is initialized using the Kubernetes response.
This mechanism provides the user with the ability to request a specific field to remain constant, while not providing an initial value for it. It uses the value set initially by the Kubernetes cluster on resource creation.
This task is performed by the hook update_last_applied_manifest_from_resp
.
Note
Only the observed which are not yet known are added to
status.last_applied_manifest
.
In the unlikely event where a field, which value is already known, has a
different value in the Kubernetes response (for instance if key1
would have a different value in the Kubernetes response), this value is
not updated in status.last_applied_manifest
. The user’s input
prevails in the definition of the desired state, represented by
status.last_applied_manifest
.
Note
The rythms
list possess two elements in the Kubernetes API response.
As only the first element is observed, the value of the second element is
not saved in status.last_applied_manifest
.
Step 7¶
Similarly, the status.last_observed_manifest
also needs to be updated in
order to reflect the current state. It holds all observed fields which
are present in the Kubernetes response.
This task is performed by the hook
update_last_observed_manifest_from_resp
.
Kubernetes Application Observer¶
Krake employs self-healing processes on its resources while running. A reconciliation is done on each resource whose status deviates from its specifications. This can happen if a resource has been modified manually, attacked, or if any anomaly occurred on the actual resource that the Krake resource describes.
Reconciliation¶
Overview¶
The reconciliation is the act of bringing the current state of a resource to its desired state. During the course of its life, the real-life pendant of a Krake resource may be updated, and thus differ from the desired state (user-defined). To correct this, Krake performs a reconciliation, and the actual state is “replaced” by the desired state. The Krake Controllers are responsible for actually doing the reconciliation over the resources they manage.
The reconciliation is based on two fields of a resource data structure:
- spec
The specifications of a resource are stored in this attribute. It corresponds to the desired state of this resource.
It has the following properties:
- set and/or updated by the user;
- should not be modified by the Krake controllers, but nothing restricts it (should be limited using RBAC, see Security principles).
- status
The current status of the resource as seen in the real-world are stored in this attribute.
It has the following properties:
- should not be modified by the user, but nothing restricts it (should be limited using RBAC, see Security principles);
- set and/or updated by the Krake controllers.
Important
Resources must have a spec
AND a status
attribute to be reconciled.
Reconciliation loop¶
The actual reconciliation is done infinitely, during the so-called reconciliation loop. This loop is not necessarily an in-code loop, and can be more of a conceptual loop between different components.
This workflow in Krake for a specific resource is presented on the following figure:

Reconciliation loop in Krake
The workflow is as follows:
- The resource is created on the API;
- The actual resource is created by the Controller in the real-world;
- The Controller responsible for this resources watches, or observes its current state in the real-world. This is the role of the Observer;
- This current state is compared to the
status
, stored internally on the Observer; - If the actual state is the same as the
status
of the resource, as stored in the Observer, nothing happens. This workflow is started again from step 3 onwards after a defined time period; - If the actual state is different from the
status
of the resource, it means that the actual resource was modified in the real-world; - The Observer notifies the API, by updating the
status
field of the resource; - The Controller receives the up-to-date version of the resource, and performs the reconciliation, by applying the desired state on the actual resource;
- The workflow starts again from step 3.
Warning
For the moment, Krake only implements reconciliation loop for the Krake
Application
resources of the Kubernetes
API.
Kubernetes Application Observer¶
The Krake applications of the Kubernetes
API have a dedicated
KubernetesApplicationObserver. For each application which has some actual resources on a
cluster, an observer is created. This KubernetesApplicationObserver watches the status
of all Kubernetes resources present in the application specification.
For instance, the nginx
application has a Kubernetes Deployment
and a
Service
. If a user changes the image version of the container in the Deployment
or a label in the Service
, this will be detected by the Kubernetes application
Observer. It will update the status
of the application and the Kubernetes Controller
will observe a deviation with the spec
and update the actual Deployment
and
Service
accordingly.
The list of fields which are observed by the Kubernetes application observer can be controlled by specifying a Custom Observer Schema.
This observer schema uses the two fields last_applied_manifest
and
last_observed_manifest
, both of which can be found in app.status
.
last_applied_manifest
contains the information about the latest applied data,
which the application should currently be running on. last_observed_manifest
on the other hand contains information about the latest observed manifest state of this
application. By comparing both datasets, the differences between the desired and
observed status can be determined and the corresponding parts can be created, updated or
deleted.
The actual workflow of the Kubernetes Application Observer is as follow:

Sequence diagram of the Kubernetes Application Observer lifecycle
Summary¶
Creation¶
After an Application’s resources are created, a Kubernetes Application Observer is also created for this specific Application.
Update¶
Before the Kubernetes resources defined in an Application are updated, its
corresponding Kubernetes Application Observer is stopped. After the update has been
performed, a new observer is started, which observes the newest status
of the
Application (the actual Kubernetes resources).
Deletion¶
Before the Kubernetes resources of an Application are deleted, its corresponding KubernetesApplicationObserver is stopped.
Actions on the API side (summary)¶
Action | Observer stopped before | Observer started after |
---|---|---|
Create | No | Yes |
Update | Yes | Yes |
Delete | Yes | No |
On status change¶
The KubernetesApplicationObserver periodically checks the current state of its
Application. The status is read and compared to the status
field of the Application.
If a Kubernetes resource of the Application changed on its cluster, the
KubernetesApplicationObserver sends an update request to the API, to change its
status
field. This field is updated to match what the Observer fetched from the
cluster.
Then the Kubernetes Controller starts processing the update normally: a discrepancy is
found between the desired state (spec
) and the current one (status
). Thus the
controller reacts and bring back the current state to match the desired one, by
reconciliation. As an update is performed, the observer is stopped before and started
after this reconciliation.
After the reconciliation, the status
field of the Application follows now the
desired state. The Kubernetes Application Observer observes this state to check for any
divergence.
Warning
If another resource is added manually (not through Krake) to a cluster managed by Krake, Krake will not be aware of it, and no management of this resource will be performed: no migration, self-healing, updates, etc.
Kubernetes Cluster Controller¶
The Kubernetes Cluster Controller manages and monitors Kubernetes clusters registered in Krake or created by Krake. To do this for each Kubernetes cluster registered or created by Krake, an observer is created. This observer directly calls the Kubernetes API of the specific cluster and checks on its current state. The Kubernetes cluster controller then updates the internally stored state of the registered or created Kubernetes cluster according to the response from the Kubernetes cluster observer.
The Kubernetes Cluster Controller is launched separately.
Note
Since this is a relatively new implementation, the Kubernetes Cluster Controller will certainly be extended by additional features and functionalities in the future.
For more information on what the Kubernetes Cluster Observer does and what features it offers, see Kubernetes Cluster Observer.
For more information about the actual Kubernetes cluster creation by Krake please see Infrastructure Controller or visit related user story Infrastructure providers.
Kubernetes Cluster Observer¶
Krake constantly observes the status of its registered or created clusters while running. For each cluster a separate Kubernetes cluster observer is created. This cluster specific observer calls the Kubernetes API of the real world Kubernetes Cluster periodically. The current status of each cluster is saved in the database of Krake. If a status change of the real world Kubernetes Cluster is detected, Krake updates the saved state of the registered Kubernetes cluster which is stored in its database. Changes in the state of a cluster may be related to Krake being able to connect to the real Kubernetes cluster or not, an unhealthy real world Kubernetes cluster, or metrics providers failing.
Kubernetes Cluster Status Polling¶
Overview¶
The polling
is the act of calling the Kubernetes API of the real world Kubernetes
cluster to get its state. During the course of its life, the real-life pendant of a
Krake resource may be updated, and thus differ from the desired state (user-defined). To
correct this, Krake performs a reconciliation, and the actual state is “replaced” by the
desired state. The Krake Controllers are responsible for actually doing the
reconciliation over the resources they manage.
Polling¶
The actual polling is done infinitely, during the so-called polling loop.
This workflow in Krake for a specific resource is presented on the following figure:

KubernetesClusterObserver polling loop
The workflow is as follows:
- The actual real-world cluster is registered or created by Krake;
- The Kubernetes cluster controller watches, or observes the clusters current
status
in the real-world. This is the role of the KubernetesClusterObserver. This is done by polling thestatus
with a call on the Kubernetes cluster API. - This current state is compared to the
status
, stored internally on the Observer; - If the actual state is the same as the
status
of the resource, as stored in the Observer, nothing happens. This workflow is started again from step 3 onwards after a defined time period; - If the actual state is different from the
status
of the resource, it means that the actual cluster was modified in the real-world; - The Observer notifies the Krake API, by updating the
status
field of the cluster; - The workflow starts again from step 3.
States¶
A Kubernetes cluster watched by it’s corresponding KubernetesClusterObserver can have the following observer related states:
- PENDING
- CONNECTING
- ONLINE
- DEGRADED
- OFFLINE
- UNHEALTHY
- NOTREADY
- FAILING_METRICS
Note
Refer to the States for the infrastructure related cluster states.
PENDING
- This state is initially set when a Kubernetes cluster is registered in Krake.
CONNECTING
- It is set by the Kubernetes Cluster Observer if the previous state of a cluster was OFFLINE, but the real cluster is available again. In this case, a reconnection is attempted with a temporary CONNECTING state.
ONLINE
- If the cluster is reachable in the real world, is in a healthy state and is ready, the status of the cluster in Krake will be ONLINE.
DEGRADED
- A cluster will be DEGRADED if the handling of the cluster was not successful, but
the number of retries is not yet exhausted. This is the intermediate state before
being OFFLINE (or back ONLINE). The behaviour is specified with the parameters
backoff
(multiplier added to retry attempts, defaults to 1),backoff_delay
(number of seconds between retry attempts) andbackoff_limit
(number of retries, defaults to -1(infinite)). So if not changed, the cluster will remain in DEGRADED state until the handling was successful. Otherwise, if the number of retries is exhausted, the cluster will transfer to OFFLINE. OFFLINE
- If the real world cluster cannot be reached by polling the Kubernetes cluster API, the status of the cluster in Krake will be OFFLINE. This can happen due to several reasons, e.g. the Kubernetes cluster itself is down, network connectivity issues or incorrect configuration of the used kubeconfig file to register the cluster in Krake.
UNHEALTHY
- This state is set for clusters in Krake when the Kubernetes API call responds with either PIDPressure, DiskPressure, or MemoryPressure.
NOTREADY
- This status is displayed when there is an internal problem in the real Kubernetes cluster. When this status is displayed, an investigation of the Kubernetes cluster itself is highly recommended. The reasons for this status vary, for example, the real Kubernetes cluster’s kubelet is not working properly or other services have failed to start.
FAILING_METRICS
- This status is set internally by Krake if a metrics provider is not reachable by Krake and thus metrics cannot be passed correctly into Krake.
Node Health¶
The cluster observer collects health data of a kubernetes cluster and formats it. Data is divided according to the nodes of the cluster and the different pressure types PID, memory and disk. They represent the problems that a kubernetes node could experience, either missing process ids due to too many process instances, memory overload or non-available disk space. These information can be found by calling:
rok kube cluster get X
+-----------------------+---------------------+
| ... | ... |
| nodes | 3/3 |
| nodes_pid_pressure | 0/3 |
| nodes_memory_pressure | 0/3 |
| nodes_disk_pressure | 0/3 |
| ... | ... |
+-----------------------+---------------------+
Nodes are shown according to their health, so 3/3 if all nodes are healthy, and the pressure parameters only get filled, if there is a current problem with one (or more) of the nodes.
Summary¶
Creation¶
After a Cluster resource was registered or successfully created, a KubernetesClusterObserver is also created for this specific cluster.
Update¶
Before the Kubernetes cluster in Krake is updated, its
corresponding KubernetesClusterObserver is stopped. After the update has been performed,
a new observer is started, which observes the newest status
of the cluster (the
actual Kubernetes cluster).
Deletion¶
Before the Kubernetes cluster is deleted, its corresponding KubernetesClusterObserver is stopped.
Actions on the API side (summary)¶
Action | Observer stopped before | Observer started after |
---|---|---|
Create | No | Yes |
Update | Yes | Yes |
Delete | Yes | No |
On status change¶
The KubernetesClusterObserver periodically checks the current state of its cluster.
The status is read and compared to the status
field of the cluster.
If a Kubernetes cluster changed, the KubernetesClusterObserver sends an update request
to the API, to change its status
field. This field is updated to match what the
Observer fetched from the cluster.
Then the Kubernetes Cluster Controller starts processing the update normally.
Warning
Currently only Kubernetes
clusters which have been registered in Krake or
created by Krake can be observed.
Infrastructure Controller¶
This part of the documentation presents the Infrastructure Controller control plane component, and how the life-cycle management of real-world Kubernetes clusters is handled.
The Infrastructure Controller should process Clusters that are bound (scheduled) to any Cloud or GlobalCloud resource. It should also process Clusters that were deleted and contain an Infrastructure Controller specific deletion finalizer: infrastructure_resources_deletion.
Note
Refer to the Cluster handler for useful information about cluster scheduling process.
Bound GlobalCloud or Cloud resources correspond to an IaaS cloud deployment (e.g. OpenStack, AWS, etc.) that will be managed by the infrastructure provider backend. Krake currently supports only OpenStack as a GlobalCloud or Cloud backend.
The GlobalCloud or Cloud resource should contain a reference to the GlobalInfrastructureProvider or InfrastructureProvider resource that corresponds to an infrastructure provider backend, that is able to deploy infrastructures (e.g. Virtual machines, Kubernetes clusters, etc.) on IaaS cloud deployments. Krake currently supports only IM (Infrastructure Manager) as an infrastructure provider backend.
Note
The global resource (e.g. GlobalInfrastructureProvider, GlobalCloud) is a non-namespaced resource that could be used by any (even namespaced) Krake resource. For example, the GlobalCloud resource could be used by any Cluster which needs to be scheduled to some cloud.
Reconciliation loop¶
In the following section, we describe what happens in the Infrastructure Controller when receiving a Cluster resource.

Step 1¶
Infrastructure Controller handles Cluster resources that have been deleted and contain the infrastructure_resources_deletion (1). If the above is true, the controller requests the cloud’s infrastructure provider for the deletion of the actual cluster counterparts (1a). The controller waits in an infinite loop for the actual cluster deletion (1b). Finally, the controller removes the finalizer from the Cluster resource (1c). This allows the garbage collector controller to remove the Cluster resource from the Krake DB.
Step 2¶
The Infrastructure Controller handles Cluster resources that are bound (scheduled) to any Cloud or GlobalCloud resource (2). The Cloud or GlobalCloud resource contains cloud API endpoints and access credentials as well as a reference to the infrastructure provider resource through which Krake can manage actual Kubernetes clusters on the bounded cloud.
Step 3¶
If the Cluster is bound (scheduled) to some cloud, the controller recursively looks for
all the changes between the desired state (which is represented by the cluster.spec.tosca
field) and the current state (which is stored in the cluster.status.last_applied_tosca
field) (3).
Step 4¶
If there is a difference between the desired and the current state, the controller checks
the resource field cluster.status.running_on
(4).
If it is empty, the resource is considered new, and the controller requests the cloud’s
infrastructure provider for the creation of the actual cluster counterparts (4a).
The TOSCA template stored in cluster.spec.tosca
represents the desired state and it is applied here.
After a successful request for creation, the cluster.status.last_applied_tosca
field is updated
with the copy of the cluster.spec.tosca
field as well as the cluster.status.running_on
is
updated with the copy of the cluster.status.scheduled_to
field (scheduled_to field contains
the bound cloud resource reference).
If the cluster.status.running_on
field is not empty, the controller requests the cloud’s
infrastructure provider for the reconciliation (update) of the actual cluster counterparts (4b).
The TOSCA template stored in cluster.spec.tosca
represents the desired state and it is applied here.
After a successful request for reconciliation, the cluster.status.last_applied_tosca
field is updated
with the copy of the cluster.spec.tosca
field.
Then, the controller waits for the cluster is being successfully configured in the infinite loop (7).
Step 5¶
If the desired and the current state are in sync, the controller checks whether the Cluster resource state
is FAILING_RECONCILIATION
(5). If so, the controller requests the cloud’s infrastructure provider
for the reconfiguration of the actual cluster counterparts (5a). This is a “special” call that may or may not be
required in case of infrastructure provider failures (e.g. restart). It depends on the underlying infrastructure
provider implementation which action should be performed under the hood of the abstract infrastructure
controller function reconfigure.
Then, the controller waits for the cluster is being successfully configured in the infinite loop (7).
Step 6¶
The controller finishes the reconciliation if the Cluster resource state is ONLINE
or CONNECTING
(6). If it is not the case,
the controller waits for the cluster is being successfully configured in the infinite loop (7).
Step 7¶
The controller waits in an infinite loop for the actual cluster creation/reconciliation/(re)configuration (7).
When the actual cluster is fully configured, the controller updates the Cluster state to
CONNECTING
and also saves its kubeconfig manifest to the cluster.spec.kubeconfig
field.
Finally, the controller finishes the reconciliation.
Note
Once the Cluster is configured, has CONNECTING
state, and contains kubeconfig manifest, the
Kubernetes Cluster Controller takes over the Cluster and
Kubernetes Cluster Observer observes its actual status.
States¶
A Kubernetes Cluster resource managed by the Infrastructure Controller can have the following infrastructure related states:
- PENDING
- CONNECTING
- CREATING
- RECONCILING
- DELETING
- FAILING_RECONCILIATION
- FAILED
Note
Refer to the States for the observer related cluster states.
PENDING
- This state is initially set when a Kubernetes cluster resource is created in Krake.
CONNECTING
- It is set when the actual Kubernetes cluster has been successfully reconciled.
CREATING
- It is set when the actual Kubernetes cluster is going to be created.
RECONCILING
- It is set when the actual Kubernetes cluster is going to be updated.
DELETING
- It is set when the actual Kubernetes cluster is going to be deleted.
FAILING_RECONCILIATION
- It is set when the reconciliation process of the actual Kubernetes cluster failed.
FAILED
- It is set on the global Infrastructure Controller level when an exceptions is raised during the reconciliation process.
Note
Since this is a relatively new implementation, the Infrastructure Controller will certainly be extended by additional features and functionalities in the future, e.g. Infrastructure Observer.
Garbage Collection¶
This part of the documentation presents the Garbage Collector component, and how the deletion of resources that others depends on is handled.
Dependency mechanism¶

Dependency relationships in Krake with examples.
In Krake, any resource can depend on any other. In this case, we say the dependent depends on the dependency. For instance, a Kubernetes Application depends on a Cluster. We also say that the Cluster owns the Application. The Cluster is one of the owners of the Application in this case.
Every resource with metadata holds a list of its owners. However, no resource holds the list of its owned resources. This is similar to the principle of relational database for instance, with the foreign key mechanism.
In the preceding diagram, a my-app
Application is owned by a cluster (see
its list of owners
) itself belonging to a Magnum cluster. The latter is
finally owned by an OpenStack project. The project has no dependency, thus its
owner list is empty.
Overview¶
The Garbage Collector is a Controller of Krake and is, as such, to be started independently from the other components of Krake.
“Marked as deleted” vs “to delete” vs “deleted”¶
The resources processed during garbage collection have three different states.
They use the "cascade_deletion"
finalizer.
- “Marked as deleted”
A resource is marked as deleted by the API, when the “delete” action is called on this resource. It means two things for the resource object:
- the
deleted
timestamp of the metadata is set to the current time; - the
"cascade_deletion"
finalizer is added to its list of finalizer.
A resource marked for deletion enters then the garbage collection process.
Caution
This state is irreversible. A resource that enters this state will be processed by the garbage collector, only to be deleted in the end of garbage collection process.
- the
- “To delete”
A resource is said to be in the “to delete” state if two conditions are met :
- its
deleted
timestamp is set; - it has no finalizer.
Such a resource can still be transferred by the components. If a resource in this state is received by the API on update, it is deleted.
- its
- “Deleted”
- A deleted resource is completely removed from the database. A last “DELETED” event can be watched on the API when the actual deletion occurs to act on the deletion but the resource itself must be considered erased, and not managed by the API anymore.
Role of the Garbage Collector¶
The role of the Garbage Collector is to handle resources marked as deleted by the API, but not yet deleted.
When a resource is received, the garbage collector has to:
- update its dependency graph (see Dependency graph);
- get the resources that directly depend on it;
- call the API with the “delete” action to let it mark the dependents as deleted;
- if a resource has no dependent, remove the
"cascade_deletion"
finalizer from it, and call the API to update the resource. The resource enters the “to delete” state.
So the role of the Garbage Collector is mostly to get the dependents of a resource, and update them to mark them as deleted. This information is taken from the dependency graph present on the garbage collector, see the Dependency graph section.
Role of the API¶
For the deletion of resources, the garbage collector works tightly with the API, as the garbage collector has no direct access to any resource on the database.
The API is then responsible for:
- actually marking the requested resources as deleted;
- completely deleting a resource from the database during an update, if the resource is in a “to delete” state.
So the API is the one that actually modifies and process the stored resources.
Garbage collection workflow¶

Garbage collection workflow, and communication between the garbage collector and the API
The exact workflow of a resource that the user wants to delete is presented on the previous diagram. Let us take for example an Application A, with a cluster C as single owner.
- A and C were created beforehand, thus they are already present in the dependency graph of the garbage collector;
- the user requests the deletion of the Cluster C, for instance with the
Rok utility or using
curl
; - the request is received by the API. The API marks the cluster C as
deleted, and an
UPDATE
event is triggered; - the garbage collector receives the event. It accepts to handle the cluster, as it is marked for deletion;
- the list of dependents of C is fetched from the dependency graph stored on the garbage collector. The garbage collector issues for each of them a “delete” call to the API. In our case, the Application A is the only dependent of C;
- the API receives the call and marks A as deleted. A is updated, and
an
UPDATE
event is triggered; - the garbage collector receives the event, and accepts to handle A;
- A has no dependent, so its
"cascade_deletion"
finalizer is removed. An “update” request is sent to the API with the new A; - the API receives the “update” request, with A being in the “to delete”
state. A is deleted from the database. A
DELETED
event is triggered; - the garbage collector receives the event. A is removed from the dependency graph. The dependencies of A are put in the worker queue of the garbage collector to be handled. The owners are collected from the dependency graph. In our case, C is added to the worker queue;
- C is handled by the garbage collector a second time. It has no dependent
this time, as A has been deleted and removed from the dependency graph.
Thus, the garbage collector removes the
"cascade_deletion"
finalizer and issues an “update” call to the API for C; - the API receives the “update” request, with C being in the “to delete”
state. C is deleted from the database. A
DELETED
event is triggered. C had no dependency, so the garbage collector does not take any action.
Dependency graph¶
Description and goal¶

Comparison example of the dependencies, as represented in the API and on the dependency graph.
The dependency graph is an acyclic directed graph stored on the garbage collector as “cache”. Its goal is to store the dependency relationships of all resources managed by the API. The graph is updated when starting the garbage collector, while listing resources, or on events triggered by the API. It is only stored in memory, and is re-created each time the garbage collector is started.
The dependency graph allows the garbage collector to access the dependents of any resource. Otherwise, to get the dependents of a resource, the garbage collector would need to request all resources on the database, and check which one of them have the resource to delete as owner. This would mean of course that all resources of the database would be looped through. This is definitely not optimal and is avoided with the dependency graph.
On the nodes, the graph stores the krake.data.core.ResourceRef
object
corresponding to a resource. The edges are directed link from a ResourceRef
object, to the dependencies of the original object.
krake.data.core.ResourceRef
objects are used because they can be keys
in dictionaries, whereas normal resources cannot. The reference to the complete
resources is still stored in the graph.
Graph workflow¶

Dependency graph workflow on the garbage collector
Five actions can be performed on the dependency graph: adding, updating or removing a resource, get the dependents of a resource, or get its dependencies.
- Adding a resource:
- Action performed when the garbage collector lists the resources on startup, or when an “ADDED” event is triggered. The resource is added to the graph as node, along with its dependency relations as edges;
- Updating a resource:
- Action performed when an “UPDATED” event is triggered. If the resource dependency relations were modified, the graph edges are modified. The node corresponding to the resource is modified.
- Removing a resource:
- Action performed when a “DELETED” event is triggered. The resource’s corresponding node is removed from the graph, along with the edges bound to it.
- Get the dependents of a resource:
- Action performed by the garbage collector, to know which resource to mark for deletion, without having to reach the API. The nodes on the edges of the resource are listed and returned.
- Get the dependencies of a resource:
- Action performed by the garbage collector, to put the owners of a resource in the worker queue. The owners stored on the resource are returned.
API Generation¶
This part of the documentation describes the API generator utility.
Role¶
The API generator was developed to automatically create the code for:
- the Krake API;
- the client for the Krake API;
- the unit tests for the Krake API;
- the unit tests for the client of the Krake API;
- the API definitions, which are the bases for the generation of the elements above.
Note
Other cases will be added, as the generator was built to be modular.
The Krake API is separated into the different APIs that are managed: core
,
kubernetes
, openstack
, and infrastructure
. Each one of them handles
the classic CRUD operations on the different resources managed by the APIs.
Having all their code written by hand would not really follow the DRY principle.
Previously, the handlers and the client methods were generated dynamically when
starting the API. This lead to the code of the API and the client being not very
flexible, but mostly, being harder to debug.
As a compromise, the API generator was introduced. It generates the code for any resource of any API in a deterministic way. The code for the API, the client and their respective unit tests are thus more or less “harcoded”, as they are not generated on the fly. This has several advantages:
- the code can be easily read, understood, and is accessible easily for debuggers and linters;
- the generation can be nicely integrated with versioning. For instance, when generating new resources or when updating the template of the handlers, the changes can be propagated easily. One only needs to rerun the generator and check the differences.
The API generator should be leveraged in the following cases:
- a new operation on an existing resource is inserted (like the binding for the
Application
resource, or the update of a subresource); - a new resource is added to an API. All operations to manage it should be handled;
- a whole new API is added. All resources should be managed as well;
Usage¶
The API generator is a Python module not integrated into the Krake main code. It is
present in the Krake repository on api_generator/
.
Requirements¶
To install the required packages in your local environment, you can use:
pip install "krake/[api_generator]"
Krake needs to be installed on your local environment as well to be able to use the generator. The previous command also installs Krake.
Commands¶
The base command for the generator is the following:
python -m api_generator <command> <parameters>
The <command>
part sets the type of generator which will be used, e.g. the Krake API
code, or unit tests for the client. The <parameters>
are the specific arguments for
the chosen generator.
Warning
You need to be in the Krake root directory to use the command.
The command above will display the generated result. To store it into a file, simply redirect the result:
python -m api_generator <command> <parameters> > <generated_file>
Templating¶
The generated content is based on Jinja templates stored in api_generator/templates
,
but the path can be overwritten, see Common arguments.
Modifying the templates will modify the generated code, and additional templates can be
added for additional operations, unit tests, handlers, etc.
Generated elements¶
API definitions¶
The API definitions describe the different operations which can be executed on a type of
resource in a specific API. For instance, it would express that the resource Bar
of
API foo
can be read or listed, but not created, updated or deleted. Additional
operations can also be added, for example for bindings, hooks, etc.
To create these definitions automatically, the generation is based on classes defined in
the Krake data module. The module inside krake.data
is imported by the generator,
which goes through the module, and filters the classes which will be persistently stored
in the database. These classes are considered as being handled by the Krake API, and the
operations will only be generated for them.
For each resource (the class handled), the following elements are generated:
- a
Resource
class; - the singular and plural word for the resource;
- the scope of the resource (namespaced or not);
- basic CRUD operations, plus
List
andListAll
(from all namespaces); - subresource classes inside the
Resource
class for each subresource of the data class (specified by the"subresource"
metadata of a field being set toTrue
.); - for each subresource, the
Update
operation is generated.
For each operation, the generated definition also describes:
- the HTTP method for the operation;
- the URL path for the operation’s endpoint;
- the name of the data class to use for the body of the request to the endpoint;
- the name of the data class that will be used for the body of the response of the Krake API.
For example:
python -m api_generator api_definition krake.data.kubernetes
will generate an API definition file which describes all the resources in the
kubernetes
API of Krake. Among many other elements, a Status
subresource is
added for he Application
resource.
Regarding the scope, each resource can be either namespaced or non-namespaced.
To handle non-namespaced resources, no namespaced should be provided for the API
endpoint when calling them. Further, the List
operation can list all of the elements
of the resource, and there is no ListAll
operation to list all resources of all
namespaces (because the instance of the resources are not separated by namespaces).
To specify the scope, use the --scopes <krake_class_name>=<scope>
argument, once for
each resource. For example, for the foo
API, with resource Bar
namespaced and
Baz
non-namespaced, the command should be:
python -m api_generator api_definition krake.data.foo --scopes Baz=NONE
After the generation, operations or the attributes of the operation can be changed to restrict or add new operations, change the body of the request or the response, add other subresources, etc.
The existing definitions are stored in the api_generator/apidefs
directory.
API/client code generation and their unit tests¶
The generation for the following elements all follow the same procedure:
- code for the Krake API;
- code for the client of the Krake API;
- the unit tests for the Krake API;
- the unit tests for the client of the Krake API.
The four generators leverage the API definitions as input. By giving the generator the path to a definition, it will be able to import it and get information from the resources, subresources and their respective operations. This will, in turn, be leveraged for the generation of the code.
python -m api_generator <command> api_generator.apidefs.foo
where the parameter (here api_generator.apidefs.foo
) is the module path to the API
definition used as input, and <command>
can be:
api_client
:
The generated output will be code to communicate with the API. For each API, a client class is created, which has a method for each defined operation. These methods take usually a resource as parameter and maybe the name and namespace of a resource. It returns usually the body of the response of the Krake API.
api_server
:
The generated output will be handlers for the Krake API, to be executed when a request is received. For each operation of each resource, a handler is generated to process the request and prepare the body of the response sent to the client.
test_client
:
The generated output will be unit tests. They verify the behavior of the client methods generated by theapi_client
command. For each method of the client, several unit tests can be added because of the different behaviors it can have.
test_server
:
The generated output will be unit tests. They verify the behavior of the handlers generated by theapi_server
command. For each handlers of the API, several unit tests can be added because of the different behaviors it can have.
All these generators share the following common arguments:
--operation
--resources
They can be used to limit respectively the operations and/or the resource that will be handled by the generator for the final output. Can be repeated once for each operation for which the output will be displayed. If one of the option is used, it will only display the mentioned operation or resource. Not using one of them will result in all operations or resources being outputted.
TOSCA¶
This section describes TOSCA integration to Krake.
Introduction¶
TOSCA is an OASIS standard language to describe a topology of cloud-based web services, their components, relationships, and the processes that manage them.
TOSCA uses the concept of service templates to describe services. TOSCA further provides a system of types to describe the possible building blocks for constructing service templates and relationship types to describe possible kinds of relations. It is possible to create custom TOSCA types for building custom TOSCA templates.
Krake allows end-users to orchestrate Kubernetes applications with TOSCA. It is required to use custom TOSCA templates for them. Krake supports Cloud Service Archive (CSAR) files as well. CSAR is a container file using the ZIP file format, that includes all artifacts required to manage the lifecycle of the corresponding cloud application using the TOSCA language.
Note
The TOSCA technical committee has decided that any profile (template base) development should be left to the community. It means, that there are not any “de facto standard” on how to describe e.g. Kubernetes applications with TOSCA. Each orchestrator that supports TOSCA is its own product with its own design paradigms and may have different assumptions and requirements for modeling applications.
TOSCA Template¶
Krake is able to manage Kubernetes applications that are described by the TOSCA YAML custom
template file. Kubernetes application should be described by
TOSCA-Simple-Profile-YAML v1.0
or v1.2
as Krake only supports those versions.
Krake supports Cloud Service Archives (CSAR) as well. The CSAR should contain
TOSCA-Simple-Profile-YAML v1.0
or v1.2
and should be in defined format.
Note
Krake uses the tosca-parser library as its underlying TOSCA parser and validator.
Currently, tosca-parser supports the TOSCA-Simple-Profile-YAML v1.0
or v1.2
,
which reflects what is supported by Krake.
Note
The Krake API could process TOSCA templates in two formats. It can receive the TOSCA template as serialized JSON or the API could receive a URL that points to some remote location, that provides a TOSCA template. In the case of providing a URL, the underlying tosca-parser library is able to (synchronously) download the TOSCA template from the defined URL and then parse and validate it.
Another prerequisite (besides the TOSCA version) is a TOSCA profile (custom type).
Krake supports and can manage only Kubernetes application that is described by the
tosca.nodes.indigo.KubernetesObject
custom type.
The tosca.nodes.indigo.KubernetesObject
custom type has been defined by the
Grycap research group. It could be imported as an external document using the imports
directive in the template or it can be directly declared as a custom
data type within the data_types
template section.
For import use the following reference to Grycap’s custom types:
imports:
- ec3_custom_types: https://raw.githubusercontent.com/grycap/ec3/tosca/tosca/custom_types.yaml
For direct definition use the following (minimal) data type:
data_types:
tosca.nodes.indigo.KubernetesObject:
derived_from: tosca.nodes.Root
properties:
spec:
type: string
description: The YAML description of the K8s object
required: true
The spec
of tosca.nodes.indigo.KubernetesObject
custom type should contain
Kubernetes manifest as a string. It is possible to applied subset of supported TOSCA functions
like:
- get_property
- get_input
The spec
of the tosca.nodes.indigo.KubernetesObject
custom type should contain a Kubernetes
manifest as a string. It is possible to apply a subset of supported TOSCA functions like:
- get_property
- get_input
- concat
Then, the example of TOSCA template for a single Kubernetes Pod could be designed as follows:
tosca_definitions_version: tosca_simple_yaml_1_0
imports:
- ec3_custom_types: https://raw.githubusercontent.com/grycap/ec3/tosca/tosca/custom_types.yaml
description: TOSCA template for launching an example Pod by Krake
topology_template:
inputs:
container_port:
type: integer
description: Container port
default: 80
node_templates:
example-pod:
type: tosca.nodes.indigo.KubernetesObject
properties:
spec:
concat:
- |-
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort:
- get_input: container_port
Let’s save the definition above to the tosca-example.yaml
file.
If you want to expose a created TOSCA template in your localhost, you can use a simple python HTTP server as follows:
# TOSCA template will then be exposed on URL: `http://127.0.0.1:8000/tosca-example.yaml`
python3 -m http.server 8000
Cloud Service Archive¶
CSAR should be in a defined format. The specification allows to create CSAR with or without
the TOSCA.meta
file.
The TOSCA.meta
file structure follows the exact same syntax as defined in the TOSCA 1.0 specification.
It is required to store this file in the TOSCA-Metadata
directory. It is also required to
include the Entry-Definitions
keyword pointing to a valid TOSCA definitions YAML file,
which should be used by a TOSCA orchestrator as an entrypoint for parsing the contents of the overall CSAR file
(the previously created tosca-example.yaml
file will be used in this example).
Note
The Krake API can process CSAR files only, if they’re defined as **URL**s. It means, that CSAR should be created and then exposed in some remote location. Then, the underlying tosca-parser library is able to (synchronously) download the CSAR archive from the defined URL and afterwards parse and validate it.
# Create TOSCA-Metadata directory
mkdir TOSCA-Metadata
# Create and fill TOSCA.meta file
echo "TOSCA-Meta-File-Version: 1.0" >> TOSCA-Metadata/TOSCA.meta
echo "CSAR-Version: 1.1" >> TOSCA-Metadata/TOSCA.meta
echo "Created-By: Krake" >> TOSCA-Metadata/TOSCA.meta
echo "Entry-Definitions: tosca-example.yaml" >> TOSCA-Metadata/TOSCA.meta
# Create CSAR
zip example.csar -r TOSCA-Metadata/ tosca-example.yaml
# Expose the created CSAR by simple HTTP python server
# CSAR will be then exposed on URL: `http://127.0.0.1:8000/example.csar`
# Expose the created CSAR file with a simple HTTP python server
# CSAR will then be exposed on URL: `http://127.0.0.1:8000/example.csar`
python3 -m http.server 8000
TOSCA/CSAR Workflow¶
The TOSCA template or CSAR archive should be composed on the client side. Then the client sends the request for the creation or update of an application together with the TOSCA template (YAML file or URL) or CSAR URL. The Krake API validates the TOSCA template or CSAR file suffixes depending on the used URL. When the TOSCA template is defined with a YAML file, parsing and validation are performed by Krake API (using the tosca-parser). After validation, the life cycle of the application is the same as a regular one (defined by Kubernetes manifest) except for the translation of the TOSCA template or CSAR archive into a Kubernetes manifest inside of the Kubernetes Application Controller. The controller is responsible for the translation of TOSCA/CSAR to Kubernetes manifests. During this process, the application will in the TRANSLATING state.
The workflow of this process can be seen in the following figure:

TOSCA/CSAR workflow in Krake
Examples¶
Prerequisites¶
The Krake repository contains a bunch of useful examples. Clone it first with the following commands:
git clone https://gitlab.com/rak-n-rok/krake.git
cd krake
TOSCA template examples are located in the rak/functionals
directory. View these TOSCA templates for example:
$ cat rak/functionals/echo-demo-tosca.yaml
$ cat rak/functionals/echo-demo-update-tosca.yaml
If you want to expose a created TOSCA template via some URL, you can use a simple python HTTP server as follows:
cd rak/functionals/
# Expose the TOSCA template examples with a simple HTTP python server
# TOSCA template examples will then be exposed on URLs:
# - `http://127.0.0.1:8000/echo-demo-tosca.yaml`
# - `http://127.0.0.1:8000/echo-demo-update-tosca.yaml`
python3 -m http.server 8000
If you are interested in CSAR, use the pre-defined TOSCA.meta
file and create and expose CSAR archive as follows:
cd rak/functionals/
zip echo-demo.csar -r TOSCA-Metadata/ echo-demo-tosca.yaml
# Expose the created CSAR by simple HTTP python server
# CSAR will be then exposed on URL: `http://127.0.0.1:8000/example.csar`
python3 -m http.server 8000
Rok¶
A TOSCA template YAML file should be applied the same way as a Kubernetes manifest file using the rok CLI, see Rok documentation.
- Create an application described by a TOSCA template YAML file:
rok kube app create --file rak/functionals/echo-demo-tosca.yaml echo-demo
- Update an application described by a TOSCA template:
rok kube app update --file rak/functionals/echo-demo-update-tosca.yaml echo-demo
A TOSCA template URL or CSAR archive URL should be defined after the optional –url argument using the rok CLI, see Rok documentation.
- Create an application described by a TOSCA template URL:
rok kube app create --url http://127.0.0.1:8000/echo-demo-tosca.yaml echo-demo
- Update an application described by a TOSCA template URL:
rok kube app update --url http://127.0.0.1:8000/echo-demo-update-tosca.yaml echo-demo
- Alternatively, create an application described by a CSAR URL:
rok kube app create --url http://127.0.0.1:8000/example.csar echo-demo
Tip
Krake allows the creation of an application using e.g. a plain Kubernetes manifest and then updating it with a TOSCA or even CSAR file. The same works vice-versa. It means, that the application could be created and then updated by any supported format (Kubernetes manifest, TOSCA, CSAR).
Krake Reference¶
This is the code reference for the Krake project.
Module hierarchy¶
This section presents the modules and sub-modules of the Krake project present
in the krake/
directory.
The tests for Krake are added in the krake/tests/
directory. The
pytest
module is used to launch all unit tests.
- krake
- The
krake
module itself only contains a few utility functions, as well as functions for reading and validating the environment variables and the configuration provided. However, this module contains several sub-modules presented in the following. - krake.api
This module contains the logic needed to start the API as a an
aiohttp
application. It exchanges objects with the various clients defined in krake.client. These objects are the ones defined in krake.data.- krake.client
This module contains all the necessary logic for any kind of client to communicate with the API described in the krake.api module.
- krake.controller
This module contains the base controller and the definition for several controllers. Each one of these controllers is a separate process, that communicates with the API or the database. For this, the controllers use elements provided by the krake.client module.
All new controller should be added in this module.
- krake.controller.kubernetes.application
- This sub-module contains the definition of the controller specialized for the Kubernetes application handling.
- krake.controller.kubernetes.cluster
- This sub-module contains the definition of the controller specialized for the Kubernetes cluster handling.
- krake.controller.scheduler
- This sub-module defines the Scheduler controller, responsible for binding the Krake applications and magnum clusters to the specific backends.
- krake.controller.gc
- This sub-module defines the Garbage Collector controller, responsible for handling the dependencies during the deletion of a resource. It marks as deleted all dependents of a resource marked as deleted, thus triggering their deletion.
- krake.controller.magnum
- This sub-module defines the Magnum controller, responsible for managing Magnum cluster resources and creating their respective Kubernetes cluster.
- krake.data
This module defines all elements used by the API and the controllers. It contains the definition of all these objects, and the logic to allow them to be serialized and deserialized.
Krake¶
-
class
krake.
ConfigurationOptionMapper
(config_cls, option_fields_mapping=None)¶ Bases:
object
Handle the creation of command line options for a specific Configuration class. For each attribute of the Configuration, and recursively, an option will be added to set it from the command line. A mapping between the option name and the hierarchical list of fields is created. Nested options keep the upper layers as prefixes, which are separated by a “-” character.
For instance, the following classes:
class SpaceShipConfiguration(Serializable): name: str propulsion: PropulsionConfiguration class PropulsionConfiguration(Serializable): power: int engine_type: TypeConfiguration class TypeConfiguration(Serializable): name: str
Will be transformed into the following options:
--name str --propulsion-power int --propulsion-engine-type-name: str
And the option-fields mapping will be:
{ "name": [Field(name="name", ...)], "propulsion-power": [ Field(name="propulsion", ...), Field(name="power", ...) ], "propulsion-engine-type-name": [ Field(name="propulsion", ...), Field(name="engine_type", ...), Field(name="name", ...), ], }
Then, from parsed arguments, the default value of an element of configuration are replaced by the elements set by the user through the parser, using this mapping.
The mapping of the option name to the list of fields is necessary here because a configuration element called
"lorem-ipsum"
with a"dolor-sit-amet"
element will be transformed into a"--lorem-ipsum-dolor-sit-amet"
option. It will then be parsed as"lorem_ipsum_dolor_sit_amet"
. This last string, if split with"_"
, could be separated into"lorem"
and"ipsum_dolor_sit_amet"
, or"lorem_ipsum_dolor"
and"sit_amet"
. Hence the idea of the mapping to get the right separation.Parameters: - config_cls (type) – the configuration class which will be used as a model to generate the options.
- option_fields_mapping (dict, optional) – a mapping of the option names, with POSIX convention (with “-” character”), to the list of fields: <option_name_with_dash>: <hierarchical_list_of_fields> This argument can be used to set the mapping directly, instead of creating it from a Configuration class.
-
add_arguments
(parser)¶ Using the configuration class given, create automatically and recursively command-line options to set the different attributes of the configuration. Nested options keep the upper layers as prefixes, which are separated by a “-” character.
Generate the mapping between the option name and the hierarchy of the attributes of the Configuration.
Parameters: parser (argparse.ArgumentParser) – the parser to which the new command-line options will be added.
-
merge
(config, args)¶ Merge the configuration taken from file and the one from the command line arguments. The arguments have priority and replace the values read from configuration.
Parameters: Returns: - the result of the merge of the CLI
arguments into the configuration, as serializable object.
Return type:
-
krake.
load_yaml_config
(filepath)¶ Load Krake base configuration settings from YAML file
Parameters: filepath (os.PathLike, optional) – Path to YAML configuration file Raises: FileNotFoundError
– If no configuration file can be foundReturns: Krake YAML file configuration Return type: dict
-
krake.
search_config
(filename)¶ Search configuration file in known directories.
The filename is searched in the following directories in given order:
- Current working directory
/etc/krake
Returns: Path to configuration file Return type: os.PathLike Raises: FileNotFoundError
– If the configuration cannot be found in any of the search locations.
-
krake.
setup_logging
(config_log)¶ Setups Krake logging based on logging configuration and global config level for each logger without log-level configuration
Parameters: config_log (dict) – dictschema logging configuration (see logging.config.dictConfig()
)
API Server¶
This module provides the HTTP RESTful API of the Krake application. It is
implemented as an aiohttp
application.
This module defines the bootstrap function for creating the aiohttp server instance serving Krake’s HTTP API.
Krake serves multiple APIs for different technologies, e.g. the core
functionality like roles and role bindings are served by the
krake.api.core
API where as the Kubernetes API is provided by
krake.api.kubernetes
.
Example
The API server can be run as follows:
from aiohttp import web
from krake.api.app import create_app
config = ...
app = create_app(config)
web.run_app(app)
-
krake.api.app.
cors_setup
(app)¶ Set the default CORS (Cross-Origin Resource Sharing) rules for all routes of the given web application.
Parameters: app (web.Application) – Web application
-
krake.api.app.
create_app
(config)¶ Create aiohttp application instance providing the Krake HTTP API
Parameters: config (krake.data.config.ApiConfiguration) – Application configuration object Returns: Krake HTTP API Return type: aiohttp.web.Application
-
krake.api.app.
db_session
(app, host, port)¶ Async generator creating a database
krake.api.database.Session
that can be used by other components (middleware, route handlers) or by the requests handlers. The database session is available under thedb
key of the application.This function should be used as cleanup context (see
aiohttp.web.Application.cleanup_ctx
).Parameters: app (aiohttp.web.Application) – Web application
-
krake.api.app.
http_session
(app, ssl_context=None)¶ Async generator creating an
aiohttp.ClientSession
HTTP(S) session that can be used by other components (middleware, route handlers). The HTTP(S) client session is available under thehttp
key of the application.This function should be used as cleanup context (see
aiohttp.web.Application.cleanup_ctx
).Parameters: app (aiohttp.web.Application) – Web application
-
krake.api.app.
load_authentication
(config)¶ Create the authentication middleware
middlewares.authentication()
.The authenticators are loaded from the “authentication” configuration key. If the server is configured with TLS, client certificates are also added as authentication (
auth.client_certificate_authentication()
) strategy.Parameters: config (krake.data.config.ApiConfiguration) – Application configuration object Returns: aiohttp middleware handling request authentication
Load authorization function from configuration.
Parameters: config (krake.data.config.ApiConfiguration) – Application configuration object Raises: ValueError
– If an unknown authorization strategy is configuredReturns: Coroutine function for authorizing resource requests
Authentication and Authorization¶
Authentication and Authorization module for Krake.
Access to the Krake API is controlled by two distinct mechanisms performed after each other:
- Authentication
- verifies the identity of a user (Who is requesting?)
- Authorization
- decides if the user has permission to access a resource
Authentication¶
Authentication is performed for every request. The
krake.api.middlewares.authentication()
middleware factory is used for
this purpose. The concrete authentication implementation will be derived from
the configuration.
# Anonymous authentication
authentication:
kind: static
name: system
# Keystone authentication
authentication:
kind: keystone
endpoint: http://localhost:5000/v3
An authenticator is a simple asynchronous function:
Currently, there are two authentication implementations available:
- Static authentication (
static_authentication()
)- Keystone authentication (
keystone_authentication()
)
Authorization¶
Authorization is established with the help of the protected()
decorator
function. The decorator annotates a given aiohttp request handler with the
required authorization information (see AuthorizationRequest
).
An authorizer is a simple asynchronous function:
The concrete authentication implementation will be derived from the
configuration and is stored under the authorizer
key of the application.
# Authorization mode
#
# - RBAC (Role-based access control)
# - always-allow (Allow all requests. No authorization is performed.)
# - always-deny (Deny all requests. Only for testing purposes.)
#
authorization: always-allow
Currently, there are three authorization implementations available:
- Always allow (
always_allow()
)- Always deny (
always_deny()
)- Role-based access control / RBAC (
rbac()
)
-
class
krake.api.auth.
AuthorizationRequest
¶ Bases:
tuple
Authorization request handled by authorizers.
-
verb
¶ Verb that should be performed on the resource.
Type: krake.data.core.Verb
-
api
Alias for field number 0
-
namespace
Alias for field number 1
-
resource
Alias for field number 2
-
verb
Alias for field number 3
-
-
krake.api.auth.
always_allow
(request, auth_request)¶ Authorizer allowing every request.
Parameters: - request (aiohttp.web.Request) – Incoming HTTP request
- auth_request (AuthorizationRequest) – Authorization request associated with the incoming HTTP request.
-
krake.api.auth.
always_deny
(request, auth_request)¶ Authorizer denying every request.
Parameters: - request (aiohttp.web.Request) – Incoming HTTP request
- auth_request (AuthorizationRequest) – Authorization request associated with the incoming HTTP request.
Raises: aiohttp.web.HTTPForbidden
– Always raised
-
krake.api.auth.
client_certificate_authentication
()¶ Authenticator factory for authenticating requests with client certificates.
The client certificate is loaded from the
peercert
attribute of the underlying TCP transport. The common name of the client certificate is used as usernameReturns: Authenticator using client certificate information for authentication. Return type: callable
-
krake.api.auth.
keycloak_authentication
(endpoint, realm)¶ Authenticator factory for Keycloak authentication.
The token in the
Authorization
header of a request sent to Krake will be sent as access token to the OpenID user information endpoint. The returned user name from Keycloak is used as authenticated user name.The authenticator requires an HTTP client session that is loaded from the
http
key of the application.Parameters: Returns: Authenticator for the given Keystone endpoint.
Return type: callable
-
krake.api.auth.
keystone_authentication
(endpoint)¶ Authenticator factory for OpenStack Keystone authentication.
The token in the
Authorization
header of a request will be used asX-Auth-Token
header for a request to the Keystone token endpoint. The returned user name from Keystone is used as authenticated user name.The authenticator requires an HTTP client session that is loaded from the
http
key of the application.Parameters: endpoint (str) – Keystone HTTP endpoint Returns: Authenticator for the given Keystone endpoint. Return type: callable
-
krake.api.auth.
protected
(api, resource, verb)¶ Decorator function for aiohttp request handlers performing authorization.
The returned decorator can be used to wrap a given aiohttp handler and call the current authorizer of the application (loaded from the
authorizer
key of the application). If the authorizer does not raise any exception the request is authorized and the wrapped request handler is called.Example
from krake.api.auth import protected @routes.get("/book/{name}") @protected(api="v1", resource="book", verb="get", namespaced=False) async def get_resource(request): assert "user" in request
Parameters: - api (str) – Name of the API group
- resource (str) – Name of the resource
- verb (str, krake.data.core.Verb) – Verb that should be performed
Returns: Decorator that can be used to wrap a given aiohttp request handler.
Return type: callable
-
krake.api.auth.
rbac
(request, auth_request)¶ Role-based access control authorizer.
The roles of a user are loaded from the database. It checks if any role allows the verb on the resource in the namespace. Roles are only permissive. There are no denial rules.
Parameters: - request (aiohttp.web.Request) – Incoming HTTP request
- auth_request (AuthorizationRequest) – Authorization request associated with the incoming HTTP request.
Returns: The role allowing access.
Return type: Raises: aiohttp.web.HTTPForbidden
– If no role allows access.
Database Abstraction¶
Database abstraction for etcd. Key idea of the abstraction is to provide an declarative way of defining persistent data structures (aka. “models”) together with a simple interface for loading and storing these data structures.
This goal is achieved by leveraging the JSON-serializable data classes based
on krake.data.serializable
and combining them with a simple database
session.
Example
from krake.api.database import Session
from krake.data import Key
from krake.data.serializable import Serializable
class Book(Serializable):
isbn: int
title: str
__etcd_key__ = Key("/books/{isbn}")
async with Session(host="localhost") as session:
book = await session.get(Book, isbn=9783453146976)
-
class
krake.api.database.
EtcdClient
(host='127.0.0.1', port=2379, protocol='http', cert=(), verify=None, timeout=None, headers=None, user_agent=None, pool_size=30, username=None, password=None, token=None, server_version='3.3.0', cluster_version='3.3.0')¶ Bases:
etcd3.aio_client.AioClient
Async etcd v3 client based on
etcd3.aio_client.AioClient
with some minor patches.
-
class
krake.api.database.
Event
¶ Bases:
tuple
Events that are yielded by
Session.watch()
-
event
Alias for field number 0
-
rev
Alias for field number 2
-
value
Alias for field number 1
-
-
class
krake.api.database.
EventType
¶ Bases:
enum.Enum
Different types of events that can occur during
Session.watch()
.
-
class
krake.api.database.
Revision
¶ Bases:
tuple
Etcd revision of a loaded key-value pair.
Etcd stores all keys in a flat binary key space. The key space has a lexically sorted index on byte string keys. The key space maintains multiple revisions of the same key. Each atomic mutative operation (e.g., a transaction operation may contain multiple operations) creates a new revision on the key space.
Every
Session.get()
request returns also the revision besides the model.-
version
¶ is the version of the key. A deletion resets the version to zero and any modification of the key increases its version.
Type: int
-
created
Alias for field number 1
-
key
Alias for field number 0
-
modified
Alias for field number 2
-
version
Alias for field number 3
-
-
class
krake.api.database.
Session
(host, port=2379, loop=None)¶ Bases:
object
Database session for managing
krake.data.serializable.Serializable
objects in an etcd database.The serializable objects need have one additional attribute:
- __etcd_key__
- A
krake.data.Key
template for the associated etcd key of a managed object.
Objects managed by a session have an attached etcd
Revision
when loaded from the database. This revision can be read byrevision()
. If an object has no revision attached, it is considered fresh or new. It is expected that the associated key of a new object does not already exist in the database.The session is an asynchronous context manager. It takes of care of opening and closing an HTTP session to the gRPC JSON gateway of the etcd server.
The etcd v3 protocol is documented by its protobuf definitions.
Example
async with Session(host="localhost") as session: pass
Parameters: -
all
(cls, **kwargs)¶ Fetch all instances of a given type
The instances can be filtered by partial identities. Every identity can be specified as keyword argument and only instances with this identity attribute are returned. The only requirement for a filtered identity attribute is that all preceding identity attributes must also be given.
Example
class Book(Serializable): isbn: int title: str author: str __metadata__ = { "key": Key("/books/{author}/{isbn}") } await db.all(Book) # Get all books by Adam Douglas await db.all(Book, author="Adam Douglas") # This will raise a TypeError because the preceding "name" # attribute is not given. await db.all(Book, isbn=42)
Parameters: - cls (type) – Serializable class that should be loaded
- **kwargs – Parameters for the etcd key
Yields: (object, Revision) – Tuple of deserialized model and revision
Raises: TypeError
– If an identity attribute is given without all preceding identity attributes.
-
client
¶ Lazy loading of the etcd client. It is only created when the first request is performed.
Returns: the client to connect to the database. Return type: EtcdClient
-
delete
(instance)¶ Delete a given instance from etcd.
A transaction is used ensuring the etcd key was not modified in-between. If the transaction is successful, the revision of the instance will be updated to the revision returned by the transaction response.
Parameters: instance (object) – Serializable object that should be deleted
Raises: ValueError
– If the passed object has no revision attached.TransactionError
– If the key was modified in between
-
get
(cls, **kwargs)¶ Fetch an serializable object from the etcd server specified by its identity attribute.
-
**kwargs
Parameters for the etcd key
Returns: Deserialized model with attached revision. If the key was not found in etcd, None is returned. Return type: object, None -
-
load_instance
(cls, kv)¶ Load an instance and its revision by an etcd key-value pair
Parameters: - cls (type) – Serializable type
- kv – etcd key-value pair
Returns: Deserialized model with attached revision
Return type:
-
put
(instance)¶ Store new revision of a serializable object on etcd server.
If the instances does not have an attached
Revision
(seerevision()
), it is assumed that a key-value pair should be created. Otherwise, it is assumed that the key-value pair is updated.A transaction ensures that
- the etcd key was not modified in-between if the key is updated
- the key does not already exists if a key is added
If the transaction is successful, the revision of the instance will updated to the revision returned by the transaction response.
Parameters: - instance (krake.data.serializable.Serializable) – Serializable object that
- be stored. (should) –
- Raise:
- TransactionError: If the key was modified in between or already
- exists
-
watch
(cls, **kwargs)¶ Watch the namespace of a given serializable type and yield every change in this namespace.
Internally, it uses the etcd watch API. The
created
future can be used to signal successful creation of an etcd watcher.Parameters: - cls (type) – Serializable type of which the namespace should be watched
- **kwargs – Parameters for the etcd key
Yields: Event – Every change in the namespace will generate an event
-
exception
krake.api.database.
TransactionError
¶
-
class
krake.api.database.
Watcher
(session, model, **kwargs)¶ Bases:
object
Async context manager for database watching requests.
This context manager is used internally by
Session.watch()
. It returns a async generator on entering. It is ensured that the watch is created on entering. This means inside the context, it can be assumed that the watch exists.Parameters: -
watch
()¶ Async generator for watching database prefix.
Yields: Event –
- Database event holding the loaded model (see
model
argument) and database revision.
- Database event holding the loaded model (see
-
-
krake.api.database.
revision
(instance)¶ Returns the etcd
Revision
of an object used with aSession
. If the object is currently unattached – which means it was not retrieved from the database withSession.get()
– this function returnsNone
.Parameters: instance (object) – Object used with Session
.Returns: The current etcd revision of the instance. Return type: Revision, None
Helpers¶
Simple helper functions that are used by the HTTP endpoints.
-
class
krake.api.helpers.
Heartbeat
(response, interval=None)¶ Bases:
object
Asynchronous context manager for heartbeating long running HTTP responses.
Writes newlines to the response body in a given heartbeat interval. If
interval
is set to 0, no heartbeat will be sent.Parameters: - response (aiohttp.web.StreamResponse) – Prepared HTTP response with chunked encoding
- interval (int, float, optional) – Heartbeat interval in seconds. Default: 10 seconds.
Raises: ValueError
– If the response is not prepared or not chunk encodedExample
import asyncio from aiohttp import web from krake.helpers import Heartbeat async def handler(request): # Prepare streaming response resp = web.StreamResponse() resp.enable_chunked_encoding() await resp.prepare(request) async with Heartbeat(resp): while True: await resp.write(b"spam\n") await asyncio.sleep(120)
-
heartbeat
()¶ Indefinitely write a new line to the response body and sleep for
interval
.
-
class
krake.api.helpers.
HttpProblem
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Store the reasons for failures of the HTTP layers for the API.
The reason is stored as an RFC 7807 Problem. It is a way to define a uniform, machine-readable details of errors in a HTTP response. See https://tools.ietf.org/html/rfc7807 for details.
-
type
¶ A URI reference that identifies the problem type. It should point the Krake API users to the concrete part of the Krake documentation where the problem type is explained in detail. Defaults to about:blank.
Type: str
-
title
¶ A short, human-readable summary of the problem type
Type: HttpProblemTitle
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶ Bases:
krake.data.serializable.ModelizedSchema
-
classmethod
remove_none_values
(data, **kwargs)¶ Remove attributes if value equals None
-
classmethod
-
__post_init__
()¶ HACK:
marshmallow.Schema
allows registering hooks likepost_dump
. This is not allowed in krakeSerializable
, therefore withinmarshmallow.Schema
allows registering hooks likepost_dump
. This is not allowed in krakeSerializable
, therefore the __post_init__ method is registered directly within the hook.
-
remove_none_values
(data, **kwargs)¶ Remove attributes if value equals None
-
-
exception
krake.api.helpers.
HttpProblemError
(exc: aiohttp.web_exceptions.HTTPException, problem: krake.api.helpers.HttpProblem = HttpProblem(type='about:blank', title=None, status=None, detail=None, instance=None), **kwargs)¶ Bases:
Exception
Custom exception raised if failures on the HTTP layers occur
-
class
krake.api.helpers.
HttpProblemTitle
¶ Bases:
enum.Enum
Store the title of an RFC 7807 problem.
The RFC 7807 Problem title is a short, human-readable summary of the problem type. The name defines the title itself. The value is used as part of the URI reference that identifies the problem type, see
middlewares.problem_response()
for details.
-
class
krake.api.helpers.
ListQuery
¶ Bases:
object
Simple mixin class for
operation
template classes.Defines default
operation.query
attribute for list and list all operations.
-
class
krake.api.helpers.
QueryFlag
(**metadata)¶ Bases:
marshmallow.fields.Field
Field used for boolean query parameters.
If the query parameter exists the field is deserialized to
True
regardless of the value. The field is marked asload_only
.-
deserialize
(value, attr=None, data=None, **kwargs)¶ Deserialize
value
.Parameters: - value – The value to deserialize.
- attr – The attribute/key in data to deserialize.
- data – The raw input data passed to Schema.load.
- kwargs – Field-specific keyword arguments.
Raises: ValidationError – If an invalid value is passed or if a required value is missing.
-
-
krake.api.helpers.
blocking
()¶ Decorator function to enable function blocking. This allows only a return of the response if the requested action is completed (eg. deletion of a resource). The function logic is therefore executed after its decorated counterpart.
Returns: JSON style response coming from the handler Return type: Response
-
krake.api.helpers.
load
(argname, cls)¶ Decorator function for loading database models from URL parameters.
The wrapper loads the
name
parameter from the requestsmatch_info
attribute. If thematch_info
contains anamespace
parameter, it is used as etcd key parameter as well.Example
from aiohttp import web from krake.data import serialize from krake.data.core import Role @load("role", Role) def get_role(request, role): return json_response(serialize(role))
Parameters: Returns: Decorator for aiohttp request handlers
Return type: callable
-
krake.api.helpers.
make_create_request_schema
(cls)¶ Create a
marshmallow.Schema
excluding subresources and read-only.Parameters: cls (type) – Data class with Schema
attributeReturns: Schema instance with excluded subresources Return type: marshmallow.Schema
-
krake.api.helpers.
session
(request)¶ Load the database session for a given aiohttp request
Internally, it just returns the value that was given as cleanup context by func:krake.api.app.db_session.
Parameters: request (aiohttp.web.Request) – HTTP request Returns: Database session for the given request Return type: krake.database.Session
-
krake.api.helpers.
use_schema
(argname, schema)¶ Decorator function for loading a
marshmallow.Schema
from the request body.If the request body is not valid JSON
aiohttp.web.HTTPUnsupportedMediaType
will be raised in the wrapper.Parameters: - argname (str) – Name of the keyword argument that will be passed to the wrapped function.
- schema (marshmallow.Schema) – Schema that should used to deserialize the request body
Returns: Decorator for aiohttp request handlers
Return type: callable
Middlewares¶
This modules defines aiohttp middlewares for the Krake HTTP API
-
krake.api.middlewares.
authentication
(authenticators, allow_anonymous)¶ Middleware factory authenticating every request.
The concrete implementation is delegated to the passed asynchronous authenticator function (see
krake.api.auth
for details). This function returns the username for an incoming request. If the request is unauthenticated – meaning the authenticator returns None –system:anonymous
is used as username.The username is registered under the
user
key of the incoming request.Anonymous requests can be allowed. If no authenticator authenticates the incoming request, “system:anonymous” is assigned as user for the request. This behavior can be disabled. In that case “401 Unauthorized” is raised if an request is not authenticated by any authenticator.
Parameters: - authenticators (List[callable]) – List if asynchronous function returning the username for a given request.
- allow_anonymous (bool) – If True, anonymous (unauthenticated) requests are allowed.
Returns: aiohttp middleware loading a username for every incoming HTTP request.
-
krake.api.middlewares.
error_log
()¶ Middleware factory for logging exceptions in request handlers
Returns: aiohttp middleware catching every exception logging it to the passed logger and reraising the exception.
-
krake.api.middlewares.
problem_response
(problem_base_url=None)¶ Middleware factory for HTTP exceptions in request handlers
Parameters: problem_base_url (str, optional) – Base URL of the Krake documentation where HTTP problems are explained in detail. Returns: aiohttp middleware catching HttpProblemError or HTTPException based exception transforming the excpetion text to the helpers.HttpProblem
(RFC 7807 Problem representation of failure) and reraising the exception.
-
krake.api.middlewares.
retry_transaction
(retry=1)¶ Middleware factory for transaction error handling.
If a
database.TransactionError
occurs, the request handler is retried for the specified number of times. If the transaction error persists, a 409 Conflict HTTP exception is raised.Parameters: retry (int, optional) – Number of retries if a transaction error occurs. Returns: aiohttp middleware handling transaction errors. Return type: coroutine
Client¶
This module provides a simple Python client to the Krake HTTP API. It
leverages the same data models as the API server from krake.data
.
-
class
krake.client.
ApiClient
(client)¶ Bases:
object
Base class for all clients of a specific Krake API.
-
client
¶ the lower-level client to use to create the actual connections.
Type: krake.client.Client
-
plurals
¶ contains the name of the resources handled by the current API and their corresponding names in plural: “<name_in_singular>”: “<name_in_plural>”
Type: dict[str, str]
Parameters: client (krake.client.Client) – client to use for the HTTP communications. -
-
class
krake.client.
Client
(url, loop=None, ssl_context=None)¶ Bases:
object
Simple async Python client for the Krake HTTP API.
The specific APIs are implemented in separate classes. Each API object requires an
Client
instance to interface the HTTP REST API.The client implements the asynchronous context manager protocol used to handle opening and closing the internal HTTP session.
Example
from krake.client import Client from krake.client.core import CoreApi async with Client("http://localhost:8080") as client: core_api = CoreApi(client) role = await core_api.read_role(name="reader")
-
close
()¶ Close the internal HTTP session and remove all resource attributes.
-
open
()¶ Open the internal HTTP session and initializes all resource attributes.
-
-
class
krake.client.
Watcher
(session, url, model)¶ Bases:
object
Async context manager used by
watch_*()
methods ofClientApi
.The context manager returns the async generator of resources. On entering it is ensured that the watch is created. This means inside the context a watch is already established.
Parameters: - session (aiohttp.ClientSession) – HTTP session that is used to access the REST API.
- url (str) – URL for the watch request
- model (type) – Type that will be used to deserialize
krake.data.core.WatchEvent.object
-
watch
()¶ Async generator yielding watch events
Yields: krake.data.core.WatchEvent –
- Watch events where
object
is already deserialized correctly according to the API definition (see
model
argument)
- Watch events where
Client APIs¶
-
class
krake.client.core.
CoreApi
(client)¶ Bases:
krake.client.ApiClient
Core API client
Example
from krake.client import Client with Client(url="http://localhost:8080") as client: core_api = CoreApi(client)
Parameters: client (krake.client.Client) – API client for accessing the Krake HTTP API -
create_global_metric
(body)¶ Create the specified GlobalMetric.
Parameters: body (GlobalMetric) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: GlobalMetric
-
create_global_metrics_provider
(body)¶ Create the specified GlobalMetricsProvider.
Parameters: body (GlobalMetricsProvider) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: GlobalMetricsProvider
-
create_metric
(body, namespace)¶ Create the specified Metric.
Parameters: Returns: Body of the HTTP response.
Return type:
-
create_metrics_provider
(body, namespace)¶ Create the specified MetricsProvider.
Parameters: - body (MetricsProvider) – Body of the HTTP request.
- namespace (str) – Namespace of the MetricsProvider.
Returns: Body of the HTTP response.
Return type:
-
create_role
(body)¶ Create the specified Role.
Parameters: body (Role) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: Role
-
create_role_binding
(body)¶ Create the specified RoleBinding.
Parameters: body (RoleBinding) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: RoleBinding
-
delete_global_metric
(name)¶ Delete the specified GlobalMetric.
Parameters: name (str) – name of the GlobalMetric. Returns: Body of the HTTP response. Return type: GlobalMetric
-
delete_global_metrics_provider
(name)¶ Delete the specified GlobalMetricsProvider.
Parameters: name (str) – name of the GlobalMetricsProvider. Returns: Body of the HTTP response. Return type: GlobalMetricsProvider
-
delete_metric
(name, namespace)¶ Delete the specified Metric.
Parameters: Returns: Body of the HTTP response.
Return type:
-
delete_metrics_provider
(name, namespace)¶ Delete the specified MetricsProvider.
Parameters: Returns: Body of the HTTP response.
Return type:
-
delete_role
(name)¶ Delete the specified Role.
Parameters: name (str) – name of the Role. Returns: Body of the HTTP response. Return type: Role
-
delete_role_binding
(name)¶ Delete the specified RoleBinding.
Parameters: name (str) – name of the RoleBinding. Returns: Body of the HTTP response. Return type: RoleBinding
-
list_global_metrics
()¶ List the GlobalMetrics in the namespace.
Returns: Body of the HTTP response. Return type: GlobalMetricList
-
list_global_metrics_providers
()¶ List the GlobalMetricsProviders in the namespace.
Returns: Body of the HTTP response. Return type: GlobalMetricsProviderList
-
list_metrics
(namespace=None)¶ List the Metrics in the namespace.
Parameters: namespace (str) – namespace of the Metric Returns: Body of the HTTP response. Return type: MetricList
-
list_metrics_providers
(namespace=None)¶ List the MetricsProviders in the namespace.
Parameters: namespace (str) – namespace of the MetricsProvider. Returns: Body of the HTTP response. Return type: MetricsProviderList
-
list_role_bindings
()¶ List the RoleBindings in the namespace.
Returns: Body of the HTTP response. Return type: RoleBindingList
-
list_roles
()¶ List the Roles in the namespace.
Returns: Body of the HTTP response. Return type: RoleList
-
read_global_metric
(name)¶ Read the specified GlobalMetric.
Parameters: name (str) – name of the GlobalMetric. Returns: Body of the HTTP response. Return type: GlobalMetric
-
read_global_metrics_provider
(name)¶ Reads the specified GlobalMetricsProvider.
Parameters: name (str) – name of the GlobalMetricsProvider. Returns: Body of the HTTP response. Return type: GlobalMetricsProvider
-
read_metric
(name, namespace)¶ Read the specified Metric.
Parameters: Returns: Body of the HTTP response.
Return type:
-
read_metrics_provider
(name, namespace)¶ Read the specified MetricsProvider.
Parameters: Returns: Body of the HTTP response.
Return type:
-
read_role
(name)¶ Read the specified Role.
Parameters: name (str) – name of the Role. Returns: Body of the HTTP response. Return type: Role
-
read_role_binding
(name)¶ Read the specified RoleBinding.
Parameters: name (str) – name of the RoleBinding. Returns: Body of the HTTP response. Return type: RoleBinding
-
update_global_metric
(body, name)¶ Update the specified GlobalMetric.
Parameters: - body (GlobalMetric) – Body of the HTTP request.
- name (str) – name of the GlobalMetric.
Returns: Body of the HTTP response.
Return type:
-
update_global_metrics_provider
(body, name)¶ Update the specified GlobalMetricsProvider.
Parameters: - body (GlobalMetricsProvider) – Body of the HTTP request.
- name (str) – name of the GlobalMetricsProvider.
Returns: Body of the HTTP response.
Return type:
-
update_metric
(body, name, namespace)¶ Update the specified GlobalMetric.
Parameters: - body (GlobalMetric) – Body of the HTTP request.
- name (str) – name of the Metric.
- namespace (str) – namespace of the Metric
Returns: Body of the HTTP response.
Return type:
-
update_metrics_provider
(body, name, namespace)¶ Update the specified MetricsProvider.
Parameters: - body (MetricsProvider) – Body of the HTTP request.
- name (str) – name of the MetricsProvider.
- namespace (str) – namespace of the MetricsProvider.
Returns: Body of the HTTP response.
Return type:
-
update_role
(body, name)¶ Update the specified Role.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_role_binding
(body, name)¶ Update the specified RoleBinding.
Parameters: - body (RoleBinding) – Body of the HTTP request.
- name (str) – name of the RoleBinding.
Returns: Body of the HTTP response.
Return type:
-
watch_global_metrics
(heartbeat=None)¶ Generate a watcher for the GlobalMetrics in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: GlobalMetricList
-
watch_global_metrics_providers
(heartbeat=None)¶ Generate a watcher for the GlobalMetricsProviders in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: GlobalMetricsProviderList
-
watch_metrics
(namespace=None, heartbeat=None)¶ Generate a watcher for the Metrics in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
watch_metrics_providers
(namespace=None, heartbeat=None)¶ Generate a watcher for the MetricsProviders in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
watch_role_bindings
(heartbeat=None)¶ Generate a watcher for the RoleBindings in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: RoleBindingList
-
watch_roles
(heartbeat=None)¶ Generate a watcher for the Roles in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: RoleList
-
-
class
krake.client.infrastructure.
InfrastructureApi
(client)¶ Bases:
krake.client.ApiClient
Infrastructure API client
Example
from krake.client import Client with Client(url="http://localhost:8080") as client: infrastructure_api = InfrastructureApi(client)
Parameters: client (krake.client.Client) – API client for accessing the Krake HTTP API -
create_cloud
(body, namespace)¶ Create the specified Cloud.
Parameters: Returns: Body of the HTTP response.
Return type:
-
create_global_cloud
(body)¶ Create the specified GlobalCloud.
Parameters: body (GlobalCloud) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: GlobalCloud
-
create_global_infrastructure_provider
(body)¶ Create the specified GlobalInfrastructureProvider.
Parameters: body (GlobalInfrastructureProvider) – Body of the HTTP request. Returns: Body of the HTTP response. Return type: GlobalInfrastructureProvider
-
create_infrastructure_provider
(body, namespace)¶ Create the specified InfrastructureProvider.
Parameters: - body (InfrastructureProvider) – Body of the HTTP request.
- namespace (str) – namespace in which the InfrastructureProvider will be updated.
Returns: Body of the HTTP response.
Return type:
-
delete_cloud
(namespace, name)¶ Delete the specified Cloud.
Parameters: Returns: Body of the HTTP response.
Return type:
-
delete_global_cloud
(name)¶ Delete the specified GlobalCloud.
Parameters: name (str) – name of the GlobalCloud. Returns: Body of the HTTP response. Return type: GlobalCloud
-
delete_global_infrastructure_provider
(name)¶ Delete the specified GlobalInfrastructureProvider.
Parameters: name (str) – name of the GlobalInfrastructureProvider. Returns: Body of the HTTP response. Return type: GlobalInfrastructureProvider
-
delete_infrastructure_provider
(namespace, name)¶ Delete the specified InfrastructureProvider.
Parameters: Returns: Body of the HTTP response.
Return type:
-
list_all_infrastructure_providers
()¶ List all InfrastructureProviders.
Returns: Body of the HTTP response. Return type: InfrastructureProviderList
-
list_clouds
(namespace)¶ List the Clouds in the namespace.
Parameters: namespace (str) – namespace in which the Cloud will be updated. Returns: Body of the HTTP response. Return type: CloudList
-
list_global_clouds
()¶ List the GlobalClouds in the namespace.
Returns: Body of the HTTP response. Return type: GlobalCloudList
-
list_global_infrastructure_providers
()¶ List the GlobalInfrastructureProviders in the namespace.
Returns: Body of the HTTP response. Return type: GlobalInfrastructureProviderList
-
list_infrastructure_providers
(namespace)¶ List the InfrastructureProviders in the namespace.
Parameters: namespace (str) – namespace in which the InfrastructureProvider will be updated. Returns: Body of the HTTP response. Return type: InfrastructureProviderList
-
read_cloud
(namespace, name)¶ Read the specified Cloud.
Parameters: Returns: Body of the HTTP response.
Return type:
-
read_global_cloud
(name)¶ Read the specified GlobalCloud.
Parameters: name (str) – name of the GlobalCloud. Returns: Body of the HTTP response. Return type: GlobalCloud
-
read_global_infrastructure_provider
(name)¶ Read the specified GlobalInfrastructureProvider.
Parameters: name (str) – name of the GlobalInfrastructureProvider. Returns: Body of the HTTP response. Return type: GlobalInfrastructureProvider
-
read_infrastructure_provider
(namespace, name)¶ Read the specified InfrastructureProvider.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_cloud
(body, namespace, name)¶ Update the specified Cloud.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_cloud_status
(body, namespace, name)¶ Update the specified Cloud.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_global_cloud
(body, name)¶ Update the specified GlobalCloud.
Parameters: - body (GlobalCloud) – Body of the HTTP request.
- name (str) – name of the GlobalCloud.
Returns: Body of the HTTP response.
Return type:
-
update_global_cloud_status
(body, name)¶ Update the specified GlobalCloud.
Parameters: - body (GlobalCloud) – Body of the HTTP request.
- name (str) – name of the GlobalCloud.
Returns: Body of the HTTP response.
Return type:
-
update_global_infrastructure_provider
(body, name)¶ Update the specified GlobalInfrastructureProvider.
Parameters: - body (GlobalInfrastructureProvider) – Body of the HTTP request.
- name (str) – name of the GlobalInfrastructureProvider.
Returns: Body of the HTTP response.
Return type:
-
update_infrastructure_provider
(body, namespace, name)¶ Update the specified InfrastructureProvider.
Parameters: - body (InfrastructureProvider) – Body of the HTTP request.
- namespace (str) – namespace in which the InfrastructureProvider will be updated.
- name (str) – name of the InfrastructureProvider.
Returns: Body of the HTTP response.
Return type:
-
watch_all_clouds
(heartbeat=None)¶ Generate a watcher for all Clouds.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: CloudList
-
watch_all_infrastructure_providers
(heartbeat=None)¶ Generate a watcher for all InfrastructureProviders.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: InfrastructureProviderList
-
watch_clouds
(namespace, heartbeat=None)¶ Generate a watcher for the Clouds in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
watch_global_clouds
(heartbeat=None)¶ Generate a watcher for the GlobalClouds in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: GlobalCloudList
-
watch_global_infrastructure_providers
(heartbeat=None)¶ Generate a watcher for the GlobalInfrastructureProviders in the namespace.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: GlobalInfrastructureProviderList
-
watch_infrastructure_providers
(namespace, heartbeat=None)¶ Generate a watcher for the InfrastructureProviders in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
-
class
krake.client.kubernetes.
KubernetesApi
(client)¶ Bases:
krake.client.ApiClient
Kubernetes API client
Example
from krake.client import Client with Client(url="http://localhost:8080") as client: kubernetes_api = KubernetesApi(client)
Parameters: client (krake.client.Client) – API client for accessing the Krake HTTP API -
create_application
(body, namespace)¶ Creates the specified Application.
Parameters: - body (Application) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
Returns: Body of the HTTP response.
Return type:
-
create_cluster
(body, namespace)¶ Creates the specified Cluster.
Parameters: Returns: Body of the HTTP response.
Return type:
-
delete_application
(namespace, name)¶ Deletes the specified Application.
Parameters: Returns: Body of the HTTP response.
Return type:
-
delete_cluster
(namespace, name)¶ Deletes the specified Cluster.
Parameters: Returns: Body of the HTTP response.
Return type:
-
list_all_applications
()¶ Lists all Applications.
Returns: Body of the HTTP response. Return type: ApplicationList
-
list_all_clusters
()¶ Lists all Clusters.
Returns: Body of the HTTP response. Return type: ClusterList
-
list_applications
(namespace)¶ Lists the Applications in the namespace.
Parameters: namespace (str) – namespace in which the Application will be updated. Returns: Body of the HTTP response. Return type: ApplicationList
-
list_clusters
(namespace)¶ Lists the Clusters in the namespace.
Parameters: namespace (str) – namespace in which the Cluster will be updated. Returns: Body of the HTTP response. Return type: ClusterList
-
read_application
(namespace, name)¶ Reads the specified Application.
Parameters: Returns: Body of the HTTP response.
Return type:
-
read_cluster
(namespace, name)¶ Reads the specified Cluster.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_application
(body, namespace, name)¶ Updates the specified Application.
Parameters: - body (Application) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
- name (str) – name of the Application.
Returns: Body of the HTTP response.
Return type:
-
update_application_binding
(body, namespace, name)¶ Updates the specified Application.
Parameters: - body (ClusterBinding) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
- name (str) – name of the Application.
Returns: Body of the HTTP response.
Return type:
-
update_application_complete
(body, namespace, name)¶ Updates the specified Application.
Parameters: - body (ApplicationComplete) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
- name (str) – name of the Application.
Returns: Body of the HTTP response.
Return type:
-
update_application_shutdown
(body, namespace, name)¶ Updates the specified Application.
Parameters: - body (ApplicationShutdown) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
- name (str) – name of the Application.
Returns: Body of the HTTP response.
Return type:
-
update_application_status
(body, namespace, name)¶ Updates the specified Application.
Parameters: - body (Application) – Body of the HTTP request.
- namespace (str) – namespace in which the Application will be updated.
- name (str) – name of the Application.
Returns: Body of the HTTP response.
Return type:
-
update_cluster
(body, namespace, name)¶ Updates the specified Cluster.
Parameters: Returns: Body of the HTTP response.
Return type:
-
update_cluster_binding
(body, namespace, name)¶ Update the specified Cluster.
Parameters: - body (CloudBinding) – Body of the HTTP request.
- namespace (str) – namespace in which the Cluster will be updated.
- name (str) – name of the Cluster.
Returns: Body of the HTTP response.
Return type:
-
update_cluster_status
(body, namespace, name)¶ Updates the specified Cluster.
Parameters: Returns: Body of the HTTP response.
Return type:
-
watch_all_applications
(heartbeat=None)¶ Generates a watcher for all Applications.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds. Returns: Body of the HTTP response. Return type: ApplicationList
-
watch_all_clusters
(heartbeat=None)¶ Generates a watcher for all Clusters.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds. Returns: Body of the HTTP response. Return type: ClusterList
-
watch_applications
(namespace, heartbeat=None)¶ Generates a watcher for the Applications in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
watch_clusters
(namespace, heartbeat=None)¶ Generates a watcher for the Clusters in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type:
-
-
class
krake.client.openstack.
OpenStackApi
(client)¶ Bases:
krake.client.ApiClient
Openstack API client
Example
from krake.client import Client with Client(url="http://localhost:8080") as client: openstack_api = OpenStackApi(client)
Parameters: client (krake.client.Client) – API client for accessing the Krake HTTP API -
create_magnum_cluster
(body, namespace)¶ Creates the specified MagnumCluster.
Parameters: - body (MagnumCluster) – Body of the HTTP request.
- namespace (str) – namespace in which the MagnumCluster will be updated.
Returns: Body of the HTTP response.
Return type: MagnumCluster
-
create_project
(body, namespace)¶ Creates the specified Project.
Parameters: - body (Project) – Body of the HTTP request.
- namespace (str) – namespace in which the Project will be updated.
Returns: Body of the HTTP response.
Return type: Project
-
delete_magnum_cluster
(namespace, name)¶ Deletes the specified MagnumCluster.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumCluster
-
delete_project
(namespace, name)¶ Deletes the specified Project.
Parameters: Returns: Body of the HTTP response.
Return type: Project
-
list_all_magnum_clusters
()¶ Lists all MagnumClusters.
Returns: Body of the HTTP response. Return type: MagnumClusterList
-
list_all_projects
()¶ Lists all Projects.
Returns: Body of the HTTP response. Return type: ProjectList
-
list_magnum_clusters
(namespace)¶ Lists the MagnumClusters in the namespace.
Parameters: namespace (str) – namespace in which the MagnumCluster will be updated. Returns: Body of the HTTP response. Return type: MagnumClusterList
-
list_projects
(namespace)¶ Lists the Projects in the namespace.
Parameters: namespace (str) – namespace in which the Project will be updated. Returns: Body of the HTTP response. Return type: ProjectList
-
read_magnum_cluster
(namespace, name)¶ Reads the specified MagnumCluster.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumCluster
-
read_project
(namespace, name)¶ Reads the specified Project.
Parameters: Returns: Body of the HTTP response.
Return type: Project
-
update_magnum_cluster
(body, namespace, name)¶ Updates the specified MagnumCluster.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumCluster
-
update_magnum_cluster_binding
(body, namespace, name)¶ Updates the specified MagnumCluster.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumCluster
-
update_magnum_cluster_status
(body, namespace, name)¶ Updates the specified MagnumCluster.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumCluster
-
update_project
(body, namespace, name)¶ Updates the specified Project.
Parameters: Returns: Body of the HTTP response.
Return type: Project
-
update_project_status
(body, namespace, name)¶ Updates the specified Project.
Parameters: Returns: Body of the HTTP response.
Return type: Project
-
watch_all_magnum_clusters
(heartbeat=None)¶ Generates a watcher for all MagnumClusters.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: MagnumClusterList
-
watch_all_projects
(heartbeat=None)¶ Generates a watcher for all Projects.
Parameters: heartbeat (int) – Number of seconds after which the server sends a heartbeat in form of an empty newline. Passing 0 disables the heartbeat. Default: 10 seconds Returns: Body of the HTTP response. Return type: ProjectList
-
watch_magnum_clusters
(namespace, heartbeat=None)¶ Generates a watcher for the MagnumClusters in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type: MagnumClusterList
-
watch_projects
(namespace, heartbeat=None)¶ Generates a watcher for the Projects in the namespace.
Parameters: Returns: Body of the HTTP response.
Return type: ProjectList
-
Controllers¶
This module comprises Krake controllers responsible for watching API resources and transferring the state of related real-world resources to the desired state specified in the API. Controllers can be written in any language and with every technique. This module provides basic functionality and paradigms to implement a simple “control loop mechanism” in Python.
-
class
krake.controller.
BurstWindow
(name, burst_time, max_retry=0, loop=None)¶ Bases:
object
Context manager that can be used to check the time arbitrary code took to run. This arbitrary code should be something that needs to run indefinitely. If this code fails too quickly, it is not restarted.
The criteria are as follows: every
max_retry
times, if the average running time of the task is more than theburst_time
, the task is considered savable and the context manager is exited. If not, an exception will be raised.window = BurstWindow("my_task", 10, max_retry=3) while True: # use any kind of loop with window: # code to retry # ...
Parameters: - name (str) – the name of the background task (for debugging purposes).
- burst_time (float) – maximal accepted average time for a retried task.
- max_retry (int, optional) – number of times the task should be retried before testing the burst time. If 0, the task will be retried indefinitely, without looking for attr:burst_time.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
-
__exit__
(*exc)¶ After the given number of tries, raise an exception if the content of the context manager failed too fast.
Raises: RuntimeError
– if a background task keep on failing more regularly than what the burst time allows.
-
class
krake.controller.
Controller
(api_endpoint, loop=None, ssl_context=None, debounce=0)¶ Bases:
object
Base class for Krake controllers providing basic functionality for watching and enqueuing API resources.
The basic workflow is as follows: the controller holds several background tasks. The API resources are watched by a Reflector, which calls a handler on each received state of a resource. Any received new state is put into a
WorkQueue
. Multiple workers consume this queue. Workers are responsible for doing the actual state transitions. The work queue ensures that a resource is processed by one worker at a time (strict sequential). The status of the real world resources is monitored by an Observer (another background task).However, this workflow is just a possibility. By modifying
__init__()
(or other functions), it is possible to add other queues, change the workers at will, add several Reflector or Observer, create additional background tasks…Parameters: - api_endpoint (str) – URL to the API
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- ssl_context (ssl.SSLContext, optional) – if given, this context will be used to communicate with the API endpoint.
- debounce (float, optional) – value of the debounce for the
WorkQueue
.
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
create_endpoint
(api_endpoint)¶ Ensure the scheme (HTTP/HTTPS) of the endpoint to connect to the API, depending on the existence of a given SSL context.
Parameters: api_endpoint (str) – the given API endpoint. Returns: the final endpoint with the right scheme. Return type: str
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
-
register_task
(corofactory, name=None)¶ - Add a coroutine to the list of task that will be run in the background
- of the Controller.
Parameters: - corofactory (coroutine) – the coroutine that will be used as task. It must
be running indefinitely and not catch
asyncio.CancelledError
. - name (str, optional) – the name of the background task, for logging purposes.
-
retry
(coro, name='')¶ Start a background task. If the task fails not too regularly, restart it A
BurstWindow
is used to decide if the task should be restarted.Parameters: - coro (coroutine) – the background task to try to restart.
- name (str) – the name of the background task (for debugging purposes).
Raises: RuntimeError
– if a background task keep on failing more regularly than what the burst time allows.
-
run
()¶ Start at once all the registered background tasks with the retry logic.
-
simple_on_receive
(resource, condition=<class 'bool'>)¶ Example of a resource receiving handler, that accepts a resource under conditions, and if they are met, add the resource to the queue. When listing values, you get a Resource, while when watching, you get an Event.
Parameters: - resource (krake.data.serializable.Serializable) – a resource received by listing.
- condition (callable, optional) – a condition to accept the given
resource. The signature should be
(resource) -> bool
.
-
exception
krake.controller.
ControllerError
(message)¶ Bases:
Exception
Base class for exceptions during handling of a resource.
-
__str__
()¶ Custom error message for exception
-
-
class
krake.controller.
Executor
(controller, loop=None, catch_signals=True)¶ Bases:
object
Component used to encapsulate the Controller. It takes care of starting the Controller, and handles all logic not directly dependent to the Controller, such as the handlers for the UNIX signals.
It implements the asynchronous context manager protocol. The controller itself can be awaited. The “await” call blocks until the Controller terminates.
executor = Executor(controller) async with executor: await executor
Parameters: - controller (krake.controller.Controller) – the controller that the executor is tasked with starting.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- catch_signals (bool, optional) – if True, the Executor will add handlers to catch killing signals in order to stop the Controller and the Executor gracefully.
-
__aenter__
()¶ Create the signal handlers and start the Controller as background task.
-
__aexit__
(*exc)¶ Wait for the managed controller to be finished and cleanup.
-
stop
()¶ Called as signal handler. Stop the Controller managed by the instance.
-
class
krake.controller.
Observer
(resource, on_res_update, time_step=1)¶ Bases:
object
Component used to watch the actual status of one instance of any resource.
Parameters: - resource – the instance of a resource that the Observer has to watch.
- on_res_update (coroutine) – a coroutine called when a resource’s actual status
differs from the status sent by the database. Its signature is:
(resource) -> updated_resource
.updated_resource
is the instance of the resource that is up-to-date with the API. The Observer internal instance of the resource to observe will be updated. If the API cannot be contacted,None
can be returned. In this case the internal instance of the Observer will not be updated. - time_step (int, optional) – how frequently the Observer should watch the actual status of the resources.
-
observe_resource
()¶ Update the watched resource if its status is different from the status observed. The status sent for the update is the observed one.
-
poll_resource
()¶ Fetch the current status of the watched resource.
Returns: Return type: krake.data.core.Status
-
run
()¶ Start the observing process indefinitely, with the Observer time step.
-
class
krake.controller.
Reflector
(listing, watching, on_list=None, on_add=None, on_update=None, on_delete=None, resource_plural=None, loop=None)¶ Bases:
object
Component used to contact the API, fetch resources and handle disconnections.
Parameters: - listing (coroutine) – the coroutine used to get the list of resources currently
stored by the API. Its signature is:
() -> <Resource>List
. - watching (coroutine) – the coroutine used to watch updates on the resources,
as sent by the API. Its signature is:
() -> watching object
. This watching object should be able to be used as context manager, and as generator. - on_list (coroutine) – the coroutine called when listing all resources with the
fetched resources as parameter. Its signature is:
(resource) -> None
. - on_add (coroutine, optional) – the coroutine called during watch, when an
ADDED event has been received. Its signature is:
(resource) -> None
. - on_update (coroutine, optional) – the coroutine called during watch, when a
MODIFIED event has been received. Its signature is:
(resource) -> None
. - on_delete (coroutine, optional) – the coroutine called during watch, when a
DELETED event has been received. Its signature is:
(resource) -> None
. - resource_plural (str, optional) – name of the resource that the reflector is
monitoring. For logging purpose. Default is
"resources"
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
-
__call__
(min_interval=2)¶ Start the Reflector. Encapsulate the connections with a retry logic, as disconnections are expected. If any other kind of error occurs, they are not swallowed.
Between two connection attempts, the connection will be retried later with a delay. If the connection fails to fast, the delay will be increased, to wait for the API to be ready. If the connection succeeded for a certain interval, the value of the delay is reset.
Parameters: min_interval (int, optional) – if the connection was kept longer than this value, the delay is reset to the base value, as it is considered that a connection was possible.
-
list_and_watch
()¶ Start the given list and watch coroutines.
-
list_resource
()¶ Pass each resource returned by the current instance’s listing function as parameter to the receiving function.
-
watch_resource
(watcher)¶ Pass each resource returned by the current instance’s watching object as parameter to the event receiving functions.
Parameters: watcher – an object that returns a new event every time an update on a resource occurs
- listing (coroutine) – the coroutine used to get the list of resources currently
stored by the API. Its signature is:
-
class
krake.controller.
WorkQueue
(maxsize=0, debounce=0, loop=None)¶ Bases:
object
Simple asynchronous work queue.
The key manages a set of key-value pairs. The queue guarantees strict sequential processing of keys: A key-value pair retrieved via
get()
is not returned viaget()
again untildone()
with the corresponding key is called, even if a new key-value pair with the corresponding key was put into the queue during the time of processing.Parameters: - maxsize (int, optional) – Maximal number of items in the queue before
put()
blocks. Defaults to 0 which means the size is infinite - debounce (float) – time in second for the debouncing of the values. A number higher than 0 means that the queue will wait the given time before giving a value. If a newer value is received, this time is reset.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used
dirty
holds the last known value of a key i.e. the next value which will be given by theget()
method.timers
holds the current debounce coroutine for a key. Either this coroutine is canceled (if a new value for a key is given to the WorkQueue through the meth:put) or the value is added to thedirty
dictionary.active
ensures that a key isn’t added twice to thequeue
. Keys are added to this set when they are first added to thedirty
dictionary, and are removed from the set when the Worker calls thedone()
method.Todo
- Implement rate limiting and delays
-
cancel
(key)¶ Cancel the corresponding debounce coroutine for the given key. An attempt to cancel the coroutine for a key which was not inserted into the queue does not raise any error, and is simply ignored.
Parameters: key – Key that identifies the value
-
close
()¶ Cancel all pending debounce timers.
-
done
(key)¶ Called by the Worker to notify that the work on the given key is done. This method first removes the key from the
active
set, and then adds this key to the set if a new value has arrived.Parameters: key – Key that used to identity the value
-
empty
()¶ Check if the queue is empty
- Returns
- bool: True if there are no dirty keys
-
get
()¶ Retrieve a key-value pair from the queue.
The queue will not return this key as long as
done()
is not called with this key.Returns: (key, value) tuple
-
put
(key, value, delay=None)¶ Put a new key-value pair into the queue.
Parameters:
- maxsize (int, optional) – Maximal number of items in the queue before
-
krake.controller.
create_ssl_context
(tls_config)¶ From a certificate, create an SSL Context that can be used on the client side for communicating with a Server.
Parameters: tls_config (krake.data.config.TlsClientConfiguration) – the “tls” configuration part of a controller. Returns: a default SSL Context tweaked with the given certificate elements Return type: ssl.SSLContext
-
krake.controller.
joint
(*aws, loop=None)¶ Start several coroutines together. Ensure that if one stops, all others are cancelled as well.
- FIXME: using asyncio.gather, if an error occurs in one of the “gathered” task, all
- the tasks are not necessarily stopped. @see https://stackoverflow.com/questions/59073556/how-to-cancel-all-remaining-tasks-in-gather-if-one-fails # noqa
Parameters: - aws (Awaitable) – a list of await-ables to start concurrently.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
-
krake.controller.
run
(controller)¶ Start the controller using an executor.
Parameters: controller (krake.controller.Controller) – the controller to start
-
krake.controller.
sigmoid_delay
(retries, maximum=60.0, steepness=0.75, midpoint=10.0, base=1.0)¶ Compute a waiting time (delay) depending on the number of retries already performed. The computing function is a sigmoid.
Parameters: - retries (int) – the number of attempts that happened already.
- maximum (float) – the maximum delay that can be attained. Maximum of the sigmoid.
- steepness (float) – how fast the delay increases. Steepness of the sigmoid.
- midpoint (float) – number of retries to reach the delay between maximum and base. Midpoint of the sigmoid.
- base (float) – minimum value for the delay.
Returns: the computed next delay.
Return type:
Controller Kubernetes Application¶
Module comprises Krake Kubernetes application controller logic.
-
class
krake.controller.kubernetes.application.
KubernetesApplicationController
(api_endpoint, worker_count=10, loop=None, ssl_context=None, debounce=0, hooks=None, time_step=2)¶ Bases:
krake.controller.Controller
Controller responsible for
krake.data.kubernetes.Application
resources. The controller manages Application resources in “SCHEDULED” and “DELETING” state.-
kubernetes_api
¶ Krake internal API to connect to the “kubernetes” API of Krake.
Type: KubernetesApi
-
"kubernetes" API of Krake.
-
hooks
¶ configuration to be used by the hooks supported by the controller.
Type: krake.data.config.HooksConfiguration
-
observer_time_step
¶ for the Observers: the number of seconds between two observations of the actual resource.
Type: float
-
observers
¶ mapping of all Application resource’ UID to their respective Observer and task responsible for the Observer. The signature is:
<uid> --> <observer>, <reference_to_observer's_task>
.Type: dict[str, (Observer, Coroutine)]
Parameters: - api_endpoint (str) – URL to the API
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- ssl_context (ssl.SSLContext, optional) – if given, this context will be used to communicate with the API endpoint.
- debounce (float, optional) – value of the debounce for the
WorkQueue
. - worker_count (int, optional) – the amount of worker function that should be run as background tasks.
- time_step (float, optional) – for the Observers: the number of seconds between two observations of the actual resource.
-
check_external_endpoint
()¶ Ensure the scheme in the external endpoint (if provided) is matching the scheme used by the Krake API (“https” or “http” if TLS is enabled or disabled respectively).
If they are not, a warning is logged and the scheme is replaced in the endpoint.
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
handle_resource
(run_once=False)¶ Infinite loop which fetches and hand over the resources to the right coroutine. The specific exceptions and error handling have to be added here.
This function is meant to be run as background task. Lock the handling of a resource with the
lock
attribute.Parameters: run_once (bool, optional) – if True, the function only handles one resource, then stops. Otherwise, continue to handle each new resource on the queue indefinitely.
-
list_app
(app)¶ Accept the Applications that need to be managed by the Controller on listing them at startup. Starts the observer for the Applications with actual resources.
Parameters: app (krake.data.kubernetes.Application) – the Application to accept or not.
-
on_status_update
(app)¶ Called when an Observer noticed a difference of the status of an application. Request an update of the status on the API.
Parameters: - app (krake.data.kubernetes.Application) – the Application whose
- has been updated or (status) –
Returns: the updated Application sent by the API.
Return type:
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
-
static
scheduled_or_deleting
(app)¶ Check if a resource should be accepted or not by the Controller to be handled.
Parameters: app (krake.data.kubernetes.Application) – the Application to check. Returns: True if the Application should be handled, False otherwise. Return type: bool
-
-
class
krake.controller.kubernetes.application.
KubernetesClient
(kubeconfig, custom_resources=None)¶ Bases:
object
Client for connecting to a Kubernetes cluster. This client:
- prepares the connection based on the information stored in the cluster’s kubeconfig file;
- prepares the connection to a custom resource’s API, if a Kubernetes resource to be managed relies on a Kubernetes custom resource;
- offers two methods:
-
apply()
: apply a manifest to create or update a resource -delete()
: delete a resource.
The client can be used as a context manager, with the Kubernetes client being deleted when leaving the context.
-
custom_resources
¶ name of all custom resources that are available on the current cluster.
Type: list[str]
-
resource_apis
¶ mapping of a Kubernetes’s resource name to the API object of the Kubernetes client which manages it (e.g. a Pod belongs to the “CoreV1” API of Kubernetes, so the mapping would be “Pod” -> <client.CoreV1Api_instance>), wrapped in an
ApiAdapter
instance.Type: dict
-
apply
(resource)¶ Apply the given resource on the cluster using its internal data as reference.
Parameters: resource (dict) – the resource to create, as a manifest file translated in dict. Returns: response from the cluster as given by the Kubernetes client. Return type: object
-
custom_resource_apis
¶ Determine custom resource apis for given cluster.
If given cluster supports custom resources, Krake determines apis from custom resource definitions.
The custom resources apis are requested only once and then are cached by cached property decorator. This is an advantage in case of the application contains multiple Kubernetes custom resources with the same kind, but with the different content, see example.
Example:
--- apiVersion: stable.example.com/v1 kind: CRD metadata: name: cdr_1 spec: crdSpec: spec_1 --- apiVersion: stable.example.com/v1 kind: CRD metadata: name: cdr_2 spec: crdSpec: spec_2
Returns: Custom resource apis Return type: dict Raises: InvalidCustomResourceDefinitionError
– If the request for the custom resource definition failed.
-
default_namespace
¶ From the kubeconfig file, get the default Kubernetes namespace where the resources will be created. If no namespace is specified, “default” will be used.
Returns: the default namespace in the kubeconfig file. Return type: str
-
delete
(resource)¶ Delete the given resource on the cluster using its internal data as reference.
Parameters: resource (dict) – the resource to delete, as a manifest file translated in dict.
Returns: - response from the
cluster as given by the Kubernetes client.
Return type: kubernetes_asyncio.client.models.v1_status.V1Status
Raises: InvalidManifestError
– if the kind or name is not present in the resource.ApiException
– by the Kubernetes API in case of malformed content or error on the cluster’s side.
-
get_immutables
(resource)¶ From a resource manifest, look for the group, version, kind, name and namespace of the resource.
If the latter is not present, the default namespace of the cluster is used instead.
Parameters: resource (dict[str, Any]) – the manifest file translated in dict of the resource from which the fields will be extracted.
Returns: - the group, version, kind, name and
namespace of the resource.
Return type: Raises: InvalidResourceError
– if the apiVersion, kind or the name is not present.Raises: InvalidManifestError
– if the apiVersion, kind or name is not present in the resource.ApiException
– by the Kubernetes API in case of malformed content or error on the cluster’s side.
-
get_resource_api
(group, version, kind)¶ - Get the Kubernetes API corresponding to the given group and version.
- If not found, look for it into the supported custom resources for the cluster.
Parameters: Returns: the API adapter to use for this resource.
Return type: ApiAdapter
Raises: UnsupportedResourceError
– if the group and version given are not supported by the Controller, and given kind is not a supported custom resource.
-
static
log_response
(response, kind, action=None)¶ Utility function to parse a response from the Kubernetes cluster and log its content.
Parameters:
-
shutdown
(app)¶ Gracefully shutdown the given application on the cluster by calling the apps exposed shutdown address.
Parameters: () (app) – the app to gracefully shutdown.
Returns: - response from the
cluster as given by the Kubernetes client.
Return type: kubernetes_asyncio.client.models.v1_status.V1Status
Raises: InvalidManifestError
– if the kind or name is not present in the resource.ApiException
– by the Kubernetes API in case of malformed content or error on the cluster’s side.
-
krake.controller.kubernetes.application.
register_service
(app, cluster, resource, response)¶ Register endpoint of Kubernetes Service object on creation and update.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- cluster (krake.data.kubernetes.Cluster) – The cluster on which the application is running
- resource (dict) – Kubernetes object description as specified in the specification of the application.
- response (kubernetes_asyncio.client.V1Service) – Response of the Kubernetes API
-
krake.controller.kubernetes.application.
unregister_service
(app, resource, **kwargs)¶ Unregister endpoint of Kubernetes Service object on deletion.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- resource (dict) – Kubernetes object description as specified in the specification of the application.
-
class
krake.controller.kubernetes.application.
KubernetesApplicationObserver
(cluster, resource, on_res_update, time_step=2)¶ Bases:
krake.controller.Observer
Observer specific for Kubernetes Applications. One observer is created for each Application managed by the Controller, but not one per Kubernetes resource (Deployment, Service…). If several resources are defined by an Application, they are all monitored by the same observer.
The observer gets the actual status of the resources on the cluster using the Kubernetes API, and compare it to the status stored in the API.
- The observer is:
- started at initial Krake resource creation;
- deleted when a resource needs to be updated, then started again when it is done;
- simply deleted on resource deletion.
Parameters: - cluster (krake.data.kubernetes.Cluster) – the cluster on which the observed Application is created.
- resource (krake.data.kubernetes.Application) – the application that will be observed.
- on_res_update (coroutine) – a coroutine called when a resource’s actual status
differs from the status sent by the database. Its signature is:
(resource) -> updated_resource
.updated_resource
is the instance of the resource that is up-to-date with the API. The Observer internal instance of the resource to observe will be updated. If the API cannot be contacted,None
can be returned. In this case the internal instance of the Observer will not be updated. - time_step (int, optional) – how frequently the Observer should watch the actual status of the resources.
-
poll_resource
()¶ Fetch the current status of the Application monitored by the Observer.
Returns: - the status object created using information from the
- real world Applications resource.
Return type: krake.data.core.Status
-
krake.controller.kubernetes.application.
get_kubernetes_resource_idx
(manifest, resource, check_namespace=False)¶ Get a resource identified by its resource api, kind and name, from a manifest file
Parameters: Raises: IndexError
– If the resource is not present in the manifestReturns: Position of the resource in the manifest
Return type:
-
krake.controller.kubernetes.application.
update_last_applied_manifest_from_resp
(app, response, **kwargs)¶ Hook run after the creation or update of an application in order to update the status.last_applied_manifest using the k8s response.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- response (kubernetes_asyncio.client.V1Status) – Response of the Kubernetes API
After a Kubernetes resource has been created/updated, the status.last_applied_manifest has to be updated. All fields already initialized (either from the mangling of spec.manifest, or by a previous call to this function) should be left untouched. Only observed fields which are not present in status.last_applied_manifest should be initialized.
-
krake.controller.kubernetes.application.
update_last_observed_manifest_from_resp
(app, response, **kwargs)¶ Handler to run after the creation or update of a Kubernetes resource to update the last_observed_manifest from the response of the Kubernetes API.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- response (kubernetes_asyncio.client.V1Service) – Response of the Kubernetes API
The target last_observed_manifest holds the value of all observed fields plus the special control dictionaries for the list length
Controller Kubernetes Cluster¶
Module comprises Krake Kubernetes cluster controller logic.
-
class
krake.controller.kubernetes.cluster.
KubernetesClusterController
(api_endpoint, worker_count=10, loop=None, ssl_context=None, debounce=0, time_step=2)¶ Bases:
krake.controller.Controller
Controller responsible for
krake.data.kubernetes.Application
andkrake.data.kubernetes.Cluster
resources. The controller manages Application resources in “SCHEDULED” and “DELETING” state and Clusters in any state.-
kubernetes_api
¶ Krake internal API to connect to the “kubernetes” API of Krake.
Type: KubernetesApi
-
"kubernetes" API of Krake.
-
observer_time_step
¶ for the Observers: the number of seconds between two observations of the actual resource.
Type: float
-
observers
¶ mapping of all Application or Cluster resource’ UID to their respective Observer and task responsible for the Observer. The signature is:
<uid> --> <observer>, <reference_to_observer's_task>
.Type: dict[str, (Observer, Coroutine)]
Parameters: - api_endpoint (str) – URL to the API
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- ssl_context (ssl.SSLContext, optional) – if given, this context will be used to communicate with the API endpoint.
- debounce (float, optional) – value of the debounce for the
WorkQueue
. - worker_count (int, optional) – the amount of worker function that should be run as background tasks.
- time_step (float, optional) – for the Observers: the number of seconds between two observations of the actual resource.
-
static
accept_accessible
(cluster)¶ Check if a resource should be accepted or not by the Controller.
Parameters: cluster (krake.data.kubernetes.Cluster) – the Cluster to check. Returns: True if the Cluster should be handled, False otherwise. Return type: bool
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
handle_resource
(run_once=False)¶ Infinite loop which fetches and hand over the resources to the right coroutine. The specific exceptions and error handling have to be added here.
This function is meant to be run as background task. Lock the handling of a resource with the
lock
attribute.Parameters: run_once (bool, optional) – if True, the function only handles one resource, then stops. Otherwise, continue to handle each new resource on the queue indefinitely.
-
list_cluster
(cluster)¶ Accept the Clusters that need to be managed by the Controller on listing them at startup. Starts the observer for the Cluster.
Parameters: cluster (krake.data.kubernetes.Cluster) – the cluster to accept or not.
-
on_status_update
(cluster)¶ Called when an Observer noticed a difference of the status of a resource. Request an update of the status on the API.
Parameters: - cluster (krake.data.kubernetes.Cluster) – the Cluster whose status
- been updated. (has) –
Returns: the updated Cluster sent by the API.
Return type:
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
-
-
krake.controller.kubernetes.cluster.
register_service
(app, cluster, resource, response)¶ Register endpoint of Kubernetes Service object on creation and update.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- cluster (krake.data.kubernetes.Cluster) – The cluster on which the application is running
- resource (dict) – Kubernetes object description as specified in the specification of the application.
- response (kubernetes_asyncio.client.V1Service) – Response of the Kubernetes API
-
krake.controller.kubernetes.cluster.
unregister_service
(app, resource, **kwargs)¶ Unregister endpoint of Kubernetes Service object on deletion.
Parameters: - app (krake.data.kubernetes.Application) – Application the service belongs to
- resource (dict) – Kubernetes object description as specified in the specification of the application.
-
class
krake.controller.kubernetes.cluster.
KubernetesClusterObserver
(resource, on_res_update, time_step=2)¶ Bases:
krake.controller.Observer
Observer specific for Kubernetes Clusters. One observer is created for each Cluster managed by the Controller.
The observer gets the actual status of the cluster using the Kubernetes API, and compare it to the status stored in the API.
- The observer is:
- started at initial Krake resource creation;
- deleted when a resource needs to be updated, then started again when it is done;
- simply deleted on resource deletion.
Parameters: - resource (krake.data.kubernetes.Cluster) – the cluster which will be observed.
- on_res_update (coroutine) – a coroutine called when a resource’s actual status
differs from the status sent by the database. Its signature is:
(resource) -> updated_resource
.updated_resource
is the instance of the resource that is up-to-date with the API. The Observer internal instance of the resource to observe will be updated. If the API cannot be contacted,None
can be returned. In this case the internal instance of the Observer will not be updated. - time_step (int, optional) – how frequently the Observer should watch the actual status of the resources.
-
poll_resource
()¶ Fetch the current status of the Cluster monitored by the Observer.
- Note regarding exceptions handling:
- The current cluster status is fetched by
poll_resource()
from its API. If the cluster API is shutting down the API server responds with a 503 (service unavailable, apiserver is shutting down) HTTP response which leads to the kubernetes client ApiException. If the cluster’s API has been successfully shut down and there is an attempt to fetch cluster status, the ClientConnectorError is raised instead. Therefore, both exceptions should be handled.
Returns: - the status object created using information from the
- real world Cluster.
Return type: krake.data.core.Status
Controller Scheduler¶
Module comprises Krake scheduling logic of the Krake application.
-
class
krake.controller.scheduler.
Scheduler
(api_endpoint, worker_count=10, reschedule_after=60, stickiness=0.1, ssl_context=None, debounce=0, loop=None)¶ Bases:
krake.controller.Controller
The scheduler is a controller that receives all pending and updated applications and selects the “best” backend for each one of them based on metrics of the backends and application specifications.
Parameters: - worker_count (int, optional) – the amount of worker function that should be run as background tasks.
- reschedule_after (float, optional) – number of seconds after which a resource should be rescheduled.
- ssl_context (ssl.SSLContext, optional) – SSL context that should be used to communicate with the API server.
- debounce (float, optional) – number of seconds the scheduler should wait before it reacts to a state change.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
Controller Garbage Collector¶
This module defines the Garbage Collector present as a background task on the API application. When a resource is marked as deleted, the GC mark all its dependents as deleted. After cleanup is done by the respective Controller, the gc handles the final deletion of resources.
Marking a resource as deleted (by setting the deleted timestamp of its metadata) is irreversible: if the garbage collector receives such a resource, it will start the complete deletion process, with no further user involvement.
The configuration should have the following structure:
api_endpoint: http://localhost:8080
worker_count: 5
debounce: 1
tls:
enabled: false
client_ca: tmp/pki/ca.pem
client_cert: tmp/pki/system:gc.pem
client_key: tmp/pki/system:gc-key.pem
log:
...
-
exception
krake.controller.gc.
DependencyCycleException
(resource, cycle, *args)¶ Bases:
krake.controller.gc.DependencyException
Raised in case a cycle in the dependencies has been discovered while adding or updating a resource.
Parameters: - resource (krake.data.core.ResourceRef) – the resource added or updated that triggered the exception.
- cycle (set) – the cycle of dependency relationships that has been discovered.
-
exception
krake.controller.gc.
DependencyException
¶ Bases:
Exception
Base class for dependency exceptions.
-
class
krake.controller.gc.
DependencyGraph
¶ Bases:
object
Representation of the dependencies of all Krake resources by an acyclic directed graph. This graph can be used to get the dependents of any resource that the graph received.
If an instance of a resource A depends on a resource B, A will have B in its owner list. In this case, * A depends on B * B is a dependency of A * A is a dependent of B
The nodes of the graph are
krake.data.core.ResourceRef
, created from the actual resources. The edges are directed links from a dependency to its dependents.krake.data.core.ResourceRef
are used instead of the resource directly, as they are hashable and can be used as key of a dictionary. Otherwise, we would need to make any newly added resource as hashable for the sake of the dependency graph.The actual resources are still referenced in the
_resources
. It allows the access to the actual owners of a resource, not theirkrake.data.core.ResourceRef
.-
add_resource
(resource, owners, check_cycles=True)¶ Add a resource and its dependencies relationships to the graph.
Parameters: - resource (krake.data.core.ResourceRef) – the resource to add to the graph.
- owners (list) – list of owners (dependencies) of the resource.
- check_cycles (bool, optional) – if False, does not check if adding the resource creates a cycle, and simply add it.
-
get_direct_dependents
(resource)¶ Get the dependents of a resource, but only the ones directly dependent, no recursion is performed.
Parameters: resource (krake.data.core.ResourceRef) – the resource for which the search will be performed. Returns: - the list of
krake.data.core.ResourceRef
to the dependents - of the given resource (=that depends on the resource).
Return type: list - the list of
-
remove_resource
(resource, check_dependents=True)¶ If a resource has no dependent, remove it from the dependency graph, and from the dependents of other resources.
Parameters: - resource (krake.data.core.ResourceRef) – the resource to remove.
- check_dependents (bool, optional) – if False, does not check if the resource to remove has dependents, and simply remove it along with the dependents.
Raises: ResourceWithDependentsException
– if the resource to remove has dependents.
-
update_resource
(resource, owners)¶ Update the dependency relationships of a resource on the graph.
Parameters: - resource (krake.data.core.ResourceRef) – the resource whose ownership may need to be modified.
- owners (list) – list of owners (dependencies) of the resource.
-
-
class
krake.controller.gc.
GarbageCollector
(api_endpoint, worker_count=10, loop=None, ssl_context=None, debounce=0)¶ Bases:
krake.controller.Controller
Controller responsible for marking the dependents of a resource as deleted, and for deleting all resources without any finalizer.
Parameters: - api_endpoint (str) – URL to the API
- worker_count (int, optional) – the amount of worker function that should be run as background tasks.
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- ssl_context (ssl.SSLContext, optional) – if given, this context will be used to communicate with the API endpoint.
- debounce (float, optional) – value of the debounce for the
WorkQueue
.
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
get_api_method
(reference, verb)¶ Retrieve the client method of the API of the given resource to do the given action.
Parameters: - reference (any) – a resource or reference to a resource for which a method of its API needs to be selected.
- verb (str) – the verb describing the action for which the method should be returned.
Returns: - a method to perform the given action on the given resource
(through its client).
Return type: callable
-
handle_resource
(run_once=False)¶ Infinite loop which fetches and hand over the resources to the right coroutine. This function is meant to be run as background task.
Parameters: run_once (bool, optional) – if True, the function only handles one resource, then stops. Otherwise, continue to handle each new resource on the queue indefinitely.
-
static
is_in_deletion
(resource)¶ Check if a resource needs to be deleted or not.
Parameters: resource (krake.data.serializable.ApiObject) – the resource to check. Returns: True if the given resource is in deletion state, False otherwise. Return type: bool
-
on_received_deleted
(resource)¶ To be called when a resource is deleted on the API. Remove the resource from the dependency graph and add its dependencies to the Worker queue.
Parameters: resource (krake.data.serializable.ApiObject) – the deleted resource.
-
on_received_new
(resource)¶ To be called when a resource is received for the first time by the garbage collector. Add the resource to the dependency graph and handle the resource if accepted.
If a cycle is detected when adding the resource, all resources of the cycle are removed.
Parameters: resource (krake.data.serializable.ApiObject) – the newly added resource.
-
on_received_update
(resource)¶ To be called when a resource is updated on the API. Update the resource on the dependency graph and handle the resource if accepted.
If a cycle is detected when adding the resource, all resources of the cycle are removed.
Parameters: resource (krake.data.serializable.ApiObject) – the updated resource.
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
-
resource_received
(resource)¶ Core functionality of the garbage collector. Mark the given resource’s direct dependents as to be deleted, or remove the deletion finalizer if the resource has no dependent.
Parameters: resource (krake.data.serializable.ApiObject) – a resource in deletion state.
-
exception
krake.controller.gc.
ResourceWithDependentsException
(dependents, *args)¶ Bases:
krake.controller.gc.DependencyException
Raise when an attempt to remove a resource from the dependency graph implies removing a resource that has still dependents, and thus should not be removed if the integrity of the dependency graph needs to be kept.
For instance: If B depends on A, A should be removed.
Parameters: dependents (list) – The list of dependents that are now orphaned.
Controller Magnum¶
Module for Krake controller responsible for managing Magnum cluster resources and creating their respective Kubernetes cluster. It connects to the Magnum service of the Project on which a MagnumCluster has been scheduled.
python -m krake.controller.magnum --help
Configuration is loaded from the controllers.scheduler
section:
api_endpoint: http://localhost:8080
worker_count: 5
debounce: 1.0
poll_interval: 30
tls:
enabled: false
client_ca: tmp/pki/ca.pem
client_cert: tmp/pki/system:magnum.pem
client_key: tmp/pki/system:magnum-key.pem
log:
...
-
exception
krake.controller.magnum.
CreateFailed
(message)¶ Bases:
krake.controller.ControllerError
Raised in case the creation of a Magnum cluster failed.
-
exception
krake.controller.magnum.
DeleteFailed
(message)¶ Bases:
krake.controller.ControllerError
Raised in case the deletion of a Magnum cluster failed.
-
exception
krake.controller.magnum.
InvalidClusterTemplateType
(message)¶ Bases:
krake.controller.ControllerError
Raised in case the given Magnum template is not a template for a Kubernetes cluster.
-
class
krake.controller.magnum.
MagnumClusterController
(*args, worker_count=5, poll_interval=30, **kwargs)¶ Bases:
krake.controller.Controller
The Magnum controller receives the MagnumCluster resources from the API and acts on it, by creating, updating or deleting their actual cluster counterparts. It uses the OpenStack Magnum client for this purpose.
Parameters: - api_endpoint (str) – URL to the API
- loop (asyncio.AbstractEventLoop, optional) – Event loop that should be used.
- ssl_context (ssl.SSLContext, optional) – if given, this context will be used to communicate with the API endpoint.
- debounce (float, optional) – value of the debounce for the
WorkQueue
. - worker_count (int, optional) – the amount of worker function that should be run as background tasks.
- poll_interval (float) – time in second before two attempts to modify a Magnum cluster (creation, deletion, update, change from FAILED state…).
-
cleanup
()¶ Unregister all background tasks that are attributes.
-
consume
(run_once=False)¶ Continuously retrieve new elements from the worker queue to be processed.
Parameters: run_once (bool, optional) – if True, the function only handles one resource, then stops. Otherwise, continue to handle each new resource on the queue indefinitely.
-
create_magnum_client
(cluster)¶ Create a client to communicate with the Magnum service API for the given Magnum cluster. The specifications defined in the OpenStack project of the cluster are used to create the client.
Parameters: cluster (krake.data.openstack.MagnumCluster) – the cluster whose project’s specifications will be used to connect to the Magnum service. Returns: - the Magnum client to use to connect to the Magnum service on
- the project of the given Magnum cluster.
Return type: MagnumV1Client
-
delete_magnum_cluster
(cluster)¶ Initiate the deletion of the actual given Magnum cluster, and wait for its deletion. The finalizer specific to the Magnum Controller is also removed from the Magnum cluster resource.
Parameters: cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster that needs to be deleted.
-
on_creating
(cluster, magnum)¶ Called when a Magnum cluster with the CREATING state needs reconciliation.
Watch over a Magnum cluster currently being created on its scheduled OpenStack project, and updates the corresponding Kubernetes cluster created in the API.
As the Magnum cluster is in a stable state at the end, no further processing method is needed to return.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster that needs to be processed.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
-
on_pending
(cluster, magnum)¶ Called when a Magnum cluster with the PENDING state needs reconciliation.
Initiate the creation of a Magnum cluster using the registered Magnum template, but does not ensure that the creation succeeded.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster to actually create on its scheduled OpenStack project.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
Returns: - the next function to be called, as the Magnum cluster changed its
state. In this case, the Magnum cluster has now the CREATING state, thus the function returned is
on_creating()
.
Return type: callable
-
on_reconciling
(cluster, magnum)¶ Called when a Magnum cluster with the RECONCILING state needs reconciliation.
Watch over a Magnum cluster already created on its scheduled OpenStack project, and updates the corresponding Kubernetes cluster created in the API.
As the Magnum cluster is in a stable state at the end, no further processing method is needed to return.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster that needs to be processed.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
-
on_running
(cluster, magnum)¶ Called when a Magnum cluster with the RUNNING state needs reconciliation.
If the Magnum cluster needs to be resized, initiate the resizing. Otherwise, updates the corresponding Kubernetes cluster created in the API.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster that needs to be processed.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
Returns: - the next function to be called, as the Magnum cluster changed its
state. In the case of resizing, the Magnum cluster has now the RECONCILING state, thus the function returned is
on_creating()
. Otherwise, as the state is stable at the end, no further processing is needed and None is returned.
Return type: callable
-
prepare
(client)¶ Start all API clients that the controller will be using. Create all necessary coroutines and register them as background tasks that will be started by the Controller.
Parameters: client (krake.client.Client) – the base client to use for the API client to connect to the API.
-
process_cluster
(cluster)¶ Process a Magnum cluster: if the given cluster is marked for deletion, delete the actual cluster. Otherwise, start the reconciliation between a Magnum cluster spec and its state.
Handle any
ControllerError
or the supported OpenStack error that are raised during the processing.Parameters: cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster to process.
-
reconcile_kubernetes_resource
(cluster, magnum)¶ Create or update the Krake resource of the Kubernetes cluster that was created from a given Magnum cluster.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Kubernetes cluster will be created using the specifications of this Magnum cluster.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
Raises: ClientResponseError
– when checking if the Kubernetes cluster resource already exists, raise if any HTTP error except 404 is raised.
-
reconcile_magnum_cluster
(cluster)¶ Depending on the state of the given Magnum cluster, start the rapprochement of the wanted state of the cluster to the desired one.
Parameters: cluster (krake.data.openstack.MagnumCluster) – the cluster whose actual state will be modified to match the desired one.
-
wait_for_running
(cluster, magnum)¶ Await for an actual Magnum cluster to be in a stable state, that means, when its creation or update is finished.
Parameters: - cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster on which an operation is performed that needs to be awaited.
- magnum (MagnumV1Client) – the Magnum client to use to connect to the Magnum service on the project.
Raises: ControllerError
– if the operation on the cluster failed, a corresponding error will be raised (for instance CreateFailed in case the creation of the cluster failed).
-
exception
krake.controller.magnum.
ReconcileFailed
(message)¶ Bases:
krake.controller.ControllerError
Raised in case the update of a Magnum cluster failed.
-
krake.controller.magnum.
concurrent
(fn)¶ Decorator function to turn a synchronous function into an asynchronous coroutine that runs in another thread, that can be awaited and thus does not block the main asyncio loop. It is particularly useful for synchronous tasks which requires a long time to be run concurrently to the main asyncio loop.
Example
@concurrent def my_function(args_1, arg2=value): # long synchronous processing... return result await my_function(value1, arg2=value2) # function run in another thread
Parameters: fn (callable) – the function to run in parallel from the main loop. Returns: - decorator around the given function. The returned callable is an
- asyncio coroutine.
Return type: callable
-
krake.controller.magnum.
create_client_certificate
(client, cluster, csr)¶ Create and get a certificate for the given Magnum cluster.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster for which a kubeconfig file will be created.
- csr (str) – the certificate signing request (CSR) to use on the Magnum service for the creation of the certificate.
Returns: the generated certificate.
Return type:
-
krake.controller.magnum.
create_magnum_cluster
(client, cluster)¶ Create an actual Magnum cluster by connecting to the the Magnum service.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the cluster to create.
Returns: the cluster created by the Magnum service.
Return type: magnumclient.v1.clusters.Cluster
-
krake.controller.magnum.
delete_magnum_cluster
(client, cluster)¶ Delete the actual Magnum cluster that corresponds to the given resource.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the cluster to delete.
Returns: the cluster deleted by the Magnum service.
Return type: magnumclient.v1.clusters.Cluster
-
krake.controller.magnum.
format_openstack_error
(error)¶ Create a more readable error message using OpenStack specific errors.
Parameters: error (BaseException) – the exception whose information is used to create a message. Returns: the generated error message. Return type: str
-
krake.controller.magnum.
generate_magnum_cluster_name
(cluster)¶ Create a unique name for a Magnum cluster from its metadata. The name has the following structure: “<namespace>-<name>-<random_lowercase_digit_string>”. Any special character that the Magnum service would see as invalid will be replaced.
Parameters: cluster (krake.data.openstack.MagnumCluster) – the cluster to use to create a name. Returns: the name generated. Return type: str
-
krake.controller.magnum.
make_csr
(key_size=4096)¶ Generates a private key and corresponding certificate and certificate signing request.
Parameters: key_size (int) – Length of private key in bits Returns: private key, certificate signing request (CSR) Return type: (str, str)
-
krake.controller.magnum.
make_keystone_session
(project)¶ Create an OpenStack Keystone session using the authentication information of the given project resource.
Parameters: project (krake.data.openstack.Project) – the OpenStack project to use for getting the credentials and endpoint. Returns: the Keystone session created. Return type: Session
-
krake.controller.magnum.
make_kubeconfig
(client, cluster)¶ Create a kubeconfig for the Kubernetes cluster associated with the given Magnum cluster. For this process, it uses (non exhaustively) the name, address and certificates associated with it.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster for which a kubeconfig will be created.
Returns: the kubeconfig created, returned as a dictionary.
Return type:
-
krake.controller.magnum.
make_magnum_client
(project)¶ Create a Magnum client to connect to the given OpenStack project.
Parameters: project (krake.data.openstack.Project) – the project to connect to. Returns: - the client to connect to the Magnum service of the given
- project.
Return type: MagnumV1Client
-
krake.controller.magnum.
randstr
(length=7)¶ Create a random string of lowercase and digit character of the given length.
Parameters: length (int) – specifies how many characters should be present in the returned string. Returns: the string randomly generated. Return type: str
-
krake.controller.magnum.
read_ca_certificate
(client, cluster)¶ Get the certificate authority used by the given Magnum cluster.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the Magnum cluster for which the certificate authority will be retrieved.
Returns: the certificate authority of the given cluster.
Return type:
-
krake.controller.magnum.
read_magnum_cluster
(client, cluster)¶ Read the actual information of the given Magnum cluster resource.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the resource whose actual cluster state will be read.
Returns: - the current information regarding the given
Magnum cluster.
Return type: magnumclient.v1.clusters.Cluster
-
krake.controller.magnum.
read_magnum_cluster_template
(client, cluster)¶ Get the actual template associated with the one specified in the given Magnum cluster resource.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the template given is the one specified by this Magnum cluster.
Returns: magnumclient.v1.cluster_templates.ClusterTemplate
-
krake.controller.magnum.
resize_magnum_cluster
(client, cluster)¶ Update the given Magnum cluster by changing its node count.
Parameters: - client (MagnumV1Client) – the Magnum client to use to connect to the Magnum service.
- cluster (krake.data.openstack.MagnumCluster) – the cluster to resize.
Returns: the cluster updated by the Magnum service.
Return type: magnumclient.v1.clusters.Cluster
Data Abstraction¶
Data abstraction module for all REST resources used by the Krake API. This
module provides common data definitions for krake.api
and
krake.client
.
The core functionality is provided by serializable
providing a Python
API for declarative definitions of data models together with serializing and
deserializing functionality.
Domain-specific models are defined in corresponding submodules, e.g.
Kubernetes-related data models are defined in kubernetes
.
-
class
krake.data.
Key
(template, attribute=None)¶ Bases:
object
Etcd key template using the same syntax as Python’s standard format strings for parameters.
Example
key = Key("/books/{namespaces}/{isbn}")
The parameters are substituted by in the corresponding methods by either attributes of the passed object or additional keyword arguments.
Parameters: - template (str) – Key template with format string-like parameters
- attribute (str, optional) – Load attributes in
format_object()
from this attribute of the passed object.
-
format_kwargs
(**kwargs)¶ Create a key from keyword arguments
Parameters: **kwargs – Keyword arguments for parameter substitution Returns: Key from the key template with all parameters substituted by the given keyword arguments. Return type: str
-
format_object
(obj)¶ Create a key from a given object
If
attribute
is given, attributes are loaded from this attribute of the object rather than the object itself.Parameters: obj (object) – Object from which attributes are looked up Returns: Key from the key template with all parameters substituted by attributes loaded from the given object. Return type: str Raises: AttributeError
– If a required parameter is missing
-
matches
(key)¶ Check if a given key matches the template
Parameters: key (str) – Key that should be checked Returns: True of the given key matches the key template Return type: bool
-
prefix
(**kwargs)¶ Create a partial key (prefix) for a given object.
Parameters: **kwargs – Parameters that will be used for substitution Returns: Partial key from the key template with some parameters substituted Return type: str Raises: TypeError
– If a parameter is passed as keyword argument but a preceding parameter is not given.
-
krake.data.
persistent
(key)¶ Decorator factory for marking a class with a template that should be used as etcd key.
The passed template will be converted into a
Key
instance using themetadata
attribute and will be assigned to the__etcd_key__
attribute of the decorated class.Example
from krake.data import persistent from krake.data.serializable import Serializable, persistent from krake.data.core import Metadata @persistent("/books/{name}") class Book(Serializable): metadata: Metadata
Parameters: key (str) – Etcd key template. Parameters will be loaded from the metadata
attribute of the decorated class.Returns: Decorator that can be used to assign an __etcd_key__
attribute to the decorated object based on the passed key template.Return type: callable
This module defines a declarative API for defining data models that are JSON-serializable and JSON-deserializable.
-
class
krake.data.serializable.
ApiObject
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Base class for objects manipulated via REST API.
api
andkind
should be defined as simple string class :variables. They are automatically converted into dataclass fields with :corresponding validators.Example
from krake.data.serializable import ApiObject from krake.data.core import Metadata, Status class Book(ApiObject): api: str = "shelf" # The book resource belongs to the "shelf api" kind: str = "Book" metadata: Metadata spec: BookSpec status: Status
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.serializable.
ModelizedSchema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶ Bases:
marshmallow.schema.Schema
Simple marshmallow schema constructing Python objects in a
post_load
hook.Subclasses can specify a callable attribute
__model__
which is called with all deserialized attributes as keyword arguments.The
Meta.unknown
field is set to avoid considering unknown fields during validation. It mostly prevents create tests from failing.-
__model__
¶ Model factory returning a new instance of a specific model
Type: callable
-
-
class
krake.data.serializable.
PolymorphicContainer
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Base class for polymorphic serializable objects.
The polymorphic serializable has a string attribute
type
which is used as discriminator for the different types. There is an attribute named exactly like the value of thetype
attribute containing the deserialized subtype.Every new subclass will create its own
Schema
attribute. This means every subclass has its own internal subtype registry.-
Schema
¶ Schema that will be used for (de-)serialization of the class.
Type: PolymorphicContainerSchema
Example:
from krake.data.serializable import Serializable, PolymorphicContainer class ValueSpec(PolymorphicContainer): pass @ProviderSpec.register("float") class FloatSpec(Serializable): min: float max: float @ProviderSpec.register("bool") class BoolSpec(Serializable): pass # Deserialization spec = ProviderSpec.deserialize({ "type": "float", "float": { "min": 0, "max": 1.0, }, }) assert isinstance(spec.float, FloatSpec) # Serialization assert ProviderSpec(type="bool", bool=BoolSpec()).serialize() == { "type": bool, "bool": {}, }
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)
-
classmethod
register
(name)¶ Decorator function for registering a class under a unique name.
Parameters: name (str) – Name that will be used as value for the type
field to identify the decorated class.Returns: Decorator that will register the decorated class in the polymorphic schema (see PolymorphicContainerSchema.register()
).Return type: callable
-
update
(overwrite)¶ Update the polymorphic container with fields from the overwrite object.
A reference to the polymorphic field – the field called like the value of the
type
attribute – of the overwrite object is assigned to the current object even if the types of the current object and the overwrite object are identical.Parameters: overwrite (Serializable) – Serializable object will be merged with the current object.
-
-
class
krake.data.serializable.
PolymorphicContainerSchema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶ Bases:
marshmallow.schema.Schema
Schema that is used by
PolymorphicContainer
It declares just one string field
type
which is used as discriminator for the different types.There should be a field called exactly like the type. The value of this field is passed to the registered schema for deserialization.
--- type: float float: min: 0 max: 1.0 --- type: int int: min: 0 max: 100
Every subclass will create its own internal subtype registry.
-
classmethod
register
(type, dataclass)¶ Register a
Serializable
for the given type stringParameters: Raises: ValueError
– If the type name is already registered
-
classmethod
-
class
krake.data.serializable.
Serializable
(**kwargs)¶ Bases:
object
Base class for declarative serialization API.
Fields can be marked with the
metadata
attribute ofdataclasses.Field
. Currently the following markers exists:- readonly
- A field marked as “readonly” is automatically generated by the
API server and not controlled by the user. The user cannot update
this field. The corresponding marshmallow field allows
None
as valid value. - subresource
- A field marked as “subresource” is ignored in update request of a resource. Extra REST call are required to update a subresource. A well known subresource is “status”.
All field metadata attributes are also passed to the
marshmallow.fields.Field
instance. This means the user can control the generated marshmallow field with the metadata attributes.The class also defines a custom
__init__
method accepting every attribute as keyword argument in arbitrary order in contrast to the standard init method of dataclasses.Example
from krake.data.serializable import Serializable class Book(Serializable): author: str title: str isbn: str = fields(metadata={"readonly": True}) assert hasattr(Book, "Schema")
There are cases where multiple levels needs to be validated together. In this case, the
validates
metadata key for a single field is not sufficient anymore. One solution is to overwrite the auto-generated schema by a custom schema using themarshmallow.decorators.validates_schema()
decorator.Another solution is leveraging the
__post_init__()
method of dataclasses. The fields can be validated in this method and a raisedmarshmallow.ValidationError
will propagate to the Schema deserialization method.from marshmallow import ValidationError class Interval(Serializable): max: int min: int def __post_init__(self): if self.min > self.max: raise ValidationError("'min' must not be greater than 'max'") # This will raise a ValidationError interval = Interval.deserialize({"min": 2, "max": 1})
-
Schema
¶ Schema for this dataclass
Type: ModelizedSchema
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)
-
__post_init__
()¶ The
__init__()
method calls this method after all fields are initialized.It is mostly useful for schema-level validation (see above).
For now,
Serializable
does not support init-only variables because they do not make much sense for object stored in a database. This means no additional parameters are passed to this method.
-
classmethod
deserialize
(data, creation_ignored=False)¶ Loading an instance of the class from JSON-encoded data.
Parameters: Raises: marshmallow.ValidationError
– If the data is invalid
-
classmethod
fields_ignored_by_creation
()¶ Return the name of all fields that do not have to be provided during the creation of an instance.
Returns: Set of name of fields that are either subresources or read-only, or nested read-only fields. Return type: set
-
classmethod
readonly_fields
(prefix=None)¶ Return the name of all read-only fields. Nested fields are returned with dot-notation, for lists also. In this case, the argument is the one taken into account for looking at the read-only fields.
Example:
class Comment(Serializable): id: int = field(metadata={"readonly": True}) content: str class BookMetadata(Serializable): name: str = field(metadata={"readonly": True}) published: datetime = field(metadata={"readonly": True}) last_borrowed: datetime class Book(Serializable): id: int = field(metadata={"readonly": True}) metadata: BookMetadata status: str comments: List[Comment] expected = {'id', 'metadata.name', 'metadata.published', 'comment.id'} assert Book.readonly_fields() == expected
Parameters: prefix (str, optional) – Used for internal recursion Returns: Set of field names that are marked as with readonly
in their metadata.Return type: set
-
serialize
(creation_ignored=False)¶ Serialize the object using the generated
Schema
.Parameters: creation_ignored (bool) – if True, all attributes not needed at the creation are ignored. This contains the read-only and subresources, which can only be created by the API. Returns: JSON representation of the object Return type: dict
-
classmethod
subresources_fields
()¶ Return the name of all fields that are defined as subresource.
Returns: - Set of field names that are marked as
subresource
in their - metadata
Return type: set - Set of field names that are marked as
-
update
(overwrite)¶ Update data class fields with corresponding fields from the overwrite object.
If a field is marked as _subresource_ or _readonly_ it is not modified. If a field is marked as _immutable_ and there is an attempt to update the value, the
ValueError
is raised. Otherwise, attributes from overwrite will replace attributes from the current object.The
update()
must ignore the _subresource_ and _readonly_ fields, to avoid accidentally overwriting e.g. status fields in read-modify-write scenarios.The function works recursively for nested
Serializable
attributes which means theupdate()
method of the attribute will be used. This means the identity of aSerializable
attribute will not change unless the current attribute or the overwrite attribute isNone
.All other attributes are updated by assigning references from the overwrite attributes to the current object. This leads to a behavior similar to “shallow copying” (see
copy.copy()
). If the attribute is mutable, e.g.list
ordict
, the attribute in the current object will reference the same object as in the overwrite object.Parameters: overwrite (Serializable) – Serializable object will be merged with the current object. Raises: ValueError
– If there is an attempt to update an _immutable_ field.
-
class
krake.data.serializable.
SerializableMeta
¶ Bases:
type
Metaclass for
Serializable
. It automatically converts a specified class into an dataclass (seedataclasses.dataclass()
) and creates a correspondingmarshmallow.Schema
class. The schema class is assigned to theSchema
attribute.
-
krake.data.serializable.
field_for_schema
(type_, default=<dataclasses._MISSING_TYPE object>, **metadata)¶ Create a corresponding
marshmallow.fields.Field
for the passed type.If
metadata
containsmarshmallow_field
key, the value will be used directly as field.If
type_
has aSchema
attribute which should be a subclass ofmarshmallow.Schema
a :class.`marshmallow.fields.Nested` field will be returned wrapping the schema.If
type_
has aField
attribute which should be a subclass ofmarshmallow.fields.Field
an instance of this attribute will be returned.Parameters: Returns: Serialization field for the passed type
Return type: Raises: NotImplementedError
– If the marshmallow field cannot not be determined for the passed type
-
krake.data.serializable.
is_base_generic
(cls)¶ Detects generic base classes, for example
List
but notList[int]
.Parameters: cls – Type annotation that should be checked Returns: True if the passed type annotation is a generic base. Return type: bool
-
krake.data.serializable.
is_generic
(cls)¶ Detects any kind of generic, for example List or List[int]. This includes “special” types like Union and Tuple - anything that’s subscriptable, basically.
Parameters: cls – Type annotation that should be checked Returns: True if the passed type annotation is a generic. Return type: bool
-
krake.data.serializable.
is_generic_subtype
(cls, base)¶ Check if a given generic class is a subtype of another generic class
If the base is a qualified generic, e.g.
List[int]
, it is checked if the types are equal. If the base or cls does not have the attribute __origin__, e.g. Union, Optional, it is checked, if the type of base or cls is equal to the opponent. This is done for every possible case. If the base and cls have the attribute __origin__, e.g.list
fortyping.List
, it is checked if the class is equal to the original type of the generic base class.Parameters: - cls – Generic type
- base – Generic type that should be the base of the given generic type.
Returns: True of the given generic type is a subtype of the given base generic type.
Return type:
-
krake.data.serializable.
is_qualified_generic
(cls)¶ Detects generics with arguments, for example
List[int]
but notList
Parameters: cls – Type annotation that should be checked Returns: True if the passed type annotation is a qualified generic. Return type: bool .
-
class
krake.data.core.
BaseMetric
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
BaseMetricsProvider
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Conflict
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
CoreMetadata
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
GlobalMetric
(**kwargs)¶ Bases:
krake.data.core.BaseMetric
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
GlobalMetricList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
GlobalMetricsProvider
(**kwargs)¶ Bases:
krake.data.core.BaseMetricsProvider
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
GlobalMetricsProviderList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
KafkaSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Specifications to connect to a KSQL database, and retrieve a specific row from a specific table.
-
comparison_column
¶ name of the column where the value will be compared to the metric name, to select the right metric.
Type: str
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.core.
ListMetadata
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Metadata
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Metric
(**kwargs)¶ Bases:
krake.data.core.BaseMetric
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricRef
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricSpecProvider
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricsProvider
(**kwargs)¶ Bases:
krake.data.core.BaseMetricsProvider
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricsProviderList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
MetricsProviderSpec
(**kwargs)¶ Bases:
krake.data.serializable.PolymorphicContainer
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
PrometheusSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Reason
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
ReasonCode
¶ Bases:
enum.IntEnum
An enumeration.
-
class
krake.data.core.
ResourceRef
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Role
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
RoleBinding
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
RoleBindingList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
RoleList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
RoleRule
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
StaticSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
Status
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.core.
WatchEvent
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
krake.data.core.
resource_ref
(resource)¶ Create a
ResourceRef
from aApiObject
Parameters: resource (serializable.ApiObject) – API object that should be referenced Returns: Corresponding reference to the API object Return type: ResourceRef
-
krake.data.core.
validate_key
(key)¶ Validate the given key against the corresponding regular expression.
Parameters: key – the string to validate Raises: ValidationError
– if the given key is not conform to the regular expression.
-
krake.data.core.
validate_value
(value)¶ Validate the given value against the corresponding regular expression.
Parameters: value – the string to validate Raises: ValidationError
– if the given value is not conform to the regular expression.
-
class
krake.data.infrastructure.
Cloud
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
CloudBinding
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
CloudList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
CloudSpec
(**kwargs)¶ Bases:
krake.data.serializable.PolymorphicContainer
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
CloudStatus
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Status subresource of
GlobalCloud
andCloud
.-
state
¶ Current state of the cloud.
Type: CloudState
-
metrics_reasons
¶ Mapping of the name of the metrics for which an error occurred to the reason for which it occurred.
Type: dict[str, Reason]
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.infrastructure.
GlobalCloud
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
__post_init__
()¶ Method automatically ran at the end of the
__init__()
method, used to validate dependent attributes.- Validations:
- A non-namespaced GlobalCloud resource cannot reference the namespaced
InfrastructureProvider resource, see #499 for details- A non-namespaced GlobalCloud resource cannot reference the namespaced
Metric resource, see #499 for details- Note: This validation cannot be achieved directly using the
validate
- metadata, since
validate
must be a zero-argument callable, with no access to the other attributes of the dataclass.
-
class
-
class
krake.data.infrastructure.
GlobalCloudList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
GlobalInfrastructureProvider
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
GlobalInfrastructureProviderList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
ImSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
IMSpec should contain access data to the IM provider instance.
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
__post_init__
()¶ Method automatically ran at the end of the
__init__()
method, used to validate dependent attributes.Validations: - At least one of the attributes from the following should be defined:
-
class
-
class
krake.data.infrastructure.
InfrastructureProvider
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
InfrastructureProviderList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
InfrastructureProviderRef
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
InfrastructureProviderSpec
(**kwargs)¶ Bases:
krake.data.serializable.PolymorphicContainer
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
OpenstackAuthMethod
(**kwargs)¶ Bases:
krake.data.serializable.PolymorphicContainer
Container for the different authentication strategies of OpenStack Identity service (Keystone).
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
OpenstackSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
Password
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Data for the password authentication strategy of the OpenStack identity service (Keystone).
-
user
¶ OpenStack user that will be used for authentication
Type: UserReference
-
project
¶ OpenStack project that will be used by Krake
Type: ProjectReference
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.infrastructure.
ProjectReference
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Reference to the OpenStack project that is used by the
Password
authentication strategy.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.infrastructure.
UserReference
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Reference to the OpenStack user that is used by the
Password
authentication strategy.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
Data model definitions for Kubernetes-related resources
-
class
krake.data.kubernetes.
Application
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ApplicationComplete
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ApplicationList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ApplicationShutdown
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ApplicationSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Spec subresource of
Application
.-
manifest
¶ List of Kubernetes resources to create. This attribute is managed by the user.
Type: list[dict]
-
tosca
¶ The to be created TOSCA template. A TOSCA template should be defined as a python dict or with the URL, where the template is located. This attribute is managed by the user.
Type: Union[dict, str], optional
-
csar
¶ The to be created CSAR archive. A CSAR file should be defined with the URL, where the archive is located. This attribute is managed by the user.
Type: str, optional
-
observer_schema
¶ List of dictionaries of fields that should be observed by the Kubernetes Observer. This attribute is managed by the user. Using this attribute as a basis, the Kubernetes Controller generates the
status.mangled_observer_schema
.Type: list[dict], optional
-
constraints
¶ Scheduling constraints
Type: Constraints, optional
-
backoff
¶ multiplier applied to backoff_delay between attempts. default: 1 (no backoff)
Type: field, optional
-
backoff_delay
¶ delay [s] between attempts. default: 1
Type: field, optional
-
backoff_limit
¶ a maximal number of attempts, default: -1 (infinite)
Type: field, optional
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
__post_init__
()¶ Method automatically ran at the end of the
__init__()
method, used to validate dependent attributes.Validations: 1. At least one of the attributes from the following should be defined: -
manifest
-tosca
-csar
If the user specified multiple attributes at once, themanifest
has the highest priority, after thattosca
andcsar
.2. If a custom
observer_schema
andmanifest
are specified by the user, theobserver_schema
needs to be validated, i.e. verified that resources are correctly identified and refer to resources defined inmanifest
, that fields are correctly identified and that all special control dictionaries are correctly defined.- Note: These validations cannot be achieved directly using the
validate
- metadata, since
validate
must be a zero-argument callable, with no access to the other attributes of the dataclass.
- Note: These validations cannot be achieved directly using the
-
-
class
krake.data.kubernetes.
ApplicationStatus
(**kwargs)¶ Bases:
krake.data.core.Status
Status subresource of
Application
.-
state
¶ Current state of the application
Type: ApplicationState
-
container_health
¶ Specific details of the application
Type: ContainerHealth
-
kube_controller_triggered
¶ Timestamp that represents the last time the current version of the Application was scheduled (version here meaning the Application after an update). It is only updated after the update of the Application led to a rescheduling, or at the first scheduling. It is used to keep a strict workflow between the Scheduler and Kubernetes Controller: the first one should always handle an Application creation or update before the latter. Only after this field has been updated by the Scheduler to be higher than the modified timestamp can the Kubernetes Controller handle the Application.
Type: datetime.datetime
-
scheduled
¶ Timestamp that represents the last time the application was scheduled to a different cluster, in other words when
scheduled_to
was modified. Thus, it is updated at the first binding to a cluster, or during the binding with a different cluster. This represents the timestamp when the current Application was scheduled to its current cluster, even if it has been updated in the meantime.Type: datetime.datetime
-
scheduled_to
¶ Reference to the cluster where the application should run.
Type: ResourceRef
-
running_on
¶ Reference to the cluster where the application is currently running.
Type: ResourceRef
-
mangled_observer_schema
¶ Actual observer schema used by the Kubernetes Observer, generated from the user inputs
spec.observer_schema
Type: list[dict]
-
last_observed_manifest
¶ List of Kubernetes resources observed on the Kubernetes API.
Type: list[dict]
-
last_applied_manifest
¶ List of Kubernetes resources created via Krake. The manifest is augmented by additional resources needed to be created for the functioning of internal mechanisms, such as the “Complete Hook”.
Type: list[dict]
-
shutdown_grace_period
¶ time period the shutdown method waits on after the shutdown command was issued to an object
Type: datetime
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.kubernetes.
CloudConstraints
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Constraints for the
Cloud
to which this cluster is scheduled.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
Cluster
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterBinding
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterCloudConstraints
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Constraints restricting the scheduling decision for a
Cluster
.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterConstraints
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterList
(**kwargs)¶ Bases:
krake.data.serializable.ApiObject
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterNode
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Cluster node subresource of
ClusterStatus
.-
status
¶ Current status of the cluster node.
Type: ClusterNodeStatus, optional
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.kubernetes.
ClusterNodeCondition
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Cluster node condition subresource of
ClusterNodeStatus
.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterNodeMetadata
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Cluster node metadata subresource of
ClusterNode
.-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ClusterNodeStatus
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Cluster node status subresource of
ClusterNode
.-
conditions
¶ List of current observed node conditions.
Type: list[ClusterNodeCondition]
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.kubernetes.
ClusterSpec
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
Spec subresource of
Cluster
-
backoff
¶ multiplier applied to backoff_delay between attempts. default: 1 (no backoff)
Type: field, optional
-
backoff_delay
¶ delay [s] between attempts. default: 1
Type: field, optional
-
backoff_limit
¶ a maximal number of attempts, default: -1 (infinite)
Type: field, optional
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
__post_init__
()¶ Method automatically ran at the end of the
__init__()
method, used to validate dependent attributes.Validations: - At least one of the attributes from the following should be defined:
kubeconfig
tosca
- Note: This validation cannot be achieved directly using the
validate
- metadata, since
validate
must be a zero-argument callable, with no access to the other attributes of the dataclass.
-
-
class
krake.data.kubernetes.
ClusterStatus
(**kwargs)¶ Bases:
krake.data.core.Status
Status subresource of
Cluster
.-
kube_controller_triggered
¶ Time when the Kubernetes controller was
Type: datetime
-
triggered. This is used to handle cluster state transitions.
-
state
¶ Current state of the cluster.
Type: ClusterState
-
metrics_reasons
¶ mapping of the name of the metrics for which an error occurred to the reason for which it occurred.
Type: dict[str, Reason]
-
nodes
¶ list of cluster nodes.
Type: list[ClusterNode]
-
cluster_id
¶ UUID or name of the cluster (infrastructure) given by the infrastructure provider
Type: str
-
scheduled
¶ Timestamp that represents the last time the cluster was scheduled to a cloud.
Type: datetime.datetime
-
scheduled_to
¶ Reference to the cloud where the cluster should run.
Type: ResourceRef
-
running_on
¶ Reference to the cloud where the cluster is running.
Type: ResourceRef
-
retries
¶ Count of remaining retries to access the cluster. Is set via the Attribute backoff in in ClusterSpec.
Type: int
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
-
class
krake.data.kubernetes.
Constraints
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
-
class
krake.data.kubernetes.
ContainerHealth
(**kwargs)¶ Bases:
krake.data.serializable.Serializable
-
class
Schema
(*, only: types.StrSequenceOrSet | None = None, exclude: types.StrSequenceOrSet = (), many: bool = False, context: dict | None = None, load_only: types.StrSequenceOrSet = (), dump_only: types.StrSequenceOrSet = (), partial: bool | types.StrSequenceOrSet = False, unknown: str | None = None)¶
-
class
Client Reference¶
rok
is a Python command line interface for the krake
API
server. It can be used to manipulate any RESTful resource handled by Krake. It
can be used by end users as well as for administrative tasks.
Fixtures¶
Simple dependency injection module for rok inspired by pytest’s fixtures.
There is a simple registration decorator fixture()
that can be used to
mark functions as fixtures. Functions using these fixtures can declare their
dependency with the use()
decorator. Finally, Resolver
is used
to wire fixtures and dependencies.
-
class
rok.fixtures.
BaseUrlSession
(base_url=None, raise_for_status=True, client_ca=None, ssl_cert=None, ssl_key=None)¶ Bases:
requests.sessions.Session
Simple requests session using a base URL for all requests.
Parameters: -
create_url
(url)¶
-
request
(method, url, *args, raise_for_status=None, **kwargs)¶ Constructs a
Request
, prepares it and sends it. ReturnsResponse
object.Parameters: - method – method for the new
Request
object. - url – URL for the new
Request
object. - params – (optional) Dictionary or bytes to be sent in the query
string for the
Request
. - data – (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the
Request
. - json – (optional) json to send in the body of the
Request
. - headers – (optional) Dictionary of HTTP Headers to send with the
Request
. - cookies – (optional) Dict or CookieJar object to send with the
Request
. - files – (optional) Dictionary of
'filename': file-like-objects
for multipart encoding upload. - auth – (optional) Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth.
- timeout (float or tuple) – (optional) How long to wait for the server to send data before giving up, as a float, or a (connect timeout, read timeout) tuple.
- allow_redirects (bool) – (optional) Set to True by default.
- proxies – (optional) Dictionary mapping protocol or protocol and hostname to the URL of the proxy.
- stream – (optional) whether to immediately download the response
content. Defaults to
False
. - verify – (optional) Either a boolean, in which case it controls whether we verify
the server’s TLS certificate, or a string, in which case it must be a path
to a CA bundle to use. Defaults to
True
. When set toFalse
, requests will accept any TLS certificate presented by the server, and will ignore hostname mismatches and/or expired certificates, which will make your application vulnerable to man-in-the-middle (MitM) attacks. Setting verify toFalse
may be useful during local development or testing. - cert – (optional) if String, path to ssl client cert file (.pem). If Tuple, (‘cert’, ‘key’) pair.
Return type: - method – method for the new
-
-
class
rok.fixtures.
Resolver
(fixtures=None)¶ Bases:
object
Dependency resolver for function arguments annotated with
depends()
.Dependencies of a function are loaded from the
depends
attribute of the function. If a fixture is not available, the resolver checks if there is a default argument. Otherwise aRuntimeError
is raised.All fixtures can be overwritten by passing a corresponding keyword argument to the resolver call.
Resolver uses the context manager protocol to manage the lifecycle of generator-based fixtures.
Example
from sqlalchemy import create_engine from krake.fixtures import fixture, depends, Resolver @fixture def engine(): yield create_engine("postgresql://user:passwd@localhost:5432/database") @depends("engine") def fetch(engine, min_uid): with engine.begin() as connection: result = connection.execute( "SELECT username FROM users WHERE uid >= ?", min_uid ) for row in result: print(row["username"]) with Resolver() as resolver: # Execute function "fetch" with resolved fixtures. Additional # keyword arguments can be passed. These can also be used to # overwrite fixtures. resolver(fetch, min_uid=1000)
Parameters: fixtures (dict, optional) – A mapping of fixture names to functions. Defaults to the mapping of fixture.mapping
-
rok.fixtures.
config
()¶
-
rok.fixtures.
depends
(*dependencies)¶ Decorator function for marking fixture dependencies of a function.
Example
from rok.fixtures import fixture, depends @depends("engine") def fetch_records(engine): # Do something with the engine ... # Fixtures themselves can also depend on other fixtures @fixture @depends("config") def engine(config): return create_engine(config=config) @fixture def config: return load_config()
Parameters: *dependencies – Fixtures the decorated function depends on Returns: Decorator for explicitly marking function dependencies. Return type: callable
-
rok.fixtures.
fixture
(func)¶ Mark a function or generator as fixtures. The name of the function is used as fixture name.
If the marked function is a generator function, the fixture can be used as kind of context manager:
@fixture def session(): with Session() as session: yield session
Parameters: func – Function that should be registered as fixture Raises: RuntimeError
– If the a fixtures with the same name is already registered.
-
rok.fixtures.
session
(config)¶
Command Line Parser¶
This module defines a declarative API for Python’s standard argparse
module.
-
class
rok.parser.
MetricAction
(*args, nargs=None, default=None, metavar=None, **kwargs)¶ Bases:
argparse.Action
argparse action for metric values
A metric argument requires two arguments. The first argument is the name of a metric (
str
). The second argument is the weight of the argument as float. The option can be called several times.Example
cli --metric-argument my-metric 1.2 --metric-argument my-other-metric 4.5
The action will populate the namespace with a list of dictionaries:
[ {"name": "my-metric", "weight": 1.2}, {"name": "my-other-metric", "weight": 4.5}, ... ]
-
class
rok.parser.
ParserSpec
(*args, **kwargs)¶ Bases:
object
Declarative parser specification for Python’s standard
argparse
module.Example
from rok.parser import ParserSpec, argument spec = ParserSpec(prog="spam", description="Spam command line interface") @spec.command("spam", help="Spam your shell") @argument("-n", type=int, default=42, help="How often should I spam?") @argument("message", help="Spam message") def spam(n, message): for _ in range(n): print(message) parser = spec.create_parser() args = parser.parse_args()
Specifications can be nested:
eggs = ParserSpec("eggs", aliases=["eg"], help="... and eggs") @eggs.command("spam") def eggs_spam(): while True: print("spam") print("eggs") spec.add_spec(eggs)
Parameters: - *args – Positional arguments that will be passed to either
argparse.ArgumentParser
or subparsers. - *kwargs – Keyword arguments that will be passed to either
argparse.ArgumentParser
or subparsers.
-
add_spec
(subparser)¶ Register another specification as subparser
Parameters: subparser (ParserSpec) – Sub-specification defining subcommands
-
command
(name, *args, **kwargs)¶ Decorator function for commands registering the name, positional and keyword arguments for a subparser.
Parameters: - name (name) – Name of the command that will be used in the command line.
- *args – Positional arguments for the subparser
- **kwargs – Keyword arguments for the subparser
Returns: Decorator for functions that will be registered as
command
default argument on the subparser.Return type: callable
-
create_parser
(parent=None)¶ Create a standard Python parser from the specification
Parameters: parent (optional) – argparse subparser that should be used instead of creating a new root argparse.ArgumentParser
Returns: Standard Python parser Return type: argparse.ArgumentParser
-
subparser
(*args, **kwargs)¶ Create a subspecification and automatically register it via
add_spec()
Parameters: - *args – Positional arguments for the specification
- **kwargs – Keyword arguments for the specification
Returns: The new subspecification for subcommands
Return type:
- *args – Positional arguments that will be passed to either
-
class
rok.parser.
StoreDict
(option_strings, dest, nargs=None, metavar='KEY=VALUE', **kwargs)¶ Bases:
argparse.Action
Action storing <key=value> pairs in a dictionary.
Example
parser = argparse.ArgumentParser() parser.add_argument( '--foo', action=StoreDict ) args = parser.parse_args('--foo label=test --foo lorem=ipsum') assert argparse.Namespace(foo={'label': 'test', 'lorem': 'ipsum'}) == args
-
rok.parser.
arg_backoff
(fn)¶
-
rok.parser.
arg_backoff_delay
(fn)¶
-
rok.parser.
arg_backoff_limit
(fn)¶
-
rok.parser.
arg_formatting
(fn)¶
-
rok.parser.
arg_global_metric
(fn)¶
-
rok.parser.
arg_labels
(fn)¶
-
rok.parser.
arg_metric
(fn)¶
-
rok.parser.
arg_namespace
(fn)¶
-
rok.parser.
argument
(*args, **kwargs)¶ Decorator function for standard
argparse
arguments.The passed arguments and keyword arguments are stored as tuple in a
parser_arguments
attribute of the decorated function. This list will be reused by class:ParserSpec to add arguments to decorated commands.Parameters: - *args – Positional arguments that should be passed to
argparse.ArgumentParser.add_argument()
. - **kwargs – Keyword arguments that should be passed to
argparse.ArgumentParser.add_argument()
.
Returns: A decorator that can be used to decorate a command function.
Return type: callable
- *args – Positional arguments that should be passed to
-
rok.parser.
mutually_exclusive_group
(group)¶ Decorator function for mutually exclusive
argparse
arguments.Parameters: group (list of tuples) – A list of the standard :mod: argparse arguments which are mutually exclusive. Each argument is represented as a tuple of its args and kwargs. Returns: A decorator that can be used to decorate a command function. Return type: callable