From 57dfae185d3d0e02ebe515263c54867bee37b45e Mon Sep 17 00:00:00 2001
From: Andrew Butcher <abutcher@redhat.com>
Date: Thu, 30 Jun 2016 13:20:10 -0400
Subject: Various hosted component improvements

* [openshift_projects] Add openshift_projects role
* [openshift_hosted] hosted deployments use openshift_hosted_infra_selector if openshift_hosted_<component>_selector is not defined
* [openshift_hosted] move openshift_projects, openshift_serviceaccounts and openshift_metrics to dependencies of openshift_hosted
* [router] improve router deployment
  - add router option to force subdomain
  - add CA to router certificate options
* [registry] move registry config into openshift_hosted role
  - additional registry fixes/tweaks
  - add s3 storage support for registry
* [serviceaccount] fix up serviceaccount creation
---
 roles/openshift_facts/library/openshift_facts.py   |  14 ++-
 roles/openshift_hosted/README.md                   |  20 ++--
 roles/openshift_hosted/defaults/main.yml           |   2 +
 roles/openshift_hosted/meta/main.yml               |  25 ++++-
 roles/openshift_hosted/tasks/main.yml              |  21 +++-
 roles/openshift_hosted/tasks/registry/registry.yml |  40 ++++++++
 .../tasks/registry/storage/object_storage.yml      | 114 +++++++++++++++++++++
 .../tasks/registry/storage/persistent_volume.yml   |  18 ++++
 .../openshift_hosted/tasks/registry/storage/s3.yml |  12 +++
 roles/openshift_hosted/tasks/router.yml            |  65 ------------
 roles/openshift_hosted/tasks/router/router.yml     |  70 +++++++++++++
 .../openshift_hosted/templates/registry_config.j2  |  70 +++++++++++++
 .../templates/registry_config_secret.j2            |   9 ++
 roles/openshift_hosted/vars/main.yml               |   1 +
 roles/openshift_hosted_facts/tasks/main.yml        |   9 ++
 roles/openshift_master_facts/tasks/main.yml        |   1 -
 roles/openshift_projects/meta/main.yml             |  15 +++
 roles/openshift_projects/tasks/main.yml            |  47 +++++++++
 roles/openshift_projects/vars/main.yml             |   2 +
 roles/openshift_registry/README.md                 |  37 -------
 roles/openshift_registry/defaults/main.yml         |   2 -
 roles/openshift_registry/handlers/main.yml         |   0
 roles/openshift_registry/meta/main.yml             |  15 ---
 roles/openshift_registry/tasks/main.yml            |  24 -----
 roles/openshift_registry/vars/main.yml             |   4 -
 roles/openshift_serviceaccounts/tasks/main.yml     |   6 +-
 26 files changed, 477 insertions(+), 166 deletions(-)
 create mode 100644 roles/openshift_hosted/defaults/main.yml
 create mode 100644 roles/openshift_hosted/tasks/registry/registry.yml
 create mode 100644 roles/openshift_hosted/tasks/registry/storage/object_storage.yml
 create mode 100644 roles/openshift_hosted/tasks/registry/storage/persistent_volume.yml
 create mode 100644 roles/openshift_hosted/tasks/registry/storage/s3.yml
 delete mode 100644 roles/openshift_hosted/tasks/router.yml
 create mode 100644 roles/openshift_hosted/tasks/router/router.yml
 create mode 100644 roles/openshift_hosted/templates/registry_config.j2
 create mode 100644 roles/openshift_hosted/templates/registry_config_secret.j2
 create mode 100644 roles/openshift_projects/meta/main.yml
 create mode 100644 roles/openshift_projects/tasks/main.yml
 create mode 100644 roles/openshift_projects/vars/main.yml
 delete mode 100644 roles/openshift_registry/README.md
 delete mode 100644 roles/openshift_registry/defaults/main.yml
 delete mode 100644 roles/openshift_registry/handlers/main.yml
 delete mode 100644 roles/openshift_registry/meta/main.yml
 delete mode 100644 roles/openshift_registry/tasks/main.yml
 delete mode 100644 roles/openshift_registry/vars/main.yml

(limited to 'roles')

diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py
index 31e70960e..4c551c37e 100755
--- a/roles/openshift_facts/library/openshift_facts.py
+++ b/roles/openshift_facts/library/openshift_facts.py
@@ -114,6 +114,12 @@ def migrate_hosted_facts(facts):
             if 'router' not in facts['hosted']:
                 facts['hosted']['router'] = {}
             facts['hosted']['router']['selector'] = facts['master'].pop('router_selector')
+        if 'registry_selector' in facts['master']:
+            if 'hosted' not in facts:
+                facts['hosted'] = {}
+            if 'registry' not in facts['hosted']:
+                facts['hosted']['registry'] = {}
+            facts['hosted']['registry']['selector'] = facts['master'].pop('registry_selector')
     return facts
 
 def first_ip(network):
@@ -466,11 +472,11 @@ def set_selectors(facts):
         facts['hosted']['router'] = {}
     if 'selector' not in facts['hosted']['router'] or facts['hosted']['router']['selector'] in [None, 'None']:
         facts['hosted']['router']['selector'] = selector
+    if 'registry' not in facts['hosted']:
+        facts['hosted']['registry'] = {}
+    if 'selector' not in facts['hosted']['registry'] or facts['hosted']['registry']['selector'] in [None, 'None']:
+        facts['hosted']['registry']['selector'] = selector
 
-    if 'master' in facts:
-        if 'infra_nodes' in facts['master']:
-            if 'registry_selector' not in facts['master']:
-                facts['master']['registry_selector'] = selector
     return facts
 
 def set_metrics_facts_if_unset(facts):
diff --git a/roles/openshift_hosted/README.md b/roles/openshift_hosted/README.md
index 633ec0937..102728820 100644
--- a/roles/openshift_hosted/README.md
+++ b/roles/openshift_hosted/README.md
@@ -4,24 +4,27 @@ OpenShift Hosted
 OpenShift Hosted Resources
 
 * OpenShift Router
+* OpenShift Registry
 
 Requirements
 ------------
 
-This role requires a running OpenShift cluster with nodes labeled to
-match the openshift_hosted_router_selector (default: region=infra).
+This role requires a running OpenShift cluster.
 
 Role Variables
 --------------
 
 From this role:
 
-| Name                                | Default value                            | Description                                                                                                          |
-|-------------------------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------|
-| openshift_hosted_router_certificate | None                                     | Dictionary containing "certfile" and "keyfile" keys with values containing paths to local certificate files.         |
-| openshift_hosted_router_registryurl | 'openshift3/ose-${component}:${version}' | The image to base the OpenShift router on.                                                                           |
-| openshift_hosted_router_replicas    | Number of nodes matching selector        | The number of replicas to configure.                                                                                 |
-| openshift_hosted_router_selector    | region=infra                             | Node selector used when creating router. The OpenShift router will only be deployed to nodes matching this selector. |
+| Name                                  | Default value                            | Description                                                                                                              |
+|---------------------------------------|------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
+| openshift_hosted_router_certificate   | None                                     | Dictionary containing "certfile", "keyfile" and "cafile" keys with values containing paths to local certificate files.   |
+| openshift_hosted_router_registryurl   | 'openshift3/ose-${component}:${version}' | The image to base the OpenShift router on.                                                                               |
+| openshift_hosted_router_replicas      | Number of nodes matching selector        | The number of replicas to configure.                                                                                     |
+| openshift_hosted_router_selector      | region=infra                             | Node selector used when creating router. The OpenShift router will only be deployed to nodes matching this selector.     |
+| openshift_hosted_registry_registryurl | 'openshift3/ose-${component}:${version}' | The image to base the OpenShift registry on.                                                                             |
+| openshift_hosted_registry_replicas    | Number of nodes matching selector        | The number of replicas to configure.                                                                                     |
+| openshift_hosted_registry_selector    | region=infra                             | Node selector used when creating registry. The OpenShift registry will only be deployed to nodes matching this selector. |
 
 Dependencies
 ------------
@@ -40,6 +43,7 @@ Example Playbook
     openshift_hosted_router_certificate:
       certfile: /path/to/my-router.crt
       keyfile: /path/to/my-router.key
+      cafile: /path/to/my-router-ca.crt
     openshift_hosted_router_registryurl: 'registry.access.redhat.com/openshift3/ose-haproxy-router:v3.0.2.0'
     openshift_hosted_router_selector: 'type=infra'
 ```
diff --git a/roles/openshift_hosted/defaults/main.yml b/roles/openshift_hosted/defaults/main.yml
new file mode 100644
index 000000000..17a0d5301
--- /dev/null
+++ b/roles/openshift_hosted/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+registry_volume_claim: 'registry-claim'
diff --git a/roles/openshift_hosted/meta/main.yml b/roles/openshift_hosted/meta/main.yml
index 75dfc24c3..c7d20f88b 100644
--- a/roles/openshift_hosted/meta/main.yml
+++ b/roles/openshift_hosted/meta/main.yml
@@ -12,5 +12,26 @@ galaxy_info:
   categories:
   - cloud
 dependencies:
-- openshift_common
-- openshift_hosted_facts
+- role: openshift_cli
+- role: openshift_hosted_facts
+- role: openshift_projects
+  # TODO: Move standard project definitions to openshift_hosted/vars/main.yml
+  # Vars are not accessible in meta/main.yml in ansible-1.9.x
+  openshift_projects: "{{ openshift_additional_projects | default({}) | oo_merge_dicts({'default':{'default_node_selector':''},'openshift-infra':{'default_node_selector':''},'logging':{'default_node_selector':''}}) }}"
+- role: openshift_serviceaccounts
+  openshift_serviceaccounts_names:
+  - router
+  openshift_serviceaccounts_namespace: default
+  openshift_serviceaccounts_sccs:
+  - hostnetwork
+  when: openshift.common.version_gte_3_2_or_1_2
+- role: openshift_serviceaccounts
+  openshift_serviceaccounts_names:
+  - router
+  - registry
+  openshift_serviceaccounts_namespace: default
+  openshift_serviceaccounts_sccs:
+  - privileged
+  when: not openshift.common.version_gte_3_2_or_1_2
+- role: openshift_metrics
+  when: openshift.hosted.metrics.deploy | bool
diff --git a/roles/openshift_hosted/tasks/main.yml b/roles/openshift_hosted/tasks/main.yml
index d42a4e365..c801a0e67 100644
--- a/roles/openshift_hosted/tasks/main.yml
+++ b/roles/openshift_hosted/tasks/main.yml
@@ -1,3 +1,22 @@
 ---
+- name: Create temp directory for kubeconfig
+  command: mktemp -d /tmp/openshift-ansible-XXXXXX
+  register: mktemp
+  changed_when: False
 
-- include: router.yml
+- set_fact:
+    openshift_hosted_kubeconfig: "{{ mktemp.stdout }}/admin.kubeconfig"
+
+- name: Copy the admin client config(s)
+  command: >
+    cp {{ openshift_master_config_dir }}/admin.kubeconfig {{ openshift_hosted_kubeconfig }}
+  changed_when: False
+
+- include: router/router.yml
+- include: registry/registry.yml
+
+- name: Delete temp directory
+  file:
+    name: "{{ mktemp.stdout }}"
+    state: absent
+  changed_when: False
diff --git a/roles/openshift_hosted/tasks/registry/registry.yml b/roles/openshift_hosted/tasks/registry/registry.yml
new file mode 100644
index 000000000..be1a172f8
--- /dev/null
+++ b/roles/openshift_hosted/tasks/registry/registry.yml
@@ -0,0 +1,40 @@
+---
+- name: Retrieve list of openshift nodes matching registry selector
+  command: >
+    {{ openshift.common.client_binary }} --api-version='v1' -o json
+    get nodes -n default --config={{ openshift_hosted_kubeconfig }}
+    --selector={{ openshift.hosted.registry.selector | default('') }}
+  register: openshift_hosted_registry_nodes_json
+  changed_when: false
+  when: openshift.hosted.registry.replicas | default(none) is none
+
+- set_fact:
+    replicas: "{{ openshift.hosted.registry.replicas | default((openshift_hosted_registry_nodes_json.stdout | from_json)['items'] | length) }}"
+
+- name: Create OpenShift registry
+  command: >
+    {{ openshift.common.admin_binary }} registry --create
+    --config={{ openshift_hosted_kubeconfig }}
+    {% if replicas > 1 -%}
+    --replicas={{ replicas }}
+    {% endif -%}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    --service-account=registry
+    {% if openshift.hosted.registry.selector | default(none) is not none -%}
+    --selector='{{ openshift.hosted.registry.selector }}'
+    {% endif -%}
+    {% if not openshift.common.version_gte_3_2_or_1_2 | bool -%}
+    --credentials={{ openshift_master_config_dir }}/openshift-registry.kubeconfig
+    {% endif -%}
+    {% if openshift.hosted.registry.registryurl | default(none) is not none -%}
+    --images='{{ openshift.hosted.registry.registryurl }}'
+    {% endif -%}
+  register: openshift_hosted_registry_results
+  changed_when: "'service exists' not in openshift_hosted_registry_results.stdout"
+  failed_when: "openshift_hosted_registry_results.rc != 0 and 'service exists' not in openshift_hosted_registry_results.stdout and 'deployment_config' not in openshift_hosted_registry_results.stderr and 'service' not in openshift_hosted_registry_results.stderr"
+
+- include: storage/object_storage.yml
+  when: openshift.hosted.registry.storage.kind | default(none) == 'object'
+
+- include: storage/persistent_volume.yml
+  when: openshift.hosted.registry.storage.kind | default(none) in ['nfs', 'openstack']
diff --git a/roles/openshift_hosted/tasks/registry/storage/object_storage.yml b/roles/openshift_hosted/tasks/registry/storage/object_storage.yml
new file mode 100644
index 000000000..9db67ecc6
--- /dev/null
+++ b/roles/openshift_hosted/tasks/registry/storage/object_storage.yml
@@ -0,0 +1,114 @@
+- fail:
+    msg: >
+      Object Storage Provider: {{ openshift.hosted.registry.storage.provider }}
+      is not currently supported
+  when: openshift.hosted.registry.storage.provider not in ['azure_blob', 's3', 'swift']
+
+- fail:
+    msg: >
+      Support for provider: "{{ openshift.hosted.registry.storage.provider }}"
+      not implemented yet
+  when: openshift.hosted.registry.storage.provider in ['azure_blob', 'swift']
+
+- include: s3.yml
+  when: openshift.hosted.registry.storage.provider == 's3'
+
+- name: Test if docker registry config secret exists
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    get secrets {{ registry_config_secret_name }} -o json
+  register: secrets
+  changed_when: false
+  failed_when: false
+
+- set_fact:
+    registry_config: "{{ lookup('template', '../templates/registry_config.j2') | b64encode }}"
+
+- set_fact:
+    registry_config_secret: "{{ lookup('template', '../templates/registry_config_secret.j2') | from_yaml }}"
+
+- set_fact:
+    same_storage_provider: "{{ (secrets.stdout|from_json)['metadata']['annotations']['provider'] | default(none) == openshift.hosted.registry.storage.provider }}"
+  when: secrets.rc == 0
+
+- name: Update registry config secret
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    patch secret/{{ registry_config_secret_name }}
+    -p '{"data": {"config.yml": "{{ registry_config }}"}}'
+  register: update_config_secret
+  when: secrets.rc == 0 and (secrets.stdout|from_json)['data']['config.yml'] != registry_config and same_storage_provider | bool
+
+- name: Create registry config secret
+  shell: >
+    echo '{{ registry_config_secret |to_json }}' |
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    create -f -
+  when: secrets.rc == 1
+
+- name: Determine if service account contains secrets
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    get serviceaccounts registry
+    -o jsonpath='{.secrets[?(@.name=="{{ registry_config_secret_name }}")].name}'
+  register: serviceaccount
+  changed_when: false
+
+- name: Add secrets to registry service account
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    secrets add serviceaccount/registry secrets/{{ registry_config_secret_name }}
+  when: serviceaccount.stdout == ''
+
+- name: Determine if deployment config contains secrets
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    set volumes dc/docker-registry --list
+  register: volume
+  changed_when: false
+
+- name: Add secrets to registry deployment config
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    set volumes dc/docker-registry --add --name=docker-config -m /etc/registry
+    --type=secret --secret-name={{ registry_config_secret_name }}
+  when: registry_config_secret_name not in volume.stdout
+
+- name: Determine if registry environment variable needs to be created
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    set env --list dc/docker-registry
+  register: oc_env
+  changed_when: false
+
+- name: Add registry environment variable
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    set env dc/docker-registry REGISTRY_CONFIGURATION_PATH=/etc/registry/config.yml
+  when: "'REGISTRY_CONFIGURATION_PATH' not in oc_env.stdout"
+
+- name: Redeploy registry
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ openshift_hosted_kubeconfig }}
+    --namespace={{ openshift.hosted.registry.namespace | default('default') }}
+    deploy dc/docker-registry --latest
+  when: secrets.rc == 0 and update_config_secret.rc == 0 and same_storage_provider | bool
diff --git a/roles/openshift_hosted/tasks/registry/storage/persistent_volume.yml b/roles/openshift_hosted/tasks/registry/storage/persistent_volume.yml
new file mode 100644
index 000000000..6bf859e82
--- /dev/null
+++ b/roles/openshift_hosted/tasks/registry/storage/persistent_volume.yml
@@ -0,0 +1,18 @@
+---
+- set_fact:
+    registry_volume_claim: "{{ openshift.hosted.registry.storage.volume.name }}-claim"
+
+- name: Determine if volume is already attached to dc/docker-registry
+  command: "{{ openshift.common.client_binary }} get -o template dc/docker-registry --template=\\{\\{.spec.template.spec.volumes\\}\\} --output-version=v1"
+  changed_when: false
+  register: registry_volumes_output
+
+- set_fact:
+    volume_attached: "{{ registry_volume_claim in registry_volumes_output.stdout }}"
+
+- name: Add volume to dc/docker-registry
+  command: >
+    {{ openshift.common.client_binary }} volume dc/docker-registry
+    --add --overwrite -t persistentVolumeClaim --claim-name={{ registry_volume_claim }}
+    --name=registry-storage
+  when: not volume_attached | bool
diff --git a/roles/openshift_hosted/tasks/registry/storage/s3.yml b/roles/openshift_hosted/tasks/registry/storage/s3.yml
new file mode 100644
index 000000000..707be9c00
--- /dev/null
+++ b/roles/openshift_hosted/tasks/registry/storage/s3.yml
@@ -0,0 +1,12 @@
+---
+- fail:
+    msg: >
+      openshift_hosted_registry_storage_s3_accesskey and
+      openshift_hosted_registry_storage_s3_secretkey are required
+  when: openshift.hosted.registry.storage.s3.accesskey | default(none) is none or openshift.hosted.registry.storage.s3.secretkey | default(none) is none
+
+- fail:
+    msg: >
+      openshift_hosted_registry_storage_s3_bucket and
+      openshift_hosted_registry_storage_s3_region are required
+  when: openshift.hosted.registry.storage.s3.bucket | default(none) is none or openshift.hosted.registry.storage.s3.region | default(none) is none
diff --git a/roles/openshift_hosted/tasks/router.yml b/roles/openshift_hosted/tasks/router.yml
deleted file mode 100644
index 4ccbf4430..000000000
--- a/roles/openshift_hosted/tasks/router.yml
+++ /dev/null
@@ -1,65 +0,0 @@
----
-- fail:
-    msg: "Both 'certfile' and 'keyfile' keys must be specified when supplying the openshift_hosted_router_certificate variable."
-  when: openshift_hosted_router_certificate is defined and ('certfile' not in openshift_hosted_router_certificate or 'keyfile' not in openshift_hosted_router_certificate)
-
-- name: Read router certificate and key
-  slurp:
-    src: "{{ item }}"
-  register: openshift_router_certificate_output
-  with_items:
-  - "{{ openshift_hosted_router_certificate.certfile }}"
-  - "{{ openshift_hosted_router_certificate.keyfile }}"
-  delegate_to: localhost
-  when: openshift_hosted_router_certificate is defined
-
-- name: Persist certificate contents
-  openshift_facts:
-    role: hosted
-    openshift_env:
-      openshift_hosted_router_certificate_contents: "{% for certificate in openshift_router_certificate_output.results -%}{{ certificate.content | b64decode }}{% endfor -%}"
-  when: openshift_hosted_router_certificate is defined
-
-- name: Create PEM certificate
-  copy:
-    content: "{{ openshift.hosted.router.certificate.contents }}"
-    dest: "{{ openshift_master_config_dir }}/openshift-router.pem"
-    mode: 0600
-  when: openshift.hosted.router.certificate | default(None) != None
-
-- name: Retrieve list of openshift nodes
-  command: >
-    {{ openshift.common.client_binary }} --api-version='v1' -o json
-    get nodes -n default --config={{ openshift.common.config_base }}/master/admin.kubeconfig
-  register: openshift_hosted_router_nodes_json
-  changed_when: false
-  when: openshift.hosted.router.replicas | default(None) == None
-
-- name: Collect nodes matching router selector
-  set_fact:
-    openshift_hosted_router_nodes: >
-      {{ (openshift_hosted_router_nodes_json.stdout|from_json)['items']
-         | oo_oc_nodes_matching_selector(openshift.hosted.router.selector) }}
-  when: openshift.hosted.router.replicas | default(None) == None
-
-- name: Create OpenShift router
-  command: >
-    {{ openshift.common.admin_binary }} router --create
-    {% if openshift.hosted.router.replicas | default(None) != None -%}
-    --replicas={{ openshift.hosted.router.replicas }}
-    {% else -%}
-    --replicas={{ openshift_hosted_router_nodes | length }}
-    {% endif %}
-    {% if openshift.hosted.router.certificate | default(None) != None -%}
-    --default-cert={{ openshift_master_config_dir }}/openshift-router.pem
-    {% endif -%}
-    --namespace=default
-    --service-account=router
-    --selector='{{ openshift.hosted.router.selector }}'
-    --credentials={{ openshift_master_config_dir }}/openshift-router.kubeconfig
-    {% if openshift.hosted.router.registryurl | default(None)!= None -%}
-    --images='{{ openshift.hosted.router.registryurl }}'
-    {% endif -%}
-  register: openshift_hosted_router_results
-  changed_when: "'service exists' not in openshift_hosted_router_results.stdout"
-  when: openshift.hosted.router.replicas | default(None) != None or (openshift_hosted_router_nodes is defined and openshift_hosted_router_nodes | length > 0)
diff --git a/roles/openshift_hosted/tasks/router/router.yml b/roles/openshift_hosted/tasks/router/router.yml
new file mode 100644
index 000000000..c011db762
--- /dev/null
+++ b/roles/openshift_hosted/tasks/router/router.yml
@@ -0,0 +1,70 @@
+---
+- fail:
+    msg: "'certfile', 'keyfile' and 'cafile' keys must be specified when supplying the openshift_hosted_router_certificate variable."
+  when: openshift_hosted_router_certificate is defined and ('certfile' not in openshift_hosted_router_certificate or 'keyfile' not in openshift_hosted_router_certificate or 'cafile' not in openshift_hosted_router_certificate) 
+
+- name: Read router certificate and key
+  become: no
+  local_action:
+    module: slurp
+    src: "{{ item }}"
+  register: openshift_router_certificate_output
+  with_items:
+  - "{{ openshift_hosted_router_certificate.certfile }}"
+  - "{{ openshift_hosted_router_certificate.keyfile }}"
+  - "{{ openshift_hosted_router_certificate.cafile }}"
+  when: openshift_hosted_router_certificate is defined
+
+- name: Persist certificate contents
+  openshift_facts:
+    role: hosted
+    openshift_env:
+      openshift_hosted_router_certificate_contents: "{% for certificate in openshift_router_certificate_output.results -%}{{ certificate.content | b64decode }}{% endfor -%}"
+  when: openshift_hosted_router_certificate is defined
+
+- name: Create PEM certificate
+  copy:
+    content: "{{ openshift.hosted.router.certificate.contents }}"
+    dest: "{{ openshift_master_config_dir }}/openshift-router.pem"
+    mode: 0600
+  when: openshift.hosted.router.certificate | default(none) is not none
+
+- name: Retrieve list of openshift nodes matching router selector
+  command: >
+    {{ openshift.common.client_binary }} --api-version='v1' -o json
+    get nodes -n default --config={{ openshift_hosted_kubeconfig }}
+    --selector={{ openshift.hosted.router.selector | default('') }}
+  register: openshift_hosted_router_nodes_json
+  changed_when: false
+  when: openshift.hosted.router.replicas | default(none) is none
+
+- set_fact:
+    replicas: "{{ openshift.hosted.router.replicas | default((openshift_hosted_router_nodes_json.stdout | from_json)['items'] | length) }}"
+
+- name: Create OpenShift router
+  command: >
+    {{ openshift.common.admin_binary }} router --create
+    --config={{ openshift_hosted_kubeconfig }}
+    {% if replicas > 1 -%}
+    --replicas={{ replicas }}
+    {% endif -%}
+    {% if openshift.hosted.router.certificate | default(none) is not none -%}
+    --default-cert={{ openshift_master_config_dir }}/openshift-router.pem
+    {% endif -%}
+    --namespace={{ openshift.hosted.router.namespace | default('default') }}
+    {% if openshift.hosted.router.force_subdomain | default(none) is not none %}
+    --force-subdomain={{ openshift.hosted.router.force_subdomain }}
+    {% endif %}
+    --service-account=router
+    {% if openshift.hosted.router.selector | default(none) is not none -%}
+    --selector='{{ openshift.hosted.router.selector }}'
+    {% endif -%}
+    {% if not openshift.common.version_gte_3_2_or_1_2 | bool -%}
+    --credentials={{ openshift_master_config_dir }}/openshift-router.kubeconfig
+    {% endif -%}
+    {% if openshift.hosted.router.registryurl | default(none) is not none -%}
+    --images='{{ openshift.hosted.router.registryurl }}'
+    {% endif -%}
+  register: openshift_hosted_router_results
+  changed_when: "'service exists' not in openshift_hosted_router_results.stdout"
+  failed_when: "openshift_hosted_router_results.rc != 0 and 'service exists' not in openshift_hosted_router_results.stdout and 'deployment_config' not in openshift_hosted_router_results.stderr and 'service' not in openshift_hosted_router_results.stderr"
diff --git a/roles/openshift_hosted/templates/registry_config.j2 b/roles/openshift_hosted/templates/registry_config.j2
new file mode 100644
index 000000000..88704d968
--- /dev/null
+++ b/roles/openshift_hosted/templates/registry_config.j2
@@ -0,0 +1,70 @@
+version: 0.1
+log:
+  level: debug
+http:
+  addr: :5000
+storage:
+  cache:
+    blobdescriptor: inmemory
+{% if openshift.hosted.registry.storage.provider == 's3' %}
+  s3:
+    accesskey: {{ openshift.hosted.registry.storage.s3.accesskey }}
+    secretkey: {{ openshift.hosted.registry.storage.s3.secretkey }}
+    region: {{ openshift.hosted.registry.storage.s3.region }}
+    bucket: {{ openshift.hosted.registry.storage.s3.bucket }}
+    encrypt: false
+    secure: true
+    v4auth: true
+    rootdirectory: /registry
+    chunksize: "{{ openshift.hosted.registry.storage.s3.chunksize | default(26214400) }}"
+{% elif openshift.hosted.registry.storage.provider == 'azure_blob' %}
+  azure:
+    accountname: {{ openshift.hosted.registry.storage.azure_blob.accountname }}
+    accountkey: {{ openshift.hosted.registry.storage.azure_blob.accountkey }}
+    container: {{ openshift.hosted.registry.storage.azure_blob.container }}
+    realm: {{ openshift.hosted.registry.storage.azure_blob.realm }}
+{% elif openshift.hosted.registry.storage.provider == 'swift' %}
+  swift:
+    authurl: {{ openshift.hosted.registry.storage.swift.authurl }}
+    username: {{ openshift.hosted.registry.storage.swift.username }}
+    password: {{ openshift.hosted.registry.storage.swift.password }}
+    container: {{ openshift.hosted.registry.storage.swift.container }}
+{%   if 'region' in openshift.hosted.registry.storage.swift %}
+    region: {{ openshift.hosted.registry.storage.swift.region }}
+{%   endif -%}
+{%   if 'tenant' in openshift.hosted.registry.storage.swift %}
+    tenant: {{ openshift.hosted.registry.storage.swift.tenant }}
+{%   endif -%}
+{%   if 'tenantid' in openshift.hosted.registry.storage.swift %}
+    tenantid: {{ openshift.hosted.registry.storage.swift.tenantid }}
+{%   endif -%}
+{%   if 'domain' in openshift.hosted.registry.storage.swift %}
+    domain: {{ openshift.hosted.registry.storage.swift.domain }}
+{%   endif -%}
+{%   if 'domainid' in openshift.hosted.registry.storage.swift %}
+    domainid: {{ openshift.hosted.registry.storage.swift.domainid }}
+{%   endif -%}
+{% elif openshift.hosted.registry.storage.provider == 'gcs' %}
+  gcs:
+    bucket: {{ openshift.hosted.registry.storage.gcs.bucket }}
+{%   if 'keyfile' in openshift.hosted.registry.storage.gcs %}
+    keyfile: {{ openshift.hosted.registry.storage.gcs.keyfile }}
+{%   endif -%}
+{%   if 'rootdirectory' in openshift.hosted.registry.storage.gcs %}
+    rootdirectory: {{ openshift.hosted.registry.storage.gcs.rootdirectory }}
+{%   endif -%}
+{% endif -%}
+auth:
+  openshift:
+    realm: openshift
+middleware:
+  repository:
+  - name: openshift
+{% if openshift.hosted.registry.storage.provider == 's3' and 'cloudfront' in openshift.hosted.registry.storage.s3 %}
+  storage:
+  - name: cloudfront
+    options:
+      baseurl: {{ openshift.hosted.registry.storage.s3.cloudfront.baseurl }}
+      privatekey: {{ openshift.hosted.registry.storage.s3.cloudfront.privatekeyfile }}
+      keypairid: {{ openshift.hosted.registry.storage.s3.cloudfront.keypairid }}
+{% endif -%}
diff --git a/roles/openshift_hosted/templates/registry_config_secret.j2 b/roles/openshift_hosted/templates/registry_config_secret.j2
new file mode 100644
index 000000000..ca68544ec
--- /dev/null
+++ b/roles/openshift_hosted/templates/registry_config_secret.j2
@@ -0,0 +1,9 @@
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: registry-config
+  annotations:
+    provider: {{ openshift.hosted.registry.storage.provider }}
+data:
+  config.yml: {{ registry_config }}
diff --git a/roles/openshift_hosted/vars/main.yml b/roles/openshift_hosted/vars/main.yml
index 9967e26f4..521578cd0 100644
--- a/roles/openshift_hosted/vars/main.yml
+++ b/roles/openshift_hosted/vars/main.yml
@@ -1,2 +1,3 @@
 ---
 openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
+registry_config_secret_name: registry-config
diff --git a/roles/openshift_hosted_facts/tasks/main.yml b/roles/openshift_hosted_facts/tasks/main.yml
index 2a11e6cbd..631bf3e2a 100644
--- a/roles/openshift_hosted_facts/tasks/main.yml
+++ b/roles/openshift_hosted_facts/tasks/main.yml
@@ -1,7 +1,16 @@
 ---
+- set_fact:
+    openshift_hosted_router_selector: "{{ openshift_hosted_infra_selector }}"
+  when: openshift_hosted_router_selector is not defined and openshift_hosted_infra_selector is defined
+- set_fact:
+    openshift_hosted_registry_selector: "{{ openshift_hosted_infra_selector }}"
+  when: openshift_hosted_registry_selector is not defined and openshift_hosted_infra_selector is defined
+
 - name: Set hosted facts
   openshift_facts:
     role: hosted
     openshift_env: "{{ hostvars
                        | oo_merge_hostvars(vars, inventory_hostname)
                        | oo_openshift_env }}"
+    openshift_env_structures:
+    - 'openshift.hosted.router.*'
diff --git a/roles/openshift_master_facts/tasks/main.yml b/roles/openshift_master_facts/tasks/main.yml
index 3377e29e6..3aba774e5 100644
--- a/roles/openshift_master_facts/tasks/main.yml
+++ b/roles/openshift_master_facts/tasks/main.yml
@@ -61,7 +61,6 @@
       registry_selector: "{{ openshift_registry_selector | default(None) }}"
       api_server_args: "{{ osm_api_server_args | default(None) }}"
       controller_args: "{{ osm_controller_args | default(None) }}"
-      infra_nodes: "{{ openshift_infra_nodes | default(None) }}"
       disabled_features: "{{ osm_disabled_features | default(None) }}"
       master_count: "{{ openshift_master_count | default(None) }}"
       controller_lease_ttl: "{{ osm_controller_lease_ttl | default(None) }}"
diff --git a/roles/openshift_projects/meta/main.yml b/roles/openshift_projects/meta/main.yml
new file mode 100644
index 000000000..107a70b83
--- /dev/null
+++ b/roles/openshift_projects/meta/main.yml
@@ -0,0 +1,15 @@
+---
+galaxy_info:
+  author: Jason DeTiberus
+  description: OpenShift Projects
+  company: Red Hat, Inc.
+  license: Apache License, Version 2.0
+  min_ansible_version: 1.9
+  platforms:
+  - name: EL
+    versions:
+    - 7
+  categories:
+  - cloud
+dependencies:
+- { role: openshift_facts }
diff --git a/roles/openshift_projects/tasks/main.yml b/roles/openshift_projects/tasks/main.yml
new file mode 100644
index 000000000..62a357cf7
--- /dev/null
+++ b/roles/openshift_projects/tasks/main.yml
@@ -0,0 +1,47 @@
+---
+- name: Create temp directory for kubeconfig
+  command: mktemp -d /tmp/openshift-ansible-XXXXXX
+  register: mktemp
+  changed_when: False
+
+- name: Copy the admin client config(s)
+  command: >
+    cp {{ openshift_master_config_dir }}/admin.kubeconfig {{ mktemp.stdout }}/admin.kubeconfig
+  changed_when: False
+
+- name: Determine if projects exist
+  command: >
+    {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig
+    get projects {{ item.key }} -o json
+  with_dict: "{{ openshift_projects }}"
+  failed_when: false
+  changed_when: false
+  register: project_test
+
+- name: Create projects
+  command: >
+    {{ openshift.common.admin_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig
+    new-project {{ item.item.key }}
+    {% if item.item.value.default_node_selector | default(none) != none %}
+    {{ '--node-selector=' ~ item.item.value.default_node_selector }}
+    {% endif %}
+  when: item.rc == 1
+  with_items:
+  - "{{ project_test.results }}"
+
+- name: Update project default node selector if necessary
+  command: >
+    {{ openshift.common.client_binary }}
+    --config={{ mktemp.stdout }}/admin.kubeconfig patch namespace {{ item.item.key }}
+    -p '{"metadata": {"annotations": {"openshift.io/node-selector": "{{ item.item.value.default_node_selector }}"}}}'
+  when: "{{ item.rc == 0 and item.item.value.default_node_selector | default(none) != none
+            and item.item.value.default_node_selector | default(none) != (item.stdout | from_json).metadata.annotations['openshift.io/node-selector'] | default(none) }}"
+  with_items:
+  - "{{ project_test.results }}"
+  register: annotate_project
+
+- name: Delete temp directory
+  file:
+    name: "{{ mktemp.stdout }}"
+    state: absent
+  changed_when: False
diff --git a/roles/openshift_projects/vars/main.yml b/roles/openshift_projects/vars/main.yml
new file mode 100644
index 000000000..9967e26f4
--- /dev/null
+++ b/roles/openshift_projects/vars/main.yml
@@ -0,0 +1,2 @@
+---
+openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
diff --git a/roles/openshift_registry/README.md b/roles/openshift_registry/README.md
deleted file mode 100644
index 247272668..000000000
--- a/roles/openshift_registry/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-OpenShift Container Docker Registry
-===================================
-
-OpenShift Docker Registry  service installation
-
-Requirements
-------------
-
-Running OpenShift cluster
-
-Role Variables
---------------
-
-From this role:
-
-| Name               | Default value                                         |                     |
-|--------------------|-------------------------------------------------------|---------------------|
-|                    |                                                       |                     |
-
-
-Dependencies
-------------
-
-Example Playbook
-----------------
-
-TODO
-
-License
--------
-
-Apache License, Version 2.0
-
-Author Information
-------------------
-
-Red Hat openshift@redhat.com
diff --git a/roles/openshift_registry/defaults/main.yml b/roles/openshift_registry/defaults/main.yml
deleted file mode 100644
index 17a0d5301..000000000
--- a/roles/openshift_registry/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-registry_volume_claim: 'registry-claim'
diff --git a/roles/openshift_registry/handlers/main.yml b/roles/openshift_registry/handlers/main.yml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/roles/openshift_registry/meta/main.yml b/roles/openshift_registry/meta/main.yml
deleted file mode 100644
index e6db8c537..000000000
--- a/roles/openshift_registry/meta/main.yml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-galaxy_info:
-  author: OpenShift Red Hat
-  description: OpenShift Embedded Docker Registry
-  company: Red Hat, Inc.
-  license: Apache License, Version 2.0
-  min_ansible_version: 1.9
-  platforms:
-  - name: EL
-    versions:
-    - 7
-  categories:
-  - cloud
-dependencies:
-- role: openshift_hosted_facts
diff --git a/roles/openshift_registry/tasks/main.yml b/roles/openshift_registry/tasks/main.yml
deleted file mode 100644
index 1eeec2fbb..000000000
--- a/roles/openshift_registry/tasks/main.yml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-- name: Deploy OpenShift Registry
-  command: >
-    {{ openshift.common.admin_binary }} registry
-    --create --replicas={{ openshift.master.infra_nodes | length }}
-    --service-account=registry {{ oreg_selector }}
-    --credentials={{ openshift_master_config_dir }}/openshift-registry.kubeconfig {{ oreg_images }}
-  register: oreg_results
-  changed_when: "'service exists' not in oreg_results.stdout"
-
-- name: Determine if volume is already attached to dc/docker-registry
-  command: "{{ openshift.common.client_binary }} get -o template dc/docker-registry --template=\\{\\{.spec.template.spec.volumes\\}\\}"
-  changed_when: false
-  register: registry_volumes_output
-
-- set_fact:
-    volume_attached: "{{ registry_volume_claim in registry_volumes_output.stdout }}"
-
-- name: Add volume to dc/docker-registry
-  command: >
-    {{ openshift.common.client_binary }} volume dc/docker-registry
-    --add --overwrite -t persistentVolumeClaim --claim-name={{ registry_volume_claim }}
-    --name=registry-storage
-  when: not volume_attached | bool
diff --git a/roles/openshift_registry/vars/main.yml b/roles/openshift_registry/vars/main.yml
deleted file mode 100644
index 306350a5a..000000000
--- a/roles/openshift_registry/vars/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-openshift_master_config_dir: "{{ openshift.common.config_base }}/master"
-oreg_images: "--images='{{ openshift.master.registry_url }}'"
-oreg_selector: "--selector='{{ openshift.master.registry_selector }}'"
diff --git a/roles/openshift_serviceaccounts/tasks/main.yml b/roles/openshift_serviceaccounts/tasks/main.yml
index bafda9695..e90384d37 100644
--- a/roles/openshift_serviceaccounts/tasks/main.yml
+++ b/roles/openshift_serviceaccounts/tasks/main.yml
@@ -24,11 +24,11 @@
   register: scc_test
   with_items: "{{ openshift_serviceaccounts_sccs }}"
 
-- name: Grant the user access to the privileged scc
+- name: Grant the user access to the appropriate scc
   command: >
       {{ openshift.common.admin_binary }} policy add-scc-to-user
-      privileged system:serviceaccount:{{ openshift_serviceaccounts_namespace }}:{{ item.0 }}
-  when: "openshift.common.version_gte_3_1_or_1_1 and item.1.rc == 0 and 'system:serviceaccount:{{ openshift_serviceaccounts_namespace }}:{{ item.0 }}' not in {{ (item.1.stdout | from_yaml).users }}"
+      {{ item.1.item }} system:serviceaccount:{{ openshift_serviceaccounts_namespace }}:{{ item.0 }}
+  when: "openshift.common.version_gte_3_1_or_1_1 and item.1.rc == 0 and 'system:serviceaccount:{{ openshift_serviceaccounts_namespace }}:{{ item.0 }}' not in {{ (item.1.stdout | from_yaml).users | default([]) }}"
   with_nested:
   - "{{ openshift_serviceaccounts_names }}"
   - "{{ scc_test.results }}"
-- 
cgit v1.2.3