From 08c8e10c2d3ae9922fe84c9bf21f9e057fbe09d7 Mon Sep 17 00:00:00 2001
From: Brendan Melville <bmelville@google.com>
Date: Tue, 3 Nov 2015 11:45:11 -0800
Subject: [PATCH] Moving replicatedservice.py to its own example to be used by
 others.

---
 .../replicatedservice/replicatedservice.py    | 187 ++++++++++++++++++
 1 file changed, 187 insertions(+)
 create mode 100644 examples/replicatedservice/replicatedservice.py

diff --git a/examples/replicatedservice/replicatedservice.py b/examples/replicatedservice/replicatedservice.py
new file mode 100644
index 000000000..02c7419a2
--- /dev/null
+++ b/examples/replicatedservice/replicatedservice.py
@@ -0,0 +1,187 @@
+"""Defines a ReplicatedService type by creating both a Service and an RC.
+
+This module creates a typical abstraction for running a service in a
+Kubernetes cluster, namely a replication controller and a service packaged
+together into a single unit.
+"""
+
+import yaml
+
+SERVICE_TYPE_COLLECTION = 'Service'
+RC_TYPE_COLLECTION = 'ReplicationController'
+
+
+def GenerateConfig(context):
+  """Generates a Replication Controller and a matching Service.
+
+  Args:
+    context: Template context, which can contain the following properties:
+             container_name - Name to use for container. If omitted, name is
+                              used.
+             namespace - Namespace to create the resources in. If omitted,
+                         'default' is used.
+             service_name - Name to use for service. If omitted name-service is
+                            used.
+             protocol - Protocol to use for the service
+             service_port - Port to use for the service
+             target_port - Target port for the service
+             container_port - Container port to use
+             replicas - Number of replicas to create in RC
+             image - Docker image to use for replicas. Required.
+             labels - labels to apply.
+             env - Environmental variables to apply (list of maps). Format
+                   should be:
+                      [{'name': ENV_VAR_NAME, 'value':'ENV_VALUE'},
+                       {'name': ENV_VAR_NAME_2, 'value':'ENV_VALUE_2'}]
+             external_service - If set to true, enable external Load Balancer
+
+  Returns:
+    A Container Manifest as a YAML string.
+  """
+  # YAML config that we're going to create for both RC & Service
+  config = {'resources': []}
+
+  name = context.env['name']
+  container_name = context.properties.get('container_name', name)
+  namespace = context.properties.get('namespace', 'default')
+
+  # Define things that the Service cares about
+  service_name = context.properties.get('service_name', name + '-service')
+  service_type = SERVICE_TYPE_COLLECTION
+
+  # Define things that the Replication Controller (rc) cares about
+  rc_name = name + '-rc'
+  rc_type = RC_TYPE_COLLECTION
+
+  service = {
+      'name': service_name,
+      'type': service_type,
+      'properties': {
+          'apiVersion': 'v1',
+          'kind': 'Service',
+          'namespace': namespace,
+          'metadata': {
+              'name': service_name,
+              'labels': GenerateLabels(context, service_name),
+          },
+          'spec': {
+              'ports': [GenerateServicePorts(context, container_name)],
+              'selector': GenerateLabels(context, name)
+          }
+      }
+  }
+  set_up_external_lb = context.properties.get('external_service', None)
+  if set_up_external_lb:
+    service['properties']['spec']['type'] = 'LoadBalancer'
+  config['resources'].append(service)
+
+  rc = {
+      'name': rc_name,
+      'type': rc_type,
+      'properties': {
+          'apiVersion': 'v1',
+          'kind': 'ReplicationController',
+          'namespace': namespace,
+          'metadata': {
+              'name': rc_name,
+              'labels': GenerateLabels(context, rc_name),
+          },
+          'spec': {
+              'replicas': context.properties['replicas'],
+              'selector': GenerateLabels(context, name),
+              'template': {
+                  'metadata': {
+                      'labels': GenerateLabels(context, name),
+                  },
+                  'spec': {
+                      'containers': [
+                          {
+                              'env': GenerateEnv(context),
+                              'name': container_name,
+                              'image': context.properties['image'],
+                              'ports': [
+                                  {
+                                      'name': container_name,
+                                      'containerPort': context.properties['container_port'],
+                                  }
+                              ]
+                          }
+                      ]
+                  }
+              }
+          }
+      }
+  }
+
+  config['resources'].append(rc)
+  return yaml.dump(config)
+
+
+# Generates labels either from the context.properties['labels'] or generates
+# a default label 'name':name
+def GenerateLabels(context, name):
+  """Generates labels from context.properties['labels'] or creates default.
+
+  We make a deep copy of the context.properties['labels'] section to avoid
+  linking in the yaml document, which I believe reduces readability of the
+  expanded template. If no labels are given, generate a default 'name':name.
+
+  Args:
+    context: Template context, which can contain the following properties:
+             labels - Labels to generate
+
+  Returns:
+    A dict containing labels in a name:value format
+  """
+  tmp_labels = context.properties.get('labels', None)
+  ret_labels = {'name': name}
+  if isinstance(tmp_labels, dict):
+    for key, value in tmp_labels.iteritems():
+      ret_labels[key] = value
+  return ret_labels
+
+
+def GenerateServicePorts(context, name):
+  """Generates a ports section for a service.
+
+  Args:
+    context: Template context, which can contain the following properties:
+             service_port - Port to use for the service
+             target_port - Target port for the service
+             protocol - Protocol to use.
+
+  Returns:
+    A dict containing a port definition
+  """
+  service_port = context.properties.get('service_port', None)
+  target_port = context.properties.get('target_port', None)
+  protocol = context.properties.get('protocol')
+
+  ports = {}
+  if name:
+    ports['name'] = name
+  if service_port:
+    ports['port'] = service_port
+  if target_port:
+    ports['targetPort'] = target_port
+  if protocol:
+    ports['protocol'] = protocol
+
+  return ports
+
+def GenerateEnv(context):
+  """Generates environmental variables for a pod.
+
+  Args:
+    context: Template context, which can contain the following properties:
+             env - Environment variables to set.
+
+  Returns:
+    A list containing env variables in dict format {name: 'name', value: 'value'}
+  """
+  env = []
+  tmp_env = context.properties.get('env', [])
+  for entry in tmp_env:
+    if isinstance(entry, dict):
+      env.append({'name': entry.get('name'), 'value': entry.get('value')})
+  return env
-- 
GitLab