summaryrefslogtreecommitdiffstats
path: root/images
diff options
context:
space:
mode:
Diffstat (limited to 'images')
-rw-r--r--images/installer/Dockerfile67
-rw-r--r--images/installer/Dockerfile.rhel757
-rw-r--r--images/installer/README_CONTAINER_IMAGE.md50
-rw-r--r--images/installer/README_INVENTORY_GENERATOR.md85
-rw-r--r--images/installer/origin-extra-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-PaaS20
-rw-r--r--images/installer/origin-extra-root/etc/yum.repos.d/centos-openshift-origin.repo7
-rw-r--r--images/installer/root/etc/inventory-generator-config.yaml20
-rw-r--r--images/installer/root/exports/config.json.template (renamed from images/installer/system-container/root/exports/config.json.template)21
-rw-r--r--images/installer/root/exports/manifest.json (renamed from images/installer/system-container/root/exports/manifest.json)3
-rw-r--r--images/installer/root/exports/service.template (renamed from images/installer/system-container/root/exports/service.template)0
-rw-r--r--images/installer/root/exports/tmpfiles.template (renamed from images/installer/system-container/root/exports/tmpfiles.template)0
-rwxr-xr-ximages/installer/root/usr/local/bin/entrypoint17
-rwxr-xr-ximages/installer/root/usr/local/bin/generate397
-rwxr-xr-ximages/installer/root/usr/local/bin/run52
-rwxr-xr-ximages/installer/root/usr/local/bin/run-system-container.sh (renamed from images/installer/system-container/root/usr/local/bin/run-system-container.sh)0
-rwxr-xr-ximages/installer/root/usr/local/bin/usage33
-rwxr-xr-ximages/installer/root/usr/local/bin/usage.ocp33
-rwxr-xr-ximages/installer/root/usr/local/bin/user_setup17
-rw-r--r--images/installer/system-container/README.md13
19 files changed, 809 insertions, 83 deletions
diff --git a/images/installer/Dockerfile b/images/installer/Dockerfile
index 1df887f32..0d977d48f 100644
--- a/images/installer/Dockerfile
+++ b/images/installer/Dockerfile
@@ -1,51 +1,46 @@
-# Using playbook2image as a base
-# See https://github.com/aweiteka/playbook2image for details on the image
-# including documentation for the settings/env vars referenced below
-FROM docker.io/aweiteka/playbook2image:latest
+FROM centos:7
MAINTAINER OpenShift Team <dev@lists.openshift.redhat.com>
-LABEL name="openshift-ansible" \
+USER root
+
+# Add origin repo for including the oc client
+COPY images/installer/origin-extra-root /
+
+# install ansible and deps
+RUN INSTALL_PKGS="python-lxml pyOpenSSL python2-cryptography openssl java-1.8.0-openjdk-headless python2-passlib httpd-tools openssh-clients origin-clients" \
+ && yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS \
+ && EPEL_PKGS="ansible python2-boto" \
+ && yum install -y epel-release \
+ && yum install -y --setopt=tsflags=nodocs $EPEL_PKGS \
+ && rpm -V $INSTALL_PKGS $EPEL_PKGS \
+ && yum clean all
+
+LABEL name="openshift/origin-ansible" \
summary="OpenShift's installation and configuration tool" \
description="A containerized openshift-ansible image to let you run playbooks to install, upgrade, maintain and check an OpenShift cluster" \
url="https://github.com/openshift/openshift-ansible" \
io.k8s.display-name="openshift-ansible" \
io.k8s.description="A containerized openshift-ansible image to let you run playbooks to install, upgrade, maintain and check an OpenShift cluster" \
io.openshift.expose-services="" \
- io.openshift.tags="openshift,install,upgrade,ansible"
+ io.openshift.tags="openshift,install,upgrade,ansible" \
+ atomic.run="once"
-USER root
+ENV USER_UID=1001 \
+ HOME=/opt/app-root/src \
+ WORK_DIR=/usr/share/ansible/openshift-ansible \
+ OPTS="-v"
-# Create a symlink to /opt/app-root/src so that files under /usr/share/ansible are accessible.
-# This is required since the system-container uses by default the playbook under
-# /usr/share/ansible/openshift-ansible. With this change we won't need to keep two different
-# configurations for the two images.
-RUN mkdir -p /usr/share/ansible/ && ln -s /opt/app-root/src /usr/share/ansible/openshift-ansible
+# Add image scripts and files for running as a system container
+COPY images/installer/root /
+# Include playbooks, roles, plugins, etc. from this repo
+COPY . ${WORK_DIR}
-RUN INSTALL_PKGS="skopeo" && \
- yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \
- rpm -V $INSTALL_PKGS && \
- yum clean all
+RUN /usr/local/bin/user_setup \
+ && rm /usr/local/bin/usage.ocp
USER ${USER_UID}
-# The playbook to be run is specified via the PLAYBOOK_FILE env var.
-# This sets a default of openshift_facts.yml as it's an informative playbook
-# that can help test that everything is set properly (inventory, sshkeys)
-ENV PLAYBOOK_FILE=playbooks/byo/openshift_facts.yml \
- OPTS="-v" \
- INSTALL_OC=true
-
-# playbook2image's assemble script expects the source to be available in
-# /tmp/src (as per the source-to-image specs) so we import it there
-ADD . /tmp/src
-
-# Running the 'assemble' script provided by playbook2image will install
-# dependencies specified in requirements.txt and install the 'oc' client
-# as per the INSTALL_OC environment setting above
-RUN /usr/libexec/s2i/assemble
-
-# Add files for running as a system container
-COPY system-container/root /
-
-CMD [ "/usr/libexec/s2i/run" ]
+WORKDIR ${WORK_DIR}
+ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
+CMD [ "/usr/local/bin/run" ]
diff --git a/images/installer/Dockerfile.rhel7 b/images/installer/Dockerfile.rhel7
index 00841e660..5245771d0 100644
--- a/images/installer/Dockerfile.rhel7
+++ b/images/installer/Dockerfile.rhel7
@@ -1,8 +1,19 @@
-FROM openshift3/playbook2image
+FROM rhel7.3:7.3-released
MAINTAINER OpenShift Team <dev@lists.openshift.redhat.com>
-LABEL name="openshift3/openshift-ansible" \
+USER root
+
+# Playbooks, roles, and their dependencies are installed from packages.
+RUN INSTALL_PKGS="atomic-openshift-utils atomic-openshift-clients python-boto openssl java-1.8.0-openjdk-headless httpd-tools" \
+ && yum repolist > /dev/null \
+ && yum-config-manager --enable rhel-7-server-ose-3.7-rpms \
+ && yum-config-manager --enable rhel-7-server-rh-common-rpms \
+ && yum install -y --setopt=tsflags=nodocs $INSTALL_PKGS \
+ && rpm -q $INSTALL_PKGS \
+ && yum clean all
+
+LABEL name="openshift3/ose-ansible" \
summary="OpenShift's installation and configuration tool" \
description="A containerized openshift-ansible image to let you run playbooks to install, upgrade, maintain and check an OpenShift cluster" \
url="https://github.com/openshift/openshift-ansible" \
@@ -11,35 +22,25 @@ LABEL name="openshift3/openshift-ansible" \
io.openshift.expose-services="" \
io.openshift.tags="openshift,install,upgrade,ansible" \
com.redhat.component="aos3-installation-docker" \
- version="v3.4.1" \
+ version="v3.6.0" \
release="1" \
- architecture="x86_64"
-
-# Playbooks, roles and their dependencies are installed from packages.
-# Unlike in Dockerfile, we don't invoke the 'assemble' script here
-# because all content and dependencies (like 'oc') is already
-# installed via yum.
-USER root
-RUN INSTALL_PKGS="atomic-openshift-utils atomic-openshift-clients python-boto" && \
- yum repolist > /dev/null && \
- yum-config-manager --enable rhel-7-server-ose-3.4-rpms && \
- yum-config-manager --enable rhel-7-server-rh-common-rpms && \
- yum install -y $INSTALL_PKGS && \
- yum clean all
+ architecture="x86_64" \
+ atomic.run="once"
-USER ${USER_UID}
-
-# The playbook to be run is specified via the PLAYBOOK_FILE env var.
-# This sets a default of openshift_facts.yml as it's an informative playbook
-# that can help test that everything is set properly (inventory, sshkeys).
-# As the playbooks are installed via packages instead of being copied to
-# $APP_HOME by the 'assemble' script, we set the WORK_DIR env var to the
-# location of openshift-ansible.
-ENV PLAYBOOK_FILE=playbooks/byo/openshift_facts.yml \
+ENV USER_UID=1001 \
+ HOME=/opt/app-root/src \
WORK_DIR=/usr/share/ansible/openshift-ansible \
+ ANSIBLE_CONFIG=/usr/share/atomic-openshift-utils/ansible.cfg \
OPTS="-v"
-# Add files for running as a system container
-COPY system-container/root /
+# Add image scripts and files for running as a system container
+COPY root /
+
+RUN /usr/local/bin/user_setup \
+ && mv /usr/local/bin/usage{.ocp,}
+
+USER ${USER_UID}
-CMD [ "/usr/libexec/s2i/run" ]
+WORKDIR ${WORK_DIR}
+ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
+CMD [ "/usr/local/bin/run" ]
diff --git a/images/installer/README_CONTAINER_IMAGE.md b/images/installer/README_CONTAINER_IMAGE.md
new file mode 100644
index 000000000..bfe3661c0
--- /dev/null
+++ b/images/installer/README_CONTAINER_IMAGE.md
@@ -0,0 +1,50 @@
+ORIGIN-ANSIBLE IMAGE INSTALLER
+===============================
+
+Contains Dockerfile information for building an openshift/origin-ansible image
+based on `centos:7` or `rhel7.3:7.3-released`.
+
+Read additional setup information for this image at: https://hub.docker.com/r/openshift/origin-ansible/
+
+Read additional information about the `openshift/origin-ansible` at: https://github.com/openshift/openshift-ansible/blob/master/README_CONTAINER_IMAGE.md
+
+Also contains necessary components for running the installer using an Atomic System Container.
+
+
+System container installer
+==========================
+
+These files are needed to run the installer using an [Atomic System container](http://www.projectatomic.io/blog/2016/09/intro-to-system-containers/).
+These files can be found under `root/exports`:
+
+* config.json.template - Template of the configuration file used for running containers.
+
+* manifest.json - Used to define various settings for the system container, such as the default values to use for the installation.
+
+* service.template - Template file for the systemd service.
+
+* tmpfiles.template - Template file for systemd-tmpfiles.
+
+These files can be found under `root/usr/local/bin`:
+
+* run-system-container.sh - Entrypoint to the container.
+
+## Options
+
+These options may be set via the ``atomic`` ``--set`` flag. For defaults see ``root/exports/manifest.json``
+
+* OPTS - Additional options to pass to ansible when running the installer
+
+* VAR_LIB_OPENSHIFT_INSTALLER - Full path of the installer code to mount into the container
+
+* VAR_LOG_OPENSHIFT_LOG - Full path of the log file to mount into the container
+
+* PLAYBOOK_FILE - Full path of the playbook inside the container
+
+* HOME_ROOT - Full path on host to mount as the root home directory inside the container (for .ssh/, etc..)
+
+* ANSIBLE_CONFIG - Full path for the ansible configuration file to use inside the container
+
+* INVENTORY_FILE - Full path for the inventory to use from the host
+
+* INVENTORY_DIR - Full path for the inventory directory to use (e.g. for use with a hybrid dynamic/static inventory)
diff --git a/images/installer/README_INVENTORY_GENERATOR.md b/images/installer/README_INVENTORY_GENERATOR.md
new file mode 100644
index 000000000..9c10e4b71
--- /dev/null
+++ b/images/installer/README_INVENTORY_GENERATOR.md
@@ -0,0 +1,85 @@
+Dynamic Inventory Generation
+============================
+
+Script within the openshift-ansible image that can dynamically
+generate an Ansible inventory file from an existing cluster.
+
+## Configure
+
+User configuration helps to provide additional details when creating an inventory file.
+The default location of this file is in `/etc/inventory-generator-config.yaml`. The
+following configuration values are either expected or default to the given values when omitted:
+
+- `master_config_path`:
+ - specifies where to look for the bind-mounted `master-config.yaml` file in the container
+ - if omitted or a `null` value is given, its value is defaulted to `/opt/app-root/src/master-config.yaml`
+
+- `admin_kubeconfig_path`:
+ - specifies where to look for the bind-mounted `admin.kubeconfig` file in the container
+ - if omitted or a `null` value is given, its value is defaulted to `/opt/app-root/src/.kube/config`
+
+- `ansible_ssh_user`:
+ - specifies the ssh user to be used by Ansible when running the specified `PLAYBOOK_FILE` (see `README_CONTAINER_IMAGE.md` for additional information on this environment variable).
+ - if omitted, its value is defaulted to `root`
+
+- `ansible_become_user`:
+ - specifies a user to "become" on the remote host. Used for privilege escalation.
+ - If a non-null value is specified, `ansible_become` is implicitly set to `yes` in the resulting inventory file.
+
+See the supplied sample user configuration file in [`root/etc/inventory-generator-config.yaml`](./root/etc/inventory-generator-config.yaml) for additional optional inventory variables that may be specified.
+
+## Build
+
+See `README_CONTAINER_IMAGE.md` for information on building this image.
+
+## Run
+
+Given a master node's `master-config.yaml` file, a user configuration file (see "Configure" section), and an `admin.kubeconfig` file, the command below will:
+
+1. Use `oc` to query the host about additional node information (using the supplied `kubeconfig` file)
+2. Generate an inventory file based on information retrieved from `oc get nodes` and the given `master-config.yaml` file.
+3. run the specified [openshift-ansible](https://github.com/openshift/openshift-ansible) `health.yml` playbook using the generated inventory file from the previous step
+
+```
+docker run -u `id -u` \
+ -v $HOME/.ssh/id_rsa:/opt/app-root/src/.ssh/id_rsa:Z,ro \
+ -v /tmp/origin/master/admin.kubeconfig:/opt/app-root/src/.kube/config:Z \
+ -v /tmp/origin/master/master-config.yaml:/opt/app-root/src/master-config.yaml:Z \
+ -e OPTS="-v --become-user root" \
+ -e PLAYBOOK_FILE=playbooks/byo/openshift-checks/health.yml \
+ -e GENERATE_INVENTORY=true \
+ -e USER=`whoami` \
+ openshift/origin-ansible
+
+```
+
+**Note** In the command above, specifying the `GENERATE_INVENTORY` environment variable will automatically generate the inventory file in an expected location.
+An `INVENTORY_FILE` variable (or any other inventory location) does not need to be supplied when generating an inventory.
+
+## Debug
+
+To debug the `generate` script, run the above script interactively
+and manually execute `/usr/local/bin/generate`:
+
+```
+...
+docker run -u `id -u` \
+ -v ...
+ ...
+ -it openshift/origin-ansible /bin/bash
+
+---
+
+bash-4.2$ cd $HOME
+bash-4.2$ ls
+master-config.yaml
+bash-4.2$ /usr/local/bin/generate $HOME/generated_hosts
+bash-4.2$ ls
+generated_hosts master-config.yaml
+bash-4.2$ less generated_hosts
+...
+```
+
+## Notes
+
+See `README_CONTAINER_IMAGE.md` for additional information about this image.
diff --git a/images/installer/origin-extra-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-PaaS b/images/installer/origin-extra-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-PaaS
new file mode 100644
index 000000000..fcbaaca0e
--- /dev/null
+++ b/images/installer/origin-extra-root/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-PaaS
@@ -0,0 +1,20 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQENBFc8iwUBCADadBGYmA2nFvq79/5uxUQOiPqC/QflWcPX1B6SQKniUhyqaSes
+gNMJsPppKRV4NZKITcL8lZ90+Gds0fmL3b5xz1r5Rfm3ilSItEqeGlLIJZBvANyx
+rAT3q8EgkkVRyhZPseUMZj04O8OKnt1jrHakVkOp0lJClqhZ+bs/7yLRmaLXTcum
++ouqUKzQoAEDnqe9nJmmJhC6n2vg7o0PCo/9qOf/scQbv4FNoJfmkcVLRmwmqzgh
+bGj6QaOgij3sl94pZ3HFop4f+eU0kNbyt9J18fKI8X0DdHkDW8kO1UwwHT2ibJ1t
+mBaUsE1zZ0DvfyFad1xXAgm+SIlJgdpPvPNLABEBAAG0WUNlbnRPUyBQYWFTIFNJ
+RyAoaHR0cHM6Ly93aWtpLmNlbnRvcy5vcmcvU3BlY2lhbEludGVyZXN0R3JvdXAv
+UGFhUykgPHNlY3VyaXR5QGNlbnRvcy5vcmc+iQE5BBMBAgAjBQJXPIsFAhsDBwsJ
+CAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQw0xb1C8pfsyT2gf9FqJoc8oZ+T5A
+8cZslMyCWziPi0o7kd/Rw91T7dkV+VIC+sFlVga7fkPEAiD8U7JFE+a1IlcjfGuY
+my4S6UH8K5zL36CRg2MF112HE5TWoBxF3KZg9nOJQ2NLapJowaP8uITYG4vlgV3g
+GJD2OC191tjcqmelFnhAN0EBdxrRrBJ7tr3OCtL6bJ6NPQ0bXPI2Fjbm7SbxTfpE
+ggEU8R7WZQApYgl8zRfyS12SfpFV8ZU+lIBmJaU1qaY4/BmNgG6e7clmq8xVZQLg
+ZH9qi9+HPh+80+8/WhJUddlVXc2g6c4VjnnFpZfsrMdTAFuEsrjkyaxqeBjXCgbb
+pzGjTg0LXg==
+=CVSF
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/images/installer/origin-extra-root/etc/yum.repos.d/centos-openshift-origin.repo b/images/installer/origin-extra-root/etc/yum.repos.d/centos-openshift-origin.repo
new file mode 100644
index 000000000..d18994fdd
--- /dev/null
+++ b/images/installer/origin-extra-root/etc/yum.repos.d/centos-openshift-origin.repo
@@ -0,0 +1,7 @@
+
+[centos-openshift-origin]
+name=CentOS OpenShift Origin
+baseurl=http://mirror.centos.org/centos/7/paas/x86_64/openshift-origin/
+enabled=1
+gpgcheck=1
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-PaaS
diff --git a/images/installer/root/etc/inventory-generator-config.yaml b/images/installer/root/etc/inventory-generator-config.yaml
new file mode 100644
index 000000000..d56e3f4d2
--- /dev/null
+++ b/images/installer/root/etc/inventory-generator-config.yaml
@@ -0,0 +1,20 @@
+---
+# meta config
+master_config_path: "/opt/app-root/src/master-config.yaml"
+admin_kubeconfig_path: "/opt/app-root/src/.kube/config"
+
+# default user configuration
+ansible_ssh_user: ec2-user
+ansible_become: "yes"
+ansible_become_user: "root"
+
+# openshift-ansible inventory vars
+openshift_uninstall_images: false
+openshift_install_examples: true
+openshift_deployment_type: origin
+
+openshift_release: 3.6
+openshift_image_tag: v3.6.0
+openshift_hosted_logging_deploy: null # defaults to "true" if loggingPublicURL is set in master-config.yaml
+openshift_logging_image_version: v3.6.0
+openshift_disable_check: ""
diff --git a/images/installer/system-container/root/exports/config.json.template b/images/installer/root/exports/config.json.template
index 383e3696e..1a009fa7b 100644
--- a/images/installer/system-container/root/exports/config.json.template
+++ b/images/installer/root/exports/config.json.template
@@ -21,9 +21,10 @@
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm",
"OPTS=$OPTS",
- "PLAYBOOK_FILE=$PLAYBOOK_FILE"
+ "PLAYBOOK_FILE=$PLAYBOOK_FILE",
+ "ANSIBLE_CONFIG=$ANSIBLE_CONFIG"
],
- "cwd": "/opt/app-root/src/",
+ "cwd": "/usr/share/ansible/openshift-ansible",
"rlimits": [
{
"type": "RLIMIT_NOFILE",
@@ -102,7 +103,7 @@
},
{
"type": "bind",
- "source": "$SSH_ROOT",
+ "source": "$HOME_ROOT/.ssh",
"destination": "/opt/app-root/src/.ssh",
"options": [
"bind",
@@ -112,8 +113,8 @@
},
{
"type": "bind",
- "source": "$SSH_ROOT",
- "destination": "/root/.ssh",
+ "source": "$HOME_ROOT",
+ "destination": "/root",
"options": [
"bind",
"rw",
@@ -171,6 +172,16 @@
]
},
{
+ "destination": "/etc/resolv.conf",
+ "type": "bind",
+ "source": "/etc/resolv.conf",
+ "options": [
+ "ro",
+ "rbind",
+ "rprivate"
+ ]
+ },
+ {
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
diff --git a/images/installer/system-container/root/exports/manifest.json b/images/installer/root/exports/manifest.json
index 1db845965..8b984d7a3 100644
--- a/images/installer/system-container/root/exports/manifest.json
+++ b/images/installer/root/exports/manifest.json
@@ -5,7 +5,8 @@
"VAR_LIB_OPENSHIFT_INSTALLER" : "/var/lib/openshift-installer",
"VAR_LOG_OPENSHIFT_LOG": "/var/log/ansible.log",
"PLAYBOOK_FILE": "/usr/share/ansible/openshift-ansible/playbooks/byo/config.yml",
- "SSH_ROOT": "/root/.ssh",
+ "HOME_ROOT": "/root",
+ "ANSIBLE_CONFIG": "/usr/share/atomic-openshift-utils/ansible.cfg",
"INVENTORY_FILE": "/dev/null"
}
}
diff --git a/images/installer/system-container/root/exports/service.template b/images/installer/root/exports/service.template
index bf5316af6..bf5316af6 100644
--- a/images/installer/system-container/root/exports/service.template
+++ b/images/installer/root/exports/service.template
diff --git a/images/installer/system-container/root/exports/tmpfiles.template b/images/installer/root/exports/tmpfiles.template
index b1f6caf47..b1f6caf47 100644
--- a/images/installer/system-container/root/exports/tmpfiles.template
+++ b/images/installer/root/exports/tmpfiles.template
diff --git a/images/installer/root/usr/local/bin/entrypoint b/images/installer/root/usr/local/bin/entrypoint
new file mode 100755
index 000000000..777bf3f11
--- /dev/null
+++ b/images/installer/root/usr/local/bin/entrypoint
@@ -0,0 +1,17 @@
+#!/bin/bash -e
+#
+# This file serves as the main entrypoint to the openshift-ansible image.
+#
+# For more information see the documentation:
+# https://github.com/openshift/openshift-ansible/blob/master/README_CONTAINER_IMAGE.md
+
+
+# Patch /etc/passwd file with the current user info.
+# The current user's entry must be correctly defined in this file in order for
+# the `ssh` command to work within the created container.
+
+if ! whoami &>/dev/null; then
+ echo "${USER:-default}:x:$(id -u):$(id -g):Default User:$HOME:/sbin/nologin" >> /etc/passwd
+fi
+
+exec "$@"
diff --git a/images/installer/root/usr/local/bin/generate b/images/installer/root/usr/local/bin/generate
new file mode 100755
index 000000000..3db7a3ee8
--- /dev/null
+++ b/images/installer/root/usr/local/bin/generate
@@ -0,0 +1,397 @@
+#!/bin/env python
+
+"""
+Attempts to read 'master-config.yaml' and extract remote
+host information to dynamically create an inventory file
+in order to run Ansible playbooks against that host.
+"""
+
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import yaml
+
+try:
+ HOME = os.environ['HOME']
+except KeyError:
+ print 'A required environment variable "$HOME" has not been set'
+ exit(1)
+
+DEFAULT_USER_CONFIG_PATH = '/etc/inventory-generator-config.yaml'
+DEFAULT_MASTER_CONFIG_PATH = HOME + '/master-config.yaml'
+DEFAULT_ADMIN_KUBECONFIG_PATH = HOME + '/.kube/config'
+
+INVENTORY_FULL_PATH = HOME + '/generated_hosts'
+USE_STDOUT = True
+
+if len(sys.argv) > 1:
+ INVENTORY_FULL_PATH = sys.argv[1]
+ USE_STDOUT = False
+
+
+class OpenShiftClientError(Exception):
+ """Base exception class for OpenShift CLI wrapper"""
+ pass
+
+
+class InvalidHost(Exception):
+ """Base exception class for host creation problems."""
+ pass
+
+
+class InvalidHostGroup(Exception):
+ """Base exception class for host-group creation problems."""
+ pass
+
+
+class OpenShiftClient:
+ oc = None
+ kubeconfig = None
+
+ def __init__(self, kubeconfig=DEFAULT_ADMIN_KUBECONFIG_PATH):
+ """Find and store path to oc binary"""
+ # https://github.com/openshift/openshift-ansible/issues/3410
+ # oc can be in /usr/local/bin in some cases, but that may not
+ # be in $PATH due to ansible/sudo
+ paths = os.environ.get("PATH", os.defpath).split(os.pathsep) + ['/usr/local/bin', os.path.expanduser('~/bin')]
+
+ oc_binary_name = 'oc'
+ oc_binary = None
+
+ # Use shutil.which if it is available, otherwise fallback to a naive path search
+ try:
+ which_result = shutil.which(oc_binary_name, path=os.pathsep.join(paths))
+ if which_result is not None:
+ oc_binary = which_result
+ except AttributeError:
+ for path in paths:
+ if os.path.exists(os.path.join(path, oc_binary_name)):
+ oc_binary = os.path.join(path, oc_binary_name)
+ break
+
+ if oc_binary is None:
+ raise OpenShiftClientError('Unable to locate `oc` binary. Not present in PATH.')
+
+ self.oc = oc_binary
+ self.kubeconfig = kubeconfig
+
+ def call(self, cmd_str):
+ """Execute a remote call using `oc`"""
+ cmd = [
+ self.oc,
+ '--config',
+ self.kubeconfig
+ ] + shlex.split(cmd_str)
+ try:
+ out = subprocess.check_output(list(cmd), stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as err:
+ raise OpenShiftClientError('[rc {}] {}\n{}'.format(err.returncode, ' '.join(err.cmd), err.output))
+ return out
+
+ def whoami(self):
+ """Retrieve information about the current user in the given kubeconfig"""
+ return self.call('whoami')
+
+ def get_nodes(self):
+ """Retrieve remote node information as a yaml object"""
+ return self.call('get nodes -o yaml')
+
+
+class HostGroup:
+ groupname = ""
+ hosts = list()
+
+ def __init__(self, hosts):
+ if not hosts:
+ return
+ first = hosts[0].get_group_name()
+ for h in hosts:
+ if h.get_group_name() != first:
+ raise InvalidHostGroup("Attempt to create HostGroup with hosts of varying groups.")
+
+ self.hosts = hosts
+ self.groupname = first
+
+ def add_host(self, host):
+ """Add a new host to this group."""
+ self.hosts.append(host)
+
+ def get_group_name(self):
+ """Return the groupname associated with each aggregated host."""
+ return self.groupname
+
+ def get_hosts(self):
+ """Return aggregated hosts"""
+ return self.hosts
+
+ def string(self):
+ """Call the print method for each aggregated host; separated by newlines."""
+ infos = ""
+ for host in self.hosts:
+ infos += host.string() + "\n"
+ return infos
+
+
+class Host:
+ group = "masters"
+ alias = ""
+ hostname = ""
+ public_hostname = ""
+ ip_addr = ""
+ public_ip_addr = ""
+
+ def __init__(self, groupname):
+ if not groupname:
+ raise InvalidHost("Attempt to create Host with no group name provided.")
+ self.group = groupname
+
+ def get_group_name(self):
+ return self.group
+
+ def get_openshift_hostname(self):
+ return self.hostname
+
+ def host_alias(self, hostalias):
+ """Set an alias for this host."""
+ self.alias = hostalias
+
+ def address(self, ip):
+ """Set the ip address for this host."""
+ self.ip_addr = ip
+
+ def public_address(self, ip):
+ """Set the external ip address for this host."""
+ self.public_ip_addr = ip
+
+ def host_name(self, hname):
+ self.hostname = parse_hostname(hname)
+
+ def public_host_name(self, phname):
+ self.public_hostname = parse_hostname(phname)
+
+ def string(self):
+ """Print an inventory-file compatible string with host information"""
+ info = ""
+ if self.alias:
+ info += self.alias + " "
+ elif self.hostname:
+ info += self.hostname + " "
+ elif self.ip_addr:
+ info += self.ip_addr + " "
+ if self.ip_addr:
+ info += "openshift_ip=" + self.ip_addr + " "
+ if self.public_ip_addr:
+ info += "openshift_public_ip=" + self.public_ip_addr + " "
+ if self.hostname:
+ info += "openshift_hostname=" + self.hostname + " "
+ if self.public_hostname:
+ info += "openshift_public_hostname=" + self.public_hostname
+
+ return info
+
+
+def parse_hostname(host):
+ """Remove protocol and port from given hostname.
+ Return parsed string"""
+ no_proto = re.split('^http(s)?\:\/\/', host)
+ if no_proto:
+ host = no_proto[-1]
+
+ no_port = re.split('\:[0-9]+(/)?$', host)
+ if no_port:
+ host = no_port[0]
+
+ return host
+
+
+def main():
+ """Parse master-config file and populate inventory file."""
+ # set default values
+ USER_CONFIG = os.environ.get('CONFIG')
+ if not USER_CONFIG:
+ USER_CONFIG = DEFAULT_USER_CONFIG_PATH
+
+ # read user configuration
+ try:
+ config_file_obj = open(USER_CONFIG, 'r')
+ raw_config_file = config_file_obj.read()
+ user_config = yaml.load(raw_config_file)
+ if not user_config:
+ user_config = dict()
+ except IOError as err:
+ print "Unable to find or read user configuration file '{}': {}".format(USER_CONFIG, err)
+ exit(1)
+
+ master_config_path = user_config.get('master_config_path', DEFAULT_MASTER_CONFIG_PATH)
+ if not master_config_path:
+ master_config_path = DEFAULT_MASTER_CONFIG_PATH
+
+ admin_kubeconfig_path = user_config.get('admin_kubeconfig_path', DEFAULT_ADMIN_KUBECONFIG_PATH)
+ if not admin_kubeconfig_path:
+ admin_kubeconfig_path = DEFAULT_ADMIN_KUBECONFIG_PATH
+
+ try:
+ file_obj = open(master_config_path, 'r')
+ except IOError as err:
+ print "Unable to find or read host master configuration file '{}': {}".format(master_config_path, err)
+ exit(1)
+
+ raw_text = file_obj.read()
+
+ y = yaml.load(raw_text)
+ if y.get("kind", "") != "MasterConfig":
+ print "Bind-mounted host master configuration file is not of 'kind' MasterConfig. Aborting..."
+ exit(1)
+
+ # finish reading config file and begin gathering
+ # cluster information for inventory file
+ file_obj.close()
+
+ # set inventory values based on user configuration
+ ansible_ssh_user = user_config.get('ansible_ssh_user', 'root')
+ ansible_become_user = user_config.get('ansible_become_user')
+
+ openshift_uninstall_images = user_config.get('openshift_uninstall_images', False)
+ openshift_install_examples = user_config.get('openshift_install_examples', True)
+ openshift_deployment_type = user_config.get('openshift_deployment_type', 'origin')
+
+ openshift_release = user_config.get('openshift_release')
+ openshift_image_tag = user_config.get('openshift_image_tag')
+ openshift_logging_image_version = user_config.get('openshift_logging_image_version')
+ openshift_disable_check = user_config.get('openshift_disable_check')
+
+ # extract host config info from parsed yaml file
+ asset_config = y.get("assetConfig")
+ master_config = y.get("kubernetesMasterConfig")
+ etcd_config = y.get("etcdClientInfo")
+
+ # if master_config is missing, error out; we expect to be running on a master to be able to
+ # gather enough information to generate the rest of the inventory file.
+ if not master_config:
+ msg = "'kubernetesMasterConfig' missing from '{}'; unable to gather all necessary host information..."
+ print msg.format(master_config_path)
+ exit(1)
+
+ master_public_url = y.get("masterPublicURL")
+ if not master_public_url:
+ msg = "'kubernetesMasterConfig.masterPublicURL' missing from '{}'; Unable to connect to master host..."
+ print msg.format(master_config_path)
+ exit(1)
+
+ oc = OpenShiftClient(admin_kubeconfig_path)
+
+ # ensure kubeconfig is logged in with provided user, or fail with a friendly message otherwise
+ try:
+ oc.whoami()
+ except OpenShiftClientError as err:
+ msg = ("Unable to obtain user information using the provided kubeconfig file. "
+ "Current context does not appear to be able to authenticate to the server. "
+ "Error returned from server:\n\n{}")
+ print msg.format(str(err))
+ exit(1)
+
+ # connect to remote host using the provided config and extract all possible node information
+ nodes_config = yaml.load(oc.get_nodes())
+
+ # contains host types (e.g. masters, nodes, etcd)
+ host_groups = dict()
+ openshift_hosted_logging_deploy = False
+ is_etcd_deployed = master_config.get("storage-backend", "") in ["etcd3", "etcd2", "etcd"]
+
+ if asset_config and asset_config.get('loggingPublicURL'):
+ openshift_hosted_logging_deploy = True
+
+ openshift_hosted_logging_deploy = user_config.get("openshift_hosted_logging_deploy", openshift_hosted_logging_deploy)
+
+ m = Host("masters")
+ m.address(master_config["masterIP"])
+ m.public_host_name(master_public_url)
+ host_groups["masters"] = HostGroup([m])
+
+ if nodes_config:
+ node_hosts = list()
+ for node in nodes_config.get("items", []):
+ if node["kind"] != "Node":
+ continue
+
+ n = Host("nodes")
+
+ address = ""
+ internal_hostname = ""
+ for item in node["status"].get("addresses", []):
+ if not address and item['type'] in ['InternalIP', 'LegacyHostIP']:
+ address = item['address']
+
+ if item['type'] == 'Hostname':
+ internal_hostname = item['address']
+
+ n.address(address)
+ n.host_name(internal_hostname)
+ node_hosts.append(n)
+
+ host_groups["nodes"] = HostGroup(node_hosts)
+
+ if etcd_config:
+ etcd_hosts = list()
+ for url in etcd_config.get("urls", []):
+ e = Host("etcd")
+ e.host_name(url)
+ etcd_hosts.append(e)
+
+ host_groups["etcd"] = HostGroup(etcd_hosts)
+
+ # open new inventory file for writing
+ if USE_STDOUT:
+ inv_file_obj = sys.stdout
+ else:
+ try:
+ inv_file_obj = open(INVENTORY_FULL_PATH, 'w+')
+ except IOError as err:
+ print "Unable to create or open generated inventory file: {}".format(err)
+ exit(1)
+
+ inv_file_obj.write("[OSEv3:children]\n")
+ for group in host_groups:
+ inv_file_obj.write("{}\n".format(group))
+ inv_file_obj.write("\n")
+
+ inv_file_obj.write("[OSEv3:vars]\n")
+ if ansible_ssh_user:
+ inv_file_obj.write("ansible_ssh_user={}\n".format(ansible_ssh_user))
+ if ansible_become_user:
+ inv_file_obj.write("ansible_become_user={}\n".format(ansible_become_user))
+ inv_file_obj.write("ansible_become=yes\n")
+
+ if openshift_uninstall_images:
+ inv_file_obj.write("openshift_uninstall_images={}\n".format(str(openshift_uninstall_images)))
+ if openshift_deployment_type:
+ inv_file_obj.write("openshift_deployment_type={}\n".format(openshift_deployment_type))
+ if openshift_install_examples:
+ inv_file_obj.write("openshift_install_examples={}\n".format(str(openshift_install_examples)))
+
+ if openshift_release:
+ inv_file_obj.write("openshift_release={}\n".format(str(openshift_release)))
+ if openshift_image_tag:
+ inv_file_obj.write("openshift_image_tag={}\n".format(str(openshift_image_tag)))
+ if openshift_logging_image_version:
+ inv_file_obj.write("openshift_logging_image_version={}\n".format(str(openshift_logging_image_version)))
+ if openshift_disable_check:
+ inv_file_obj.write("openshift_disable_check={}\n".format(str(openshift_disable_check)))
+ inv_file_obj.write("\n")
+
+ inv_file_obj.write("openshift_hosted_logging_deploy={}\n".format(str(openshift_hosted_logging_deploy)))
+ inv_file_obj.write("\n")
+
+ for group in host_groups:
+ inv_file_obj.write("[{}]\n".format(host_groups[group].get_group_name()))
+ inv_file_obj.write(host_groups[group].string())
+ inv_file_obj.write("\n")
+
+ inv_file_obj.close()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/images/installer/root/usr/local/bin/run b/images/installer/root/usr/local/bin/run
new file mode 100755
index 000000000..cd38a6ff0
--- /dev/null
+++ b/images/installer/root/usr/local/bin/run
@@ -0,0 +1,52 @@
+#!/bin/bash -e
+#
+# This file serves as the default command to the openshift-ansible image.
+# Runs a playbook with inventory as specified by environment variables.
+#
+# For more information see the documentation:
+# https://github.com/openshift/openshift-ansible/blob/master/README_CONTAINER_IMAGE.md
+
+# SOURCE and HOME DIRECTORY: /opt/app-root/src
+
+if [[ -z "${PLAYBOOK_FILE}" ]]; then
+ echo
+ echo "PLAYBOOK_FILE must be provided."
+ exec /usr/local/bin/usage
+fi
+
+INVENTORY="$(mktemp)"
+if [[ -v INVENTORY_FILE ]]; then
+ # Make a copy so that ALLOW_ANSIBLE_CONNECTION_LOCAL below
+ # does not attempt to modify the original
+ cp -a ${INVENTORY_FILE} ${INVENTORY}
+elif [[ -v INVENTORY_DIR ]]; then
+ INVENTORY="$(mktemp -d)"
+ cp -R ${INVENTORY_DIR}/* ${INVENTORY}
+elif [[ -v INVENTORY_URL ]]; then
+ curl -o ${INVENTORY} ${INVENTORY_URL}
+elif [[ -v DYNAMIC_SCRIPT_URL ]]; then
+ curl -o ${INVENTORY} ${DYNAMIC_SCRIPT_URL}
+ chmod 755 ${INVENTORY}
+elif [[ -v GENERATE_INVENTORY ]]; then
+ # dynamically generate inventory file using bind-mounted info
+ /usr/local/bin/generate ${INVENTORY}
+else
+ echo
+ echo "One of INVENTORY_FILE, INVENTORY_DIR, INVENTORY_URL, GENERATE_INVENTORY, or DYNAMIC_SCRIPT_URL must be provided."
+ exec /usr/local/bin/usage
+fi
+INVENTORY_ARG="-i ${INVENTORY}"
+
+if [[ "$ALLOW_ANSIBLE_CONNECTION_LOCAL" = false ]]; then
+ sed -i s/ansible_connection=local// ${INVENTORY}
+fi
+
+if [[ -v VAULT_PASS ]]; then
+ VAULT_PASS_FILE="$(mktemp)"
+ echo ${VAULT_PASS} > ${VAULT_PASS_FILE}
+ VAULT_PASS_ARG="--vault-password-file ${VAULT_PASS_FILE}"
+fi
+
+cd ${WORK_DIR}
+
+exec ansible-playbook ${INVENTORY_ARG} ${VAULT_PASS_ARG} ${OPTS} ${PLAYBOOK_FILE}
diff --git a/images/installer/system-container/root/usr/local/bin/run-system-container.sh b/images/installer/root/usr/local/bin/run-system-container.sh
index 9ce7c7328..9ce7c7328 100755
--- a/images/installer/system-container/root/usr/local/bin/run-system-container.sh
+++ b/images/installer/root/usr/local/bin/run-system-container.sh
diff --git a/images/installer/root/usr/local/bin/usage b/images/installer/root/usr/local/bin/usage
new file mode 100755
index 000000000..3518d7f19
--- /dev/null
+++ b/images/installer/root/usr/local/bin/usage
@@ -0,0 +1,33 @@
+#!/bin/bash -e
+cat <<"EOF"
+
+The origin-ansible image provides several options to control the behaviour of the containers.
+For more details on these options see the documentation:
+
+ https://github.com/openshift/openshift-ansible/blob/master/README_CONTAINER_IMAGE.md
+
+At a minimum, when running a container using this image you must provide:
+
+* ssh keys so that Ansible can reach your hosts. These should be mounted as a volume under
+ /opt/app-root/src/.ssh
+* An inventory file. This can be mounted inside the container as a volume and specified with the
+ INVENTORY_FILE environment variable. Alternatively you can serve the inventory file from a web
+ server and use the INVENTORY_URL environment variable to fetch it.
+* The playbook to run. This is set using the PLAYBOOK_FILE environment variable.
+
+Here is an example of how to run a containerized origin-ansible with
+the openshift_facts playbook, which collects and displays facts about your
+OpenShift environment. The inventory and ssh keys are mounted as volumes
+(the latter requires setting the uid in the container and SELinux label
+in the key file via :Z so they can be accessed) and the PLAYBOOK_FILE
+environment variable is set to point to the playbook within the image:
+
+docker run -tu `id -u` \
+ -v $HOME/.ssh/id_rsa:/opt/app-root/src/.ssh/id_rsa:Z,ro \
+ -v /etc/ansible/hosts:/tmp/inventory:Z,ro \
+ -e INVENTORY_FILE=/tmp/inventory \
+ -e OPTS="-v" \
+ -e PLAYBOOK_FILE=playbooks/byo/openshift_facts.yml \
+ openshift/origin-ansible
+
+EOF
diff --git a/images/installer/root/usr/local/bin/usage.ocp b/images/installer/root/usr/local/bin/usage.ocp
new file mode 100755
index 000000000..50593af6e
--- /dev/null
+++ b/images/installer/root/usr/local/bin/usage.ocp
@@ -0,0 +1,33 @@
+#!/bin/bash -e
+cat <<"EOF"
+
+The ose-ansible image provides several options to control the behaviour of the containers.
+For more details on these options see the documentation:
+
+ https://github.com/openshift/openshift-ansible/blob/master/README_CONTAINER_IMAGE.md
+
+At a minimum, when running a container using this image you must provide:
+
+* ssh keys so that Ansible can reach your hosts. These should be mounted as a volume under
+ /opt/app-root/src/.ssh
+* An inventory file. This can be mounted inside the container as a volume and specified with the
+ INVENTORY_FILE environment variable. Alternatively you can serve the inventory file from a web
+ server and use the INVENTORY_URL environment variable to fetch it.
+* The playbook to run. This is set using the PLAYBOOK_FILE environment variable.
+
+Here is an example of how to run a containerized ose-ansible with
+the openshift_facts playbook, which collects and displays facts about your
+OpenShift environment. The inventory and ssh keys are mounted as volumes
+(the latter requires setting the uid in the container and SELinux label
+in the key file via :Z so they can be accessed) and the PLAYBOOK_FILE
+environment variable is set to point to the playbook within the image:
+
+docker run -tu `id -u` \
+ -v $HOME/.ssh/id_rsa:/opt/app-root/src/.ssh/id_rsa:Z,ro \
+ -v /etc/ansible/hosts:/tmp/inventory:Z,ro \
+ -e INVENTORY_FILE=/tmp/inventory \
+ -e OPTS="-v" \
+ -e PLAYBOOK_FILE=playbooks/byo/openshift_facts.yml \
+ openshift3/ose-ansible
+
+EOF
diff --git a/images/installer/root/usr/local/bin/user_setup b/images/installer/root/usr/local/bin/user_setup
new file mode 100755
index 000000000..b76e60a4d
--- /dev/null
+++ b/images/installer/root/usr/local/bin/user_setup
@@ -0,0 +1,17 @@
+#!/bin/sh
+set -x
+
+# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be)
+mkdir -p ${HOME}
+chown ${USER_UID}:0 ${HOME}
+chmod ug+rwx ${HOME}
+
+# runtime user will need to be able to self-insert in /etc/passwd
+chmod g+rw /etc/passwd
+
+# ensure that the ansible content is accessible
+chmod -R g+r ${WORK_DIR}
+find ${WORK_DIR} -type d -exec chmod g+x {} +
+
+# no need for this script to remain in the image after running
+rm $0
diff --git a/images/installer/system-container/README.md b/images/installer/system-container/README.md
deleted file mode 100644
index dc95307e5..000000000
--- a/images/installer/system-container/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# System container installer
-
-These files are needed to run the installer using an [Atomic System container](http://www.projectatomic.io/blog/2016/09/intro-to-system-containers/).
-
-* config.json.template - Template of the configuration file used for running containers.
-
-* manifest.json - Used to define various settings for the system container, such as the default values to use for the installation.
-
-* run-system-container.sh - Entrypoint to the container.
-
-* service.template - Template file for the systemd service.
-
-* tmpfiles.template - Template file for systemd-tmpfiles.