# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. Namespaces: =: com.mirantis.docker.kubernetes docker: com.mirantis.docker std: io.murano sys: io.murano.system Name: KubernetesPod Extends: - docker:DockerContainerHost - docker:DockerHelpers Properties: name: Contract: $.string().notNull() kubernetesCluster: Contract: $.class(KubernetesCluster).notNull() labels: Contract: $.string().notNull() # convert to key-value map as soon as it will be possible to input it in UI Default: '' replicas: Contract: $.int().notNull().check($ >= 0) Usage: InOut Methods: .init: Body: - $._environment: $.find(std:Environment).require() - $._podDefinition: null # this is a workaround for early initialization. If docker application was deleted # its destroy method will call deleteContainer method that will change _podDefinition # on KubernetesPod loaded from ObjectsCopy # but ininitialize method on a KubernetesPod from Objects is called before destruction # and because we have 2 different KubernetesPod objects that share attributes but # not private variables _podDefinition of real object will still contain outdated data _loadCurrentPodDefinition: Body: - If: $._podDefinition = null Then: - $podName: $._getPodName() - $podDefinition: $.getAttr(lastPodDeployed, null) - If: $podDefinition = null Then: - $podDefinition: apiVersion: v1 kind: Pod metadata: name: $podName labels: $._getPodLabels($podName) spec: containers: [] volumes: [] - $.setAttr(lastPodDeployed, $podDefinition) - $._podDefinition: $podDefinition - Return: $._podDefinition _getPodName: Body: - Return: $.name.toLower() _getPodLabels: Arguments: - podName: Contract: $.string().notNull() Body: Return: $.labels2Map($.labels.toLower()).mergeWith(dict(id => $podName)) hostContainer: Arguments: - container: Contract: $.class(docker:DockerContainer) Body: - $._loadCurrentPodDefinition() - $podName: $._getPodName() - For: port In: $container.ports Do: - $endpoints: $.kubernetesCluster.serviceEndpoints.where( $.containerPort = $port.port and $.protocol = $port.protocol and $.podId = $podName) - If: len($endpoints) > 0 Then: - $msg: format('Port {0} is already used in the Pod {1}', $port.port, $.name) - Throw: PortConflictException Message: $msg - $._deleteContainer($container.name) - $containerDef: name: $container.name.toLower() image: $container.image args: $container.commands ports: $container.ports.select($this._getPortDefinition($)) volumeMounts: $container.volumes.keys().select( dict( name => $this._generateVolumeName($container.name, $container.volumes.get($)), mountPath => $ )) env: $container.env.keys().select(dict(name => $, value => $container.env.get($))) - $newVolumes: $container.volumes.values().select( $this._buildVolumeEntry($container.name, $)) - $diff: spec: containers: [$containerDef] volumes: $newVolumes - $._podDefinition: $._podDefinition.mergeWith($diff) - $.deploy() - $._environment.reporter.report($, 'Creating services for Pod {0}'.format($.name)) - $.kubernetesCluster.createService( applicationName => $container.name, applicationPorts => $container.ports, podId => $podName) - Return: $.getEndpoints($container.name) getEndpoints: Arguments: - applicationName: Contract: $.string().notNull() Body: - Return: $.kubernetesCluster.serviceEndpoints.where($.applicationName = $applicationName) _getPortDefinition: Arguments: - port: Contract: $.class(docker:ApplicationPort).notNull() Body: - $result: containerPort: $port.port - If: $port.scope = node Then: $result.hostPort: $port.port - Return: $result _buildVolumeEntry: Arguments: - name: Contract: $.string().notNull() - volume: Contract: $.class(docker:DockerVolume).notNull() Body: - $type: $volume.getType() - Value: $type Match: HostDir: - $spec: hostDir: path: $volume.getParameters() TempVolume: - $spec: emptyDir: {} Default: - Throw: UnknownDockerVolumeType Message: format('Unknown docker volume type {0}', $type) - Return: name: $._generateVolumeName($name, $volume) source: $spec _deleteContainer: Arguments: - name: Contract: $.string().notNull() Body: - $lenBefore: len($._podDefinition.spec.containers) + len($._podDefinition.spec.volumes) - $containerName: $name.toLower() - $newContainers: $._podDefinition.spec.containers.where($.name != $containerName) - $volumeNameMap: $.getAttr(volumeNameMap, dict()) - $newVolumeNameMap: {} - $volumesToDelete: [] - $prefix: format('{0}/'.format($name)) - For: key In: $volumeNameMap.keys() Do: - $volumeName: $volumeNameMap.get($key) - If: $key.startsWith($prefix) Then: - $volumesToDelete: $volumesToDelete + list($volumeName) Else: - $newVolumeNameMap[$key]: $volumeName - $.setAttr(volumeNameMap, $newVolumeNameMap) - $newVolumes: $._podDefinition.spec.volumes.where( not ($.name in $volumesToDelete)) - If: len($newContainers) + len($newVolumes) != $lenBefore Then: - $._podDefinition.spec.containers: $newContainers - $._podDefinition.spec.volumes: $newVolumes deleteContainer: Arguments: - name: Contract: $.string().notNull() Body: - If: $.kubernetesCluster.isAvailable() Then: - $._loadCurrentPodDefinition() - $._deleteContainer($name) - $.kubernetesCluster.deleteServices( applicationName => $name, podId => $._getPodName()) - $.deploy() _generateVolumeName: Arguments: - name: Contract: $.string().notNull() - volume: Contract: $.class(docker:DockerVolume).notNull() Body: - $key: format('{0}/{1}', $name, $volume.name) - $map: $.getAttr(volumeNameMap, dict()) - $volumeName: $map.get($key) - If: $volumeName = null Then: - $volumeName: randomName() - $map[$key]: $volumeName - $.setAttr(volumeNameMap, $map) - Return: $volumeName deploy: Body: - $._loadCurrentPodDefinition() - $prevPod: $.getAttr(lastPodDeployed, null) - $prevReplicas: $.getAttr(lastReplicas, 0) - $podDefinition: $._podDefinition - $replicas: $.replicas - If: len($podDefinition.spec.containers) = 0 Then: - $replicas: 0 - $.setAttr(lastReplicas, $replicas) - If: $replicas != $prevReplicas or $prevPod != $podDefinition Then: - If: $replicas > 0 Then: - $._environment.reporter.report($, 'Deploying Replication Controller for Pod {0}'.format($.name)) - $rcDefinition: $._buildReplicationControllerDefinition($podDefinition) - $.kubernetesCluster.createReplicationController( definition => $rcDefinition, isNew => $prevReplicas = 0) - If: $replicas = 0 and $prevReplicas > 0 Then: - $.kubernetesCluster.deleteReplicationController($._getReplicationControllerId()) - If: $prevPod != $podDefinition and len($prevPod.spec.containers) > 0 Then: - $.kubernetesCluster.deletePods(dict(id => $._getPodName())) - If: $.replicas = 0 and len($podDefinition.spec.containers) > 0 Then: - $.kubernetesCluster.createPod(definition => $podDefinition, isNew => true) - $._environment.reporter.report($, 'Pod {0} is ready'.format($.name)) - $.setAttr(lastPodDeployed, $podDefinition) _buildReplicationControllerDefinition: Arguments: - podDefinition: Contract: {} Body: Return: apiVersion: v1 kind: ReplicationController metadata: name: $._getReplicationControllerId() labels: $podDefinition.metadata.labels spec: replicas: $.replicas selector: id: $._getPodName() template: metadata: labels: $podDefinition.metadata.labels spec: $podDefinition.spec _getReplicationControllerId: Body: - Return: $._getPodName() getInternalScopeId: Body: Return: id($.kubernetesCluster) scalePodDown: Usage: Action Body: - If: $.replicas > 1 Then: - $._environment.reporter.report($this, 'Scaling Pod down') - $.replicas: $.replicas - 1 - $.kubernetesCluster.scaleRc(rcName => $._getReplicationControllerId(), newSize => $.replicas) Else: - $._environment.reporter.report($this, 'Cannot scale Pod down') scalePodUp: Usage: Action Body: - If: $.replicas > 0 Then: - $._environment.reporter.report($this, 'Scaling Pod up') - $.replicas: $.replicas + 1 - $.kubernetesCluster.scaleRc(rcName => $._getReplicationControllerId(), newSize => $.replicas) Else: - $._environment.reporter.report($this, 'Cannot scale Pod up') recreatePod: Usage: Action Body: - $._environment.reporter.report($this, 'Recreating Pod {0}'.format($.name)) - $.kubernetesCluster.deletePods(dict(id => $._getPodName())) - If: $.replicas = 0 Then: - $._loadCurrentPodDefinition() - $.kubernetesCluster.createPod(definition => $._podDefinition, isNew => true) - $._environment.reporter.report($this, 'Pod {0} recreated'.format($.name)) restartContainers: Usage: Action Body: - $.kubernetesCluster.restartContainers(podName => $._getPodName())