Repository: zalando-stups/senza

Issue:
CoreOS Auto Configuration Component
We are currently testing [Kubernetes on AWS](https://github.com/zalando-incubator/kubernetes-on-aws) with CoreOS AMIs. We take the AMI ID from https://coreos.com/dist/aws/aws-stable.json and put it into the Senza definition YAML manually. It would be better to have a Senza component to automatically find and use the latest CoreOS AMI (similar to what the `StupsAutoConfiguration` component does for Taupage).


Comments:

Patch:
diff --git a/senza/components/coreos_auto_configuration.py b/senza/components/coreos_auto_configuration.py
new file mode 100644
index 0000000..707fdaf
--- /dev/null
+++ b/senza/components/coreos_auto_configuration.py
@@ -0,0 +1,23 @@
+import requests
+
+from senza.components.subnet_auto_configuration import component_subnet_auto_configuration
+from senza.utils import ensure_keys
+
+
+def find_coreos_image(release_channel: str, region: str):
+    '''Find the latest CoreOS AMI'''
+
+    response = requests.get('https://coreos.com/dist/aws/aws-{}.json'.format(release_channel), timeout=5)
+    response.raise_for_status()
+    data = response.json()
+    return data[region]['hvm']
+
+
+def component_coreos_auto_configuration(definition, configuration, args, info, force, account_info):
+    ami_id = find_coreos_image(configuration.get('ReleaseChannel') or 'stable', args.region)
+    configuration = ensure_keys(configuration, "Images", 'LatestCoreOSImage', args.region)
+    configuration["Images"]['LatestCoreOSImage'][args.region] = ami_id
+
+    component_subnet_auto_configuration(definition, configuration, args, info, force, account_info)
+
+    return definition


Test patch:
diff --git a/tests/test_components.py b/tests/test_components.py
index e9a3f7c..d109065 100644
--- a/tests/test_components.py
+++ b/tests/test_components.py
@@ -11,6 +11,7 @@ from senza.components.auto_scaling_group import (component_auto_scaling_group,
                                                  normalize_asg_success,
                                                  normalize_network_threshold,
                                                  to_iso8601_duration)
+from senza.components.coreos_auto_configuration import component_coreos_auto_configuration
 from senza.components.elastic_load_balancer import (component_elastic_load_balancer,
                                                     get_load_balancer_name)
 from senza.components.elastic_load_balancer_v2 import component_elastic_load_balancer_v2
@@ -1094,3 +1095,29 @@ def test_component_subnet_auto_configuration(monkeypatch):
     }
     result = component_subnet_auto_configuration(definition, configuration, args, info, False, MagicMock())
     assert ['subnet-1', 'subnet-2'] == result['Mappings']['ServerSubnets']['foo']['Subnets']
+
+
+def test_component_coreos_auto_configuration(monkeypatch):
+    configuration = {
+        'ReleaseChannel': 'gamma'
+    }
+    info = {'StackName': 'foobar', 'StackVersion': '0.1'}
+    definition = {"Resources": {}}
+
+    args = MagicMock()
+    args.region = "foo"
+
+    subnet1 = MagicMock()
+    subnet1.id = 'subnet-1'
+
+    ec2 = MagicMock()
+    ec2.subnets.filter.return_value = [subnet1]
+
+    get = MagicMock()
+    get.return_value.json.return_value = {'foo': {'hvm': 'ami-007'}}
+
+    monkeypatch.setattr('boto3.resource', lambda *args: ec2)
+    monkeypatch.setattr('requests.get', get)
+    result = component_coreos_auto_configuration(definition, configuration, args, info, False, MagicMock())
+    assert 'ami-007' == result['Mappings']['Images']['foo']['LatestCoreOSImage']
+