diff options
388 files changed, 33411 insertions, 2565 deletions
diff --git a/.tito/packages/.readme b/.tito/packages/.readme new file mode 100644 index 000000000..b9411e2d1 --- /dev/null +++ b/.tito/packages/.readme @@ -0,0 +1,3 @@ +the .tito/packages directory contains metadata files +named after their packages. Each file has the latest tagged +version and the project's relative directory. diff --git a/.tito/packages/openshift-ansible b/.tito/packages/openshift-ansible new file mode 100644 index 000000000..a5750f1ac --- /dev/null +++ b/.tito/packages/openshift-ansible @@ -0,0 +1 @@ +3.0.4-1 ./ diff --git a/.tito/packages/openshift-ansible-bin b/.tito/packages/openshift-ansible-bin new file mode 100644 index 000000000..5275dfcf9 --- /dev/null +++ b/.tito/packages/openshift-ansible-bin @@ -0,0 +1 @@ +0.0.21-1 bin/ diff --git a/.tito/packages/openshift-ansible-inventory b/.tito/packages/openshift-ansible-inventory new file mode 100644 index 000000000..85502438a --- /dev/null +++ b/.tito/packages/openshift-ansible-inventory @@ -0,0 +1 @@ +0.0.11-1 inventory/ diff --git a/.tito/releasers.conf b/.tito/releasers.conf new file mode 100644 index 000000000..f863ce9b1 --- /dev/null +++ b/.tito/releasers.conf @@ -0,0 +1,13 @@ +[brew] +releaser = tito.release.DistGitReleaser +branches = libra-rhel-7 + +[ose-3.0] +releaser = tito.release.DistGitReleaser +branches = rhose-3.0-rhel-7 +srpm_disttag = .el7ose + +[aos-3.1] +releaser = tito.release.DistGitReleaser +branches = rhaos-3.1-rhel-7 +srpm_disttag = .el7aos diff --git a/.tito/tito.props b/.tito/tito.props new file mode 100644 index 000000000..eab3f190d --- /dev/null +++ b/.tito/tito.props @@ -0,0 +1,5 @@ +[buildconfig] +builder = tito.builder.Builder +tagger = tito.tagger.VersionTagger +changelog_do_not_remove_cherrypick = 0 +changelog_format = %s (%ae) diff --git a/DEPLOYMENT_TYPES.md b/DEPLOYMENT_TYPES.md new file mode 100644 index 000000000..1f64e223a --- /dev/null +++ b/DEPLOYMENT_TYPES.md @@ -0,0 +1,23 @@ +#Deployment Types + +This module supports OpenShift Origin, OpenShift Enterprise, and Atomic +Enterprise Platform. Each deployment type sets various defaults used throughout +your environment. + +The table below outlines the defaults per `deployment_type`. + +| deployment_type | origin | enterprise (< 3.1) | atomic-enterprise | openshift-enterprise (>= 3.1) | +|-----------------------------------------------------------------|------------------------------------------|----------------------------------------|----------------------------------|----------------------------------| +| **openshift.common.service_type** (also used for package names) | origin | openshift | atomic-openshift | | +| **openshift.common.config_base** | /etc/origin | /etc/openshift | /etc/origin | /etc/origin | +| **openshift.common.data_dir** | /var/lib/origin | /var/lib/openshift | /var/lib/origin | /var/lib/origin | +| **openshift.master.registry_url openshift.node.registry_url** | openshift/origin-${component}:${version} | openshift3/ose-${component}:${version} | aos3/aos-${component}:${version} | aos3/aos-${component}:${version} | +| **Image Streams** | centos | rhel + xpaas | N/A | rhel | + + +**NOTE** `enterprise` deloyment type is used for OpenShift Enterprise version +3.0.x OpenShift Enterprise deployments utilizing version 3.1 and later will +make use of the new `openshift-enterprise` deployment type. Additional work to +migrate between the two will be forthcoming. + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..ab16ca609 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM rhel7 + +MAINTAINER Aaron Weitekamp <aweiteka@redhat.com> + +RUN yum -y install http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + +# Not sure if all of these packages are necessary +# only git and ansible are known requirements +RUN yum install -y --enablerepo rhel-7-server-extras-rpms net-tools bind-utils git ansible + +ADD ./ /opt/openshift-ansible/ + +ENTRYPOINT ["/usr/bin/ansible-playbook"] + +CMD ["/opt/openshift-ansible/playbooks/byo/config.yml"] + +LABEL RUN docker run -it --rm --privileged --net=host -v ~/.ssh:/root/.ssh -v /etc/ansible:/etc/ansible --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE @@ -1,6 +1,6 @@ -#openshift-ansible +#OpenShift and Atomic Enterprise Ansible -This repo contains OpenShift Ansible code. +This repo contains Ansible code for OpenShift and Atomic Enterprise. ##Setup - Install base dependencies: @@ -23,12 +23,13 @@ This repo contains OpenShift Ansible code. - Bring your own host deployments: - [OpenShift Enterprise](README_OSE.md) - [OpenShift Origin](README_origin.md) + - [Atomic Enterprise](README_AEP.md) - Build - [How to build the openshift-ansible rpms](BUILD.md) - Directory Structure: - - [bin/cluster](bin/cluster) - python script to easily create OpenShift 3 clusters + - [bin/cluster](bin/cluster) - python script to easily create clusters - [docs](docs) - Documentation for the project - [filter_plugins/](filter_plugins) - custom filters used to manipulate data in Ansible - [inventory/](inventory) - houses Ansible dynamic inventory scripts @@ -36,6 +37,9 @@ This repo contains OpenShift Ansible code. - [roles/](roles) - shareable Ansible tasks ##Contributing +- [Best Practices Guide](docs/best_practices_guide.adoc) +- [Core Concepts](docs/core_concepts_guide.adoc) +- [Style Guide](docs/style_guide.adoc) ###Feature Roadmap Our Feature Roadmap is available on the OpenShift Origin Infrastructure [Trello board](https://trello.com/b/nbkIrqKa/openshift-origin-infrastructure). All ansible items will be tagged with [installv3]. diff --git a/README_AEP.md b/README_AEP.md new file mode 100644 index 000000000..e29888617 --- /dev/null +++ b/README_AEP.md @@ -0,0 +1,240 @@ +# Installing AEP from dev puddles using ansible + +* [Requirements](#requirements) +* [Caveats](#caveats) +* [Known Issues](#known-issues) +* [Configuring the host inventory](#configuring-the-host-inventory) +* [Creating the default variables for the hosts and host groups](#creating-the-default-variables-for-the-hosts-and-host-groups) +* [Running the ansible playbooks](#running-the-ansible-playbooks) +* [Post-ansible steps](#post-ansible-steps) +* [Overriding detected ip addresses and hostnames](#overriding-detected-ip-addresses-and-hostnames) + +## Requirements +* ansible + * Tested using ansible 1.9.1 and 1.9.2 + * There is currently a known issue with ansible-1.9.0, you can downgrade to 1.8.4 on Fedora by installing one of the builds from Koji: http://koji.fedoraproject.org/koji/packageinfo?packageID=13842 + * Available in Fedora channels + * Available for EL with EPEL and Optional channel +* One or more RHEL 7.1 VMs +* Either ssh key based auth for the root user or ssh key based auth for a user + with sudo access (no password) +* A checkout of atomic-enterprise-ansible from https://github.com/projectatomic/atomic-enterprise-ansible/ + + ```sh + git clone https://github.com/projectatomic/atomic-enterprise-ansible.git + cd atomic-enterprise-ansible + ``` + +## Caveats +This ansible repo is currently under heavy revision for providing OSE support; +the following items are highly likely to change before the OSE support is +merged into the upstream repo: + * the current git branch for testing + * how the inventory file should be configured + * variables that need to be set + * bootstrapping steps + * other configuration steps + +## Known Issues +* Host subscriptions are not configurable yet, the hosts need to be + pre-registered with subscription-manager or have the RHEL base repo + pre-configured. If using subscription-manager the following commands will + disable all but the rhel-7-server rhel-7-server-extras and + rhel-server7-ose-beta repos: +```sh +subscription-manager repos --disable="*" +subscription-manager repos \ +--enable="rhel-7-server-rpms" \ +--enable="rhel-7-server-extras-rpms" \ +--enable="rhel-7-server-ose-3.0-rpms" +``` +* Configuration of router is not automated yet +* Configuration of docker-registry is not automated yet + +## Configuring the host inventory +[Ansible docs](http://docs.ansible.com/intro_inventory.html) + +Example inventory file for configuring one master and two nodes for the test +environment. This can be configured in the default inventory file +(/etc/ansible/hosts), or using a custom file and passing the --inventory +option to ansible-playbook. + +/etc/ansible/hosts: +```ini +# This is an example of a bring your own (byo) host inventory + +# Create an OSEv3 group that contains the masters and nodes groups +[OSEv3:children] +masters +nodes + +# Set variables common for all OSEv3 hosts +[OSEv3:vars] +# SSH user, this user should allow ssh based auth without requiring a password +ansible_ssh_user=root + +# If ansible_ssh_user is not root, ansible_sudo must be set to true +#ansible_sudo=true + +# To deploy origin, change deployment_type to origin +deployment_type=enterprise + +# Pre-release registry URL +oreg_url=docker-buildvm-rhose.usersys.redhat.com:5000/openshift3/ose-${component}:${version} + +# Pre-release additional repo +openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', +'baseurl': +'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterprise/3.0/latest/RH7-RHOSE-3.0/$basearch/os', +'enabled': 1, 'gpgcheck': 0}] + +# Origin copr repo +#openshift_additional_repos=[{'id': 'openshift-origin-copr', 'name': +'OpenShift Origin COPR', 'baseurl': +'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/epel-7-$basearch/', +'enabled': 1, 'gpgcheck': 1, gpgkey: +'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/pubkey.gpg'}] + +# host group for masters +[masters] +ose3-master.example.com + +# host group for nodes +[nodes] +ose3-node[1:2].example.com +``` + +The hostnames above should resolve both from the hosts themselves and +the host where ansible is running (if different). + +## Running the ansible playbooks +From the atomic-enterprise-ansible checkout run: +```sh +ansible-playbook playbooks/byo/config.yml +``` +**Note:** this assumes that the host inventory is /etc/ansible/hosts, if using a different +inventory file use the -i option for ansible-playbook. + +## Post-ansible steps +#### Create the default router +On the master host: +```sh +oadm router --create=true \ + --credentials=/etc/openshift/master/openshift-router.kubeconfig \ + --images='docker-buildvm-rhose.usersys.redhat.com:5000/openshift3/ose-${component}:${version}' +``` + +#### Create the default docker-registry +On the master host: +```sh +oadm registry --create=true \ + --credentials=/etc/openshift/master/openshift-registry.kubeconfig \ + --images='docker-buildvm-rhose.usersys.redhat.com:5000/openshift3/ose-${component}:${version}' \ + --mount-host=/var/lib/openshift/docker-registry +``` + +## Overriding detected ip addresses and hostnames +Some deployments will require that the user override the detected hostnames +and ip addresses for the hosts. To see what the default values will be you can +run the openshift_facts playbook: +```sh +ansible-playbook playbooks/byo/openshift_facts.yml +``` +The output will be similar to: +``` +ok: [10.3.9.45] => { + "result": { + "ansible_facts": { + "openshift": { + "common": { + "hostname": "jdetiber-osev3-ansible-005dcfa6-27c6-463d-9b95-ef059579befd.os1.phx2.redhat.com", + "ip": "172.16.4.79", + "public_hostname": "jdetiber-osev3-ansible-005dcfa6-27c6-463d-9b95-ef059579befd.os1.phx2.redhat.com", + "public_ip": "10.3.9.45", + "use_openshift_sdn": true + }, + "provider": { + ... <snip> ... + } + } + }, + "changed": false, + "invocation": { + "module_args": "", + "module_name": "openshift_facts" + } + } +} +ok: [10.3.9.42] => { + "result": { + "ansible_facts": { + "openshift": { + "common": { + "hostname": "jdetiber-osev3-ansible-c6ae8cdc-ba0b-4a81-bb37-14549893f9d3.os1.phx2.redhat.com", + "ip": "172.16.4.75", + "public_hostname": "jdetiber-osev3-ansible-c6ae8cdc-ba0b-4a81-bb37-14549893f9d3.os1.phx2.redhat.com", + "public_ip": "10.3.9.42", + "use_openshift_sdn": true + }, + "provider": { + ...<snip>... + } + } + }, + "changed": false, + "invocation": { + "module_args": "", + "module_name": "openshift_facts" + } + } +} +ok: [10.3.9.36] => { + "result": { + "ansible_facts": { + "openshift": { + "common": { + "hostname": "jdetiber-osev3-ansible-bc39a3d3-cdd7-42fe-9c12-9fac9b0ec320.os1.phx2.redhat.com", + "ip": "172.16.4.73", + "public_hostname": "jdetiber-osev3-ansible-bc39a3d3-cdd7-42fe-9c12-9fac9b0ec320.os1.phx2.redhat.com", + "public_ip": "10.3.9.36", + "use_openshift_sdn": true + }, + "provider": { + ...<snip>... + } + } + }, + "changed": false, + "invocation": { + "module_args": "", + "module_name": "openshift_facts" + } + } +} +``` +Now, we want to verify the detected common settings to verify that they are +what we expect them to be (if not, we can override them). + +* hostname + * Should resolve to the internal ip from the instances themselves. + * openshift_hostname will override. +* ip + * Should be the internal ip of the instance. + * openshift_ip will override. +* public hostname + * Should resolve to the external ip from hosts outside of the cloud + * provider openshift_public_hostname will override. +* public_ip + * Should be the externally accessible ip associated with the instance + * openshift_public_ip will override +* use_openshift_sdn + * Should be true unless the cloud is GCE. + * openshift_use_openshift_sdn overrides + +To override the the defaults, you can set the variables in your inventory: +``` +...snip... +[masters] +ose3-master.example.com openshift_ip=1.1.1.1 openshift_hostname=ose3-master.example.com openshift_public_ip=2.2.2.2 openshift_public_hostname=ose3-master.public.example.com +...snip... +``` diff --git a/README_ANSIBLE_CONTAINER.md b/README_ANSIBLE_CONTAINER.md new file mode 100644 index 000000000..30c5f8503 --- /dev/null +++ b/README_ANSIBLE_CONTAINER.md @@ -0,0 +1,15 @@ +# Running ansible in a docker container +* Building ansible container: + + ```sh + git clone https://github.com/openshift/openshift-ansible.git + cd openshift-ansible + docker build --rm -t ansible . + ``` +* Create /etc/ansible directory on the host machine and copy inventory file (hosts) into it. +* Copy ssh public key of the host machine to master and nodes machines in the cluster. +* Running the ansible container: + + ```sh + docker run -it --rm --privileged --net=host -v ~/.ssh:/root/.ssh -v /etc/ansible:/etc/ansible ansible + ``` diff --git a/README_AWS.md b/README_AWS.md index 7f4b1832b..6757e2892 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -20,17 +20,39 @@ Create a credentials file ``` Note: You must source this file before running any Ansible commands. +Alternatively, you could configure credentials in either ~/.boto or ~/.aws/credentials, see the [boto docs](http://docs.pythonboto.org/en/latest/boto_config_tut.html) for the format. + +Subscribe to CentOS +------------------- + +1. [CentOS on AWS](https://aws.amazon.com/marketplace/pp/B00O7WM7QW) + + +Set up Security Group +--------------------- +By default, a cluster is launched into the `public` security group. Make sure you allow hosts to talk to each other on port `4789` for SDN. +You may also want to allow access from the outside world on the following ports: + +``` +• 22 - ssh +• 80 - Web Apps +• 443 - Web Apps (https) +• 4789 - SDN / VXLAN +• 8443 - OpenShift Console +• 10250 - kubelet +``` + (Optional) Setup your $HOME/.ssh/config file ------------------------------------------- -In case of a cluster creation, or any other case where you don't know the machine hostname in advance, you can use '.ssh/config' +In case of a cluster creation, or any other case where you don't know the machine hostname in advance, you can use `.ssh/config` to setup a private key file to allow ansible to connect to the created hosts. To do so, add the the following entry to your $HOME/.ssh/config file and make it point to the private key file which allows you to login on AWS. -''' +``` Host *.compute-1.amazonaws.com PrivateKey $HOME/.ssh/my_private_key.pem -''' +``` Alternatively, you can configure your ssh-agent to hold the credentials to connect to your AWS instances. @@ -39,7 +61,7 @@ Alternatively, you can configure your ssh-agent to hold the credentials to conne By default, a cluster is launched with the following configuration: -- Instance type: m3.large +- Instance type: m4.large - AMI: ami-307b3658 (for online deployments, ami-acd999c4 for origin deployments and ami-10663b78 for enterprise deployments) - Region: us-east-1 - Keypair name: libra @@ -61,11 +83,17 @@ Node specific defaults: If needed, these values can be changed by setting environment variables on your system. -- export ec2_instance_type='m3.large' -- export ec2_ami='ami-307b3658' +- export ec2_instance_type='m4.large' +- export ec2_image='ami-307b3658' - export ec2_region='us-east-1' - export ec2_keypair='libra' - export ec2_security_groups="['public']" +- export ec2_vpc_subnet='my_vpc_subnet' +- export ec2_assign_public_ip='true' +- export os_etcd_root_vol_size='20' +- export os_etcd_root_vol_type='standard' +- export os_etcd_vol_size='20' +- export os_etcd_vol_type='standard' - export os_master_root_vol_size='20' - export os_master_root_vol_type='standard' - export os_node_root_vol_size='15' @@ -114,3 +142,22 @@ Terminating a cluster ``` bin/cluster terminate aws <cluster-id> ``` + +Specifying a deployment type +--------------------------- +The --deployment-type flag can be passed to bin/cluster to specify the deployment type +1. To launch an online cluster (requires access to private repositories and amis): +``` + bin/cluster create aws --deployment-type=online <cluster-id> +``` +Note: If no deployment type is specified, then the default is origin. + + +## Post-ansible steps + +You should now be ready to follow the **What's Next?** section of the advanced installation guide to deploy your router, registry, and other components. + +Refer to the advanced installation guide for your deployment type: + +* [OpenShift Enterprise](https://docs.openshift.com/enterprise/3.0/install_config/install/advanced_install.html#what-s-next) +* [OpenShift Origin](https://docs.openshift.org/latest/install_config/install/advanced_install.html#what-s-next) diff --git a/README_GCE.md b/README_GCE.md index f6c5138c1..50f8ade70 100644 --- a/README_GCE.md +++ b/README_GCE.md @@ -39,6 +39,13 @@ Create a gce.ini file for GCE * gce_service_account_pem_file_path - Full path from previous steps * gce_project_id - Found in "Projects", it list all the gce projects you are associated with. The page lists their "Project Name" and "Project ID". You want the "Project ID" +Mandatory customization variables (check the values according to your tenant): +* zone = europe-west1-d +* network = default +* gce_machine_type = n1-standard-2 +* gce_machine_image = preinstalled-slave-50g-v5 + + 1. vi ~/.gce/gce.ini 1. make the contents look like this: ``` @@ -46,11 +53,15 @@ Create a gce.ini file for GCE gce_service_account_email_address = long...@developer.gserviceaccount.com gce_service_account_pem_file_path = /full/path/to/project_id-gce_key_hash.pem gce_project_id = project_id +zone = europe-west1-d +network = default +gce_machine_type = n1-standard-2 +gce_machine_image = preinstalled-slave-50g-v5 + ``` -1. Setup a sym link so that gce.py will pick it up (link must be in same dir as gce.py) +1. Define the environment variable GCE_INI_PATH so gce.py can pick it up and bin/cluster can also read it ``` - cd openshift-ansible/inventory/gce - ln -s ~/.gce/gce.ini gce.ini +export GCE_INI_PATH=~/.gce/gce.ini ``` diff --git a/README_OSE.md b/README_OSE.md index dffabc714..79ad07044 100644 --- a/README_OSE.md +++ b/README_OSE.md @@ -19,7 +19,7 @@ * Either ssh key based auth for the root user or ssh key based auth for a user with sudo access (no password) * A checkout of openshift-ansible from https://github.com/openshift/openshift-ansible/ - + ```sh git clone https://github.com/openshift/openshift-ansible.git cd openshift-ansible @@ -46,7 +46,7 @@ subscription-manager repos --disable="*" subscription-manager repos \ --enable="rhel-7-server-rpms" \ --enable="rhel-7-server-extras-rpms" \ ---enable="rhel-server-7-ose-beta-rpms" +--enable="rhel-7-server-ose-3.0-rpms" ``` * Configuration of router is not automated yet * Configuration of docker-registry is not automated yet @@ -80,7 +80,7 @@ ansible_ssh_user=root deployment_type=enterprise # Pre-release registry URL -oreg_url=docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version} +oreg_url=rcm-img-docker01.build.eng.bos.redhat.com:5001/openshift3/ose-${component}:${version} # Pre-release additional repo openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', @@ -101,6 +101,7 @@ ose3-master.example.com # host group for nodes [nodes] +ose3-master.example.com ose3-node[1:2].example.com ``` @@ -116,22 +117,8 @@ ansible-playbook playbooks/byo/config.yml inventory file use the -i option for ansible-playbook. ## Post-ansible steps -#### Create the default router -On the master host: -```sh -openshift ex router --create=true \ - --credentials=/var/lib/openshift/openshift.local.certificates/openshift-router/.kubeconfig \ - --images='docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version}' -``` -#### Create the default docker-registry -On the master host: -```sh -openshift ex registry --create=true \ - --credentials=/var/lib/openshift/openshift.local.certificates/openshift-registry/.kubeconfig \ - --images='docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version}' \ - --mount-host=/var/lib/openshift/docker-registry -``` +You should now be ready to follow the [What's Next?](https://docs.openshift.com/enterprise/3.0/install_config/install/advanced_install.html#what-s-next) section of the advanced installation guide to deploy your router, registry, and other components. ## Overriding detected ip addresses and hostnames Some deployments will require that the user override the detected hostnames diff --git a/README_libvirt.md b/README_libvirt.md index bcbaf4bd5..fd0250781 100644 --- a/README_libvirt.md +++ b/README_libvirt.md @@ -3,21 +3,23 @@ LIBVIRT Setup instructions `libvirt` is an `openshift-ansible` provider that uses `libvirt` to create local Fedora VMs that are provisioned exactly the same way that cloud VMs would be provisioned. -This makes `libvirt` useful to develop, test and debug Openshift and openshift-ansible locally on the developer’s workstation before going to the cloud. +This makes `libvirt` useful to develop, test and debug OpenShift and openshift-ansible locally on the developer’s workstation before going to the cloud. Install dependencies -------------------- -1. Install [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) -2. Install [ebtables](http://ebtables.netfilter.org/) -3. Install [qemu](http://wiki.qemu.org/Main_Page) -4. Install [libvirt](http://libvirt.org/) -5. Enable and start the libvirt daemon, e.g: +1. Install [ansible](http://www.ansible.com/) +2. Install [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) +3. Install [ebtables](http://ebtables.netfilter.org/) +4. Install [qemu and qemu-system-x86](http://wiki.qemu.org/Main_Page) +5. Install [libvirt-python and libvirt](http://libvirt.org/) +6. Install [genisoimage](http://cdrkit.org/) +7. Enable and start the libvirt daemon, e.g: - `systemctl enable libvirtd` - `systemctl start libvirtd` -6. [Grant libvirt access to your user¹](https://libvirt.org/aclpolkit.html) -7. Check that your `$HOME` is accessible to the qemu user² -8. Configure dns resolution on the host³ +8. [Grant libvirt access to your user¹](https://libvirt.org/aclpolkit.html) +9. Check that your `$HOME` is accessible to the qemu user² +10. Configure dns resolution on the host³ #### ¹ Depending on your distribution, libvirt access may be denied by default or may require a password at each access. @@ -68,9 +70,14 @@ If your `$HOME` is world readable, everything is fine. If your `$HOME` is privat error: Cannot access storage file '$HOME/libvirt-storage-pool-openshift/lenaic-master-216d8.qcow2' (as uid:99, gid:78): Permission denied ``` -In order to fix that issue, you have several possibilities:* set `libvirt_storage_pool_path` inside `playbooks/libvirt/openshift-cluster/launch.yml` and `playbooks/libvirt/openshift-cluster/terminate.yml` to a directory: * backed by a filesystem with a lot of free disk space * writable by your user; * accessible by the qemu user.* Grant the qemu user access to the storage pool. +In order to fix that issue, you have several possibilities: + * set `libvirt_storage_pool_path` inside `playbooks/libvirt/openshift-cluster/launch.yml` and `playbooks/libvirt/openshift-cluster/terminate.yml` to a directory: + * backed by a filesystem with a lot of free disk space + * writable by your user; + * accessible by the qemu user. + * Grant the qemu user access to the storage pool. -On Arch: +On Arch or Fedora 22+: ``` setfacl -m g:kvm:--x ~ @@ -89,7 +96,8 @@ dns=dnsmasq - Configure dnsmasq to use the Virtual Network router for example.com: ```sh -sudo vi /etc/NetworkManager/dnsmasq.d/libvirt_dnsmasq.conf server=/example.com/192.168.55.1 +sudo vi /etc/NetworkManager/dnsmasq.d/libvirt_dnsmasq.conf +server=/example.com/192.168.55.1 ``` Test The Setup @@ -102,6 +110,16 @@ Test The Setup bin/cluster list libvirt '' ``` +Configuration +------------- + +The following options can be passed via the `-o` flag of the `create` command or as environment variables: + +* `image_url` (default to `http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2`): URL of the QCOW2 image to download +* `image_name` (default to `CentOS-7-x86_64-GenericCloud.qcow2`): Name of the QCOW2 image to boot the VMs on +* `image_sha256` (default to `e324e3ab1d24a1bbf035ddb365e7f9058c0b454acf48d7aa15c5519fae5998ab`): Expected SHA256 checksum of the downloaded image +* `skip_image_download` (default to `no`): Skip QCOW2 image download. This requires the `image_name` QCOW2 image to be already present in `$HOME/libvirt-storage-pool-openshift-ansible` + Creating a cluster ------------------ diff --git a/README_openstack.md b/README_openstack.md index 57977d1f5..8d8f6ef3f 100644 --- a/README_openstack.md +++ b/README_openstack.md @@ -25,24 +25,20 @@ Configuration The following options can be passed via the `-o` flag of the `create` command: -* `image_name`: Name of the image to use to spawn VMs -* `keypair` (default to `${LOGNAME}_key`): Name of the ssh key -* `public_key` (default to `~/.ssh/id_rsa.pub`): filename of the ssh public key -* `master_flavor_ram` (default to `2048`): VM flavor for the master (by amount of RAM) -* `master_flavor_id`: VM flavor for the master (by ID) -* `master_flavor_include`: VM flavor for the master (by name) -* `node_flavor_ram` (default to `4096`): VM flavor for the nodes (by amount of RAM) -* `node_flavor_id`: VM flavor for the nodes (by ID) -* `node_flavor_include`: VM flavor for the nodes (by name) -* `infra_heat_stack` (default to `playbooks/openstack/openshift-cluster/files/heat_stack.yml`): filename of the HEAT template to use to create the cluster infrastructure +* `infra_heat_stack` (default to `playbooks/openstack/openshift-cluster/files/heat_stack.yaml`): filename of the HEAT template to use to create the cluster infrastructure -The following options are used only by `heat_stack.yml`. They are so used only if the `infra_heat_stack` option is left with its default value. +The following options are used only by `heat_stack.yaml`. They are so used only if the `infra_heat_stack` option is left with its default value. +* `image_name`: Name of the image to use to spawn VMs +* `public_key` (default to `~/.ssh/id_rsa.pub`): filename of the ssh public key +* `master_flavor` (default to `m1.small`): The ID or name of the flavor for the master +* `node_flavor` (default to `m1.medium`): The ID or name of the flavor for the compute nodes +* `infra_flavor` (default to `m1.small`): The ID or name of the flavor for the infrastructure nodes * `network_prefix` (default to `openshift-ansible-<cluster_id>`): prefix prepended to all network objects (net, subnet, router, security groups) * `dns` (default to `8.8.8.8,8.8.4.4`): comma separated list of DNS to use -* `net_cidr` (default to `192.168.<rand()>.0/24`): CIDR of the network created by `heat_stack.yml` +* `net_cidr` (default to `192.168.<rand()>.0/24`): CIDR of the network created by `heat_stack.yaml` * `external_net` (default to `external`): Name of the external network to connect to -* `floating_ip_pools` (default to `external`): comma separated list of floating IP pools +* `floating_ip_pool` (default to `external`): comma separated list of floating IP pools * `ssh_from` (default to `0.0.0.0/0`): IPs authorized to connect to the VMs via ssh diff --git a/README_origin.md b/README_origin.md index 5b3fd2435..cb213a93a 100644 --- a/README_origin.md +++ b/README_origin.md @@ -19,7 +19,7 @@ * Either ssh key based auth for the root user or ssh key based auth for a user with sudo access (no password) * A checkout of openshift-ansible from https://github.com/openshift/openshift-ansible/ - + ```sh git clone https://github.com/openshift/openshift-ansible.git cd openshift-ansible @@ -35,7 +35,7 @@ subscription-manager repos --disable="*" subscription-manager repos \ --enable="rhel-7-server-rpms" \ --enable="rhel-7-server-extras-rpms" \ ---enable="rhel-server-7-ose-beta-rpms" +--enable="rhel-7-server-ose-3.0-rpms" ``` * Configuration of router is not automated yet * Configuration of docker-registry is not automated yet @@ -73,6 +73,7 @@ osv3-master.example.com # host group for nodes [nodes] +osv3-master.example.com osv3-node[1:2].example.com ``` @@ -88,20 +89,8 @@ ansible-playbook playbooks/byo/config.yml inventory file use the -i option for ansible-playbook. ## Post-ansible steps -#### Create the default router -On the master host: -```sh -openshift ex router --create=true \ - --credentials=/var/lib/openshift/openshift.local.certificates/openshift-router/.kubeconfig -``` -#### Create the default docker-registry -On the master host: -```sh -openshift ex registry --create=true \ - --credentials=/var/lib/openshift/openshift.local.certificates/openshift-registry/.kubeconfig \ - --mount-host=/var/lib/openshift/docker-registry -``` +You should now be ready to follow the [What's Next?](https://docs.openshift.org/latest/install_config/install/advanced_install.html#what-s-next) section of the advanced installation guide to deploy your router, registry, and other components. ## Overriding detected ip addresses and hostnames Some deployments will require that the user override the detected hostnames diff --git a/README_vagrant.md b/README_vagrant.md index e3b3b5551..5f87d6633 100644 --- a/README_vagrant.md +++ b/README_vagrant.md @@ -1,10 +1,29 @@ Requirements ------------ - vagrant (tested against version 1.7.2) -- vagrant-hostmaster plugin (tested against version 1.5.0) +- vagrant-hostmanager plugin (tested against version 1.5.0) +- vagrant-registration plugin (only required for enterprise deployment type) - vagrant-libvirt (tested against version 0.0.26) - Only required if using libvirt instead of virtualbox +For ``enterprise`` deployment types the base RHEL box has to be added to Vagrant: + +1. Download the RHEL7 vagrant image (libvirt or virtualbox) available from the [Red Hat Container Development Kit downloads in the customer portal](https://access.redhat.com/downloads/content/293/ver=1/rhel---7/1.0.1/x86_64/product-downloads) + +2. Install it into vagrant + + ``$ vagrant box add --name rhel-7 /path/to/rhel-server-libvirt-7.1-3.x86_64.box`` + +3. (optional, recommended) Increase the disk size of the image to 20GB - This is a two step process. (these instructions are specific to libvirt) + + Resize the actual qcow2 image: + + ``$ qemu-img resize ~/.vagrant.d/boxes/rhel-7/0/libvirt/box.img 20GB`` + + Edit `~/.vagrant.d/boxes/rhel-7/0/libvirt/metadata.json` to reflect the new size. A corrected metadata.json looks like this: + + ``{"provider": "libvirt", "format": "qcow2", "virtual_size": 20}`` + Usage ----- ``` @@ -21,5 +40,10 @@ vagrant provision Environment Variables --------------------- The following environment variables can be overriden: -- OPENSHIFT_DEPLOYMENT_TYPE (defaults to origin, choices: origin, enterprise, online) -- OPENSHIFT_NUM_NODES (the number of nodes to create, defaults to 2) +- ``OPENSHIFT_DEPLOYMENT_TYPE`` (defaults to origin, choices: origin, enterprise, online) +- ``OPENSHIFT_NUM_NODES`` (the number of nodes to create, defaults to 2) + +For ``enterprise`` deployment types these env variables should also be specified: +- ``rhel_subscription_user``: rhsm user +- ``rhel_subscription_pass``: rhsm password +- (optional) ``rhel_subscription_pool``: poolID to attach a specific subscription besides what auto-attach detects diff --git a/Vagrantfile b/Vagrantfile index 648bc5171..33532cd63 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -15,8 +15,30 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.hostmanager.manage_host = true config.hostmanager.include_offline = true config.ssh.insert_key = false + + if deployment_type === 'enterprise' + unless Vagrant.has_plugin?('vagrant-registration') + raise 'vagrant-registration-plugin is required for enterprise deployment' + end + username = ENV['rhel_subscription_user'] + password = ENV['rhel_subscription_pass'] + unless username and password + raise 'rhel_subscription_user and rhel_subscription_pass are required' + end + config.registration.username = username + config.registration.password = password + # FIXME this is temporary until vagrant/ansible registration modules + # are capable of handling specific subscription pools + if not ENV['rhel_subscription_pool'].nil? + config.vm.provision "shell" do |s| + s.inline = "subscription-manager attach --pool=$1 || true" + s.args = "#{ENV['rhel_subscription_pool']}" + end + end + end + config.vm.provider "virtualbox" do |vbox, override| - override.vm.box = "chef/centos-7.1" + override.vm.box = "centos/7" vbox.memory = 1024 vbox.cpus = 2 @@ -28,10 +50,14 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| libvirt.cpus = 2 libvirt.memory = 1024 libvirt.driver = 'kvm' - override.vm.box = "centos-7.1" - override.vm.box_url = "https://download.gluster.org/pub/gluster/purpleidea/vagrant/centos-7.1/centos-7.1.box" - override.vm.box_download_checksum = "b2a9f7421e04e73a5acad6fbaf4e9aba78b5aeabf4230eebacc9942e577c1e05" - override.vm.box_download_checksum_type = "sha256" + case deployment_type + when "enterprise" + override.vm.box = "rhel-7" + when "origin" + override.vm.box = "centos/7" + override.vm.box_download_checksum = "b2a9f7421e04e73a5acad6fbaf4e9aba78b5aeabf4230eebacc9942e577c1e05" + override.vm.box_download_checksum_type = "sha256" + end end num_nodes.times do |n| @@ -39,6 +65,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.define "node#{node_index}" do |node| node.vm.hostname = "ose3-node#{node_index}.example.com" node.vm.network :private_network, ip: "192.168.100.#{200 + n}" + config.vm.provision "shell", inline: "nmcli connection reload; systemctl restart NetworkManager.service" end end @@ -46,17 +73,18 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| master.vm.hostname = "ose3-master.example.com" master.vm.network :private_network, ip: "192.168.100.100" master.vm.network :forwarded_port, guest: 8443, host: 8443 + config.vm.provision "shell", inline: "nmcli connection reload; systemctl restart NetworkManager.service" master.vm.provision "ansible" do |ansible| ansible.limit = 'all' ansible.sudo = true ansible.groups = { "masters" => ["master"], - "nodes" => ["node1", "node2"], + "nodes" => ["master", "node1", "node2"], } ansible.extra_vars = { - openshift_deployment_type: "origin", + deployment_type: deployment_type, } - ansible.playbook = "playbooks/byo/config.yml" + ansible.playbook = "playbooks/byo/vagrant.yml" end end end diff --git a/ansible-profile/README.md b/ansible-profile/README.md new file mode 100644 index 000000000..4f10817d4 --- /dev/null +++ b/ansible-profile/README.md @@ -0,0 +1,6 @@ +# Ansible profile + +This is a callback plugin for timing tasks. + +The upstream project lies in: +https://github.com/jlafon/ansible-profile diff --git a/ansible-profile/callback_plugins/profile_tasks.py b/ansible-profile/callback_plugins/profile_tasks.py new file mode 100644 index 000000000..e9728a803 --- /dev/null +++ b/ansible-profile/callback_plugins/profile_tasks.py @@ -0,0 +1,83 @@ +# The MIT License (MIT) + +# Copyright (c) 2014 Jharrod LaFon + +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +''' +A plugin for timing tasks + +This plugin records the time spent in each task. +At the end of the playbook, it displays the time spent in the 10 slowest tasks. +''' + +import time + + +class CallbackModule(object): + """ + A plugin for timing tasks + """ + def __init__(self): + self.stats = {} + self.current = None + + # Reason: The is_conditional parameter is part of the Ansible plugin API + # Status: permanently disabled + # pylint: disable=unused-argument + def playbook_on_task_start(self, name, is_conditional): + """ + Logs the start of each task + """ + if self.current is not None: + # Record the running time of the last executed task + self.stats[self.current] = time.time() - self.stats[self.current] + + # Record the start time of the current task + self.current = name + self.stats[self.current] = time.time() + + # Reason: The stats parameter is part of the Ansible plugin API + # Status: permanently disabled + # pylint: disable=unused-argument + def playbook_on_stats(self, stats): + """ + Prints the timings + """ + # Record the timing of the very last task + if self.current is not None: + self.stats[self.current] = time.time() - self.stats[self.current] + + # Sort the tasks by their running time + results = sorted( + self.stats.items(), + key=lambda value: value[1], + reverse=True, + ) + + # Just keep the top 10 + results = results[:10] + + # Print the timings + for name, elapsed in results: + print( + "{0:-<70}{1:->9}".format( + '{0} '.format(name), + ' {0:.02f}s'.format(elapsed), + ) + ) diff --git a/bin/cluster b/bin/cluster index 2ea389523..59a6755d3 100755 --- a/bin/cluster +++ b/bin/cluster @@ -3,8 +3,10 @@ import argparse import ConfigParser -import sys import os +import sys +import subprocess +import traceback class Cluster(object): @@ -22,6 +24,16 @@ class Cluster(object): '-o ControlMaster=auto ' '-o ControlPersist=600s ' ) + # Because of `UserKnownHostsFile=/dev/null` + # our `.ssh/known_hosts` file most probably misses the ssh host public keys + # of our servers. + # In that case, ansible serializes the execution of ansible modules + # because we might be interactively prompted to accept the ssh host public keys. + # Because of `StrictHostKeyChecking=no` we know that we won't be prompted + # So, we don't want our modules execution to be serialized. + os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False' + # TODO: A more secure way to proceed would consist in dynamically + # retrieving the ssh host public keys from the IaaS interface def get_deployment_type(self, args): """ @@ -37,11 +49,11 @@ class Cluster(object): deployment_type = os.environ['OS_DEPLOYMENT_TYPE'] return deployment_type + def create(self, args): """ Create an OpenShift cluster for given provider :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args)} @@ -50,66 +62,63 @@ class Cluster(object): env['num_masters'] = args.masters env['num_nodes'] = args.nodes + env['num_infra'] = args.infra + env['num_etcd'] = args.etcd - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def terminate(self, args): """ Destroy OpenShift cluster :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args)} playbook = "playbooks/{}/openshift-cluster/terminate.yml".format(args.provider) inventory = self.setup_provider(args.provider) - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def list(self, args): """ List VMs in cluster :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args)} playbook = "playbooks/{}/openshift-cluster/list.yml".format(args.provider) inventory = self.setup_provider(args.provider) - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def config(self, args): """ Configure or reconfigure OpenShift across clustered VMs :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args)} playbook = "playbooks/{}/openshift-cluster/config.yml".format(args.provider) inventory = self.setup_provider(args.provider) - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def update(self, args): """ Update to latest OpenShift across clustered VMs :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args)} playbook = "playbooks/{}/openshift-cluster/update.yml".format(args.provider) inventory = self.setup_provider(args.provider) - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def service(self, args): """ Make the same service call across all nodes in the cluster :param args: command line arguments provided by user - :return: exit status from run command """ env = {'cluster_id': args.cluster_id, 'deployment_type': self.get_deployment_type(args), @@ -118,7 +127,7 @@ class Cluster(object): playbook = "playbooks/{}/openshift-cluster/service.yml".format(args.provider) inventory = self.setup_provider(args.provider) - return self.action(args, inventory, env, playbook) + self.action(args, inventory, env, playbook) def setup_provider(self, provider): """ @@ -128,10 +137,14 @@ class Cluster(object): """ config = ConfigParser.ConfigParser() if 'gce' == provider: - config.readfp(open('inventory/gce/hosts/gce.ini')) + gce_ini_default_path = os.path.join( + 'inventory/gce/hosts/gce.ini') + gce_ini_path = os.environ.get('GCE_INI_PATH', gce_ini_default_path) + if os.path.exists(gce_ini_path): + config.readfp(open(gce_ini_path)) - for key in config.options('gce'): - os.environ[key] = config.get('gce', key) + for key in config.options('gce'): + os.environ[key] = config.get('gce', key) inventory = '-i inventory/gce/hosts' elif 'aws' == provider: @@ -141,6 +154,17 @@ class Cluster(object): os.environ[key] = config.get('ec2', key) inventory = '-i inventory/aws/hosts' + + key_vars = ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'] + key_missing = [key for key in key_vars if key not in os.environ] + + boto_conf_files = ['~/.aws/credentials', '~/.boto'] + conf_exists = lambda conf: os.path.isfile(os.path.expanduser(conf)) + boto_configs = [conf for conf in boto_conf_files if conf_exists(conf)] + + if len(key_missing) > 0 and len(boto_configs) == 0: + raise ValueError("PROVIDER aws requires {} environment variable(s). See README_AWS.md".format(key_missing)) + elif 'libvirt' == provider: inventory = '-i inventory/libvirt/hosts' elif 'openstack' == provider: @@ -158,7 +182,6 @@ class Cluster(object): :param inventory: derived provider library :param env: environment variables for kubernetes :param playbook: ansible playbook to execute - :return: exit status from ansible-playbook command """ verbose = '' @@ -168,7 +191,7 @@ class Cluster(object): if args.option: for opt in args.option: k, v = opt.split('=', 1) - env['opt_'+k] = v + env['cli_' + k] = v ansible_env = '-e \'{}\''.format( ' '.join(['%s=%s' % (key, value) for (key, value) in env.items()]) @@ -178,6 +201,9 @@ class Cluster(object): verbose, inventory, ansible_env, playbook ) + if args.profile: + command = 'ANSIBLE_CALLBACK_PLUGINS=ansible-profile/callback_plugins ' + command + if args.verbose > 1: command = 'time {}'.format(command) @@ -185,7 +211,18 @@ class Cluster(object): sys.stderr.write('RUN [{}]\n'.format(command)) sys.stderr.flush() - return os.system(command) + try: + subprocess.check_call(command, shell=True) + except subprocess.CalledProcessError as exc: + raise ActionFailed("ACTION [{}] failed: {}" + .format(args.action, exc)) + + +class ActionFailed(Exception): + """ + Raised when action failed. + """ + pass if __name__ == '__main__': @@ -231,9 +268,15 @@ if __name__ == '__main__': meta_parser.add_argument('-t', '--deployment-type', choices=['origin', 'online', 'enterprise'], help='Deployment type. (default: origin)') + meta_parser.add_argument('-T', '--product-type', + choices=['openshift', 'atomic-enterprise'], + help='Product type. (default: openshift)') meta_parser.add_argument('-o', '--option', action='append', help='options') + meta_parser.add_argument('-p', '--profile', action='store_true', + help='Enable playbook profiling') + action_parser = parser.add_subparsers(dest='action', title='actions', description='Choose from valid actions') @@ -243,6 +286,10 @@ if __name__ == '__main__': help='number of masters to create in cluster') create_parser.add_argument('-n', '--nodes', default=2, type=int, help='number of nodes to create in cluster') + create_parser.add_argument('-i', '--infra', default=1, type=int, + help='number of infra nodes to create in cluster') + create_parser.add_argument('-e', '--etcd', default=0, type=int, + help='number of external etcd hosts to create in cluster') create_parser.set_defaults(func=cluster.create) config_parser = action_parser.add_parser('config', @@ -290,7 +337,11 @@ if __name__ == '__main__': sys.stderr.write('\nACTION [update] aborted by user!\n') exit(1) - status = args.func(args) - if status != 0: - sys.stderr.write("ACTION [{}] failed with exit status {}\n".format(args.action, status)) - exit(status) + try: + args.func(args) + except Exception as exc: + if args.verbose: + traceback.print_exc(file=sys.stderr) + else: + print >>sys.stderr, exc + exit(1) @@ -83,7 +83,7 @@ class Ohi(object): """Setup the command line parser with the options we want """ - parser = argparse.ArgumentParser(description='Openshift Host Inventory') + parser = argparse.ArgumentParser(description='OpenShift Host Inventory') parser.add_argument('--list-host-types', default=False, action='store_true', help='List all of the host types') diff --git a/bin/openshift-ansible-bin.spec b/bin/openshift-ansible-bin.spec deleted file mode 100644 index fd2386c9a..000000000 --- a/bin/openshift-ansible-bin.spec +++ /dev/null @@ -1,104 +0,0 @@ -Summary: OpenShift Ansible Scripts for working with metadata hosts -Name: openshift-ansible-bin -Version: 0.0.18 -Release: 1%{?dist} -License: ASL 2.0 -URL: https://github.com/openshift/openshift-ansible -Source0: %{name}-%{version}.tar.gz -Requires: python2, openshift-ansible-inventory -BuildRequires: python2-devel -BuildArch: noarch - -%description -Scripts to make it nicer when working with hosts that are defined only by metadata. - -%prep -%setup -q - -%build - -%install -mkdir -p %{buildroot}%{_bindir} -mkdir -p %{buildroot}%{python_sitelib}/openshift_ansible -mkdir -p %{buildroot}/etc/bash_completion.d -mkdir -p %{buildroot}/etc/openshift_ansible - -cp -p ossh oscp opssh opscp ohi %{buildroot}%{_bindir} -cp -pP openshift_ansible/* %{buildroot}%{python_sitelib}/openshift_ansible - -# Make it so we can load multi_ec2.py as a library. -rm %{buildroot}%{python_sitelib}/openshift_ansible/multi_ec2.py* -ln -sf /usr/share/ansible/inventory/multi_ec2.py %{buildroot}%{python_sitelib}/openshift_ansible/multi_ec2.py -ln -sf /usr/share/ansible/inventory/multi_ec2.pyc %{buildroot}%{python_sitelib}/openshift_ansible/multi_ec2.pyc - -cp -p ossh_bash_completion %{buildroot}/etc/bash_completion.d - -cp -p openshift_ansible.conf.example %{buildroot}/etc/openshift_ansible/openshift_ansible.conf - -%files -%{_bindir}/* -%{python_sitelib}/openshift_ansible/ -/etc/bash_completion.d/* -%config(noreplace) /etc/openshift_ansible/ - -%changelog -* Tue Jun 09 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.18-1 -- Implement OpenStack provider (lhuard@amadeus.com) -- * Update defaults and examples to track core concepts guide - (jhonce@redhat.com) -- Issue 119 - Add support for ~/.openshift-ansible (jhonce@redhat.com) -- Infrastructure - Add service action to bin/cluster (jhonce@redhat.com) - -* Fri May 15 2015 Thomas Wiest <twiest@redhat.com> 0.0.17-1 -- fixed the openshift-ansible-bin build (twiest@redhat.com) - -* Fri May 15 2015 Thomas Wiest <twiest@redhat.com> 0.0.14-1 -- Command line tools import multi_ec2 as lib (kwoodson@redhat.com) -- Adding cache location for multi ec2 (kwoodson@redhat.com) -* Thu May 07 2015 Thomas Wiest <twiest@redhat.com> 0.0.13-1 -- added '-e all' to ohi and fixed pylint errors. (twiest@redhat.com) - -* Tue May 05 2015 Thomas Wiest <twiest@redhat.com> 0.0.12-1 -- fixed opssh and opscp to allow just environment or just host-type. - (twiest@redhat.com) - -* Mon May 04 2015 Thomas Wiest <twiest@redhat.com> 0.0.11-1 -- changed opssh to a bash script using ohi to make it easier to maintain, and - to expose all of the pssh features directly. (twiest@redhat.com) -- Added --user option to ohi to pre-pend the username in the hostlist output. - (twiest@redhat.com) -- Added utils.py that contains a normalize_dnsname function good for sorting - dns names to a human readable list. (twiest@redhat.com) - -* Thu Apr 30 2015 Thomas Wiest <twiest@redhat.com> 0.0.10-1 -- added --list-host-types option to opscp (twiest@redhat.com) - -* Thu Apr 30 2015 Thomas Wiest <twiest@redhat.com> 0.0.9-1 -- added opscp (twiest@redhat.com) -* Mon Apr 13 2015 Thomas Wiest <twiest@redhat.com> 0.0.8-1 -- fixed bug in opssh where it wouldn't actually run pssh (twiest@redhat.com) - -* Mon Apr 13 2015 Thomas Wiest <twiest@redhat.com> 0.0.7-1 -- added the ability to run opssh and ohi on all hosts in an environment, as - well as all hosts of the same host-type regardless of environment - (twiest@redhat.com) -- added ohi (twiest@redhat.com) -* Thu Apr 09 2015 Thomas Wiest <twiest@redhat.com> 0.0.6-1 -- fixed bug where opssh would throw an exception if pssh returned a non-zero - exit code (twiest@redhat.com) - -* Wed Apr 08 2015 Thomas Wiest <twiest@redhat.com> 0.0.5-1 -- fixed the opssh default output behavior to be consistent with pssh. Also - fixed a bug in how directories are named for --outdir and --errdir. - (twiest@redhat.com) -* Tue Mar 31 2015 Thomas Wiest <twiest@redhat.com> 0.0.4-1 -- Fixed when tag was missing and added opssh completion (kwoodson@redhat.com) - -* Mon Mar 30 2015 Thomas Wiest <twiest@redhat.com> 0.0.3-1 -- created a python package named openshift_ansible (twiest@redhat.com) - -* Mon Mar 30 2015 Thomas Wiest <twiest@redhat.com> 0.0.2-1 -- added config file support to opssh, ossh, and oscp (twiest@redhat.com) -* Tue Mar 24 2015 Thomas Wiest <twiest@redhat.com> 0.0.1-1 -- new package built with tito - diff --git a/bin/openshift_ansible/aws b/bin/openshift_ansible/aws new file mode 120000 index 000000000..eb0575b4d --- /dev/null +++ b/bin/openshift_ansible/aws @@ -0,0 +1 @@ +../../inventory/aws/
\ No newline at end of file @@ -55,7 +55,7 @@ class Oscp(object): config.read(self.config_path) def parse_cli_args(self): - parser = argparse.ArgumentParser(description='Openshift Online SSH Tool.') + parser = argparse.ArgumentParser(description='OpenShift Online SSH Tool.') parser.add_argument('-e', '--env', action="store", help="Environment where this server exists.") parser.add_argument('-d', '--debug', default=False, @@ -167,7 +167,7 @@ class Oscp(object): name = server_info['ec2_tag_Name'] ec2_id = server_info['ec2_id'] ip = server_info['ec2_ip_address'] - print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address}'.format(**server_info) + print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address:<18} {ec2_private_ip_address}'.format(**server_info) if limit: print @@ -180,7 +180,7 @@ class Oscp(object): name = server_info['ec2_tag_Name'] ec2_id = server_info['ec2_id'] ip = server_info['ec2_ip_address'] - print '{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<15} {ec2_ip_address}'.format(**server_info) + print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address:<18} {ec2_private_ip_address}'.format(**server_info) def scp(self): '''scp files to or from a specified host @@ -53,7 +53,7 @@ class Ossh(object): config.read(self.config_path) def parse_cli_args(self): - parser = argparse.ArgumentParser(description='Openshift Online SSH Tool.') + parser = argparse.ArgumentParser(description='OpenShift Online SSH Tool.') parser.add_argument('-e', '--env', action="store", help="Which environment to search for the host ") parser.add_argument('-d', '--debug', default=False, @@ -156,7 +156,7 @@ class Ossh(object): name = server_info['ec2_tag_Name'] ec2_id = server_info['ec2_id'] ip = server_info['ec2_ip_address'] - print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address}'.format(**server_info) + print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address:<18} {ec2_private_ip_address}'.format(**server_info) if limit: print @@ -169,7 +169,7 @@ class Ossh(object): name = server_info['ec2_tag_Name'] ec2_id = server_info['ec2_id'] ip = server_info['ec2_ip_address'] - print '{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<15} {ec2_ip_address}'.format(**server_info) + print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address:<18} {ec2_private_ip_address}'.format(**server_info) def ssh(self): '''SSH to a specified host diff --git a/bin/ossh_bash_completion b/bin/ossh_bash_completion index 1467de858..5072161f0 100755 --- a/bin/ossh_bash_completion +++ b/bin/ossh_bash_completion @@ -1,6 +1,12 @@ __ossh_known_hosts(){ - if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then - /usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' + if python -c 'import openshift_ansible' &>/dev/null; then + /usr/bin/python -c 'from openshift_ansible import multi_ec2; m=multi_ec2.MultiEc2(); m.run(); z=m.result; print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' + + elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then + /usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' + + elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then + /usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' fi } @@ -19,8 +25,15 @@ _ossh() complete -F _ossh ossh oscp __opssh_known_hosts(){ - if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then - /usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + if python -c 'import openshift_ansible' &>/dev/null; then + /usr/bin/python -c 'from openshift_ansible.multi_ec2 import MultiEc2; m=MultiEc2(); m.run(); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in m.result["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + + elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then + /usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + + elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then + /usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + fi } diff --git a/bin/ossh_zsh_completion b/bin/ossh_zsh_completion index 6ab930dc4..44500c618 100644 --- a/bin/ossh_zsh_completion +++ b/bin/ossh_zsh_completion @@ -1,9 +1,16 @@ #compdef ossh oscp _ossh_known_hosts(){ - if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then - print $(/usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items()])') - fi + if python -c 'import openshift_ansible' &>/dev/null; then + print $(/usr/bin/python -c 'from openshift_ansible import multi_ec2; m=multi_ec2.MultiEc2(); m.run(); z=m.result; print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + + elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then + print $(/usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + + elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then + print $(/usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + + fi } _ossh(){ diff --git a/docs/best_practices_guide.adoc b/docs/best_practices_guide.adoc index 841f6e72c..08d95b2b8 100644 --- a/docs/best_practices_guide.adoc +++ b/docs/best_practices_guide.adoc @@ -1,6 +1,6 @@ // vim: ft=asciidoc -= Openshift-Ansible Best Practices Guide += openshift-ansible Best Practices Guide The purpose of this guide is to describe the preferred patterns and best practices used in this repository (both in ansible and python). @@ -27,6 +27,49 @@ The tooling is flexible enough that exceptions can be made so that the tool the == Python +=== Python Source Files + +''' +[cols="2v,v"] +|=== +| **Rule** +| Python source files MUST contain the following vim mode line. +|=== + +[source] +---- +# vim: expandtab:tabstop=4:shiftwidth=4 +---- + +Since most developers contributing to this repository use vim, this rule helps to promote consistency. + +If mode lines for other editors are needed, please open a GitHub issue. + +=== Method Signatures + +''' +[cols="2v,v"] +|=== +| **Rule** +| When adding a new paramemter to an existing method, a default value SHOULD be used +|=== +The purpose of this rule is to make it so that method signatures are backwards compatible. + +If this rule isn't followed, it will be necessary for the person who changed the method to search out all callers and make sure that they're able to use the new method signature. + +.Before: +[source,python] +---- +def add_person(first_name, last_name): +---- + +.After: +[source,python] +---- +def add_person(first_name, last_name, age=None): +---- + + === PyLint http://www.pylint.org/[PyLint] is used in an attempt to keep the python code as clean and as managable as possible. The build bot runs each pull request through PyLint and any warnings or errors cause the build bot to fail the pull request. @@ -99,6 +142,137 @@ YAML is a superset of JSON, which means that Ansible allows JSON syntax to be in Every effort should be made to keep our Ansible YAML files in pure YAML. +=== Modules +''' +[cols="2v,v"] +|=== +| **Rule** +| Custom Ansible modules SHOULD be embedded in a role. +|=== + +.Context +* http://docs.ansible.com/ansible/playbooks_roles.html#embedding-modules-in-roles[Ansible doc on how to embed modules in roles] + +The purpose of this rule is to make it easy to include custom modules in our playbooks and share them on Ansible Galaxy. + +.Custom module `openshift_facts.py` is embedded in the `openshift_facts` role. +---- +> ll openshift-ansible/roles/openshift_facts/library/ +-rwxrwxr-x. 1 user group 33616 Jul 22 09:36 openshift_facts.py +---- + +.Custom module `openshift_facts` can be used after `openshift_facts` role has been referenced. +[source,yaml] +---- +- hosts: openshift_hosts + gather_facts: no + roles: + - role: openshift_facts + post_tasks: + - openshift_facts + role: common + hostname: host + public_hostname: host.example.com +---- + + +''' +[cols="2v,v"] +|=== +| **Rule** +| Parameters to Ansible modules SHOULD use the Yaml dictionary format when 3 or more parameters are being passed +|=== + +When a module has several parameters that are being passed in, it's hard to see exactly what value each parameter is getting. It is preferred to use the Ansible Yaml syntax to pass in parameters so that it's more clear what values are being passed for each paramemter. + +.Bad: +[source,yaml] +---- +- file: src=/file/to/link/to dest=/path/to/symlink owner=foo group=foo state=link +---- + +.Good: +[source,yaml] +---- +- file: + src: /file/to/link/to + dest: /path/to/symlink + owner: foo + group: foo + state: link +---- + + +''' +[cols="2v,v"] +|=== +| **Rule** +| Parameters to Ansible modules SHOULD use the Yaml dictionary format when the line length exceeds 120 characters +|=== + +Lines that are long quickly become a wall of text that isn't easily parsable. It is preferred to use the Ansible Yaml syntax to pass in parameters so that it's more clear what values are being passed for each paramemter. + +.Bad: +[source,yaml] +---- +- get_url: url=http://example.com/path/file.conf dest=/etc/foo.conf sha256sum=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c +---- + +.Good: +[source,yaml] +---- +- get_url: + url: http://example.com/path/file.conf + dest: /etc/foo.conf + sha256sum: b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c +---- + +''' +[cols="2v,v"] +|=== +| **Rule** +| The Ansible `command` module SHOULD be used instead of the Ansible `shell` module. +|=== +.Context +* http://docs.ansible.com/shell_module.html#notes[Ansible doc on why using the command module is a best practice] + +The Ansible `shell` module can run most commands that can be run from a bash CLI. This makes it extremely powerful, but it also opens our playbooks up to being exploited by attackers. + +.Bad: +[source,yaml] +---- +- shell: "/bin/echo {{ cli_var }}" +---- + +.Better: +[source,yaml] +---- +- command: "/bin/echo {{ cli_var }}" +---- + +''' +[cols="2v,v"] +|=== +| **Rule** +| The Ansible `quote` filter MUST be used with any variable passed into the shell module. +|=== +.Context +* http://docs.ansible.com/shell_module.html#notes[Ansible doc describing why to use the quote filter] + +It is recommended not to use the `shell` module. However, if it absolutely must be used, all variables passed into the `shell` module MUST use the `quote` filter to ensure they are shell safe. + +.Bad: +[source,yaml] +---- +- shell: "/bin/echo {{ cli_var }}" +---- + +.Good: +[source,yaml] +---- +- shell: "/bin/echo {{ cli_var | quote }}" +---- + === Defensive Programming .Context @@ -142,12 +316,88 @@ If an Ansible role requires certain variables to be set, it's best to check for when: arl_environment is not defined or arl_environment == '' ---- +=== Tasks +''' +[cols="2v,v"] +|=== +| **Rule** +| Ansible tasks SHOULD NOT be used in ansible playbooks. Instead, use pre_tasks and post_tasks. +|=== +An Ansible play is defined as a Yaml dictionary. Because of that, ansible doesn't know if the play's tasks list or roles list was specified first. Therefore Ansible always runs tasks after roles. + +This can be quite confusing if the tasks list is defined in the playbook before the roles list because people assume in order execution in Ansible. + +Therefore, we SHOULD use pre_tasks and post_tasks to make it more clear when the tasks will be run. + +.Context +* https://docs.ansible.com/playbooks_roles.html[Ansible documentation on pre_tasks and post_tasks] + +.Bad: +[source,yaml] +---- +--- +# playbook.yml +- hosts: localhost + gather_facts: no + tasks: + - name: This will execute AFTER the example_role, so it's confusing + debug: msg="in tasks list" + roles: + - role: example_role + +# roles/example_role/tasks/main.yml +- debug: msg="in example_role" +---- + +.Good: +[source,yaml] +---- +--- +# playbook.yml +- hosts: localhost + gather_facts: no + pre_tasks: + - name: This will execute BEFORE the example_role, so it makes sense + debug: msg="in pre_tasks list" + roles: + - role: example_role + +# roles/example_role/tasks/main.yml +- debug: msg="in example_role" +---- + + === Roles ''' [cols="2v,v"] |=== | **Rule** +| All tasks in a role SHOULD be tagged with the role name. +|=== + +.Context +* http://docs.ansible.com/playbooks_tags.html[Ansible doc explaining tags] + +Ansible tasks can be tagged, and then these tags can be used to either _run_ or _skip_ the tagged tasks using the `--tags` and `--skip-tags` ansible-playbook options respectively. + +This is very useful when developing and debugging new tasks. It can also significantly speed up playbook runs if the user specifies only the roles that changed. + +.Example: +[source,yaml] +---- +--- +# roles/example_role/tasks/main.yml +- debug: msg="in example_role" + tags: + - example_role +---- + + +''' +[cols="2v,v"] +|=== +| **Rule** | The Ansible roles directory MUST maintain a flat structure. |=== @@ -171,7 +421,7 @@ For consistency, role names SHOULD follow the above naming pattern. It is import Many times the `technology` portion of the pattern will line up with a package name. It is advised that whenever possible, the package name should be used. .Examples: -* The role to configure an OpenShift Master is called `openshift_master` +* The role to configure a master is called `openshift_master` * The role to configure OpenShift specific yum repositories is called `openshift_repos` === Filters diff --git a/docs/core_concepts_guide.adoc b/docs/core_concepts_guide.adoc index 38187c55e..b29e467e2 100644 --- a/docs/core_concepts_guide.adoc +++ b/docs/core_concepts_guide.adoc @@ -1,6 +1,6 @@ // vim: ft=asciidoc -= Openshift-Ansible Core Concepts Guide += openshift-ansible Core Concepts Guide The purpose of this guide is to describe core concepts used in this repository. diff --git a/docs/style_guide.adoc b/docs/style_guide.adoc index 3b888db12..09d4839c7 100644 --- a/docs/style_guide.adoc +++ b/docs/style_guide.adoc @@ -1,6 +1,6 @@ // vim: ft=asciidoc -= Openshift-Ansible Style Guide += openshift-ansible Style Guide The purpose of this guide is to describe the preferred coding conventions used in this repository (both in ansible and python). @@ -43,18 +43,48 @@ This is a hard limit and is enforced by the build bot. This check MUST NOT be di == Ansible -=== Ansible Global Variables -Ansible global variables are defined as any variables outside of ansible roles. Examples include playbook variables, variables passed in on the cli, etc. +=== Ansible Yaml file extension +''' +[cols="2v,v"] +|=== +| **Rule** +| All Ansible Yaml files MUST have a .yml extension (and NOT .YML, .yaml etc). +|=== + +Ansible tooling (like `ansible-galaxy init`) create files with a .yml extension. Also, the Ansible documentation website references files with a .yml extension several times. Because of this, it is normal in the Ansible community to use a .yml extension for all Ansible Yaml files. + +Example: `tasks.yml` + + +=== Ansible CLI Variables +''' +[cols="2v,v"] +|=== +| **Rule** +| Variables meant to be passed in from the ansible CLI MUST have a prefix of cli_ +|=== + +Ansible allows variables to be passed in on the command line using the `-e` option. These variables MUST have a prefix of cli_ so that it's clear where they came from, and that they could be exploited. + + +.Example: +[source] +---- +ansible-playbook -e cli_foo=bar someplays.yml +---- + +=== Ansible Global Variables ''' [cols="2v,v"] |=== | **Rule** | Global variables MUST have a prefix of g_ |=== +Ansible global variables are defined as any variables outside of ansible roles. Examples include playbook variables, variables passed in on the cli, etc. -Example: +.Example: [source] ---- g_environment: someval diff --git a/filter_plugins/oo_filters.py b/filter_plugins/oo_filters.py index b7248efaa..a57b0f895 100644 --- a/filter_plugins/oo_filters.py +++ b/filter_plugins/oo_filters.py @@ -8,6 +8,8 @@ Custom filters for use in openshift-ansible from ansible import errors from operator import itemgetter import pdb +import re +import json class FilterModule(object): @@ -48,12 +50,12 @@ class FilterModule(object): return [item for sublist in data for item in sublist] - @staticmethod def oo_collect(data, attribute=None, filters=None): ''' This takes a list of dict and collects all attributes specified into a - list If filter is specified then we will include all items that match - _ALL_ of filters. + list. If filter is specified then we will include all items that + match _ALL_ of filters. If a dict entry is missing the key in a + filter it will be excluded from the match. Ex: data = [ {'a':1, 'b':5, 'z': 'z'}, # True, return {'a':2, 'z': 'z'}, # True, return {'a':3, 'z': 'z'}, # True, return @@ -71,16 +73,35 @@ class FilterModule(object): if filters is not None: if not issubclass(type(filters), dict): - raise errors.AnsibleFilterError("|fialed expects filter to be a" + raise errors.AnsibleFilterError("|failed expects filter to be a" " dict") retval = [FilterModule.get_attr(d, attribute) for d in data if ( - all([d[key] == filters[key] for key in filters]))] + all([d.get(key, None) == filters[key] for key in filters]))] else: retval = [FilterModule.get_attr(d, attribute) for d in data] return retval @staticmethod + def oo_select_keys_from_list(data, keys): + ''' This returns a list, which contains the value portions for the keys + Ex: data = { 'a':1, 'b':2, 'c':3 } + keys = ['a', 'c'] + returns [1, 3] + ''' + + if not issubclass(type(data), list): + raise errors.AnsibleFilterError("|failed expects to filter on a list") + + if not issubclass(type(keys), list): + raise errors.AnsibleFilterError("|failed expects first param is a list") + + # Gather up the values for the list of keys passed in + retval = [FilterModule.oo_select_keys(item, keys) for item in data] + + return FilterModule.oo_flatten(retval) + + @staticmethod def oo_select_keys(data, keys): ''' This returns a list, which contains the value portions for the keys Ex: data = { 'a':1, 'b':2, 'c':3 } @@ -95,7 +116,7 @@ class FilterModule(object): raise errors.AnsibleFilterError("|failed expects first param is a list") # Gather up the values for the list of keys passed in - retval = [data[key] for key in keys] + retval = [data[key] for key in keys if data.has_key(key)] return retval @@ -130,6 +151,16 @@ class FilterModule(object): return rval @staticmethod + def oo_combine_dict(data, in_joiner='=', out_joiner=' '): + '''Take a dict in the form of { 'key': 'value', 'key': 'value' } and + arrange them as a string 'key=value key=value' + ''' + if not issubclass(type(data), dict): + raise errors.AnsibleFilterError("|failed expects first param is a dict") + + return out_joiner.join([in_joiner.join([k, v]) for k, v in data.items()]) + + @staticmethod def oo_ami_selector(data, image_name): ''' This takes a list of amis and an image name and attempts to return the latest ami. @@ -174,9 +205,9 @@ class FilterModule(object): ''' if not issubclass(type(data), dict): raise errors.AnsibleFilterError("|failed expects first param is a dict") - if host_type not in ['master', 'node']: - raise errors.AnsibleFilterError("|failed expects either master or node" - " host type") + if host_type not in ['master', 'node', 'etcd']: + raise errors.AnsibleFilterError("|failed expects etcd, master or node" + " as the host type") root_vol = data[host_type]['root'] root_vol['device_name'] = '/dev/sda1' @@ -194,6 +225,13 @@ class FilterModule(object): docker_vol.pop('delete_on_termination', None) docker_vol['ephemeral'] = 'ephemeral0' return [root_vol, docker_vol] + elif host_type == 'etcd': + etcd_vol = data[host_type]['etcd'] + etcd_vol['device_name'] = '/dev/xvdb' + etcd_vol['delete_on_termination'] = True + if etcd_vol['device_type'] != 'io1': + etcd_vol.pop('iops', None) + return [root_vol, etcd_vol] return [root_vol] @staticmethod @@ -222,10 +260,78 @@ class FilterModule(object): # Gather up the values for the list of keys passed in return [x for x in data if x[filter_attr]] + @staticmethod + def oo_parse_heat_stack_outputs(data): + ''' Formats the HEAT stack output into a usable form + + The goal is to transform something like this: + + +---------------+-------------------------------------------------+ + | Property | Value | + +---------------+-------------------------------------------------+ + | capabilities | [] | | + | creation_time | 2015-06-26T12:26:26Z | | + | description | OpenShift cluster | | + | … | … | + | outputs | [ | + | | { | + | | "output_value": "value_A" | + | | "description": "This is the value of Key_A" | + | | "output_key": "Key_A" | + | | }, | + | | { | + | | "output_value": [ | + | | "value_B1", | + | | "value_B2" | + | | ], | + | | "description": "This is the value of Key_B" | + | | "output_key": "Key_B" | + | | }, | + | | ] | + | parameters | { | + | … | … | + +---------------+-------------------------------------------------+ + + into something like this: + + { + "Key_A": "value_A", + "Key_B": [ + "value_B1", + "value_B2" + ] + } + ''' + + # Extract the “outputs” JSON snippet from the pretty-printed array + in_outputs = False + outputs = '' + + line_regex = re.compile(r'\|\s*(.*?)\s*\|\s*(.*?)\s*\|') + for line in data['stdout_lines']: + match = line_regex.match(line) + if match: + if match.group(1) == 'outputs': + in_outputs = True + elif match.group(1) != '': + in_outputs = False + if in_outputs: + outputs += match.group(2) + + outputs = json.loads(outputs) + + # Revamp the “outputs” to put it in the form of a “Key: value” map + revamped_outputs = {} + for output in outputs: + revamped_outputs[output['output_key']] = output['output_value'] + + return revamped_outputs + def filters(self): ''' returns a mapping of filters to methods ''' return { "oo_select_keys": self.oo_select_keys, + "oo_select_keys_from_list": self.oo_select_keys_from_list, "oo_collect": self.oo_collect, "oo_flatten": self.oo_flatten, "oo_pdb": self.oo_pdb, @@ -233,6 +339,8 @@ class FilterModule(object): "oo_ami_selector": self.oo_ami_selector, "oo_ec2_volume_definition": self.oo_ec2_volume_definition, "oo_combine_key_value": self.oo_combine_key_value, + "oo_combine_dict": self.oo_combine_dict, "oo_split": self.oo_split, - "oo_filter_list": self.oo_filter_list + "oo_filter_list": self.oo_filter_list, + "oo_parse_heat_stack_outputs": self.oo_parse_heat_stack_outputs } diff --git a/filter_plugins/oo_zabbix_filters.py b/filter_plugins/oo_zabbix_filters.py new file mode 100644 index 000000000..c44b874e8 --- /dev/null +++ b/filter_plugins/oo_zabbix_filters.py @@ -0,0 +1,108 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vim: expandtab:tabstop=4:shiftwidth=4 +''' +Custom zabbix filters for use in openshift-ansible +''' + +import pdb + +class FilterModule(object): + ''' Custom zabbix ansible filters ''' + + @staticmethod + def create_data(data, results, key, new_key): + '''Take a dict, filter through results and add results['key'] to dict + ''' + new_list = [app[key] for app in results] + data[new_key] = new_list + return data + + @staticmethod + def oo_set_zbx_trigger_triggerid(item, trigger_results): + '''Set zabbix trigger id from trigger results + ''' + if isinstance(trigger_results, list): + item['triggerid'] = trigger_results[0]['triggerid'] + return item + + item['triggerid'] = trigger_results['triggerids'][0] + return item + + @staticmethod + def oo_set_zbx_item_hostid(item, template_results): + ''' Set zabbix host id from template results + ''' + if isinstance(template_results, list): + item['hostid'] = template_results[0]['templateid'] + return item + + item['hostid'] = template_results['templateids'][0] + return item + + @staticmethod + def oo_pdb(arg): + ''' This pops you into a pdb instance where arg is the data passed in + from the filter. + Ex: "{{ hostvars | oo_pdb }}" + ''' + pdb.set_trace() + return arg + + @staticmethod + def select_by_name(ans_data, data): + ''' test + ''' + for zabbix_item in data: + if ans_data['name'] == zabbix_item: + data[zabbix_item]['params']['hostid'] = ans_data['templateid'] + return data[zabbix_item]['params'] + return None + + @staticmethod + def oo_build_zabbix_collect(data, string, value): + ''' Build a list of dicts from a list of data matched on string attribute + ''' + rval = [] + for item in data: + if item[string] == value: + rval.append(item) + + return rval + + @staticmethod + def oo_build_zabbix_list_dict(values, string): + ''' Build a list of dicts with string as key for each value + ''' + rval = [] + for value in values: + rval.append({string: value}) + return rval + + @staticmethod + def oo_remove_attr_from_list_dict(data, attr): + ''' Remove a specific attribute from a dict + ''' + attrs = [] + if isinstance(attr, str): + attrs.append(attr) + else: + attrs = attr + + for attribute in attrs: + for _entry in data: + _entry.pop(attribute, None) + + return data + + def filters(self): + ''' returns a mapping of filters to methods ''' + return { + "select_by_name": self.select_by_name, + "oo_set_zbx_item_hostid": self.oo_set_zbx_item_hostid, + "oo_set_zbx_trigger_triggerid": self.oo_set_zbx_trigger_triggerid, + "oo_build_zabbix_list_dict": self.oo_build_zabbix_list_dict, + "create_data": self.create_data, + "oo_build_zabbix_collect": self.oo_build_zabbix_collect, + "oo_remove_attr_from_list_dict": self.oo_remove_attr_from_list_dict, + } diff --git a/git/.pylintrc b/git/.pylintrc index af8f1656f..fe6eef6de 100644 --- a/git/.pylintrc +++ b/git/.pylintrc @@ -71,7 +71,7 @@ confidence= # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" # w0511 - fixme - disabled because TODOs are acceptable -disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511 +disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511,R0801 [REPORTS] @@ -205,7 +205,7 @@ docstring-min-length=-1 [SIMILARITIES] # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=0 # Ignore comments when computing similarities. ignore-comments=yes @@ -214,7 +214,7 @@ ignore-comments=yes ignore-docstrings=yes # Ignore imports when computing similarities. -ignore-imports=no +ignore-imports=yes [VARIABLES] diff --git a/git/pylint.sh b/git/pylint.sh index 286747565..55e8b6131 100755 --- a/git/pylint.sh +++ b/git/pylint.sh @@ -1,14 +1,48 @@ #!/usr/bin/env bash +set -eu +ANSIBLE_UPSTREAM_FILES=( + 'inventory/aws/hosts/ec2.py' + 'inventory/gce/hosts/gce.py' + 'inventory/libvirt/hosts/libvirt_generic.py' + 'inventory/openstack/hosts/nova.py' + 'lookup_plugins/sequence.py' + ) OLDREV=$1 NEWREV=$2 -TRG_BRANCH=$3 +#TRG_BRANCH=$3 -PYTHON=/var/lib/jenkins/python27/bin/python +PYTHON=$(which python) -/usr/bin/git diff --name-only $OLDREV $NEWREV --diff-filter=ACM | \ - grep ".py$" | \ - xargs -r -I{} ${PYTHON} -m pylint --rcfile ${WORKSPACE}/git/.pylintrc {} +set +e +PY_DIFF=$(/usr/bin/git diff --name-only $OLDREV $NEWREV --diff-filter=ACM | grep ".py$") +set -e -exit $? +FILES_TO_TEST="" + +for PY_FILE in $PY_DIFF; do + IGNORE_FILE=false + for UPSTREAM_FILE in "${ANSIBLE_UPSTREAM_FILES[@]}"; do + if [ "${PY_FILE}" == "${UPSTREAM_FILE}" ]; then + IGNORE_FILE=true + break + fi + done + + if [ "${IGNORE_FILE}" == true ]; then + echo "Skipping file ${PY_FILE} as an upstream Ansible file..." + continue + fi + + if [ -e "${PY_FILE}" ]; then + FILES_TO_TEST="${FILES_TO_TEST} ${PY_FILE}" + fi +done + +if [ "${FILES_TO_TEST}" != "" ]; then + echo "Testing files: ${FILES_TO_TEST}" + exec ${PYTHON} -m pylint --rcfile ${WORKSPACE}/git/.pylintrc ${FILES_TO_TEST} +else + exit 0 +fi diff --git a/inventory/aws/hosts/hosts b/inventory/aws/hosts/hosts index 34a4396bd..bf4e0845a 100644 --- a/inventory/aws/hosts/hosts +++ b/inventory/aws/hosts/hosts @@ -1 +1 @@ -localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter='/usr/bin/env python2' diff --git a/inventory/byo/.gitignore b/inventory/byo/.gitignore new file mode 100644 index 000000000..6ff331c7e --- /dev/null +++ b/inventory/byo/.gitignore @@ -0,0 +1 @@ +hosts diff --git a/inventory/byo/hosts b/inventory/byo/hosts deleted file mode 100644 index 4d4da5468..000000000 --- a/inventory/byo/hosts +++ /dev/null @@ -1,39 +0,0 @@ -# This is an example of a bring your own (byo) host inventory - -# Create an OSEv3 group that contains the masters and nodes groups -[OSEv3:children] -masters -nodes - -# Set variables common for all OSEv3 hosts -[OSEv3:vars] -# SSH user, this user should allow ssh based auth without requiring a password -ansible_ssh_user=root - -# If ansible_ssh_user is not root, ansible_sudo must be set to true -#ansible_sudo=true - -# To deploy origin, change deployment_type to origin -deployment_type=enterprise - -# Pre-release registry URL -oreg_url=docker-buildvm-rhose.usersys.redhat.com:5000/openshift3_beta/ose-${component}:${version} - -# Pre-release additional repo -openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterprise/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] -#openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterpriseErrata/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] - -# Origin copr repo -#openshift_additional_repos=[{'id': 'openshift-origin-copr', 'name': 'OpenShift Origin COPR', 'baseurl': 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/epel-7-$basearch/', 'enabled': 1, 'gpgcheck': 1, gpgkey: 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/pubkey.gpg'}] - -# htpasswd auth -#openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/openshift/htpasswd'}] - -# host group for masters -[masters] -ose3-master-ansible.test.example.com - -# host group for nodes -[nodes] -#ose3-master-ansible.test.example.com openshift_node_labels="{'region': 'infra', 'zone': 'default'}" -ose3-node[1:2]-ansible.test.example.com openshift_node_labels="{'region': 'primary', 'zone': 'default'}" diff --git a/inventory/byo/hosts.example b/inventory/byo/hosts.example new file mode 100644 index 000000000..8a5d5c719 --- /dev/null +++ b/inventory/byo/hosts.example @@ -0,0 +1,114 @@ +# This is an example of a bring your own (byo) host inventory + +# Create an OSEv3 group that contains the masters and nodes groups +[OSEv3:children] +masters +nodes +etcd + +# Set variables common for all OSEv3 hosts +[OSEv3:vars] +# SSH user, this user should allow ssh based auth without requiring a +# password. If using ssh key based auth, then the key should be managed by an +# ssh agent. +ansible_ssh_user=root + +# If ansible_ssh_user is not root, ansible_sudo must be set to true and the +# user must be configured for passwordless sudo +#ansible_sudo=true + +# deployment type valid values are origin, online and enterprise +deployment_type=atomic-enterprise + +# Enable cluster metrics +#use_cluster_metrics=true + +# Pre-release registry URL +#oreg_url=rcm-img-docker01.build.eng.bos.redhat.com:5001/openshift3/ose-${component}:${version} + +# Pre-release Dev puddle repo +#openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterprise/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] + +# Pre-release Errata puddle repo +#openshift_additional_repos=[{'id': 'ose-devel', 'name': 'ose-devel', 'baseurl': 'http://buildvm-devops.usersys.redhat.com/puddle/build/OpenShiftEnterpriseErrata/3.0/latest/RH7-RHOSE-3.0/$basearch/os', 'enabled': 1, 'gpgcheck': 0}] + +# Origin copr repo +#openshift_additional_repos=[{'id': 'openshift-origin-copr', 'name': 'OpenShift Origin COPR', 'baseurl': 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/epel-7-$basearch/', 'enabled': 1, 'gpgcheck': 1, gpgkey: 'https://copr-be.cloud.fedoraproject.org/results/maxamillion/origin-next/pubkey.gpg'}] + +# htpasswd auth +openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/openshift/htpasswd'}] + +# Allow all auth +#openshift_master_identity_providers=[{'name': 'allow_all', 'login': 'true', 'challenge': 'true', 'kind': 'AllowAllPasswordIdentityProvider'}] + +# Project Configuration +#osm_project_request_message='' +#osm_project_request_template='' +#osm_mcs_allocator_range='s0:/2' +#osm_mcs_labels_per_project=5 +#osm_uid_allocator_range='1000000000-1999999999/10000' + +# Configure Fluentd +#use_fluentd=true + +# Enable cockpit +#osm_use_cockpit=true +# +# Set cockpit plugins +#osm_cockpit_plugins=['cockpit-kubernetes'] + +# master cluster ha variables using pacemaker or RHEL HA +#openshift_master_cluster_password=openshift_cluster +#openshift_master_cluster_vip=192.168.133.25 +#openshift_master_cluster_public_vip=192.168.133.25 +#openshift_master_cluster_hostname=openshift-ansible.test.example.com +#openshift_master_cluster_public_hostname=openshift-ansible.test.example.com + +# master cluster ha variables when using a different HA solution +# For installation the value of openshift_master_cluster_hostname must resolve +# to the first master defined in the inventory. +# The HA solution must be manually configured after installation and must ensure +# that the master is running on a single master host. +#openshift_master_cluster_hostname=openshift-ansible.test.example.com +#openshift_master_cluster_public_hostname=openshift-ansible.test.example.com +#openshift_master_cluster_defer_ha=True + +# default subdomain to use for exposed routes +#osm_default_subdomain=apps.test.example.com + +# additional cors origins +#osm_custom_cors_origins=['foo.example.com', 'bar.example.com'] + +# default project node selector +#osm_default_node_selector='region=primary' + +# default storage plugin dependencies to install, by default the ceph and +# glusterfs plugin dependencies will be installed, if available. +#osn_storage_plugin_deps=['ceph','glusterfs'] + +# default selectors for router and registry services +# openshift_router_selector='region=infra' +# openshift_registry_selector='region=infra' + +# Configure the multi-tenant SDN plugin (default is 'redhat/openshift-ovs-subnet') +# os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant' + +# Disable the OpenShift SDN plugin +# openshift_use_openshift_sdn=False + +# set RPM version for debugging purposes +#openshift_pkg_version=-3.0.0.0 + +# host group for masters +[masters] +ose3-master[1:3]-ansible.test.example.com + +[etcd] +ose3-etcd[1:3]-ansible.test.example.com + +# NOTE: Currently we require that masters be part of the SDN which requires that they also be nodes +# However, in order to ensure that your masters are not burdened with running pods you should +# make them unschedulable by adding openshift_scheduleable=False any node that's also a master. +[nodes] +ose3-master[1:3]-ansible.test.example.com +ose3-node[1:2]-ansible.test.example.com openshift_node_labels="{'region': 'primary', 'zone': 'default'}" diff --git a/inventory/gce/hosts/gce.py b/inventory/gce/hosts/gce.py index 3403f735e..6ed12e011 100755 --- a/inventory/gce/hosts/gce.py +++ b/inventory/gce/hosts/gce.py @@ -120,6 +120,7 @@ class GceInventory(object): os.path.dirname(os.path.realpath(__file__)), "gce.ini") gce_ini_path = os.environ.get('GCE_INI_PATH', gce_ini_default_path) + # Create a ConfigParser. # This provides empty defaults to each key, so that environment # variable configuration (as opposed to INI configuration) is able @@ -173,6 +174,7 @@ class GceInventory(object): args[1] = os.environ.get('GCE_PEM_FILE_PATH', args[1]) kwargs['project'] = os.environ.get('GCE_PROJECT', kwargs['project']) + # Retrieve and return the GCE driver. gce = get_driver(Provider.GCE)(*args, **kwargs) gce.connection.user_agent_append( @@ -211,7 +213,8 @@ class GceInventory(object): 'gce_image': inst.image, 'gce_machine_type': inst.size, 'gce_private_ip': inst.private_ips[0], - 'gce_public_ip': inst.public_ips[0], + # Hosts don't always have a public IP name + #'gce_public_ip': inst.public_ips[0], 'gce_name': inst.name, 'gce_description': inst.extra['description'], 'gce_status': inst.extra['status'], @@ -219,8 +222,8 @@ class GceInventory(object): 'gce_tags': inst.extra['tags'], 'gce_metadata': md, 'gce_network': net, - # Hosts don't have a public name, so we add an IP - 'ansible_ssh_host': inst.public_ips[0] + # Hosts don't always have a public IP name + #'ansible_ssh_host': inst.public_ips[0] } def get_instance(self, instance_name): diff --git a/inventory/gce/hosts/hosts b/inventory/gce/hosts/hosts index 34a4396bd..bf4e0845a 100644 --- a/inventory/gce/hosts/hosts +++ b/inventory/gce/hosts/hosts @@ -1 +1 @@ -localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter='/usr/bin/env python2' diff --git a/inventory/libvirt/hosts/hosts b/inventory/libvirt/hosts/hosts index 34a4396bd..bf4e0845a 100644 --- a/inventory/libvirt/hosts/hosts +++ b/inventory/libvirt/hosts/hosts @@ -1 +1 @@ -localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 +localhost ansible_connection=local ansible_sudo=no ansible_python_interpreter='/usr/bin/env python2' diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index b7ce9e5dc..23cf5ecf1 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -78,7 +78,7 @@ class MultiEc2(object): }, ] - self.config['cache_max_age'] = 0 + self.config['cache_max_age'] = 300 else: raise RuntimeError("Could not find valid ec2 credentials in the environment.") @@ -239,22 +239,33 @@ class MultiEc2(object): def apply_account_config(self, acc_config): ''' Apply account config settings ''' - if not acc_config.has_key('hostvars') and not acc_config.has_key('all_group'): - return - results = self.all_ec2_results[acc_config['name']] - # Update each hostvar with the newly desired key: value - for host_property, value in acc_config['hostvars'].items(): + + # Update each hostvar with the newly desired key: value + for new_var, value in acc_config.get('extra_vars', {}).items(): # Verify the account results look sane # by checking for these keys ('_meta' and 'hostvars' exist) if results.has_key('_meta') and results['_meta'].has_key('hostvars'): for data in results['_meta']['hostvars'].values(): - data[str(host_property)] = str(value) + data[str(new_var)] = str(value) # Add this group if results.has_key(acc_config['all_group']): - results["%s_%s" % (host_property, value)] = \ - copy.copy(results[acc_config['all_group']]) + results["%s_%s" % (new_var, value)] = \ + copy.copy(results[acc_config['all_group']]) + + # Clone groups goes here + for name_from, name_to in acc_config.get('clone_groups', {}).items(): + if results.has_key(name_from): + results[name_to] = copy.copy(results[name_from]) + + # Clone vars goes here + for to_name, from_name in acc_config.get('clone_vars', {}).items(): + # Verify the account results look sane + # by checking for these keys ('_meta' and 'hostvars' exist) + if results.has_key('_meta') and results['_meta'].has_key('hostvars'): + for data in results['_meta']['hostvars'].values(): + data[str(to_name)] = data.get(str(from_name), 'nil') # store the results back into all_ec2_results self.all_ec2_results[acc_config['name']] = results diff --git a/inventory/multi_ec2.yaml.example b/inventory/multi_ec2.yaml.example index 99f157b11..bbd81ad20 100644 --- a/inventory/multi_ec2.yaml.example +++ b/inventory/multi_ec2.yaml.example @@ -18,7 +18,7 @@ accounts: AWS_ACCESS_KEY_ID: XXXXXXXXXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX all_group: ec2 - hostvars: + extra_vars: cloud: aws account: aws1 diff --git a/inventory/openshift-ansible-inventory.spec b/inventory/openshift-ansible-inventory.spec deleted file mode 100644 index 900a27f3a..000000000 --- a/inventory/openshift-ansible-inventory.spec +++ /dev/null @@ -1,82 +0,0 @@ -Summary: OpenShift Ansible Inventories -Name: openshift-ansible-inventory -Version: 0.0.8 -Release: 1%{?dist} -License: ASL 2.0 -URL: https://github.com/openshift/openshift-ansible -Source0: %{name}-%{version}.tar.gz -Requires: python2 -BuildRequires: python2-devel -BuildArch: noarch - -%description -Ansible Inventories used with the openshift-ansible scripts and playbooks. - -%prep -%setup -q - -%build - -%install -mkdir -p %{buildroot}/etc/ansible -mkdir -p %{buildroot}/usr/share/ansible/inventory -mkdir -p %{buildroot}/usr/share/ansible/inventory/aws -mkdir -p %{buildroot}/usr/share/ansible/inventory/gce - -cp -p multi_ec2.py %{buildroot}/usr/share/ansible/inventory -cp -p multi_ec2.yaml.example %{buildroot}/etc/ansible/multi_ec2.yaml -cp -p aws/hosts/ec2.py %{buildroot}/usr/share/ansible/inventory/aws -cp -p gce/hosts/gce.py %{buildroot}/usr/share/ansible/inventory/gce - -%files -%config(noreplace) /etc/ansible/* -%dir /usr/share/ansible/inventory -/usr/share/ansible/inventory/multi_ec2.py* -/usr/share/ansible/inventory/aws/ec2.py* -/usr/share/ansible/inventory/gce/gce.py* - -%changelog -* Tue Jun 09 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.8-1 -- Added more verbosity when error happens. Also fixed a bug. - (kwoodson@redhat.com) -- Implement OpenStack provider (lhuard@amadeus.com) -- * rename openshift_registry_url oreg_url * rename option_images to - _{oreg|ortr}_images (jhonce@redhat.com) -- Fix the remaining pylint warnings (lhuard@amadeus.com) -- Fix some of the pylint warnings (lhuard@amadeus.com) -- [libvirt cluster] Use net-dhcp-leases to find VMs’ IPs (lhuard@amadeus.com) -- fixed the openshift-ansible-bin build (twiest@redhat.com) - -* Fri May 15 2015 Kenny Woodson <kwoodson@redhat.com> 0.0.7-1 -- Making multi_ec2 into a library (kwoodson@redhat.com) - -* Wed May 13 2015 Thomas Wiest <twiest@redhat.com> 0.0.6-1 -- Added support for grouping and a bug fix. (kwoodson@redhat.com) - -* Tue May 12 2015 Thomas Wiest <twiest@redhat.com> 0.0.5-1 -- removed ec2.ini from the openshift-ansible-inventory.spec file so that we're - not dictating what the ec2.ini file should look like. (twiest@redhat.com) -- Added capability to pass in ec2.ini file. (kwoodson@redhat.com) - -* Thu May 07 2015 Thomas Wiest <twiest@redhat.com> 0.0.4-1 -- Fixed a bug due to renaming of variables. (kwoodson@redhat.com) - -* Thu May 07 2015 Thomas Wiest <twiest@redhat.com> 0.0.3-1 -- fixed build problems with openshift-ansible-inventory.spec - (twiest@redhat.com) -- Allow option in multi_ec2 to set cache location. (kwoodson@redhat.com) -- Add ansible_connection=local to localhost in inventory (jdetiber@redhat.com) -- Adding refresh-cache option and cleanup for pylint. Also updated for - aws/hosts/ being added. (kwoodson@redhat.com) - -* Thu Mar 26 2015 Thomas Wiest <twiest@redhat.com> 0.0.2-1 -- added the ability to have a config file in /etc/openshift_ansible to - multi_ec2.py. (twiest@redhat.com) -- Merge pull request #97 from jwhonce/wip/cluster (jhonce@redhat.com) -- gce inventory/playbook updates for node registration changes - (jdetiber@redhat.com) -- Various fixes (jdetiber@redhat.com) - -* Tue Mar 24 2015 Thomas Wiest <twiest@redhat.com> 0.0.1-1 -- new package built with tito - diff --git a/inventory/openstack/hosts/hosts b/inventory/openstack/hosts/hosts index 9cdc31449..2d2194a4d 100644 --- a/inventory/openstack/hosts/hosts +++ b/inventory/openstack/hosts/hosts @@ -1 +1 @@ -localhost ansible_sudo=no ansible_python_interpreter=/usr/bin/python2 connection=local +localhost ansible_sudo=no ansible_python_interpreter='/usr/bin/env python2' connection=local diff --git a/inventory/openstack/hosts/nova.py b/inventory/openstack/hosts/nova.py index d5bd8d1ee..3197a57bc 100755 --- a/inventory/openstack/hosts/nova.py +++ b/inventory/openstack/hosts/nova.py @@ -34,7 +34,7 @@ except ImportError: # executed with no parameters, return the list of # all groups and hosts -NOVA_CONFIG_FILES = [os.getcwd() + "/nova.ini", +NOVA_CONFIG_FILES = [os.path.join(os.path.dirname(os.path.realpath(__file__)), "nova.ini"), os.path.expanduser(os.environ.get('ANSIBLE_CONFIG', "~/nova.ini")), "/etc/ansible/nova.ini"] diff --git a/lookup_plugins/oo_option.py b/lookup_plugins/oo_option.py new file mode 100644 index 000000000..35dce48f9 --- /dev/null +++ b/lookup_plugins/oo_option.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +# vim: expandtab:tabstop=4:shiftwidth=4 + +''' +oo_option lookup plugin for openshift-ansible + +Usage: + + - debug: + msg: "{{ lookup('oo_option', '<key>') | default('<default_value>', True) }}" + +This returns, by order of priority: + +* if it exists, the `cli_<key>` ansible variable. This variable is set by `bin/cluster --option <key>=<value> …` +* if it exists, the envirnoment variable named `<key>` +* if none of the above conditions are met, empty string is returned +''' + +from ansible.utils import template +import os + +# Reason: disable too-few-public-methods because the `run` method is the only +# one required by the Ansible API +# Status: permanently disabled +# pylint: disable=too-few-public-methods +class LookupModule(object): + ''' oo_option lookup plugin main class ''' + + # Reason: disable unused-argument because Ansible is calling us with many + # parameters we are not interested in. + # The lookup plugins of Ansible have this kwargs “catch-all” parameter + # which is not used + # Status: permanently disabled unless Ansible API evolves + # pylint: disable=unused-argument + def __init__(self, basedir=None, **kwargs): + ''' Constructor ''' + self.basedir = basedir + + # Reason: disable unused-argument because Ansible is calling us with many + # parameters we are not interested in. + # The lookup plugins of Ansible have this kwargs “catch-all” parameter + # which is not used + # Status: permanently disabled unless Ansible API evolves + # pylint: disable=unused-argument + def run(self, terms, inject=None, **kwargs): + ''' Main execution path ''' + + try: + terms = template.template(self.basedir, terms, inject) + # Reason: disable broad-except to really ignore any potential exception + # This is inspired by the upstream "env" lookup plugin: + # https://github.com/ansible/ansible/blob/devel/v1/ansible/runner/lookup_plugins/env.py#L29 + # pylint: disable=broad-except + except Exception: + pass + + if isinstance(terms, basestring): + terms = [terms] + + ret = [] + + for term in terms: + option_name = term.split()[0] + cli_key = 'cli_' + option_name + if inject and cli_key in inject: + ret.append(inject[cli_key]) + elif option_name in os.environ: + ret.append(os.environ[option_name]) + else: + ret.append('') + + return ret diff --git a/lookup_plugins/sequence.py b/lookup_plugins/sequence.py new file mode 100644 index 000000000..8ca9e7b39 --- /dev/null +++ b/lookup_plugins/sequence.py @@ -0,0 +1,215 @@ +# (c) 2013, Jayson Vantuyl <jayson@aggressive.ly> +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +from ansible.errors import AnsibleError +import ansible.utils as utils +from re import compile as re_compile, IGNORECASE + +# shortcut format +NUM = "(0?x?[0-9a-f]+)" +SHORTCUT = re_compile( + "^(" + # Group 0 + NUM + # Group 1: Start + "-)?" + + NUM + # Group 2: End + "(/" + # Group 3 + NUM + # Group 4: Stride + ")?" + + "(:(.+))?$", # Group 5, Group 6: Format String + IGNORECASE +) + + +class LookupModule(object): + """ + sequence lookup module + + Used to generate some sequence of items. Takes arguments in two forms. + + The simple / shortcut form is: + + [start-]end[/stride][:format] + + As indicated by the brackets: start, stride, and format string are all + optional. The format string is in the style of printf. This can be used + to pad with zeros, format in hexadecimal, etc. All of the numerical values + can be specified in octal (i.e. 0664) or hexadecimal (i.e. 0x3f8). + Negative numbers are not supported. + + Some examples: + + 5 -> ["1","2","3","4","5"] + 5-8 -> ["5", "6", "7", "8"] + 2-10/2 -> ["2", "4", "6", "8", "10"] + 4:host%02d -> ["host01","host02","host03","host04"] + + The standard Ansible key-value form is accepted as well. For example: + + start=5 end=11 stride=2 format=0x%02x -> ["0x05","0x07","0x09","0x0a"] + + This format takes an alternate form of "end" called "count", which counts + some number from the starting value. For example: + + count=5 -> ["1", "2", "3", "4", "5"] + start=0x0f00 count=4 format=%04x -> ["0f00", "0f01", "0f02", "0f03"] + start=0 count=5 stride=2 -> ["0", "2", "4", "6", "8"] + start=1 count=5 stride=2 -> ["1", "3", "5", "7", "9"] + + The count option is mostly useful for avoiding off-by-one errors and errors + calculating the number of entries in a sequence when a stride is specified. + """ + + def __init__(self, basedir, **kwargs): + """absorb any keyword args""" + self.basedir = basedir + + def reset(self): + """set sensible defaults""" + self.start = 1 + self.count = None + self.end = None + self.stride = 1 + self.format = "%d" + + def parse_kv_args(self, args): + """parse key-value style arguments""" + for arg in ["start", "end", "count", "stride"]: + try: + arg_raw = args.pop(arg, None) + if arg_raw is None: + continue + arg_cooked = int(arg_raw, 0) + setattr(self, arg, arg_cooked) + except ValueError: + raise AnsibleError( + "can't parse arg %s=%r as integer" + % (arg, arg_raw) + ) + if 'format' in args: + self.format = args.pop("format") + if args: + raise AnsibleError( + "unrecognized arguments to with_sequence: %r" + % args.keys() + ) + + def parse_simple_args(self, term): + """parse the shortcut forms, return True/False""" + match = SHORTCUT.match(term) + if not match: + return False + + _, start, end, _, stride, _, format = match.groups() + + if start is not None: + try: + start = int(start, 0) + except ValueError: + raise AnsibleError("can't parse start=%s as integer" % start) + if end is not None: + try: + end = int(end, 0) + except ValueError: + raise AnsibleError("can't parse end=%s as integer" % end) + if stride is not None: + try: + stride = int(stride, 0) + except ValueError: + raise AnsibleError("can't parse stride=%s as integer" % stride) + + if start is not None: + self.start = start + if end is not None: + self.end = end + if stride is not None: + self.stride = stride + if format is not None: + self.format = format + + def sanity_check(self): + if self.count is None and self.end is None: + raise AnsibleError( + "must specify count or end in with_sequence" + ) + elif self.count is not None and self.end is not None: + raise AnsibleError( + "can't specify both count and end in with_sequence" + ) + elif self.count is not None: + # convert count to end + if self.count != 0: + self.end = self.start + self.count * self.stride - 1 + else: + self.start = 0 + self.end = 0 + self.stride = 0 + del self.count + if self.stride > 0 and self.end < self.start: + raise AnsibleError("to count backwards make stride negative") + if self.stride < 0 and self.end > self.start: + raise AnsibleError("to count forward don't make stride negative") + if self.format.count('%') != 1: + raise AnsibleError("bad formatting string: %s" % self.format) + + def generate_sequence(self): + if self.stride > 0: + adjust = 1 + else: + adjust = -1 + numbers = xrange(self.start, self.end + adjust, self.stride) + + for i in numbers: + try: + formatted = self.format % i + yield formatted + except (ValueError, TypeError): + raise AnsibleError( + "problem formatting %r with %r" % self.format + ) + + def run(self, terms, inject=None, **kwargs): + results = [] + + terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject) + + if isinstance(terms, basestring): + terms = [ terms ] + + for term in terms: + try: + self.reset() # clear out things for this iteration + + try: + if not self.parse_simple_args(term): + self.parse_kv_args(utils.parse_kv(term)) + except Exception: + raise AnsibleError( + "unknown error parsing with_sequence arguments: %r" + % term + ) + + self.sanity_check() + if self.stride != 0: + results.extend(self.generate_sequence()) + except AnsibleError: + raise + except Exception, e: + raise AnsibleError( + "unknown error generating sequence: %s" % str(e) + ) + + return results diff --git a/openshift-ansible.spec b/openshift-ansible.spec new file mode 100644 index 000000000..a5f25d966 --- /dev/null +++ b/openshift-ansible.spec @@ -0,0 +1,272 @@ +# %commit is intended to be set by tito custom builders provided +# in the .tito/lib directory. The values in this spec file will not be kept up to date. +%{!?commit: +%global commit c64d09e528ca433832c6b6e6f5c7734a9cc8ee6f +} + +Name: openshift-ansible +Version: 3.0.4 +Release: 1%{?dist} +Summary: Openshift and Atomic Enterprise Ansible +License: ASL 2.0 +URL: https://github.com/openshift/openshift-ansible +Source0: https://github.com/openshift/openshift-ansible/archive/%{commit}/%{name}-%{version}.tar.gz +BuildArch: noarch + +Requires: ansible + +%description +Openshift and Atomic Enterprise Ansible + +This repo contains Ansible code and playbooks +for Openshift and Atomic Enterprise. + +%prep +%setup -q + +%build + +# atomic-openshift-utils install +pushd utils +%{__python} setup.py build +popd + +%install +# Base openshift-ansible install +mkdir -p %{buildroot}%{_datadir}/%{name} +mkdir -p %{buildroot}%{_datadir}/ansible/%{name} +mkdir -p %{buildroot}%{_datadir}/ansible_plugins + +# openshift-ansible-bin install +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{python_sitelib}/openshift_ansible +mkdir -p %{buildroot}/etc/bash_completion.d +mkdir -p %{buildroot}/etc/openshift_ansible +cp -p bin/{ossh,oscp,opssh,opscp,ohi} %{buildroot}%{_bindir} +cp -pP bin/openshift_ansible/* %{buildroot}%{python_sitelib}/openshift_ansible +cp -p bin/ossh_bash_completion %{buildroot}/etc/bash_completion.d +cp -p bin/openshift_ansible.conf.example %{buildroot}/etc/openshift_ansible/openshift_ansible.conf +# Fix links +rm -f %{buildroot}%{python_sitelib}/openshift_ansible/multi_ec2.py +rm -f %{buildroot}%{python_sitelib}/openshift_ansible/aws +ln -sf %{_datadir}/ansible/inventory/multi_ec2.py %{buildroot}%{python_sitelib}/openshift_ansible/multi_ec2.py +ln -sf %{_datadir}/ansible/inventory/aws %{buildroot}%{python_sitelib}/openshift_ansible/aws + +# openshift-ansible-docs install +# -docs are currently just %doc, no install needed + +# openshift-ansible-inventory install +mkdir -p %{buildroot}/etc/ansible +mkdir -p %{buildroot}%{_datadir}/ansible/inventory +mkdir -p %{buildroot}%{_datadir}/ansible/inventory/aws +mkdir -p %{buildroot}%{_datadir}/ansible/inventory/gce +cp -p inventory/multi_ec2.py %{buildroot}%{_datadir}/ansible/inventory +cp -p inventory/multi_ec2.yaml.example %{buildroot}/etc/ansible/multi_ec2.yaml +cp -p inventory/aws/hosts/ec2.py %{buildroot}%{_datadir}/ansible/inventory/aws +cp -p inventory/gce/hosts/gce.py %{buildroot}%{_datadir}/ansible/inventory/gce + +# openshift-ansible-playbooks install +cp -rp playbooks %{buildroot}%{_datadir}/ansible/%{name}/ + +# openshift-ansible-roles install +cp -rp roles %{buildroot}%{_datadir}/ansible/%{name}/ + +# openshift-ansible-filter-plugins install +cp -rp filter_plugins %{buildroot}%{_datadir}/ansible_plugins/ + +# openshift-ansible-lookup-plugins install +cp -rp lookup_plugins %{buildroot}%{_datadir}/ansible_plugins/ + +# atomic-openshift-utils install +pushd utils +%{__python} setup.py install --skip-build --root %{buildroot} +# Remove this line once the name change has happened +mv -f %{buildroot}%{_bindir}/oo-install %{buildroot}%{_bindir}/atomic-openshift-installer +popd + +# Base openshift-ansible files +%files +%doc LICENSE.md README* +%dir %{_datadir}/ansible/%{name} + +# ---------------------------------------------------------------------------------- +# openshift-ansible-bin subpackage +# ---------------------------------------------------------------------------------- +%package bin +Summary: Openshift and Atomic Enterprise Ansible Scripts for working with metadata hosts +Requires: %{name}-inventory +Requires: python2 +BuildRequires: python2-devel +BuildArch: noarch + +%description bin +Scripts to make it nicer when working with hosts that are defined only by metadata. + +%files bin +%{_bindir}/* +%{python_sitelib}/openshift_ansible/ +/etc/bash_completion.d/* +%config(noreplace) /etc/openshift_ansible/ + + +# ---------------------------------------------------------------------------------- +# openshift-ansible-docs subpackage +# ---------------------------------------------------------------------------------- +%package docs +Summary: Openshift and Atomic Enterprise Ansible documents +Requires: %{name} +BuildArch: noarch + +%description docs +%{summary}. + +%files docs +%doc docs + +# ---------------------------------------------------------------------------------- +# openshift-ansible-inventory subpackage +# ---------------------------------------------------------------------------------- +%package inventory +Summary: Openshift and Atomic Enterprise Ansible Inventories +Requires: python2 +BuildArch: noarch + +%description inventory +Ansible Inventories used with the openshift-ansible scripts and playbooks. + +%files inventory +%config(noreplace) /etc/ansible/* +%dir %{_datadir}/ansible/inventory +%{_datadir}/ansible/inventory/multi_ec2.py* +%{_datadir}/ansible/inventory/aws/ec2.py* +%{_datadir}/ansible/inventory/gce/gce.py* + + +# ---------------------------------------------------------------------------------- +# openshift-ansible-playbooks subpackage +# ---------------------------------------------------------------------------------- +%package playbooks +Summary: Openshift and Atomic Enterprise Ansible Playbooks +Requires: %{name} +BuildArch: noarch + +%description playbooks +%{summary}. + +%files playbooks +%{_datadir}/ansible/%{name}/playbooks + + +# ---------------------------------------------------------------------------------- +# openshift-ansible-roles subpackage +# ---------------------------------------------------------------------------------- +%package roles +Summary: Openshift and Atomic Enterprise Ansible roles +Requires: %{name} +BuildArch: noarch + +%description roles +%{summary}. + +%files roles +%{_datadir}/ansible/%{name}/roles + + +# ---------------------------------------------------------------------------------- +# openshift-ansible-filter-plugins subpackage +# ---------------------------------------------------------------------------------- +%package filter-plugins +Summary: Openshift and Atomic Enterprise Ansible filter plugins +Requires: %{name} +BuildArch: noarch + +%description filter-plugins +%{summary}. + +%files filter-plugins +%{_datadir}/ansible_plugins/filter_plugins + + +# ---------------------------------------------------------------------------------- +# openshift-ansible-lookup-plugins subpackage +# ---------------------------------------------------------------------------------- +%package lookup-plugins +Summary: Openshift and Atomic Enterprise Ansible lookup plugins +Requires: %{name} +BuildArch: noarch + +%description lookup-plugins +%{summary}. + +%files lookup-plugins +%{_datadir}/ansible_plugins/lookup_plugins + +# ---------------------------------------------------------------------------------- +# atomic-openshift-utils subpackage +# ---------------------------------------------------------------------------------- + +%package -n atomic-openshift-utils +Summary: Atomic OpenShift Utilities +BuildRequires: python-setuptools +Requires: ansible +Requires: python-click +Requires: python-setuptools +Requires: PyYAML +BuildArch: noarch + +%description -n atomic-openshift-utils +Atomic OpenShift Utilities includes + - atomic-openshift-installer + - other utilities + +%files -n atomic-openshift-utils +%{python_sitelib}/ooinstall* +%{_bindir}/atomic-openshift-installer + + +%changelog +* Wed Oct 28 2015 Kenny Woodson <kwoodson@redhat.com> 3.0.4-1 +- Removing spec files. (kwoodson@redhat.com) +- Updated example (kwoodson@redhat.com) +- Automatic commit of package [openshift-ansible-inventory] release [0.0.11-1]. + (kwoodson@redhat.com) +- Automatic commit of package [openshift-ansible-bin] release [0.0.21-1]. + (kwoodson@redhat.com) +- Automatic commit of package [openshift-ansible-inventory] release [0.0.10-1]. + (kwoodson@redhat.com) +- Automatic commit of package [openshift-ansible-bin] release [0.0.20-1]. + (kwoodson@redhat.com) +- Adding tito releasers configuration (bleanhar@redhat.com) +- Bug fixes for the uninstall playbook (bleanhar@redhat.com) +- Adding clone vars and groups. Renamed hostvars to extra_vars. + (kwoodson@redhat.com) +- Start tracking docker info execution time (jdiaz@redhat.com) +- The uninstall playbook should remove the kubeconfig for non-root installs + (bleanhar@redhat.com) +- Adding uninstall support for Atomic Host (bleanhar@redhat.com) +- add examples for SDN configuration (jdetiber@redhat.com) + +* Tue Oct 27 2015 Troy Dawson <tdawson@redhat.com> 3.0.3-1 +- Pylint fixes and ignores for incoming oo-install code. (dgoodwin@redhat.com) +- Pylint fixes (abutcher@redhat.com) +- Adding zabbix type and fixing zabbix agent vars (kwoodson@redhat.com) +- Add atomic-openshift-utils add atomic-openshift-utils to openshift- + ansible.spec file (tdawson@redhat.com) +- Fix quotes (spinolacastro@gmail.com) +- Use standard library for version comparison. (abutcher@redhat.com) +- added docker info to the end of docker loop to direct lvm playbook. + (twiest@redhat.com) +- Add missing quotes (spinolacastro@gmail.com) +- Adding Docker Log Options capabilities (epo@jemba.net) +- Move version greater_than_fact into openshift_facts (abutcher@redhat.com) +- Don't include proxy client cert when <3.1 or <1.1 (abutcher@redhat.com) +- Add proxy client certs to master config. (abutcher@redhat.com) +- Update imagestreams and quickstarts from origin (sdodson@redhat.com) +- Get default values from openshift_facts (spinolacastro@gmail.com) +- Cleanup (spinolacastro@gmail.com) +- Add missing inventory example (spinolacastro@gmail.com) +- Custom Project Config (spinolacastro@gmail.com) + +* Mon Oct 19 2015 Troy Dawson <tdawson@redhat.com> 3.0.2-1 +- Initial Package + diff --git a/playbooks/adhoc/atomic_openshift_tutorial_reset.yml b/playbooks/adhoc/atomic_openshift_tutorial_reset.yml new file mode 100644 index 000000000..c14d08e87 --- /dev/null +++ b/playbooks/adhoc/atomic_openshift_tutorial_reset.yml @@ -0,0 +1,29 @@ +# This deletes *ALL* Docker images, and uninstalls OpenShift and +# Atomic Enterprise RPMs. It is primarily intended for use +# with the tutorial as well as for developers to reset state. +# +--- +- include: uninstall.yml + +- hosts: + - OSEv3:children + + sudo: yes + + tasks: + - shell: docker ps -a -q | xargs docker stop + changed_when: False + failed_when: False + + - shell: docker ps -a -q| xargs docker rm + changed_when: False + failed_when: False + + - shell: docker images -q |xargs docker rmi + changed_when: False + failed_when: False + + - user: name={{ item }} state=absent remove=yes + with_items: + - alice + - joe diff --git a/playbooks/adhoc/create_pv/create_pv.yaml b/playbooks/adhoc/create_pv/create_pv.yaml new file mode 100644 index 000000000..4f0ef7a75 --- /dev/null +++ b/playbooks/adhoc/create_pv/create_pv.yaml @@ -0,0 +1,159 @@ +--- +#example run: +# ansible-playbook -e "cli_volume_size=1" \ +# -e "cli_device_name=/dev/xvdf" \ +# -e "cli_hosttype=master" \ +# -e "cli_environment=ops" \ +# create_pv.yaml +# FIXME: we need to change "environment" to "clusterid" as that's what it really is now. +# +- name: Create a volume and attach it to master + hosts: localhost + gather_facts: no + vars: + cli_volume_type: gp2 + cli_volume_iops: '' + oo_name: "{{ groups['tag_host-type_' ~ cli_hosttype] | + intersect(groups['tag_environment_' ~ cli_environment]) | + first }}" + pre_tasks: + - fail: + msg: "This playbook requires {{item}} to be set." + when: "{{ item }} is not defined or {{ item }} == ''" + with_items: + - cli_volume_size + - cli_device_name + - cli_hosttype + - cli_environment + + - name: set oo_name fact + set_fact: + oo_name: "{{ oo_name }}" + + + - name: Select a single master to run this on + add_host: + hostname: "{{ oo_name }}" + ansible_ssh_host: "{{ hostvars[oo_name].ec2_public_dns_name }}" + groups: oo_master + + - name: Create a volume and attach it + ec2_vol: + state: present + instance: "{{ hostvars[oo_name]['ec2_id'] }}" + region: "{{ hostvars[oo_name]['ec2_region'] }}" + volume_size: "{{ cli_volume_size }}" + volume_type: "{{ cli_volume_type }}" + device_name: "{{ cli_device_name }}" + iops: "{{ cli_volume_iops }}" + register: vol + + - debug: var=vol + + - name: tag the vol with a name + ec2_tag: region={{ hostvars[oo_name]['ec2_region'] }} resource={{vol.volume_id}} + args: + tags: + Name: "pv-{{ hostvars[oo_name]['ec2_tag_Name'] }}" + env: "{{cli_environment}}" + register: voltags + + - debug: var=voltags + +- name: Configure the drive + gather_facts: no + hosts: oo_master + user: root + connection: ssh + vars: + pv_tmpdir: /tmp/persistentvolumes + + post_tasks: + - name: Setting facts for template + set_fact: + pv_name: "pv-{{cli_volume_size}}-{{ hostvars[hostvars.localhost.oo_name]['ec2_tag_Name'] }}-{{hostvars.localhost.vol.volume_id }}" + vol_az: "{{ hostvars[hostvars.localhost.oo_name]['ec2_placement'] }}" + vol_id: "{{ hostvars.localhost.vol.volume_id }}" + vol_size: "{{ cli_volume_size }}" + pv_mntdir: "{{ pv_tmpdir }}/mnt-{{ 1000 | random }}" + + - set_fact: + pv_template: "{{ pv_tmpdir }}/{{ pv_name }}.yaml" + + - name: "Mkdir {{ pv_tmpdir }}" + file: + state: directory + path: "{{ pv_tmpdir }}" + mode: '0750' + + - name: "Mkdir {{ pv_mntdir }}" + file: + state: directory + path: "{{ pv_mntdir }}" + mode: '0750' + + - name: Create pv file from template + template: + src: ./pv-template.j2 + dest: "{{ pv_template }}" + owner: root + mode: '0640' + + - name: mkfs + filesystem: + dev: "{{ cli_device_name }}" + fstype: ext4 + + - name: Mount the dev + mount: + name: "{{ pv_mntdir }}" + src: "{{ cli_device_name }}" + fstype: ext4 + state: mounted + + - name: chgrp g+rwXs + file: + path: "{{ pv_mntdir }}" + mode: 'g+rwXs' + recurse: yes + seuser: system_u + serole: object_r + setype: svirt_sandbox_file_t + selevel: s0 + + - name: umount + mount: + name: "{{ pv_mntdir }}" + src: "{{ cli_device_name }}" + state: unmounted + fstype: ext4 + + - name: remove from fstab + mount: + name: "{{ pv_mntdir }}" + src: "{{ cli_device_name }}" + state: absent + fstype: ext4 + + - name: detach drive + delegate_to: localhost + ec2_vol: + region: "{{ hostvars[hostvars.localhost.oo_name].ec2_region }}" + id: "{{ hostvars.localhost.vol.volume_id }}" + instance: None + + - name: "Remove {{ pv_mntdir }}" + file: + state: absent + path: "{{ pv_mntdir }}" + + # We have to use the shell module because we can't set env vars with the command module. + - name: "Place PV into oc" + shell: "KUBECONFIG=/etc/openshift/master/admin.kubeconfig oc create -f {{ pv_template | quote }}" + register: oc_output + + - debug: var=oc_output + + - fail: + msg: "Failed to add {{ pv_template }} to master." + when: oc_output.rc != 0 diff --git a/playbooks/adhoc/create_pv/pv-template.j2 b/playbooks/adhoc/create_pv/pv-template.j2 new file mode 100644 index 000000000..5654ef6c4 --- /dev/null +++ b/playbooks/adhoc/create_pv/pv-template.j2 @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ pv_name }} + labels: + type: ebs +spec: + capacity: + storage: {{ vol_size }}Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Recycle + awsElasticBlockStore: + volumeID: aws://{{ vol_az }}/{{ vol_id }} + fsType: ext4 diff --git a/playbooks/adhoc/docker_loopback_to_lvm/docker-storage-setup b/playbooks/adhoc/docker_loopback_to_lvm/docker-storage-setup new file mode 100644 index 000000000..059058823 --- /dev/null +++ b/playbooks/adhoc/docker_loopback_to_lvm/docker-storage-setup @@ -0,0 +1,2 @@ +DEVS=/dev/xvdb +VG=docker_vg diff --git a/playbooks/adhoc/docker_loopback_to_lvm/docker_loopback_to_direct_lvm.yml b/playbooks/adhoc/docker_loopback_to_lvm/docker_loopback_to_direct_lvm.yml new file mode 100644 index 000000000..b6a2d2f26 --- /dev/null +++ b/playbooks/adhoc/docker_loopback_to_lvm/docker_loopback_to_direct_lvm.yml @@ -0,0 +1,142 @@ +--- +# This playbook coverts docker to go from loopback to direct-lvm (the Red Hat recommended way to run docker) +# in AWS. This adds an additional EBS volume and creates the Volume Group on this EBS volume to use. +# +# To run: +# 1. Source your AWS credentials (make sure it's the corresponding AWS account) into your environment +# export AWS_ACCESS_KEY_ID='XXXXX' +# export AWS_SECRET_ACCESS_KEY='XXXXXX' +# +# 2. run the playbook: +# ansible-playbook -e 'cli_tag_name=<tag-name>' -e "cli_volume_size=30" docker_loopback_to_direct_lvm.yml +# +# Example: +# ansible-playbook -e 'cli_tag_name=ops-master-12345' -e "cli_volume_size=30" docker_loopback_to_direct_lvm.yml +# +# Notes: +# * By default this will do a 30GB volume. +# * iops are calculated by Disk Size * 30. e.g ( 30GB * 30) = 900 iops +# * This will remove /var/lib/docker! +# * You may need to re-deploy docker images after this is run (like monitoring) +# + +- name: Fix docker to have a provisioned iops drive + hosts: "tag_Name_{{ cli_tag_name }}" + user: root + connection: ssh + gather_facts: no + + vars: + cli_volume_type: gp2 + cli_volume_size: 30 + + pre_tasks: + - fail: + msg: "This playbook requires {{item}} to be set." + when: "{{ item }} is not defined or {{ item }} == ''" + with_items: + - cli_tag_name + - cli_volume_size + + - debug: + var: hosts + + - name: start docker + service: + name: docker + state: started + + - name: Determine if loopback + shell: docker info | grep 'Data file:.*loop' + register: loop_device_check + ignore_errors: yes + + - debug: + var: loop_device_check + + - name: fail if we don't detect loopback + fail: + msg: loopback not detected! Please investigate manually. + when: loop_device_check.rc == 1 + + - name: stop zagg client monitoring container + service: + name: oso-rhel7-zagg-client + state: stopped + ignore_errors: yes + + - name: stop pcp client monitoring container + service: + name: oso-f22-host-monitoring + state: stopped + ignore_errors: yes + + - name: stop docker + service: + name: docker + state: stopped + + - name: delete /var/lib/docker + command: rm -rf /var/lib/docker + + - name: remove /var/lib/docker + command: rm -rf /var/lib/docker + + - name: check to see if /dev/xvdb exists + command: test -e /dev/xvdb + register: xvdb_check + ignore_errors: yes + + - debug: var=xvdb_check + + - name: fail if /dev/xvdb already exists + fail: + msg: /dev/xvdb already exists. Please investigate + when: xvdb_check.rc == 0 + + - name: Create a volume and attach it + delegate_to: localhost + ec2_vol: + state: present + instance: "{{ ec2_id }}" + region: "{{ ec2_region }}" + volume_size: "{{ cli_volume_size | default(30, True)}}" + volume_type: "{{ cli_volume_type }}" + device_name: /dev/xvdb + register: vol + + - debug: var=vol + + - name: tag the vol with a name + delegate_to: localhost + ec2_tag: region={{ ec2_region }} resource={{ vol.volume_id }} + args: + tags: + Name: "{{ ec2_tag_Name }}" + env: "{{ ec2_tag_environment }}" + register: voltags + + - name: Wait for volume to attach + pause: + seconds: 30 + + - name: copy the docker-storage-setup config file + copy: + src: docker-storage-setup + dest: /etc/sysconfig/docker-storage-setup + owner: root + group: root + mode: 0664 + + - name: docker storage setup + command: docker-storage-setup + register: setup_output + + - debug: var=setup_output + + - name: start docker + command: systemctl start docker.service + register: dockerstart + + - debug: var=dockerstart + diff --git a/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml b/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml new file mode 100755 index 000000000..72fcd77b3 --- /dev/null +++ b/playbooks/adhoc/docker_loopback_to_lvm/ops-docker-loopback-to-direct-lvm.yml @@ -0,0 +1,115 @@ +#!/usr/bin/ansible-playbook +--- +# This playbook coverts docker to go from loopback to direct-lvm (the Red Hat recommended way to run docker). +# +# It requires the block device to be already provisioned and attached to the host. This is a generic playbook, +# meant to be used for manual conversion. For AWS specific conversions, use the other playbook in this directory. +# +# To run: +# ./ops-docker-loopback-to-direct-lvm.yml -e cli_host=<host to run on> -e cli_docker_device=<path to device> +# +# Example: +# ./ops-docker-loopback-to-direct-lvm.yml -e cli_host=twiesttest-master-fd32 -e cli_docker_device=/dev/sdb +# +# Notes: +# * This will remove /var/lib/docker! +# * You may need to re-deploy docker images after this is run (like monitoring) + +- name: Fix docker to have a provisioned iops drive + hosts: "{{ cli_name }}" + user: root + connection: ssh + gather_facts: no + + pre_tasks: + - fail: + msg: "This playbook requires {{item}} to be set." + when: "{{ item }} is not defined or {{ item }} == ''" + with_items: + - cli_docker_device + + - name: start docker + service: + name: docker + state: started + + - name: Determine if loopback + shell: docker info | grep 'Data file:.*loop' + register: loop_device_check + ignore_errors: yes + + - debug: + var: loop_device_check + + - name: fail if we don't detect loopback + fail: + msg: loopback not detected! Please investigate manually. + when: loop_device_check.rc == 1 + + - name: stop zagg client monitoring container + service: + name: oso-rhel7-zagg-client + state: stopped + ignore_errors: yes + + - name: stop pcp client monitoring container + service: + name: oso-f22-host-monitoring + state: stopped + ignore_errors: yes + + - name: "check to see if {{ cli_docker_device }} exists" + command: "test -e {{ cli_docker_device }}" + register: docker_dev_check + ignore_errors: yes + + - debug: var=docker_dev_check + + - name: "fail if {{ cli_docker_device }} doesn't exist" + fail: + msg: "{{ cli_docker_device }} doesn't exist. Please investigate" + when: docker_dev_check.rc != 0 + + - name: stop docker + service: + name: docker + state: stopped + + - name: delete /var/lib/docker + command: rm -rf /var/lib/docker + + - name: remove /var/lib/docker + command: rm -rf /var/lib/docker + + - name: copy the docker-storage-setup config file + copy: + content: > + DEVS={{ cli_docker_device }} + VG=docker_vg + dest: /etc/sysconfig/docker-storage-setup + owner: root + group: root + mode: 0664 + + - name: docker storage setup + command: docker-storage-setup + register: setup_output + + - debug: var=setup_output + + - name: extend the vg + command: lvextend -l 90%VG /dev/docker_vg/docker-pool + register: extend_output + + - debug: var=extend_output + + - name: start docker + service: + name: docker + state: restarted + + - name: docker info + command: docker info + register: dockerinfo + + - debug: var=dockerinfo diff --git a/playbooks/adhoc/docker_storage_cleanup/docker_storage_cleanup.yml b/playbooks/adhoc/docker_storage_cleanup/docker_storage_cleanup.yml new file mode 100644 index 000000000..a19291a9f --- /dev/null +++ b/playbooks/adhoc/docker_storage_cleanup/docker_storage_cleanup.yml @@ -0,0 +1,69 @@ +--- +# This playbook attempts to cleanup unwanted docker files to help alleviate docker disk space issues. +# +# To run: +# +# 1. run the playbook: +# +# ansible-playbook -e 'cli_tag_name=<tag-name>' docker_storage_cleanup.yml +# +# Example: +# +# ansible-playbook -e 'cli_tag_name=ops-node-compute-12345' docker_storage_cleanup.yml +# +# Notes: +# * This *should* not interfere with running docker images +# + +- name: Clean up Docker Storage + gather_facts: no + hosts: "tag_Name_{{ cli_tag_name }}" + user: root + connection: ssh + + pre_tasks: + + - fail: + msg: "This playbook requires {{item}} to be set." + when: "{{ item }} is not defined or {{ item }} == ''" + with_items: + - cli_tag_name + + - name: Ensure docker is running + service: + name: docker + state: started + enabled: yes + + - name: Get docker info + command: docker info + register: docker_info + + - name: Show docker info + debug: + var: docker_info.stdout_lines + + - name: Remove exited and dead containers + shell: "docker ps -a | awk '/Exited|Dead/ {print $1}' | xargs --no-run-if-empty docker rm" + ignore_errors: yes + + - name: Remove dangling docker images + shell: "docker images -q -f dangling=true | xargs --no-run-if-empty docker rmi" + ignore_errors: yes + + - name: Remove non-running docker images + shell: "docker images | grep -v -e registry.access.redhat.com -e docker-registry.usersys.redhat.com -e docker-registry.ops.rhcloud.com | awk '{print $3}' | xargs --no-run-if-empty docker rmi 2>/dev/null" + ignore_errors: yes + + # leaving off the '-t' for docker exec. With it, it doesn't work with ansible and tty support + - name: update zabbix docker items + command: docker exec -i oso-rhel7-zagg-client /usr/local/bin/cron-send-docker-metrics.py + + # Get and show docker info again. + - name: Get docker info + command: docker info + register: docker_info + + - name: Show docker info + debug: + var: docker_info.stdout_lines diff --git a/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py b/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py new file mode 100644 index 000000000..d0264cde9 --- /dev/null +++ b/playbooks/adhoc/grow_docker_vg/filter_plugins/oo_filters.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vim: expandtab:tabstop=4:shiftwidth=4 +''' +Custom filters for use in openshift-ansible +''' + +import pdb + + +class FilterModule(object): + ''' Custom ansible filters ''' + + @staticmethod + def oo_pdb(arg): + ''' This pops you into a pdb instance where arg is the data passed in + from the filter. + Ex: "{{ hostvars | oo_pdb }}" + ''' + pdb.set_trace() + return arg + + @staticmethod + def translate_volume_name(volumes, target_volume): + ''' + This filter matches a device string /dev/sdX to /dev/xvdX + It will then return the AWS volume ID + ''' + for vol in volumes: + translated_name = vol["attachment_set"]["device"].replace("/dev/sd", "/dev/xvd") + if target_volume.startswith(translated_name): + return vol["id"] + + return None + + + def filters(self): + ''' returns a mapping of filters to methods ''' + return { + "translate_volume_name": self.translate_volume_name, + } diff --git a/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml b/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml new file mode 100644 index 000000000..63d473146 --- /dev/null +++ b/playbooks/adhoc/grow_docker_vg/grow_docker_vg.yml @@ -0,0 +1,206 @@ +--- +# This playbook grows the docker VG on a node by: +# * add a new volume +# * add volume to the existing VG. +# * pv move to the new volume. +# * remove old volume +# * detach volume +# * mark old volume in AWS with "REMOVE ME" tag +# * grow docker LVM to 90% of the VG +# +# To run: +# 1. Source your AWS credentials (make sure it's the corresponding AWS account) into your environment +# export AWS_ACCESS_KEY_ID='XXXXX' +# export AWS_SECRET_ACCESS_KEY='XXXXXX' +# +# 2. run the playbook: +# ansible-playbook -e 'cli_tag_name=<tag-name>' grow_docker_vg.yml +# +# Example: +# ansible-playbook -e 'cli_tag_name=ops-compute-12345' grow_docker_vg.yml +# +# Notes: +# * By default this will do a 55GB GP2 volume. The can be overidden with the "-e 'cli_volume_size=100'" variable +# * This does a GP2 by default. Support for Provisioned IOPS has not been added +# * This will assign the new volume to /dev/xvdc. This is not variablized, yet. +# * This can be done with NO downtime on the host +# * This playbook assumes that there is a Logical Volume that is installed and called "docker-pool". This is +# the LV that gets created via the "docker-storage-setup" command +# + +- name: Grow the docker volume group + hosts: "tag_Name_{{ cli_tag_name }}" + user: root + connection: ssh + gather_facts: no + + vars: + cli_volume_type: gp2 + cli_volume_size: 55 +# cli_volume_iops: "{{ 30 * cli_volume_size }}" + + pre_tasks: + - fail: + msg: "This playbook requires {{item}} to be set." + when: "{{ item }} is not defined or {{ item }} == ''" + with_items: + - cli_tag_name + - cli_volume_size + + - debug: + var: hosts + + - name: start docker + service: + name: docker + state: started + + - name: Determine if Storage Driver (docker info) is devicemapper + shell: docker info | grep 'Storage Driver:.*devicemapper' + register: device_mapper_check + ignore_errors: yes + + - debug: + var: device_mapper_check + + - name: fail if we don't detect devicemapper + fail: + msg: The "Storage Driver" in "docker info" is not set to "devicemapper"! Please investigate manually. + when: device_mapper_check.rc == 1 + + # docker-storage-setup creates a docker-pool as the lvm. I am using docker-pool lvm to test + # and find the volume group. + - name: Attempt to find the Volume Group that docker is using + shell: lvs | grep docker-pool | awk '{print $2}' + register: docker_vg_name + ignore_errors: yes + + - debug: + var: docker_vg_name + + - name: fail if we don't find a docker volume group + fail: + msg: Unable to find docker volume group. Please investigate manually. + when: docker_vg_name.stdout_lines|length != 1 + + # docker-storage-setup creates a docker-pool as the lvm. I am using docker-pool lvm to test + # and find the physical volume. + - name: Attempt to find the Phyisical Volume that docker is using + shell: "pvs | grep {{ docker_vg_name.stdout }} | awk '{print $1}'" + register: docker_pv_name + ignore_errors: yes + + - debug: + var: docker_pv_name + + - name: fail if we don't find a docker physical volume + fail: + msg: Unable to find docker physical volume. Please investigate manually. + when: docker_pv_name.stdout_lines|length != 1 + + + - name: get list of volumes from AWS + delegate_to: localhost + ec2_vol: + state: list + instance: "{{ ec2_id }}" + region: "{{ ec2_region }}" + register: attached_volumes + + - debug: var=attached_volumes + + - name: get volume id of current docker volume + set_fact: + old_docker_volume_id: "{{ attached_volumes.volumes | translate_volume_name(docker_pv_name.stdout) }}" + + - debug: var=old_docker_volume_id + + - name: check to see if /dev/xvdc exists + command: test -e /dev/xvdc + register: xvdc_check + ignore_errors: yes + + - debug: var=xvdc_check + + - name: fail if /dev/xvdc already exists + fail: + msg: /dev/xvdc already exists. Please investigate + when: xvdc_check.rc == 0 + + - name: Create a volume and attach it + delegate_to: localhost + ec2_vol: + state: present + instance: "{{ ec2_id }}" + region: "{{ ec2_region }}" + volume_size: "{{ cli_volume_size | default(30, True)}}" + volume_type: "{{ cli_volume_type }}" + device_name: /dev/xvdc + register: create_volume + + - debug: var=create_volume + + - name: Fail when problems creating volumes and attaching + fail: + msg: "Failed to create or attach volume msg: {{ create_volume.msg }}" + when: create_volume.msg is defined + + - name: tag the vol with a name + delegate_to: localhost + ec2_tag: region={{ ec2_region }} resource={{ create_volume.volume_id }} + args: + tags: + Name: "{{ ec2_tag_Name }}" + env: "{{ ec2_tag_environment }}" + register: voltags + + - name: check for attached drive + command: test -b /dev/xvdc + register: attachment_check + until: attachment_check.rc == 0 + retries: 30 + delay: 2 + + - name: partition the new drive and make it lvm + command: parted /dev/xvdc --script -- mklabel msdos mkpart primary 0% 100% set 1 lvm + + - name: pvcreate /dev/xvdc + command: pvcreate /dev/xvdc1 + + - name: Extend the docker volume group + command: vgextend "{{ docker_vg_name.stdout }}" /dev/xvdc1 + + - name: pvmove onto new volume + command: "pvmove {{ docker_pv_name.stdout }} /dev/xvdc1" + async: 43200 + poll: 10 + + - name: Remove the old docker drive from the volume group + command: "vgreduce {{ docker_vg_name.stdout }} {{ docker_pv_name.stdout }}" + + - name: Remove the pv from the old drive + command: "pvremove {{ docker_pv_name.stdout }}" + + - name: Extend the docker lvm + command: "lvextend -l '90%VG' /dev/{{ docker_vg_name.stdout }}/docker-pool" + + - name: detach old docker volume + delegate_to: localhost + ec2_vol: + region: "{{ ec2_region }}" + id: "{{ old_docker_volume_id }}" + instance: None + + - name: tag the old vol valid label + delegate_to: localhost + ec2_tag: region={{ ec2_region }} resource={{old_docker_volume_id}} + args: + tags: + Name: "{{ ec2_tag_Name }} REMOVE ME" + register: voltags + + - name: Update the /etc/sysconfig/docker-storage-setup with new device + lineinfile: + dest: /etc/sysconfig/docker-storage-setup + regexp: ^DEVS= + line: DEVS=/dev/xvdc diff --git a/playbooks/adhoc/noc/create_host.yml b/playbooks/adhoc/noc/create_host.yml new file mode 100644 index 000000000..d250e6e69 --- /dev/null +++ b/playbooks/adhoc/noc/create_host.yml @@ -0,0 +1,55 @@ +--- +- name: 'Create a host object in zabbix' + hosts: localhost + gather_facts: no + roles: + - os_zabbix + post_tasks: + + - zbxapi: + server: https://noc2.ops.rhcloud.com/zabbix/api_jsonrpc.php + zbx_class: Template + state: list + params: + host: ctr_test_kwoodson + filter: + host: + - ctr_kwoodson_test_tmpl + + register: tmpl_results + + - debug: var=tmpl_results + +#ansible-playbook -e 'oo_desc=kwoodson test' -e 'oo_name=kwoodson test name' -e 'oo_start=1435715357' -e 'oo_stop=1435718985' -e 'oo_hostids=11549' create_maintenance.yml +- name: 'Create a host object in zabbix' + hosts: localhost + gather_facts: no + roles: + - os_zabbix + post_tasks: + + - zbxapi: + server: https://noc2.ops.rhcloud.com/zabbix/api_jsonrpc.php + zbx_class: Host + state: absent + params: + host: ctr_test_kwoodson + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 127.0.0.1 + dns: "" + port: 10050 + groups: + - groupid: 1 + templates: "{{ tmpl_results.results | oo_collect('templateid') | oo_build_zabbix_list_dict('templateid') }}" + output: extend + filter: + host: + - ctr_test_kwoodson + + register: host_results + + - debug: var=host_results + diff --git a/playbooks/adhoc/noc/create_maintenance.yml b/playbooks/adhoc/noc/create_maintenance.yml new file mode 100644 index 000000000..c0ec57ce1 --- /dev/null +++ b/playbooks/adhoc/noc/create_maintenance.yml @@ -0,0 +1,36 @@ +--- +#ansible-playbook -e 'oo_desc=kwoodson test' -e 'oo_name=kwoodson test name' -e 'oo_start=1435715357' -e 'oo_stop=1435718985' -e 'oo_hostids=11549' create_maintenance.yml +- name: 'Create a maintenace object in zabbix' + hosts: localhost + gather_facts: no + roles: + - os_zabbix + vars: + oo_hostids: '' + oo_groupids: '' + post_tasks: + - assert: + that: oo_desc is defined + + - zbxapi: + server: https://noc2.ops.rhcloud.com/zabbix/api_jsonrpc.php + zbx_class: Maintenance + state: present + params: + name: "{{ oo_name }}" + description: "{{ oo_desc }}" + active_since: "{{ oo_start }}" + active_till: "{{ oo_stop }}" + maintenance_type: "0" + output: extend + hostids: "{{ oo_hostids.split(',') | default([]) }}" +#groupids: "{{ oo_groupids.split(',') | default([]) }}" + timeperiods: + - start_time: "{{ oo_start }}" + period: "{{ oo_stop }}" + selectTimeperiods: extend + + register: maintenance + + - debug: var=maintenance + diff --git a/playbooks/adhoc/noc/get_zabbix_problems.yml b/playbooks/adhoc/noc/get_zabbix_problems.yml index 02bffc1d2..4b94fa228 100644 --- a/playbooks/adhoc/noc/get_zabbix_problems.yml +++ b/playbooks/adhoc/noc/get_zabbix_problems.yml @@ -11,7 +11,7 @@ - zbxapi: server: https://noc2.ops.rhcloud.com/zabbix/api_jsonrpc.php zbx_class: Trigger - action: get + state: list params: only_true: true output: extend diff --git a/playbooks/adhoc/s3_registry/s3_registry.j2 b/playbooks/adhoc/s3_registry/s3_registry.j2 new file mode 100644 index 000000000..acfa89515 --- /dev/null +++ b/playbooks/adhoc/s3_registry/s3_registry.j2 @@ -0,0 +1,20 @@ +version: 0.1 +log: + level: debug +http: + addr: :5000 +storage: + cache: + layerinfo: inmemory + s3: + accesskey: {{ aws_access_key }} + secretkey: {{ aws_secret_key }} + region: us-east-1 + bucket: {{ clusterid }}-docker + encrypt: true + secure: true + v4auth: true + rootdirectory: /registry +middleware: + repository: + - name: openshift diff --git a/playbooks/adhoc/s3_registry/s3_registry.yml b/playbooks/adhoc/s3_registry/s3_registry.yml new file mode 100644 index 000000000..4dcef1a42 --- /dev/null +++ b/playbooks/adhoc/s3_registry/s3_registry.yml @@ -0,0 +1,71 @@ +--- +# This playbook creates an S3 bucket named after your cluster and configures the docker-registry service to use the bucket as its backend storage. +# Usage: +# ansible-playbook s3_registry.yml -e clusterid="mycluster" +# +# The AWS access/secret keys should be the keys of a separate user (not your main user), containing only the necessary S3 access role. +# The 'clusterid' is the short name of your cluster. + +- hosts: tag_env-host-type_{{ clusterid }}-openshift-master + remote_user: root + gather_facts: False + + vars: + aws_access_key: "{{ lookup('env', 'S3_ACCESS_KEY_ID') }}" + aws_secret_key: "{{ lookup('env', 'S3_SECRET_ACCESS_KEY') }}" + + tasks: + + - name: Check for AWS creds + fail: + msg: "Couldn't find {{ item }} creds in ENV" + when: "{{ item }} == ''" + with_items: + - aws_access_key + - aws_secret_key + + - name: Scale down registry + command: oc scale --replicas=0 dc/docker-registry + + - name: Create S3 bucket + local_action: + module: s3 bucket="{{ clusterid }}-docker" mode=create + + - name: Set up registry environment variable + command: oc env dc/docker-registry REGISTRY_CONFIGURATION_PATH=/etc/registryconfig/config.yml + + - name: Generate docker registry config + template: src="s3_registry.j2" dest="/root/config.yml" owner=root mode=0600 + + - name: Determine if new secrets are needed + command: oc get secrets + register: secrets + + - name: Create registry secrets + command: oc secrets new dockerregistry /root/config.yml + when: "'dockerregistry' not in secrets.stdout" + + - name: Determine if service account contains secrets + command: oc describe serviceaccount/registry + register: serviceaccount + + - name: Add secrets to registry service account + command: oc secrets add serviceaccount/registry secrets/dockerregistry + when: "'dockerregistry' not in serviceaccount.stdout" + + - name: Determine if deployment config contains secrets + command: oc volume dc/docker-registry --list + register: dc + + - name: Add secrets to registry deployment config + command: oc volume dc/docker-registry --add --name=dockersecrets -m /etc/registryconfig --type=secret --secret-name=dockerregistry + when: "'dockersecrets' not in dc.stdout" + + - name: Wait for deployment config to take effect before scaling up + pause: seconds=30 + + - name: Scale up registry + command: oc scale --replicas=1 dc/docker-registry + + - name: Delete temporary config file + file: path=/root/config.yml state=absent diff --git a/playbooks/adhoc/uninstall.yml b/playbooks/adhoc/uninstall.yml new file mode 100644 index 000000000..7d1544be8 --- /dev/null +++ b/playbooks/adhoc/uninstall.yml @@ -0,0 +1,145 @@ +# This deletes *ALL* Origin, Atomic Enterprise Platform and OpenShift +# Enterprise content installed by ansible. This includes: +# +# configuration +# containers +# example templates and imagestreams +# images +# RPMs +--- +- hosts: + - OSEv3:children + + sudo: yes + + tasks: + - name: Detecting Operating System + shell: ls /run/ostree-booted + ignore_errors: yes + failed_when: false + register: ostree_output + + - set_fact: + is_atomic: "{{ ostree_output.rc == 0 }}" + + - service: name={{ item }} state=stopped + with_items: + - atomic-enterprise-master + - atomic-enterprise-node + - atomic-openshift-master + - atomic-openshift-master-api + - atomic-openshift-master-controllers + - atomic-openshift-node + - etcd + - openshift-master + - openshift-master-api + - openshift-master-controllers + - openshift-node + - openvswitch + - origin-master + - origin-master-api + - origin-master-controllers + - origin-node + + - yum: name={{ item }} state=absent + when: not is_atomic | bool + with_items: + - atomic-enterprise + - atomic-enterprise-master + - atomic-enterprise-node + - atomic-enterprise-sdn-ovs + - atomic-openshift + - atomic-openshift-clients + - atomic-openshift-master + - atomic-openshift-node + - atomic-openshift-sdn-ovs + - etcd + - openshift + - openshift-master + - openshift-node + - openshift-sdn + - openshift-sdn-ovs + - openvswitch + - origin + - origin-master + - origin-node + - origin-sdn-ovs + - tuned-profiles-atomic-enterprise-node + - tuned-profiles-atomic-openshift-node + - tuned-profiles-openshift-node + - tuned-profiles-origin-node + + - shell: systemctl reset-failed + changed_when: False + + - shell: systemctl daemon-reload + changed_when: False + + - shell: find /var/lib/origin/openshift.local.volumes -type d -exec umount {} \; 2>/dev/null || true + changed_when: False + + - shell: find /var/lib/atomic-enterprise/openshift.local.volumes -type d -exec umount {} \; 2>/dev/null || true + changed_when: False + + - shell: find /var/lib/openshift/openshift.local.volumes -type d -exec umount {} \; 2>/dev/null || true + changed_when: False + + - shell: docker rm -f "{{ item }}"-master "{{ item }}"-node + changed_when: False + failed_when: False + with_items: + - openshift-enterprise + - atomic-enterprise + - origin + + - shell: docker ps -a | grep Exited | grep "{{ item }}" | awk '{print $1}' + changed_when: False + failed_when: False + register: exited_containers_to_delete + with_items: + - aep3/aep + - openshift3/ose + - openshift/origin + + - shell: "docker rm {{ item.stdout_lines | join(' ') }}" + changed_when: False + failed_when: False + with_items: "{{ exited_containers_to_delete.results }}" + + - shell: docker images | grep {{ item }} | awk '{ print $3 }' + changed_when: False + failed_when: False + register: images_to_delete + with_items: + - registry.access.redhat.com/openshift3 + - registry.access.redhat.com/aep3 + - docker.io/openshift + + - shell: "docker rmi -f {{ item.stdout_lines | join(' ') }}" + changed_when: False + failed_when: False + with_items: "{{ images_to_delete.results }}" + + - file: path={{ item }} state=absent + with_items: + - /etc/ansible/facts.d/openshift.fact + - /etc/atomic-enterprise + - /etc/etcd + - /etc/openshift + - /etc/openshift-sdn + - /etc/origin + - /etc/sysconfig/atomic-enterprise-master + - /etc/sysconfig/atomic-enterprise-node + - /etc/sysconfig/atomic-openshift-master + - /etc/sysconfig/atomic-openshift-node + - /etc/sysconfig/openshift-master + - /etc/sysconfig/openshift-node + - /etc/sysconfig/origin-master + - /etc/sysconfig/origin-node + - /root/.kube + - "~{{ ansible_ssh_user }}/.kube" + - /usr/share/openshift/examples + - /var/lib/atomic-enterprise + - /var/lib/etcd + - /var/lib/openshift + - /var/lib/origin diff --git a/playbooks/adhoc/upgrades/README.md b/playbooks/adhoc/upgrades/README.md new file mode 100644 index 000000000..6de8a970f --- /dev/null +++ b/playbooks/adhoc/upgrades/README.md @@ -0,0 +1,21 @@ +# [NOTE] +This playbook will re-run installation steps overwriting any local +modifications. You should ensure that your inventory has been updated with any +modifications you've made after your initial installation. If you find any items +that cannot be configured via ansible please open an issue at +https://github.com/openshift/openshift-ansible + +# Overview +This playbook is available as a technical preview. It currently performs the +following steps. + + * Upgrade and restart master services + * Upgrade and restart node services + * Applies latest configuration by re-running the installation playbook + * Applies the latest cluster policies + * Updates the default router if one exists + * Updates the default registry if one exists + * Updates image streams and quickstarts + +# Usage +ansible-playbook -i ~/ansible-inventory openshift-ansible/playbooks/adhoc/upgrades/upgrade.yml diff --git a/playbooks/adhoc/upgrades/filter_plugins b/playbooks/adhoc/upgrades/filter_plugins new file mode 120000 index 000000000..b0b7a3414 --- /dev/null +++ b/playbooks/adhoc/upgrades/filter_plugins @@ -0,0 +1 @@ +../../../filter_plugins/
\ No newline at end of file diff --git a/playbooks/adhoc/upgrades/lookup_plugins b/playbooks/adhoc/upgrades/lookup_plugins new file mode 120000 index 000000000..73cafffe5 --- /dev/null +++ b/playbooks/adhoc/upgrades/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins/
\ No newline at end of file diff --git a/playbooks/adhoc/upgrades/roles b/playbooks/adhoc/upgrades/roles new file mode 120000 index 000000000..e2b799b9d --- /dev/null +++ b/playbooks/adhoc/upgrades/roles @@ -0,0 +1 @@ +../../../roles/
\ No newline at end of file diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml new file mode 100644 index 000000000..ae1d0127c --- /dev/null +++ b/playbooks/adhoc/upgrades/upgrade.yml @@ -0,0 +1,138 @@ +--- +- name: Upgrade base package on masters + hosts: masters + roles: + - openshift_facts + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade base package + yum: pkg={{ openshift.common.service_type }}{{ openshift_version }} state=latest + +- name: Re-Run cluster configuration to apply latest configuration changes + include: ../../common/openshift-cluster/config.yml + vars: + g_etcd_group: "{{ 'etcd' }}" + g_masters_group: "{{ 'masters' }}" + g_nodes_group: "{{ 'nodes' }}" + openshift_cluster_id: "{{ cluster_id | default('default') }}" + openshift_deployment_type: "{{ deployment_type }}" + +- name: Upgrade masters + hosts: masters + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade master packages + yum: pkg={{ openshift.common.service_type }}-master{{ openshift_version }} state=latest + - name: Restart master services + service: name="{{ openshift.common.service_type}}-master" state=restarted + +- name: Upgrade nodes + hosts: nodes + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade node packages + yum: pkg={{ openshift.common.service_type }}-node{{ openshift_version }} state=latest + - name: Restart node services + service: name="{{ openshift.common.service_type }}-node" state=restarted + +- name: Determine new master version + hosts: oo_first_master + tasks: + - name: Determine new version + command: > + rpm -q --queryformat '%{version}' {{ openshift.common.service_type }}-master + register: _new_version + +- name: Ensure AOS 3.0.2 or Origin 1.0.6 + hosts: oo_first_master + tasks: + fail: This playbook requires Origin 1.0.6 or Atomic OpenShift 3.0.2 or later + when: _new_version.stdout | version_compare('1.0.6','<') or ( _new_version.stdout | version_compare('3.0','>=' and _new_version.stdout | version_compare('3.0.2','<') ) + +- name: Update cluster policy + hosts: oo_first_master + tasks: + - name: oadm policy reconcile-cluster-roles --confirm + command: > + {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig + policy reconcile-cluster-roles --confirm + +- name: Update cluster policy bindings + hosts: oo_first_master + tasks: + - name: oadm policy reconcile-cluster-role-bindings --confirm + command: > + {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig + policy reconcile-cluster-role-bindings + --exclude-groups=system:authenticated + --exclude-groups=system:unauthenticated + --exclude-users=system:anonymous + --additive-only=true --confirm + when: ( _new_version.stdout | version_compare('1.0.6', '>') and _new_version.stdout | version_compare('3.0','<') ) or _new_version.stdout | version_compare('3.0.2','>') + +- name: Upgrade default router + hosts: oo_first_master + vars: + - router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" + - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" + tasks: + - name: Check for default router + command: > + {{ oc_cmd }} get -n default dc/router + register: _default_router + failed_when: false + changed_when: false + - name: Check for allowHostNetwork and allowHostPorts + when: _default_router.rc == 0 + shell: > + {{ oc_cmd }} get -o yaml scc/privileged | /usr/bin/grep -e allowHostPorts -e allowHostNetwork + register: _scc + - name: Grant allowHostNetwork and allowHostPorts + when: + - _default_router.rc == 0 + - "'false' in _scc.stdout" + command: > + {{ oc_cmd }} patch scc/privileged -p '{"allowHostPorts":true,"allowHostNetwork":true}' --loglevel=9 + - name: Update deployment config to 1.0.4/3.0.1 spec + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"strategy":{"rollingParams":{"updatePercent":-10},"spec":{"serviceAccount":"router","serviceAccountName":"router"}}}}' + - name: Switch to hostNetwork=true + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p '{"spec":{"template":{"spec":{"hostNetwork":true}}}}' + - name: Update router image to current version + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}"}]}}}}' + +- name: Upgrade default + hosts: oo_first_master + vars: + - registry_image: "{{ openshift.master.registry_url | replace( '${component}', 'docker-registry' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" + - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" + tasks: + - name: Check for default registry + command: > + {{ oc_cmd }} get -n default dc/docker-registry + register: _default_registry + failed_when: false + changed_when: false + - name: Update registry image to current version + when: _default_registry.rc == 0 + command: > + {{ oc_cmd }} patch dc/docker-registry -p + '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' + +- name: Update image streams and templates + hosts: oo_first_master + vars: + openshift_examples_import_command: "update" + openshift_deployment_type: "{{ deployment_type }}" + roles: + - openshift_examples diff --git a/playbooks/adhoc/zabbix_setup/clean_zabbix.yml b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml new file mode 100644 index 000000000..1e884240a --- /dev/null +++ b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml @@ -0,0 +1,58 @@ +--- +- hosts: localhost + gather_facts: no + vars: + g_server: http://localhost:8080/zabbix/api_jsonrpc.php + g_user: '' + g_password: '' + + roles: + - lib_zabbix + + post_tasks: + - name: CLEAN List template for heartbeat + zbx_template: + zbx_server: "{{ g_server }}" + zbx_user: "{{ g_user }}" + zbx_password: "{{ g_password }}" + state: list + name: 'Template Heartbeat' + register: templ_heartbeat + + - name: CLEAN List template app zabbix server + zbx_template: + zbx_server: "{{ g_server }}" + zbx_user: "{{ g_user }}" + zbx_password: "{{ g_password }}" + state: list + name: 'Template App Zabbix Server' + register: templ_zabbix_server + + - name: CLEAN List template app zabbix server + zbx_template: + zbx_server: "{{ g_server }}" + zbx_user: "{{ g_user }}" + zbx_password: "{{ g_password }}" + state: list + name: 'Template App Zabbix Agent' + register: templ_zabbix_agent + + - name: CLEAN List all templates + zbx_template: + zbx_server: "{{ g_server }}" + zbx_user: "{{ g_user }}" + zbx_password: "{{ g_password }}" + state: list + register: templates + + - debug: var=templ_heartbeat.results + + - name: Remove templates if heartbeat template is missing + zbx_template: + zbx_server: "{{ g_server }}" + zbx_user: "{{ g_user }}" + zbx_password: "{{ g_password }}" + name: "{{ item }}" + state: absent + with_items: "{{ templates.results | difference(templ_zabbix_agent.results) | difference(templ_zabbix_server.results) | oo_collect('host') }}" + when: templ_heartbeat.results | length == 0 diff --git a/playbooks/adhoc/zabbix_setup/filter_plugins b/playbooks/adhoc/zabbix_setup/filter_plugins new file mode 120000 index 000000000..b0b7a3414 --- /dev/null +++ b/playbooks/adhoc/zabbix_setup/filter_plugins @@ -0,0 +1 @@ +../../../filter_plugins/
\ No newline at end of file diff --git a/playbooks/adhoc/zabbix_setup/oo-clean-zaio.yml b/playbooks/adhoc/zabbix_setup/oo-clean-zaio.yml new file mode 100755 index 000000000..0fe65b338 --- /dev/null +++ b/playbooks/adhoc/zabbix_setup/oo-clean-zaio.yml @@ -0,0 +1,7 @@ +#!/usr/bin/env ansible-playbook +--- +- include: clean_zabbix.yml + vars: + g_server: http://localhost/zabbix/api_jsonrpc.php + g_user: Admin + g_password: zabbix diff --git a/playbooks/adhoc/zabbix_setup/oo-config-zaio.yml b/playbooks/adhoc/zabbix_setup/oo-config-zaio.yml new file mode 100755 index 000000000..e2b8150c6 --- /dev/null +++ b/playbooks/adhoc/zabbix_setup/oo-config-zaio.yml @@ -0,0 +1,13 @@ +#!/usr/bin/ansible-playbook +--- +- hosts: localhost + gather_facts: no + vars: + g_server: http://localhost/zabbix/api_jsonrpc.php + g_user: Admin + g_password: zabbix + roles: + - role: os_zabbix + ozb_server: "{{ g_server }}" + ozb_user: "{{ g_user }}" + ozb_password: "{{ g_password }}" diff --git a/playbooks/aws/openshift-master/roles b/playbooks/adhoc/zabbix_setup/roles index 20c4c58cf..20c4c58cf 120000 --- a/playbooks/aws/openshift-master/roles +++ b/playbooks/adhoc/zabbix_setup/roles diff --git a/playbooks/aws/ansible-tower/launch.yml b/playbooks/aws/ansible-tower/launch.yml index 4bcc8b8dc..850238ffb 100644 --- a/playbooks/aws/ansible-tower/launch.yml +++ b/playbooks/aws/ansible-tower/launch.yml @@ -6,7 +6,7 @@ vars: inst_region: us-east-1 - rhel7_ami: ami-78756d10 + rhel7_ami: ami-9101c8fa user_data_file: user_data.txt vars_files: diff --git a/playbooks/aws/openshift-cluster/config.yml b/playbooks/aws/openshift-cluster/config.yml index 7188312ed..a8e3e27bb 100644 --- a/playbooks/aws/openshift-cluster/config.yml +++ b/playbooks/aws/openshift-cluster/config.yml @@ -1,37 +1,23 @@ --- -- name: Populate oo_masters_to_config host group - hosts: localhost +- hosts: localhost gather_facts: no vars_files: - vars.yml tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - groups: oo_masters_to_config - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | default([]) - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - groups: oo_nodes_to_config - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-node"] | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type_' ~ cluster_id ~ '-openshift-master'][0] }}" - groups: oo_first_master - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - when: "'tag_env-host-type_{{ cluster_id }}-openshift-master' in groups" + - set_fact: + g_ssh_user_tmp: "{{ deployment_vars[deployment_type].ssh_user }}" + g_sudo_tmp: "{{ deployment_vars[deployment_type].sudo }}" - include: ../../common/openshift-cluster/config.yml vars: + g_etcd_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-etcd' }}" + g_masters_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-master' }}" + g_nodes_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-node' }}" + g_ssh_user: "{{ hostvars.localhost.g_ssh_user_tmp }}" + g_sudo: "{{ hostvars.localhost.g_sudo_tmp }}" + g_nodeonmaster: true openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 + openshift_debug_level: 2 openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" openshift_hostname: "{{ ec2_private_ip_address }}" openshift_public_hostname: "{{ ec2_ip_address }}" diff --git a/playbooks/aws/openshift-cluster/launch.yml b/playbooks/aws/openshift-cluster/launch.yml index 33e1ec25d..786918929 100644 --- a/playbooks/aws/openshift-cluster/launch.yml +++ b/playbooks/aws/openshift-cluster/launch.yml @@ -11,28 +11,48 @@ msg: Deployment type not supported for aws provider yet when: deployment_type == 'enterprise' + - include: ../../common/openshift-cluster/set_etcd_launch_facts_tasks.yml + - include: tasks/launch_instances.yml + vars: + instances: "{{ etcd_names }}" + cluster: "{{ cluster_id }}" + type: "{{ k8s_type }}" + g_sub_host_type: "default" + - include: ../../common/openshift-cluster/set_master_launch_facts_tasks.yml - include: tasks/launch_instances.yml vars: instances: "{{ master_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "default" - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "compute" + count: "{{ num_nodes }}" - include: tasks/launch_instances.yml vars: instances: "{{ node_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" - - set_fact: - a_master: "{{ master_names[0] }}" - - add_host: name={{ a_master }} groups=service_master - -- include: update.yml + - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "infra" + count: "{{ num_infra }}" + - include: tasks/launch_instances.yml + vars: + instances: "{{ node_names }}" + cluster: "{{ cluster_id }}" + type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" -- include: ../../common/openshift-cluster/create_services.yml - vars: - g_svc_master: "{{ service_master }}" + - add_host: + name: "{{ master_names.0 }}" + groups: service_master + when: master_names is defined and master_names.0 is defined +- include: update.yml - include: list.yml diff --git a/playbooks/aws/openshift-cluster/library/ec2_ami_find.py b/playbooks/aws/openshift-cluster/library/ec2_ami_find.py index 29e594a65..2b1db62d8 100644 --- a/playbooks/aws/openshift-cluster/library/ec2_ami_find.py +++ b/playbooks/aws/openshift-cluster/library/ec2_ami_find.py @@ -158,7 +158,7 @@ EXAMPLES = ''' # Launch an EC2 instance - ec2: image: "{{ ami_search.results[0].ami_id }}" - instance_type: m3.medium + instance_type: m4.medium key_name: mykey wait: yes ''' diff --git a/playbooks/aws/openshift-cluster/lookup_plugins b/playbooks/aws/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/aws/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/aws/openshift-cluster/tasks/launch_instances.yml b/playbooks/aws/openshift-cluster/tasks/launch_instances.yml index 060147659..9c699120b 100644 --- a/playbooks/aws/openshift-cluster/tasks/launch_instances.yml +++ b/playbooks/aws/openshift-cluster/tasks/launch_instances.yml @@ -5,6 +5,7 @@ env: "{{ cluster }}" env_host_type: "{{ cluster }}-openshift-{{ type }}" host_type: "{{ type }}" + sub_host_type: "{{ g_sub_host_type }}" - set_fact: ec2_region: "{{ lookup('env', 'ec2_region') @@ -34,6 +35,35 @@ ec2_assign_public_ip: "{{ lookup('env', 'ec2_assign_public_ip') | default(deployment_vars[deployment_type].assign_public_ip, true) }}" when: ec2_assign_public_ip is not defined + +- set_fact: + ec2_instance_type: "{{ ec2_master_instance_type | default(deployment_vars[deployment_type].type, true) }}" + ec2_security_groups: "{{ ec2_master_security_groups + | default(deployment_vars[deployment_type].security_groups, true) }}" + when: host_type == "master" and sub_host_type == "default" + +- set_fact: + ec2_instance_type: "{{ ec2_etcd_instance_type | default(deployment_vars[deployment_type].type, true) }}" + ec2_security_groups: "{{ ec2_etcd_security_groups + | default(deployment_vars[deployment_type].security_groups, true)}}" + when: host_type == "etcd" and sub_host_type == "default" + +- set_fact: + ec2_instance_type: "{{ ec2_infra_instance_type | default(deployment_vars[deployment_type].type, true) }}" + ec2_security_groups: "{{ ec2_infra_security_groups + | default(deployment_vars[deployment_type].security_groups, true) }}" + when: host_type == "node" and sub_host_type == "infra" + +- set_fact: + ec2_instance_type: "{{ ec2_node_instance_type | default(deployment_vars[deployment_type].type, true) }}" + ec2_security_groups: "{{ ec2_node_security_groups + | default(deployment_vars[deployment_type].security_groups, true) }}" + when: host_type == "node" and sub_host_type == "compute" + +- set_fact: + ec2_instance_type: "{{ lookup('env', 'ec2_instance_type') + | default(deployment_vars[deployment_type].type, true) }}" + when: ec2_instance_type is not defined - set_fact: ec2_security_groups: "{{ lookup('env', 'ec2_security_groups') | default(deployment_vars[deployment_type].security_groups, true) }}" @@ -51,8 +81,17 @@ - set_fact: latest_ami: "{{ ami_result.results | oo_ami_selector(ec2_image_name) }}" - user_data: "{{ lookup('template', '../templates/user_data.j2') if type == 'node' else None | default('omit') }}" + user_data: "{{ lookup('template', '../templates/user_data.j2') }}" volume_defs: + etcd: + root: + volume_size: "{{ lookup('env', 'os_etcd_root_vol_size') | default(25, true) }}" + device_type: "{{ lookup('env', 'os_etcd_root_vol_type') | default('gp2', true) }}" + iops: "{{ lookup('env', 'os_etcd_root_vol_iops') | default(500, true) }}" + etcd: + volume_size: "{{ lookup('env', 'os_etcd_vol_size') | default(32, true) }}" + device_type: "{{ lookup('env', 'os_etcd_vol_type') | default('gp2', true) }}" + iops: "{{ lookup('env', 'os_etcd_vol_iops') | default(500, true) }}" master: root: volume_size: "{{ lookup('env', 'os_master_root_vol_size') | default(25, true) }}" @@ -60,7 +99,7 @@ iops: "{{ lookup('env', 'os_master_root_vol_iops') | default(500, true) }}" node: root: - volume_size: "{{ lookup('env', 'os_node_root_vol_size') | default(25, true) }}" + volume_size: "{{ lookup('env', 'os_node_root_vol_size') | default(85, true) }}" device_type: "{{ lookup('env', 'os_node_root_vol_type') | default('gp2', true) }}" iops: "{{ lookup('env', 'os_node_root_vol_iops') | default(500, true) }}" docker: @@ -90,6 +129,7 @@ env: "{{ env }}" host-type: "{{ host_type }}" env-host-type: "{{ env_host_type }}" + sub-host-type: "{{ sub_host_type }}" volumes: "{{ volumes }}" register: ec2 @@ -103,7 +143,38 @@ Name: "{{ item.0 }}" - set_fact: - instance_groups: tag_created-by_{{ created_by }}, tag_env_{{ env }}, tag_host-type_{{ host_type }}, tag_env-host-type_{{ env_host_type }} + instance_groups: "tag_created-by_{{ created_by }}, tag_env_{{ env }}, + tag_host-type_{{ host_type }}, tag_env-host-type_{{ env_host_type }}, + tag_sub-host-type_{{ sub_host_type }}" + +- set_fact: + node_label: + region: "{{ec2_region}}" + type: "{{sub_host_type}}" + when: host_type == "node" + +- set_fact: + node_label: + region: "{{ec2_region}}" + type: "{{host_type}}" + when: host_type != "node" + +- set_fact: + logrotate: + - name: syslog + path: "/var/log/cron + \n/var/log/maillog + \n/var/log/messages + \n/var/log/secure + \n/var/log/spooler \n" + options: + - daily + - rotate 7 + - compress + - sharedscripts + - missingok + scripts: + postrotate: "/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true" - name: Add new instances groups and variables add_host: @@ -114,6 +185,8 @@ groups: "{{ instance_groups }}" ec2_private_ip_address: "{{ item.1.private_ip }}" ec2_ip_address: "{{ item.1.public_ip }}" + openshift_node_labels: "{{ node_label }}" + logrotate_scripts: "{{ logrotate }}" with_together: - instances - ec2.instances diff --git a/playbooks/aws/openshift-cluster/templates/user_data.j2 b/playbooks/aws/openshift-cluster/templates/user_data.j2 index 7dbc8f552..82c2f4d57 100644 --- a/playbooks/aws/openshift-cluster/templates/user_data.j2 +++ b/playbooks/aws/openshift-cluster/templates/user_data.j2 @@ -1,17 +1,25 @@ #cloud-config -yum_repos: - jdetiber-copr: - name: Copr repo for origin owned by jdetiber - baseurl: https://copr-be.cloud.fedoraproject.org/results/jdetiber/origin/epel-7-$basearch/ - skip_if_unavailable: true - gpgcheck: true - gpgkey: https://copr-be.cloud.fedoraproject.org/results/jdetiber/origin/pubkey.gpg - enabled: true +{% if type =='etcd' %} +cloud_config_modules: +- disk_setup +- mounts -packages: -- xfsprogs # can be dropped after docker-storage-setup properly requires it: https://github.com/projectatomic/docker-storage-setup/pull/8 -- docker-storage-setup +mounts: +- [ xvdb, /var/lib/etcd, xfs, "defaults" ] + +disk_setup: + xvdb: + table_type: mbr + layout: True +fs_setup: +- label: etcd_storage + filesystem: xfs + device: /dev/xvdb + partition: auto +{% endif %} + +{% if type == 'node' %} mounts: - [ xvdb ] - [ ephemeral0 ] @@ -23,7 +31,15 @@ write_files: path: /etc/sysconfig/docker-storage-setup owner: root:root permissions: '0644' +{% endif %} + +{% if deployment_type == 'online' %} +devices: ['/var'] # Workaround for https://bugs.launchpad.net/bugs/1455436 +disable_root: 0 +growpart: + mode: auto + devices: ['/var'] runcmd: -- systemctl daemon-reload -- systemctl enable lvm2-lvmetad.service docker-storage-setup.service +- xfs_growfs /var +{% endif %} diff --git a/playbooks/aws/openshift-cluster/terminate.yml b/playbooks/aws/openshift-cluster/terminate.yml index 617d0d456..77287cad0 100644 --- a/playbooks/aws/openshift-cluster/terminate.yml +++ b/playbooks/aws/openshift-cluster/terminate.yml @@ -13,4 +13,63 @@ ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" with_items: groups[scratch_group] | default([]) | difference(['localhost']) -- include: ../terminate.yml +- name: Unsubscribe VMs + hosts: oo_hosts_to_terminate + roles: + - role: rhel_unsubscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] + +- name: Terminate instances + hosts: localhost + connection: local + gather_facts: no + vars: + host_vars: "{{ hostvars + | oo_select_keys(groups['oo_hosts_to_terminate']) }}" + tasks: + - name: Remove tags from instances + ec2_tag: resource={{ item.ec2_id }} region={{ item.ec2_region }} state=absent + args: + tags: + env: "{{ item['ec2_tag_env'] }}" + host-type: "{{ item['ec2_tag_host-type'] }}" + env-host-type: "{{ item['ec2_tag_env-host-type'] }}" + sub_host_type: "{{ item['ec2_tag_sub-host-type'] }}" + with_items: host_vars + when: "'oo_hosts_to_terminate' in groups" + + - name: Terminate instances + ec2: + state: absent + instance_ids: ["{{ item.ec2_id }}"] + region: "{{ item.ec2_region }}" + ignore_errors: yes + register: ec2_term + with_items: host_vars + when: "'oo_hosts_to_terminate' in groups" + + # Fail if any of the instances failed to terminate with an error other + # than 403 Forbidden + - fail: msg=Terminating instance {{ item.ec2_id }} failed with message {{ item.msg }} + when: "'oo_hosts_to_terminate' in groups and item.failed and not item.msg | search(\"error: EC2ResponseError: 403 Forbidden\")" + with_items: ec2_term.results + + - name: Stop instance if termination failed + ec2: + state: stopped + instance_ids: ["{{ item.item.ec2_id }}"] + region: "{{ item.item.ec2_region }}" + register: ec2_stop + when: "'oo_hosts_to_terminate' in groups and item.failed" + with_items: ec2_term.results + + - name: Rename stopped instances + ec2_tag: resource={{ item.item.item.ec2_id }} region={{ item.item.item.ec2_region }} state=present + args: + tags: + Name: "{{ item.item.item.ec2_tag_Name }}-terminate" + with_items: ec2_stop.results + when: "'oo_hosts_to_terminate' in groups" diff --git a/playbooks/aws/openshift-cluster/update.yml b/playbooks/aws/openshift-cluster/update.yml index 5e7ab4e58..e006aa74a 100644 --- a/playbooks/aws/openshift-cluster/update.yml +++ b/playbooks/aws/openshift-cluster/update.yml @@ -11,7 +11,9 @@ groups: oo_hosts_to_update ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-node"]) | default([]) + with_items: (groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | default([])) + | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-node"] | default([])) + | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-etcd"] | default([])) - include: ../../common/openshift-cluster/update_repos_and_packages.yml diff --git a/playbooks/aws/openshift-cluster/vars.online.int.yml b/playbooks/aws/openshift-cluster/vars.online.int.yml index e115615d5..2e2f25ccd 100644 --- a/playbooks/aws/openshift-cluster/vars.online.int.yml +++ b/playbooks/aws/openshift-cluster/vars.online.int.yml @@ -1,9 +1,15 @@ --- -ec2_image: ami-78756d10 +ec2_image: ami-9101c8fa ec2_image_name: libra-ops-rhel7* ec2_region: us-east-1 ec2_keypair: mmcgrath_libra -ec2_instance_type: m3.large -ec2_security_groups: [ 'int-v3' ] +ec2_master_instance_type: t2.medium +ec2_master_security_groups: [ 'integration', 'integration-master' ] +ec2_infra_instance_type: c4.large +ec2_infra_security_groups: [ 'integration', 'integration-infra' ] +ec2_node_instance_type: m4.large +ec2_node_security_groups: [ 'integration', 'integration-node' ] +ec2_etcd_instance_type: m4.large +ec2_etcd_security_groups: [ 'integration', 'integration-etcd' ] ec2_vpc_subnet: subnet-987c0def ec2_assign_public_ip: yes diff --git a/playbooks/aws/openshift-cluster/vars.online.prod.yml b/playbooks/aws/openshift-cluster/vars.online.prod.yml index e115615d5..18a53e12e 100644 --- a/playbooks/aws/openshift-cluster/vars.online.prod.yml +++ b/playbooks/aws/openshift-cluster/vars.online.prod.yml @@ -1,9 +1,15 @@ --- -ec2_image: ami-78756d10 +ec2_image: ami-9101c8fa ec2_image_name: libra-ops-rhel7* ec2_region: us-east-1 ec2_keypair: mmcgrath_libra -ec2_instance_type: m3.large -ec2_security_groups: [ 'int-v3' ] +ec2_master_instance_type: t2.medium +ec2_master_security_groups: [ 'production', 'production-master' ] +ec2_infra_instance_type: c4.large +ec2_infra_security_groups: [ 'production', 'production-infra' ] +ec2_node_instance_type: m4.large +ec2_node_security_groups: [ 'production', 'production-node' ] +ec2_etcd_instance_type: m4.large +ec2_etcd_security_groups: [ 'production', 'production-etcd' ] ec2_vpc_subnet: subnet-987c0def ec2_assign_public_ip: yes diff --git a/playbooks/aws/openshift-cluster/vars.online.stage.yml b/playbooks/aws/openshift-cluster/vars.online.stage.yml index e115615d5..1f9ac4252 100644 --- a/playbooks/aws/openshift-cluster/vars.online.stage.yml +++ b/playbooks/aws/openshift-cluster/vars.online.stage.yml @@ -1,9 +1,15 @@ --- -ec2_image: ami-78756d10 +ec2_image: ami-9101c8fa ec2_image_name: libra-ops-rhel7* ec2_region: us-east-1 ec2_keypair: mmcgrath_libra -ec2_instance_type: m3.large -ec2_security_groups: [ 'int-v3' ] +ec2_master_instance_type: t2.medium +ec2_master_security_groups: [ 'stage', 'stage-master' ] +ec2_infra_instance_type: c4.large +ec2_infra_security_groups: [ 'stage', 'stage-infra' ] +ec2_node_instance_type: m4.large +ec2_node_security_groups: [ 'stage', 'stage-node' ] +ec2_etcd_instance_type: m4.large +ec2_etcd_security_groups: [ 'stage', 'stage-etcd' ] ec2_vpc_subnet: subnet-987c0def ec2_assign_public_ip: yes diff --git a/playbooks/aws/openshift-cluster/vars.yml b/playbooks/aws/openshift-cluster/vars.yml index 07e453f89..95bc4b3e2 100644 --- a/playbooks/aws/openshift-cluster/vars.yml +++ b/playbooks/aws/openshift-cluster/vars.yml @@ -1,14 +1,14 @@ --- deployment_vars: origin: - # fedora, since centos requires marketplace - image: ami-acd999c4 + # centos-7, requires marketplace + image: ami-96a818fe image_name: region: us-east-1 - ssh_user: fedora + ssh_user: centos sudo: yes keypair: libra - type: m3.large + type: m4.large security_groups: [ 'public' ] vpc_subnet: assign_public_ip: @@ -20,7 +20,7 @@ deployment_vars: ssh_user: root sudo: no keypair: libra - type: m3.large + type: m4.large security_groups: [ 'public' ] vpc_subnet: assign_public_ip: @@ -32,7 +32,7 @@ deployment_vars: ssh_user: ec2-user sudo: yes keypair: libra - type: m3.large + type: m4.large security_groups: [ 'public' ] vpc_subnet: assign_public_ip: diff --git a/playbooks/aws/openshift-master/config.yml b/playbooks/aws/openshift-master/config.yml deleted file mode 100644 index 37ab4fbe6..000000000 --- a/playbooks/aws/openshift-master/config.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -- name: Populate oo_masters_to_config host group - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - groups: oo_masters_to_config - ansible_ssh_user: root - with_items: oo_host_group_exp | default([]) - -- include: ../../common/openshift-master/config.yml - vars: - openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" - openshift_hostname: "{{ ec2_private_ip_address }}" - openshift_public_hostname: "{{ ec2_ip_address }}" diff --git a/playbooks/aws/openshift-master/launch.yml b/playbooks/aws/openshift-master/launch.yml deleted file mode 100644 index 1cefad492..000000000 --- a/playbooks/aws/openshift-master/launch.yml +++ /dev/null @@ -1,70 +0,0 @@ ---- -- name: Launch instance(s) - hosts: localhost - connection: local - gather_facts: no - -# TODO: modify g_ami based on deployment_type - vars: - inst_region: us-east-1 - g_ami: ami-86781fee - user_data_file: user_data.txt - - tasks: - - name: Launch instances - ec2: - state: present - region: "{{ inst_region }}" - keypair: libra - group: ['public'] - instance_type: m3.large - image: "{{ g_ami }}" - count: "{{ oo_new_inst_names | length }}" - user_data: "{{ lookup('file', user_data_file) }}" - wait: yes - register: ec2 - - - name: Add new instances public IPs to the host group - add_host: "hostname={{ item.public_ip }} groupname=new_ec2_instances" - with_items: ec2.instances - - - name: Add Name and environment tags to instances - ec2_tag: "resource={{ item.1.id }} region={{ inst_region }} state=present" - with_together: - - oo_new_inst_names - - ec2.instances - args: - tags: - Name: "{{ item.0 }}" - - - name: Add other tags to instances - ec2_tag: resource={{ item.id }} region={{ inst_region }} state=present - with_items: ec2.instances - args: - tags: "{{ oo_new_inst_tags }}" - - - name: Add new instances public IPs to oo_masters_to_config - add_host: - hostname: "{{ item.0 }}" - ansible_ssh_host: "{{ item.1.dns_name }}" - groupname: oo_masters_to_config - ec2_private_ip_address: "{{ item.1.private_ip }}" - ec2_ip_address: "{{ item.1.public_ip }}" - with_together: - - oo_new_inst_names - - ec2.instances - - - name: Wait for ssh - wait_for: port=22 host={{ item.dns_name }} - with_items: ec2.instances - - - name: Wait for root user setup - command: "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null root@{{ item.dns_name }} echo root user is setup" - register: result - until: result.rc == 0 - retries: 20 - delay: 10 - with_items: ec2.instances - -# Apply the configs, seprate so that just the configs can be run by themselves -- include: config.yml diff --git a/playbooks/aws/openshift-master/terminate.yml b/playbooks/aws/openshift-master/terminate.yml deleted file mode 100644 index 07d9961bc..000000000 --- a/playbooks/aws/openshift-master/terminate.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -- include: ../terminate.yml diff --git a/playbooks/aws/openshift-node/config.yml b/playbooks/aws/openshift-node/config.yml deleted file mode 100644 index a993a1e99..000000000 --- a/playbooks/aws/openshift-node/config.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Populate oo_nodes_to_config and oo_first_master host groups - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - groups: oo_nodes_to_config - ansible_ssh_user: root - with_items: oo_host_group_exp | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type_' ~ cluster_id ~ '-openshift-master'][0] }}" - groups: oo_first_master - ansible_ssh_user: root - - -- include: ../../common/openshift-node/config.yml - vars: - openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" - openshift_hostname: "{{ ec2_private_ip_address }}" - openshift_public_hostname: "{{ ec2_ip_address }}" diff --git a/playbooks/aws/openshift-node/launch.yml b/playbooks/aws/openshift-node/launch.yml deleted file mode 100644 index e7d1f7310..000000000 --- a/playbooks/aws/openshift-node/launch.yml +++ /dev/null @@ -1,72 +0,0 @@ ---- -- name: Launch instance(s) - hosts: localhost - connection: local - gather_facts: no - -# TODO: modify g_ami based on deployment_type - vars: - inst_region: us-east-1 - g_ami: ami-86781fee - user_data_file: user_data.txt - - tasks: - - name: Launch instances - ec2: - state: present - region: "{{ inst_region }}" - keypair: libra - group: ['public'] - instance_type: m3.large - image: "{{ g_ami }}" - count: "{{ oo_new_inst_names | length }}" - user_data: "{{ lookup('file', user_data_file) }}" - wait: yes - register: ec2 - - - name: Add new instances public IPs to the host group - add_host: - hostname: "{{ item.public_ip }}" - groupname: new_ec2_instances" - with_items: ec2.instances - - - name: Add Name and environment tags to instances - ec2_tag: resource={{ item.1.id }} region={{ inst_region }} state=present - with_together: - - oo_new_inst_names - - ec2.instances - args: - tags: - Name: "{{ item.0 }}" - - - name: Add other tags to instances - ec2_tag: resource={{ item.id }} region={{ inst_region }} state=present - with_items: ec2.instances - args: - tags: "{{ oo_new_inst_tags }}" - - - name: Add new instances public IPs to oo_nodes_to_config - add_host: - hostname: "{{ item.0 }}" - ansible_ssh_host: "{{ item.1.dns_name }}" - groupname: oo_nodes_to_config - ec2_private_ip_address: "{{ item.1.private_ip }}" - ec2_ip_address: "{{ item.1.public_ip }}" - with_together: - - oo_new_inst_names - - ec2.instances - - - name: Wait for ssh - wait_for: port=22 host={{ item.dns_name }} - with_items: ec2.instances - - - name: Wait for root user setup - command: "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null root@{{ item.dns_name }} echo root user is setup" - register: result - until: result.rc == 0 - retries: 20 - delay: 10 - with_items: ec2.instances - -# Apply the configs, seprate so that just the configs can be run by themselves -- include: config.yml diff --git a/playbooks/aws/openshift-node/terminate.yml b/playbooks/aws/openshift-node/terminate.yml deleted file mode 100644 index 07d9961bc..000000000 --- a/playbooks/aws/openshift-node/terminate.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -- include: ../terminate.yml diff --git a/playbooks/aws/terminate.yml b/playbooks/aws/terminate.yml deleted file mode 100644 index e9767b260..000000000 --- a/playbooks/aws/terminate.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- -- name: Populate oo_hosts_to_terminate host group - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_hosts_to_terminate - add_host: name={{ item }} groups=oo_hosts_to_terminate - with_items: oo_host_group_exp | default([]) - -- name: Gather dynamic inventory variables for hosts to terminate - hosts: oo_hosts_to_terminate - gather_facts: no - -- name: Terminate instances - hosts: localhost - connection: local - gather_facts: no - vars: - host_vars: "{{ hostvars - | oo_select_keys(groups['oo_hosts_to_terminate']) }}" - tasks: - - name: Remove tags from instances - ec2_tag: resource={{ item.ec2_id }} region={{ item.ec2_region }} state=absent - args: - tags: - env: "{{ item['ec2_tag_env'] }}" - host-type: "{{ item['ec2_tag_host-type'] }}" - env-host-type: "{{ item['ec2_tag_env-host-type'] }}" - with_items: host_vars - when: "'oo_hosts_to_terminate' in groups" - - - name: Terminate instances - ec2: - state: absent - instance_ids: ["{{ item.ec2_id }}"] - region: "{{ item.ec2_region }}" - ignore_errors: yes - register: ec2_term - with_items: host_vars - when: "'oo_hosts_to_terminate' in groups" - - # Fail if any of the instances failed to terminate with an error other - # than 403 Forbidden - - fail: msg=Terminating instance {{ item.item.ec2_id }} failed with message {{ item.msg }} - when: "'oo_hosts_to_terminate' in groups and item.failed and not item.msg | search(\"error: EC2ResponseError: 403 Forbidden\")" - with_items: ec2_term.results - - - name: Stop instance if termination failed - ec2: - state: stopped - instance_ids: ["{{ item.item.ec2_id }}"] - region: "{{ item.item.ec2_region }}" - register: ec2_stop - when: item.failed - with_items: ec2_term.results - when: "'oo_hosts_to_terminate' in groups" - - - name: Rename stopped instances - ec2_tag: resource={{ item.item.item.ec2_id }} region={{ item.item.item.ec2_region }} state=present - args: - tags: - Name: "{{ item.item.item.ec2_tag_Name }}-terminate" - with_items: ec2_stop.results - when: "'oo_hosts_to_terminate' in groups" diff --git a/playbooks/byo/config.yml b/playbooks/byo/config.yml index e059514db..7d03914a2 100644 --- a/playbooks/byo/config.yml +++ b/playbooks/byo/config.yml @@ -1,8 +1,2 @@ --- -- name: Run the openshift-master config playbook - include: openshift-master/config.yml - when: groups.masters is defined and groups.masters - -- name: Run the openshift-node config playbook - include: openshift-node/config.yml - when: groups.nodes is defined and groups.nodes and groups.masters is defined and groups.masters +- include: openshift-cluster/config.yml diff --git a/playbooks/byo/lookup_plugins b/playbooks/byo/lookup_plugins new file mode 120000 index 000000000..c528bcd1d --- /dev/null +++ b/playbooks/byo/lookup_plugins @@ -0,0 +1 @@ +../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/byo/openshift-cluster/config.yml b/playbooks/byo/openshift-cluster/config.yml new file mode 100644 index 000000000..9e50a4a18 --- /dev/null +++ b/playbooks/byo/openshift-cluster/config.yml @@ -0,0 +1,9 @@ +--- +- include: ../../common/openshift-cluster/config.yml + vars: + g_etcd_group: "{{ 'etcd' }}" + g_masters_group: "{{ 'masters' }}" + g_nodes_group: "{{ 'nodes' }}" + openshift_cluster_id: "{{ cluster_id | default('default') }}" + openshift_debug_level: 2 + openshift_deployment_type: "{{ deployment_type }}" diff --git a/playbooks/aws/openshift-master/filter_plugins b/playbooks/byo/openshift-cluster/filter_plugins index 99a95e4ca..99a95e4ca 120000 --- a/playbooks/aws/openshift-master/filter_plugins +++ b/playbooks/byo/openshift-cluster/filter_plugins diff --git a/playbooks/byo/openshift-cluster/lookup_plugins b/playbooks/byo/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/byo/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/aws/openshift-node/roles b/playbooks/byo/openshift-cluster/roles index 20c4c58cf..20c4c58cf 120000 --- a/playbooks/aws/openshift-node/roles +++ b/playbooks/byo/openshift-cluster/roles diff --git a/playbooks/byo/openshift-master/config.yml b/playbooks/byo/openshift-master/config.yml deleted file mode 100644 index f61d277c6..000000000 --- a/playbooks/byo/openshift-master/config.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Populate oo_masters_to_config host group - hosts: localhost - gather_facts: no - tasks: - - add_host: - name: "{{ item }}" - groups: oo_masters_to_config - with_items: groups['masters'] - -- include: ../../common/openshift-master/config.yml - vars: - openshift_cluster_id: "{{ cluster_id | default('default') }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" diff --git a/playbooks/byo/openshift-master/filter_plugins b/playbooks/byo/openshift-master/filter_plugins deleted file mode 120000 index 99a95e4ca..000000000 --- a/playbooks/byo/openshift-master/filter_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../filter_plugins
\ No newline at end of file diff --git a/playbooks/byo/openshift-master/roles b/playbooks/byo/openshift-master/roles deleted file mode 120000 index 20c4c58cf..000000000 --- a/playbooks/byo/openshift-master/roles +++ /dev/null @@ -1 +0,0 @@ -../../../roles
\ No newline at end of file diff --git a/playbooks/byo/openshift-node/config.yml b/playbooks/byo/openshift-node/config.yml deleted file mode 100644 index f50903061..000000000 --- a/playbooks/byo/openshift-node/config.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -- name: Populate oo_nodes_to_config and oo_first_master host groups - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - groups: oo_nodes_to_config - with_items: groups.nodes - - name: Evaluate oo_first_master - add_host: - name: "{{ item }}" - groups: oo_first_master - with_items: groups.masters.0 - - -- include: ../../common/openshift-node/config.yml - vars: - openshift_first_master: "{{ groups.masters.0 }}" - openshift_cluster_id: "{{ cluster_id | default('default') }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" diff --git a/playbooks/byo/openshift-node/filter_plugins b/playbooks/byo/openshift-node/filter_plugins deleted file mode 120000 index 99a95e4ca..000000000 --- a/playbooks/byo/openshift-node/filter_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../filter_plugins
\ No newline at end of file diff --git a/playbooks/byo/openshift-node/roles b/playbooks/byo/openshift-node/roles deleted file mode 120000 index 20c4c58cf..000000000 --- a/playbooks/byo/openshift-node/roles +++ /dev/null @@ -1 +0,0 @@ -../../../roles
\ No newline at end of file diff --git a/playbooks/byo/openshift_facts.yml b/playbooks/byo/openshift_facts.yml index cd282270f..6d7c12fd4 100644 --- a/playbooks/byo/openshift_facts.yml +++ b/playbooks/byo/openshift_facts.yml @@ -1,5 +1,5 @@ --- -- name: Gather OpenShift facts +- name: Gather Cluster facts hosts: all gather_facts: no roles: diff --git a/playbooks/byo/rhel_subscribe.yml b/playbooks/byo/rhel_subscribe.yml new file mode 100644 index 000000000..f564905ea --- /dev/null +++ b/playbooks/byo/rhel_subscribe.yml @@ -0,0 +1,12 @@ +--- +- hosts: all + vars: + openshift_deployment_type: "{{ deployment_type }}" + roles: + - role: rhel_subscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] + - openshift_repos + - os_update_latest diff --git a/playbooks/byo/vagrant.yml b/playbooks/byo/vagrant.yml new file mode 100644 index 000000000..76246e7b0 --- /dev/null +++ b/playbooks/byo/vagrant.yml @@ -0,0 +1,4 @@ +--- +- include: rhel_subscribe.yml + +- include: config.yml diff --git a/playbooks/common/openshift-cluster/config.yml b/playbooks/common/openshift-cluster/config.yml index 14ffa928f..4c74f96db 100644 --- a/playbooks/common/openshift-cluster/config.yml +++ b/playbooks/common/openshift-cluster/config.yml @@ -1,4 +1,74 @@ --- +- name: Populate config host groups + hosts: localhost + gather_facts: no + tasks: + - fail: + msg: This playbook rquires g_etcd_group to be set + when: g_etcd_group is not defined + + - fail: + msg: This playbook rquires g_masters_group to be set + when: g_masters_group is not defined + + - fail: + msg: This playbook rquires g_nodes_group to be set + when: g_nodes_group is not defined + + - name: Evaluate oo_etcd_to_config + add_host: + name: "{{ item }}" + groups: oo_etcd_to_config + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + with_items: groups[g_etcd_group] | default([]) + + - name: Evaluate oo_masters_to_config + add_host: + name: "{{ item }}" + groups: oo_masters_to_config + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + with_items: groups[g_masters_group] | default([]) + + - name: Evaluate oo_nodes_to_config + add_host: + name: "{{ item }}" + groups: oo_nodes_to_config + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + with_items: groups[g_nodes_group] | default([]) + + - name: Evaluate oo_nodes_to_config + add_host: + name: "{{ item }}" + groups: oo_nodes_to_config + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + with_items: groups[g_masters_group] | default([]) + when: g_nodeonmaster is defined and g_nodeonmaster == true + + - name: Evaluate oo_first_etcd + add_host: + name: "{{ groups[g_etcd_group][0] }}" + groups: oo_first_etcd + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + when: g_etcd_group in groups and (groups[g_etcd_group] | length) > 0 + + - name: Evaluate oo_first_master + add_host: + name: "{{ groups[g_masters_group][0] }}" + groups: oo_first_master + ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" + ansible_sudo: "{{ g_sudo | default(omit) }}" + when: g_masters_group in groups and (groups[g_masters_group] | length) > 0 + +- include: ../openshift-etcd/config.yml + - include: ../openshift-master/config.yml - include: ../openshift-node/config.yml + vars: + osn_cluster_dns_domain: "{{ hostvars[groups.oo_first_master.0].openshift.dns.domain }}" + osn_cluster_dns_ip: "{{ hostvars[groups.oo_first_master.0].openshift.dns.ip }}" diff --git a/playbooks/common/openshift-cluster/create_services.yml b/playbooks/common/openshift-cluster/create_services.yml deleted file mode 100644 index e70709d19..000000000 --- a/playbooks/common/openshift-cluster/create_services.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- name: Deploy OpenShift Services - hosts: "{{ g_svc_master }}" - connection: ssh - gather_facts: yes - roles: - - openshift_registry - - openshift_router diff --git a/playbooks/common/openshift-cluster/lookup_plugins b/playbooks/common/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/common/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/common/openshift-cluster/set_etcd_launch_facts_tasks.yml b/playbooks/common/openshift-cluster/set_etcd_launch_facts_tasks.yml new file mode 100644 index 000000000..1a6580795 --- /dev/null +++ b/playbooks/common/openshift-cluster/set_etcd_launch_facts_tasks.yml @@ -0,0 +1,13 @@ +--- +- set_fact: k8s_type="etcd" + +- name: Generate etcd instance names(s) + set_fact: + scratch_name: "{{ cluster_id }}-{{ k8s_type }}-{{ '%05x' | format(1048576 | random) }}" + register: etcd_names_output + with_sequence: count={{ num_etcd }} + +- set_fact: + etcd_names: "{{ etcd_names_output.results | default([]) + | oo_collect('ansible_facts') + | oo_collect('scratch_name') }}" diff --git a/playbooks/common/openshift-cluster/set_master_launch_facts_tasks.yml b/playbooks/common/openshift-cluster/set_master_launch_facts_tasks.yml index 118727273..36d7b7870 100644 --- a/playbooks/common/openshift-cluster/set_master_launch_facts_tasks.yml +++ b/playbooks/common/openshift-cluster/set_master_launch_facts_tasks.yml @@ -5,7 +5,9 @@ set_fact: scratch_name: "{{ cluster_id }}-{{ k8s_type }}-{{ '%05x' | format(1048576 | random) }}" register: master_names_output - with_sequence: start=1 end={{ num_masters }} + with_sequence: count={{ num_masters }} - set_fact: - master_names: "{{ master_names_output.results | oo_collect('ansible_facts') | oo_collect('scratch_name') }}" + master_names: "{{ master_names_output.results | default([]) + | oo_collect('ansible_facts') + | oo_collect('scratch_name') }}" diff --git a/playbooks/common/openshift-cluster/set_node_launch_facts_tasks.yml b/playbooks/common/openshift-cluster/set_node_launch_facts_tasks.yml index 162315d46..278942f8b 100644 --- a/playbooks/common/openshift-cluster/set_node_launch_facts_tasks.yml +++ b/playbooks/common/openshift-cluster/set_node_launch_facts_tasks.yml @@ -1,11 +1,15 @@ --- -- set_fact: k8s_type="node" +- set_fact: k8s_type=node +- set_fact: sub_host_type="{{ type }}" +- set_fact: number_nodes="{{ count }}" - name: Generate node instance names(s) set_fact: - scratch_name: "{{ cluster_id }}-{{ k8s_type }}-{{ '%05x' | format(1048576 | random) }}" + scratch_name: "{{ cluster_id }}-{{ k8s_type }}-{{ sub_host_type }}-{{ '%05x' | format(1048576 | random) }}" register: node_names_output - with_sequence: start=1 end={{ num_nodes }} + with_sequence: count={{ number_nodes }} - set_fact: - node_names: "{{ node_names_output.results | oo_collect('ansible_facts') | oo_collect('scratch_name') }}" + node_names: "{{ node_names_output.results | default([]) + | oo_collect('ansible_facts') + | oo_collect('scratch_name') }}" diff --git a/playbooks/common/openshift-cluster/update_repos_and_packages.yml b/playbooks/common/openshift-cluster/update_repos_and_packages.yml index e92c6f1ee..190e2d862 100644 --- a/playbooks/common/openshift-cluster/update_repos_and_packages.yml +++ b/playbooks/common/openshift-cluster/update_repos_and_packages.yml @@ -3,5 +3,10 @@ vars: openshift_deployment_type: "{{ deployment_type }}" roles: + - role: rhel_subscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] - openshift_repos - os_update_latest diff --git a/playbooks/common/openshift-etcd/config.yml b/playbooks/common/openshift-etcd/config.yml new file mode 100644 index 000000000..952960652 --- /dev/null +++ b/playbooks/common/openshift-etcd/config.yml @@ -0,0 +1,97 @@ +--- +- name: Set etcd facts needed for generating certs + hosts: oo_etcd_to_config + roles: + - openshift_facts + tasks: + - openshift_facts: + role: "{{ item.role }}" + local_facts: "{{ item.local_facts }}" + with_items: + - role: common + local_facts: + hostname: "{{ openshift_hostname | default(None) }}" + public_hostname: "{{ openshift_public_hostname | default(None) }}" + deployment_type: "{{ openshift_deployment_type }}" + - name: Check status of etcd certificates + stat: + path: "{{ item }}" + with_items: + - /etc/etcd/server.crt + - /etc/etcd/peer.crt + - /etc/etcd/ca.crt + register: g_etcd_server_cert_stat_result + - set_fact: + etcd_server_certs_missing: "{{ g_etcd_server_cert_stat_result.results | map(attribute='stat.exists') + | list | intersect([false])}}" + etcd_cert_subdir: etcd-{{ openshift.common.hostname }} + etcd_cert_config_dir: /etc/etcd + etcd_cert_prefix: + +- name: Create temp directory for syncing certs + hosts: localhost + connection: local + sudo: false + gather_facts: no + tasks: + - name: Create local temp directory for syncing certs + local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX + register: g_etcd_mktemp + changed_when: False + +- name: Configure etcd certificates + hosts: oo_first_etcd + vars: + etcd_generated_certs_dir: /etc/etcd/generated_certs + etcd_needing_server_certs: "{{ hostvars + | oo_select_keys(groups['oo_etcd_to_config']) + | oo_filter_list(filter_attr='etcd_server_certs_missing') }}" + sync_tmpdir: "{{ hostvars.localhost.g_etcd_mktemp.stdout }}" + roles: + - etcd_certificates + post_tasks: + - name: Create a tarball of the etcd certs + command: > + tar -czvf {{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz + -C {{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }} . + args: + creates: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz" + with_items: etcd_needing_server_certs + - name: Retrieve the etcd cert tarballs + fetch: + src: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz" + dest: "{{ sync_tmpdir }}/" + flat: yes + fail_on_missing: yes + validate_checksum: yes + with_items: etcd_needing_server_certs + +- name: Configure etcd hosts + hosts: oo_etcd_to_config + vars: + sync_tmpdir: "{{ hostvars.localhost.g_etcd_mktemp.stdout }}" + etcd_url_scheme: https + etcd_peer_url_scheme: https + etcd_peers_group: oo_etcd_to_config + pre_tasks: + - name: Ensure certificate directory exists + file: + path: "{{ etcd_cert_config_dir }}" + state: directory + - name: Unarchive the tarball on the etcd host + unarchive: + src: "{{ sync_tmpdir }}/{{ etcd_cert_subdir }}.tgz" + dest: "{{ etcd_cert_config_dir }}" + when: etcd_server_certs_missing + roles: + - etcd + - role: nickhammond.logrotate + +- name: Delete temporary directory on localhost + hosts: localhost + connection: local + sudo: false + gather_facts: no + tasks: + - file: name={{ g_etcd_mktemp.stdout }} state=absent + changed_when: False diff --git a/playbooks/aws/openshift-node/filter_plugins b/playbooks/common/openshift-etcd/filter_plugins index 99a95e4ca..99a95e4ca 120000 --- a/playbooks/aws/openshift-node/filter_plugins +++ b/playbooks/common/openshift-etcd/filter_plugins diff --git a/playbooks/common/openshift-etcd/lookup_plugins b/playbooks/common/openshift-etcd/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/common/openshift-etcd/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/common/openshift-etcd/roles b/playbooks/common/openshift-etcd/roles new file mode 120000 index 000000000..e2b799b9d --- /dev/null +++ b/playbooks/common/openshift-etcd/roles @@ -0,0 +1 @@ +../../../roles/
\ No newline at end of file diff --git a/playbooks/common/openshift-etcd/service.yml b/playbooks/common/openshift-etcd/service.yml new file mode 100644 index 000000000..0bf69b22f --- /dev/null +++ b/playbooks/common/openshift-etcd/service.yml @@ -0,0 +1,18 @@ +--- +- name: Populate g_service_masters host group if needed + hosts: localhost + gather_facts: no + tasks: + - fail: msg="new_cluster_state is required to be injected in this playbook" + when: new_cluster_state is not defined + + - name: Evaluate g_service_etcd + add_host: name={{ item }} groups=g_service_etcd + with_items: oo_host_group_exp | default([]) + +- name: Change etcd state on etcd instance(s) + hosts: g_service_etcd + connection: ssh + gather_facts: no + tasks: + - service: name=etcd state="{{ new_cluster_state }}" diff --git a/playbooks/common/openshift-master/config.yml b/playbooks/common/openshift-master/config.yml index 052ed14c7..1dec923fc 100644 --- a/playbooks/common/openshift-master/config.yml +++ b/playbooks/common/openshift-master/config.yml @@ -1,18 +1,280 @@ --- +- name: Set master facts and determine if external etcd certs need to be generated + hosts: oo_masters_to_config + pre_tasks: + - name: Check for RPM generated config marker file .config_managed + stat: + path: /etc/origin/.config_managed + register: rpmgenerated_config + + - name: Remove RPM generated config files if present + file: + path: "/etc/origin/{{ item }}" + state: absent + when: rpmgenerated_config.stat.exists == true and deployment_type in ['openshift-enterprise', 'atomic-enterprise'] + with_items: + - master + - node + - .config_managed + + - set_fact: + openshift_master_etcd_port: "{{ (etcd_client_port | default('2379')) if (groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config) else none }}" + openshift_master_etcd_hosts: "{{ hostvars + | oo_select_keys(groups['oo_etcd_to_config'] + | default([])) + | oo_collect('openshift.common.hostname') + | default(none, true) }}" + roles: + - openshift_facts + post_tasks: + - openshift_facts: + role: "{{ item.role }}" + local_facts: "{{ item.local_facts }}" + with_items: + - role: common + local_facts: + hostname: "{{ openshift_hostname | default(None) }}" + public_hostname: "{{ openshift_public_hostname | default(None) }}" + deployment_type: "{{ openshift_deployment_type }}" + - role: master + local_facts: + api_port: "{{ openshift_master_api_port | default(None) }}" + api_url: "{{ openshift_master_api_url | default(None) }}" + api_use_ssl: "{{ openshift_master_api_use_ssl | default(None) }}" + public_api_url: "{{ openshift_master_public_api_url | default(None) }}" + cluster_hostname: "{{ openshift_master_cluster_hostname | default(None) }}" + cluster_public_hostname: "{{ openshift_master_cluster_public_hostname | default(None) }}" + cluster_defer_ha: "{{ openshift_master_cluster_defer_ha | default(None) }}" + console_path: "{{ openshift_master_console_path | default(None) }}" + console_port: "{{ openshift_master_console_port | default(None) }}" + console_url: "{{ openshift_master_console_url | default(None) }}" + console_use_ssl: "{{ openshift_master_console_use_ssl | default(None) }}" + public_console_url: "{{ openshift_master_public_console_url | default(None) }}" + - name: Check status of external etcd certificatees + stat: + path: "{{ openshift.common.config_base }}/master/{{ item }}" + with_items: + - master.etcd-client.crt + - master.etcd-ca.crt + register: g_external_etcd_cert_stat_result + - set_fact: + etcd_client_certs_missing: "{{ g_external_etcd_cert_stat_result.results + | map(attribute='stat.exists') + | list | intersect([false])}}" + etcd_cert_subdir: openshift-master-{{ openshift.common.hostname }} + etcd_cert_config_dir: "{{ openshift.common.config_base }}/master" + etcd_cert_prefix: master.etcd- + when: groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config + +- name: Create temp directory for syncing certs + hosts: localhost + connection: local + sudo: false + gather_facts: no + tasks: + - name: Create local temp directory for syncing certs + local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX + register: g_master_mktemp + changed_when: False + +- name: Configure etcd certificates + hosts: oo_first_etcd + vars: + etcd_generated_certs_dir: /etc/etcd/generated_certs + etcd_needing_client_certs: "{{ hostvars + | oo_select_keys(groups['oo_masters_to_config']) + | oo_filter_list(filter_attr='etcd_client_certs_missing') }}" + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + roles: + - etcd_certificates + post_tasks: + - name: Create a tarball of the etcd certs + command: > + tar -czvf {{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz + -C {{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }} . + args: + creates: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz" + with_items: etcd_needing_client_certs + - name: Retrieve the etcd cert tarballs + fetch: + src: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}.tgz" + dest: "{{ sync_tmpdir }}/" + flat: yes + fail_on_missing: yes + validate_checksum: yes + with_items: etcd_needing_client_certs + +- name: Copy the external etcd certs to the masters + hosts: oo_masters_to_config + vars: + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + tasks: + - name: Ensure certificate directory exists + file: + path: "{{ openshift.common.config_base }}/master" + state: directory + when: etcd_client_certs_missing is defined and etcd_client_certs_missing + - name: Unarchive the tarball on the master + unarchive: + src: "{{ sync_tmpdir }}/{{ etcd_cert_subdir }}.tgz" + dest: "{{ etcd_cert_config_dir }}" + when: etcd_client_certs_missing is defined and etcd_client_certs_missing + - file: + path: "{{ etcd_cert_config_dir }}/{{ item }}" + owner: root + group: root + mode: 0600 + with_items: + - master.etcd-client.crt + - master.etcd-client.key + - master.etcd-ca.crt + when: etcd_client_certs_missing is defined and etcd_client_certs_missing + +- name: Determine if master certificates need to be generated + hosts: oo_masters_to_config + tasks: + - set_fact: + openshift_master_certs_no_etcd: + - admin.crt + - master.kubelet-client.crt + - "{{ 'master.proxy-client.crt' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}" + - master.server.crt + - openshift-master.crt + - openshift-registry.crt + - openshift-router.crt + - etcd.server.crt + openshift_master_certs_etcd: + - master.etcd-client.crt + + - set_fact: + openshift_master_certs: "{{ (openshift_master_certs_no_etcd | union(openshift_master_certs_etcd)) if (groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config) else openshift_master_certs_no_etcd }}" + + - name: Check status of master certificates + stat: + path: "{{ openshift.common.config_base }}/master/{{ item }}" + with_items: openshift_master_certs + register: g_master_cert_stat_result + - set_fact: + master_certs_missing: "{{ False in (g_master_cert_stat_result.results + | map(attribute='stat.exists') + | list ) }}" + master_cert_subdir: master-{{ openshift.common.hostname }} + master_cert_config_dir: "{{ openshift.common.config_base }}/master" + +- name: Configure master certificates + hosts: oo_first_master + vars: + master_generated_certs_dir: "{{ openshift.common.config_base }}/generated-configs" + masters_needing_certs: "{{ hostvars + | oo_select_keys(groups['oo_masters_to_config'] | difference(groups['oo_first_master'])) + | oo_filter_list(filter_attr='master_certs_missing') }}" + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + roles: + - openshift_master_certificates + post_tasks: + - name: Remove generated etcd client certs when using external etcd + file: + path: "{{ master_generated_certs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}" + state: absent + when: groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config + with_nested: + - masters_needing_certs + - - master.etcd-client.crt + - master.etcd-client.key + + - name: Create a tarball of the master certs + command: > + tar -czvf {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz + -C {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }} . + args: + creates: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz" + with_items: masters_needing_certs + + - name: Retrieve the master cert tarball from the master + fetch: + src: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz" + dest: "{{ sync_tmpdir }}/" + flat: yes + fail_on_missing: yes + validate_checksum: yes + with_items: masters_needing_certs + - name: Configure master instances hosts: oo_masters_to_config + vars: + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + openshift_master_ha: "{{ groups.oo_masters_to_config | length > 1 }}" + embedded_etcd: "{{ openshift.master.embedded_etcd }}" + pre_tasks: + - name: Ensure certificate directory exists + file: + path: "{{ openshift.common.config_base }}/master" + state: directory + when: master_certs_missing and 'oo_first_master' not in group_names + - name: Unarchive the tarball on the master + unarchive: + src: "{{ sync_tmpdir }}/{{ master_cert_subdir }}.tgz" + dest: "{{ master_cert_config_dir }}" + when: master_certs_missing and 'oo_first_master' not in group_names roles: - openshift_master + - role: nickhammond.logrotate - role: fluentd_master when: openshift.common.use_fluentd | bool - tasks: + post_tasks: - name: Create group for deployment type group_by: key=oo_masters_deployment_type_{{ openshift.common.deployment_type }} changed_when: False +- name: Additional master configuration + hosts: oo_first_master + vars: + openshift_master_ha: "{{ groups.oo_masters_to_config | length > 1 }}" + omc_cluster_hosts: "{{ groups.oo_masters_to_config | join(' ')}}" + roles: + - role: openshift_master_cluster + when: openshift_master_ha | bool + - openshift_examples + - role: openshift_cluster_metrics + when: openshift.common.use_cluster_metrics | bool + +- name: Enable cockpit + hosts: oo_first_master + vars: + cockpit_plugins: "{{ osm_cockpit_plugins | default(['cockpit-kubernetes']) }}" + roles: + - role: cockpit + when: ( deployment_type in ['atomic-enterprise','openshift-enterprise'] ) and + (osm_use_cockpit | bool or osm_use_cockpit is undefined ) + # Additional instance config for online deployments - name: Additional instance config hosts: oo_masters_deployment_type_online roles: - pods - os_env_extras + +- name: Delete temporary directory on localhost + hosts: localhost + connection: local + sudo: false + gather_facts: no + tasks: + - file: name={{ g_master_mktemp.stdout }} state=absent + changed_when: False + +- name: Configure service accounts + hosts: oo_first_master + + vars: + accounts: ["router", "registry"] + + roles: + - openshift_serviceaccounts + +- name: Create services + hosts: oo_first_master + roles: + - role: openshift_router + when: openshift.master.infra_nodes is defined + #- role: openshift_registry diff --git a/playbooks/common/openshift-master/lookup_plugins b/playbooks/common/openshift-master/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/common/openshift-master/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/common/openshift-master/service.yml b/playbooks/common/openshift-master/service.yml index 5636ad156..27e1e66f9 100644 --- a/playbooks/common/openshift-master/service.yml +++ b/playbooks/common/openshift-master/service.yml @@ -10,9 +10,9 @@ add_host: name={{ item }} groups=g_service_masters with_items: oo_host_group_exp | default([]) -- name: Change openshift-master state on master instance(s) +- name: Change state on master instance(s) hosts: g_service_masters connection: ssh gather_facts: no tasks: - - service: name=openshift-master state="{{ new_cluster_state }}" + - service: name={{ openshift.common.service_type }}-master state="{{ new_cluster_state }}" diff --git a/playbooks/common/openshift-node/config.yml b/playbooks/common/openshift-node/config.yml index 9e642f3d3..a14ca8e11 100644 --- a/playbooks/common/openshift-node/config.yml +++ b/playbooks/common/openshift-node/config.yml @@ -18,26 +18,26 @@ deployment_type: "{{ openshift_deployment_type }}" - role: node local_facts: - resources_cpu: "{{ openshift_node_resources_cpu | default(None) }}" - resources_memory: "{{ openshift_node_resources_memory | default(None) }}" - pod_cidr: "{{ openshift_node_pod_cidr | default(None) }}" labels: "{{ openshift_node_labels | default(None) }}" annotations: "{{ openshift_node_annotations | default(None) }}" + schedulable: "{{ openshift_schedulable | default(openshift_scheduleable) | default(None) }}" - name: Check status of node certificates stat: - path: "{{ item }}" + path: "{{ openshift.common.config_base }}/node/{{ item }}" with_items: - - "/etc/openshift/node/node.key" - - "/etc/openshift/node/node.kubeconfig" - - "/etc/openshift/node/ca.crt" - - "/etc/openshift/node/server.key" + - "system:node:{{ openshift.common.hostname }}.crt" + - "system:node:{{ openshift.common.hostname }}.key" + - "system:node:{{ openshift.common.hostname }}.kubeconfig" + - ca.crt + - server.key + - server.crt register: stat_result - set_fact: certs_missing: "{{ stat_result.results | map(attribute='stat.exists') | list | intersect([false])}}" node_subdir: node-{{ openshift.common.hostname }} - config_dir: /etc/openshift/generated-configs/node-{{ openshift.common.hostname }} - node_cert_dir: /etc/openshift/node + config_dir: "{{ openshift.common.config_base }}/generated-configs/node-{{ openshift.common.hostname }}" + node_cert_dir: "{{ openshift.common.config_base }}/node" - name: Create temp directory for syncing certs hosts: localhost @@ -50,17 +50,16 @@ register: mktemp changed_when: False -- name: Register nodes +- name: Create node certificates hosts: oo_first_master vars: nodes_needing_certs: "{{ hostvars - | oo_select_keys(groups['oo_nodes_to_config']) + | oo_select_keys(groups['oo_nodes_to_config'] + | default([])) | oo_filter_list(filter_attr='certs_missing') }}" - openshift_nodes: "{{ hostvars - | oo_select_keys(groups['oo_nodes_to_config']) }}" sync_tmpdir: "{{ hostvars.localhost.mktemp.stdout }}" roles: - - openshift_register_nodes + - openshift_node_certificates post_tasks: - name: Create a tarball of the node config directories command: > @@ -84,16 +83,16 @@ hosts: oo_nodes_to_config vars: sync_tmpdir: "{{ hostvars.localhost.mktemp.stdout }}" - openshift_node_master_api_url: "{{ hostvars[openshift_first_master].openshift.master.api_url }}" + openshift_node_master_api_url: "{{ hostvars[groups.oo_first_master.0].openshift.master.api_url }}" pre_tasks: - name: Ensure certificate directory exists file: path: "{{ node_cert_dir }}" state: directory - # TODO: notify restart openshift-node + # TODO: notify restart node # possibly test service started time against certificate/config file - # timestamps in openshift-node to trigger notify + # timestamps in node to trigger notify - name: Unarchive the tarball on the node unarchive: src: "{{ sync_tmpdir }}/{{ node_subdir }}.tgz" @@ -101,6 +100,7 @@ when: certs_missing roles: - openshift_node + - role: nickhammond.logrotate - role: fluentd_node when: openshift.common.use_fluentd | bool tasks: @@ -108,15 +108,6 @@ group_by: key=oo_nodes_deployment_type_{{ openshift.common.deployment_type }} changed_when: False -- name: Delete the temporary directory on the master - hosts: oo_first_master - gather_facts: no - vars: - sync_tmpdir: "{{ hostvars.localhost.mktemp.stdout }}" - tasks: - - file: name={{ sync_tmpdir }} state=absent - changed_when: False - - name: Delete temporary directory on localhost hosts: localhost connection: local @@ -133,3 +124,15 @@ roles: - os_env_extras - os_env_extras_node + +- name: Set schedulability + hosts: oo_first_master + vars: + openshift_nodes: "{{ hostvars + | oo_select_keys(groups['oo_nodes_to_config']) + | oo_collect('openshift.common.hostname') }}" + openshift_node_vars: "{{ hostvars | oo_select_keys(groups['oo_nodes_to_config']) }}" + pre_tasks: + + roles: + - openshift_manage_node diff --git a/playbooks/common/openshift-node/lookup_plugins b/playbooks/common/openshift-node/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/common/openshift-node/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/common/openshift-node/service.yml b/playbooks/common/openshift-node/service.yml index f76df089f..5cf83e186 100644 --- a/playbooks/common/openshift-node/service.yml +++ b/playbooks/common/openshift-node/service.yml @@ -10,9 +10,9 @@ add_host: name={{ item }} groups=g_service_nodes with_items: oo_host_group_exp | default([]) -- name: Change openshift-node state on node instance(s) +- name: Change state on node instance(s) hosts: g_service_nodes connection: ssh gather_facts: no tasks: - - service: name=openshift-node state="{{ new_cluster_state }}" + - service: name={{ service_type }}-node state="{{ new_cluster_state }}" diff --git a/playbooks/gce/openshift-cluster/config.yml b/playbooks/gce/openshift-cluster/config.yml index 8c320dbd2..6ca4f7395 100644 --- a/playbooks/gce/openshift-cluster/config.yml +++ b/playbooks/gce/openshift-cluster/config.yml @@ -1,38 +1,29 @@ --- # TODO: fix firewall related bug with GCE and origin, since GCE is overriding # /etc/sysconfig/iptables -- name: Populate oo_masters_to_config host group - hosts: localhost + +- hosts: localhost gather_facts: no vars_files: - vars.yml tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - groups: oo_masters_to_config - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | default([]) - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - groups: oo_nodes_to_config - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-node"] | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type-' ~ cluster_id ~ '-openshift-master'][0] }}" - groups: oo_first_master - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - when: "'tag_env-host-type-{{ cluster_id }}-openshift-master' in groups" + - set_fact: + g_ssh_user_tmp: "{{ deployment_vars[deployment_type].ssh_user }}" + g_sudo_tmp: "{{ deployment_vars[deployment_type].sudo }}" + use_sdn: "{{ do_we_use_openshift_sdn }}" + sdn_plugin: "{{ sdn_network_plugin }}" - include: ../../common/openshift-cluster/config.yml vars: + g_etcd_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-etcd' }}" + g_masters_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-master' }}" + g_nodes_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-node' }}" + g_ssh_user: "{{ hostvars.localhost.g_ssh_user_tmp }}" + g_sudo: "{{ hostvars.localhost.g_sudo_tmp }}" + g_nodeonmaster: true openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 + openshift_debug_level: 2 openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" openshift_hostname: "{{ gce_private_ip }}" + openshift_use_openshift_sdn: "{{ hostvars.localhost.use_sdn }}" + os_sdn_network_plugin_name: "{{ hostvars.localhost.sdn_plugin }}" diff --git a/playbooks/gce/openshift-cluster/join_node.yml b/playbooks/gce/openshift-cluster/join_node.yml new file mode 100644 index 000000000..0dfa3e9d7 --- /dev/null +++ b/playbooks/gce/openshift-cluster/join_node.yml @@ -0,0 +1,49 @@ +--- +- name: Populate oo_hosts_to_update group + hosts: localhost + gather_facts: no + vars_files: + - vars.yml + tasks: + - name: Evaluate oo_hosts_to_update + add_host: + name: "{{ node_ip }}" + groups: oo_hosts_to_update + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + +- include: ../../common/openshift-cluster/update_repos_and_packages.yml + +- name: Populate oo_masters_to_config host group + hosts: localhost + gather_facts: no + vars_files: + - vars.yml + tasks: + - name: Evaluate oo_nodes_to_config + add_host: + name: "{{ node_ip }}" + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + groups: oo_nodes_to_config + + - name: Evaluate oo_first_master + add_host: + name: "{{ groups['tag_env-host-type-' ~ cluster_id ~ '-openshift-master'][0] }}" + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + groups: oo_first_master + when: "'tag_env-host-type-{{ cluster_id }}-openshift-master' in groups" + +#- include: config.yml +- include: ../../common/openshift-node/config.yml + vars: + openshift_cluster_id: "{{ cluster_id }}" + openshift_debug_level: 4 + openshift_deployment_type: "{{ deployment_type }}" + openshift_hostname: "{{ ansible_default_ipv4.address }}" + openshift_use_openshift_sdn: true + openshift_node_labels: "{{ lookup('oo_option', 'openshift_node_labels') }} " + os_sdn_network_plugin_name: "redhat/openshift-ovs-subnet" + osn_cluster_dns_domain: "{{ hostvars[groups.oo_first_master.0].openshift.dns.domain }}" + osn_cluster_dns_ip: "{{ hostvars[groups.oo_first_master.0].openshift.dns.ip }}" diff --git a/playbooks/gce/openshift-cluster/launch.yml b/playbooks/gce/openshift-cluster/launch.yml index 35737f03d..c22b897d5 100644 --- a/playbooks/gce/openshift-cluster/launch.yml +++ b/playbooks/gce/openshift-cluster/launch.yml @@ -15,30 +15,47 @@ instances: "{{ master_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "default" - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "compute" + count: "{{ num_nodes }}" - include: tasks/launch_instances.yml vars: instances: "{{ node_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" - - set_fact: - a_master: "{{ master_names[0] }}" - - add_host: name={{ a_master }} groups=service_master - -- include: update.yml + - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "infra" + count: "{{ num_infra }}" + - include: tasks/launch_instances.yml + vars: + instances: "{{ node_names }}" + cluster: "{{ cluster_id }}" + type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" -- name: Deploy OpenShift Services - hosts: service_master - connection: ssh - gather_facts: yes - roles: - - openshift_registry - - openshift_router + - add_host: + name: "{{ master_names.0 }}" + groups: service_master + when: master_names is defined and master_names.0 is defined -- include: ../../common/openshift-cluster/create_services.yml - vars: - g_svc_master: "{{ service_master }}" +- include: update.yml +# +#- name: Deploy OpenShift Services +# hosts: service_master +# connection: ssh +# gather_facts: yes +# roles: +# - openshift_registry +# - openshift_router +# +#- include: ../../common/openshift-cluster/create_services.yml +# vars: +# g_svc_master: "{{ service_master }}" - include: list.yml diff --git a/playbooks/gce/openshift-cluster/list.yml b/playbooks/gce/openshift-cluster/list.yml index 5ba0f5a48..53b2b9a5e 100644 --- a/playbooks/gce/openshift-cluster/list.yml +++ b/playbooks/gce/openshift-cluster/list.yml @@ -14,11 +14,11 @@ groups: oo_list_hosts ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups[scratch_group] | default([]) | difference(['localhost']) | difference(groups.status_terminated) + with_items: groups[scratch_group] | default([], true) | difference(['localhost']) | difference(groups.status_terminated | default([], true)) - name: List instance(s) hosts: oo_list_hosts gather_facts: no tasks: - debug: - msg: "public ip:{{ hostvars[inventory_hostname].gce_public_ip }} private ip:{{ hostvars[inventory_hostname].gce_private_ip }}" + msg: "private ip:{{ hostvars[inventory_hostname].gce_private_ip }}" diff --git a/playbooks/gce/openshift-cluster/lookup_plugins b/playbooks/gce/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/gce/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/gce/openshift-cluster/tasks/launch_instances.yml b/playbooks/gce/openshift-cluster/tasks/launch_instances.yml index 9a9848f05..c428cb465 100644 --- a/playbooks/gce/openshift-cluster/tasks/launch_instances.yml +++ b/playbooks/gce/openshift-cluster/tasks/launch_instances.yml @@ -10,13 +10,33 @@ service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" project_id: "{{ lookup('env', 'gce_project_id') }}" + zone: "{{ lookup('env', 'zone') }}" + network: "{{ lookup('env', 'network') }}" +# unsupported in 1.9.+ + #service_account_permissions: "datastore,logging-write" tags: - created-by-{{ lookup('env', 'LOGNAME') |default(cluster, true) }} - env-{{ cluster }} - host-type-{{ type }} + - sub-host-type-{{ g_sub_host_type }} - env-host-type-{{ cluster }}-openshift-{{ type }} + when: instances |length > 0 register: gce +- set_fact: + node_label: + # There doesn't seem to be a way to get the region directly, so parse it out of the zone. + region: "{{ gce.zone | regex_replace('^(.*)-.*$', '\\\\1') }}" + type: "{{ g_sub_host_type }}" + when: instances |length > 0 and type == "node" + +- set_fact: + node_label: + # There doesn't seem to be a way to get the region directly, so parse it out of the zone. + region: "{{ gce.zone | regex_replace('^(.*)-.*$', '\\\\1') }}" + type: "{{ type }}" + when: instances |length > 0 and type != "node" + - name: Add new instances to groups and set variables needed add_host: hostname: "{{ item.name }}" @@ -26,16 +46,17 @@ groups: "{{ item.tags | oo_prepend_strings_in_list('tag_') | join(',') }}" gce_public_ip: "{{ item.public_ip }}" gce_private_ip: "{{ item.private_ip }}" - with_items: gce.instance_data + openshift_node_labels: "{{ node_label }}" + with_items: gce.instance_data | default([], true) - name: Wait for ssh wait_for: port=22 host={{ item.public_ip }} - with_items: gce.instance_data + with_items: gce.instance_data | default([], true) - name: Wait for user setup command: "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null {{ hostvars[item.name].ansible_ssh_user }}@{{ item.public_ip }} echo {{ hostvars[item.name].ansible_ssh_user }} user is setup" register: result until: result.rc == 0 - retries: 20 - delay: 10 - with_items: gce.instance_data + retries: 30 + delay: 5 + with_items: gce.instance_data | default([], true) diff --git a/playbooks/gce/openshift-cluster/terminate.yml b/playbooks/gce/openshift-cluster/terminate.yml index abe6a4c95..e20e0a8bc 100644 --- a/playbooks/gce/openshift-cluster/terminate.yml +++ b/playbooks/gce/openshift-cluster/terminate.yml @@ -1,34 +1,58 @@ --- - name: Terminate instance(s) hosts: localhost + connection: local gather_facts: no vars_files: - vars.yml tasks: - - set_fact: scratch_group=tag_env-host-type-{{ cluster_id }}-openshift-node + - set_fact: scratch_group=tag_env-{{ cluster_id }} - add_host: name: "{{ item }}" - groups: oo_nodes_to_terminate + groups: oo_hosts_to_terminate ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups[scratch_group] | default([]) | difference(['localhost']) | difference(groups.status_terminated) + with_items: groups[scratch_group] | default([], true) | difference(['localhost']) | difference(groups.status_terminated | default([], true)) - - set_fact: scratch_group=tag_env-host-type-{{ cluster_id }}-openshift-master - - add_host: - name: "{{ item }}" - groups: oo_masters_to_terminate - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups[scratch_group] | default([]) | difference(['localhost']) | difference(groups.status_terminated) +- name: Unsubscribe VMs + hosts: oo_hosts_to_terminate + vars_files: + - vars.yml + roles: + - role: rhel_unsubscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] + +- name: Terminate instances(s) + hosts: localhost + connection: local + gather_facts: no + vars_files: + - vars.yml + tasks: -- include: ../openshift-node/terminate.yml - vars: - gce_service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" - gce_pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" - gce_project_id: "{{ lookup('env', 'gce_project_id') }}" + - name: Terminate instances that were previously launched + local_action: + module: gce + state: 'absent' + name: "{{ item }}" + service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" + pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" + project_id: "{{ lookup('env', 'gce_project_id') }}" + zone: "{{ lookup('env', 'zone') }}" + with_items: groups['oo_hosts_to_terminate'] | default([], true) + when: item is defined -- include: ../openshift-master/terminate.yml - vars: - gce_service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" - gce_pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" - gce_project_id: "{{ lookup('env', 'gce_project_id') }}" +#- include: ../openshift-node/terminate.yml +# vars: +# gce_service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" +# gce_pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" +# gce_project_id: "{{ lookup('env', 'gce_project_id') }}" +# +#- include: ../openshift-master/terminate.yml +# vars: +# gce_service_account_email: "{{ lookup('env', 'gce_service_account_email_address') }}" +# gce_pem_file: "{{ lookup('env', 'gce_service_account_pem_file_path') }}" +# gce_project_id: "{{ lookup('env', 'gce_project_id') }}" diff --git a/playbooks/gce/openshift-cluster/update.yml b/playbooks/gce/openshift-cluster/update.yml index 9ebf39a13..8096aa654 100644 --- a/playbooks/gce/openshift-cluster/update.yml +++ b/playbooks/gce/openshift-cluster/update.yml @@ -11,7 +11,9 @@ groups: oo_hosts_to_update ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user | default(ansible_ssh_user, true) }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-node"]) | default([]) + with_items: (groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | default([])) + | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-node"] | default([])) + | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-etcd"] | default([])) - include: ../../common/openshift-cluster/update_repos_and_packages.yml diff --git a/playbooks/gce/openshift-cluster/vars.yml b/playbooks/gce/openshift-cluster/vars.yml index ae33083b9..6de007807 100644 --- a/playbooks/gce/openshift-cluster/vars.yml +++ b/playbooks/gce/openshift-cluster/vars.yml @@ -1,8 +1,11 @@ --- +do_we_use_openshift_sdn: true +sdn_network_plugin: redhat/openshift-ovs-subnet +# os_sdn_network_plugin_name can be ovssubnet or multitenant, see https://docs.openshift.org/latest/architecture/additional_concepts/sdn.html#ovssubnet-plugin-operation deployment_vars: origin: - image: centos-7 - ssh_user: + image: preinstalled-slave-50g-v5 + ssh_user: root sudo: yes online: image: libra-rhel7 @@ -12,4 +15,3 @@ deployment_vars: image: rhel-7 ssh_user: sudo: yes - diff --git a/playbooks/gce/openshift-master/config.yml b/playbooks/gce/openshift-master/config.yml deleted file mode 100644 index af6000bc8..000000000 --- a/playbooks/gce/openshift-master/config.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- name: Populate oo_masters_to_config host group - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - groups: oo_masters_to_config - ansible_ssh_user: root - with_items: oo_host_group_exp | default([]) - -- include: ../../common/openshift-master/config.yml - vars: - openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" - openshift_hostname: "{{ gce_private_ip }}" diff --git a/playbooks/gce/openshift-master/filter_plugins b/playbooks/gce/openshift-master/filter_plugins deleted file mode 120000 index 99a95e4ca..000000000 --- a/playbooks/gce/openshift-master/filter_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../filter_plugins
\ No newline at end of file diff --git a/playbooks/gce/openshift-master/launch.yml b/playbooks/gce/openshift-master/launch.yml deleted file mode 100644 index ef10b6cf0..000000000 --- a/playbooks/gce/openshift-master/launch.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -# TODO: when we are ready to go to ansible 1.9+ support only, we can update to -# the gce task to use the disk_auto_delete parameter to avoid having to delete -# the disk as a separate step on termination - -- name: Launch instance(s) - hosts: localhost - connection: local - gather_facts: no - -# TODO: modify image based on deployment_type - vars: - inst_names: "{{ oo_new_inst_names }}" - machine_type: n1-standard-1 - image: libra-rhel7 - - tasks: - - name: Launch instances - gce: - instance_names: "{{ inst_names }}" - machine_type: "{{ machine_type }}" - image: "{{ image }}" - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - tags: "{{ oo_new_inst_tags }}" - register: gce - - - name: Add new instances public IPs to oo_masters_to_config - add_host: - hostname: "{{ item.name }}" - ansible_ssh_host: "{{ item.public_ip }}" - groupname: oo_masters_to_config - gce_private_ip: "{{ item.private_ip }}" - with_items: gce.instance_data - - - name: Wait for ssh - wait_for: port=22 host={{ item.public_ip }} - with_items: gce.instance_data - - - name: Wait for root user setup - command: "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null root@{{ item.public_ip }} echo root user is setup" - register: result - until: result.rc == 0 - retries: 20 - delay: 10 - with_items: gce.instance_data - - -# Apply the configs, separate so that just the configs can be run by themselves -- include: config.yml diff --git a/playbooks/gce/openshift-master/roles b/playbooks/gce/openshift-master/roles deleted file mode 120000 index 20c4c58cf..000000000 --- a/playbooks/gce/openshift-master/roles +++ /dev/null @@ -1 +0,0 @@ -../../../roles
\ No newline at end of file diff --git a/playbooks/gce/openshift-master/terminate.yml b/playbooks/gce/openshift-master/terminate.yml deleted file mode 100644 index 452ac5199..000000000 --- a/playbooks/gce/openshift-master/terminate.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -- name: Populate oo_masters_to_terminate host group if needed - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_masters_to_terminate - add_host: name={{ item }} groups=oo_masters_to_terminate - with_items: oo_host_group_exp | default([]) - -- name: Terminate master instances - hosts: localhost - connection: local - gather_facts: no - tasks: - - name: Terminate master instances - gce: - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - state: 'absent' - instance_names: "{{ groups['oo_masters_to_terminate'] }}" - disks: "{{ groups['oo_masters_to_terminate'] }}" - register: gce - when: "'oo_masters_to_terminate' in groups" - - - name: Remove disks of instances - gce_pd: - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - name: "{{ item }}" - zone: "{{ gce.zone }}" - state: absent - with_items: gce.instance_names - when: "'oo_masters_to_terminate' in groups" diff --git a/playbooks/gce/openshift-node/config.yml b/playbooks/gce/openshift-node/config.yml deleted file mode 100644 index 54b0da2ca..000000000 --- a/playbooks/gce/openshift-node/config.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -- name: Populate oo_nodes_to_config and oo_first_master host groups - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - groups: oo_nodes_to_config - ansible_ssh_user: root - with_items: oo_host_group_exp | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type-' ~ cluster_id ~ '-openshift-master'][0] }}" - groups: oo_first_master - ansible_ssh_user: root - - -- include: ../../common/openshift-node/config.yml - vars: - openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 - openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" - openshift_hostname: "{{ gce_private_ip }}" diff --git a/playbooks/gce/openshift-node/filter_plugins b/playbooks/gce/openshift-node/filter_plugins deleted file mode 120000 index 99a95e4ca..000000000 --- a/playbooks/gce/openshift-node/filter_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../filter_plugins
\ No newline at end of file diff --git a/playbooks/gce/openshift-node/launch.yml b/playbooks/gce/openshift-node/launch.yml deleted file mode 100644 index 086ba58bc..000000000 --- a/playbooks/gce/openshift-node/launch.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -# TODO: when we are ready to go to ansible 1.9+ support only, we can update to -# the gce task to use the disk_auto_delete parameter to avoid having to delete -# the disk as a separate step on termination - -- name: Launch instance(s) - hosts: localhost - connection: local - gather_facts: no - -# TODO: modify image based on deployment_type - vars: - inst_names: "{{ oo_new_inst_names }}" - machine_type: n1-standard-1 - image: libra-rhel7 - - tasks: - - name: Launch instances - gce: - instance_names: "{{ inst_names }}" - machine_type: "{{ machine_type }}" - image: "{{ image }}" - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - tags: "{{ oo_new_inst_tags }}" - register: gce - - - name: Add new instances public IPs to oo_nodes_to_config - add_host: - hostname: "{{ item.name }}" - ansible_ssh_host: "{{ item.public_ip }}" - groupname: oo_nodes_to_config - gce_private_ip: "{{ item.private_ip }}" - with_items: gce.instance_data - - - name: Wait for ssh - wait_for: port=22 host={{ item.public_ip }} - with_items: gce.instance_data - - - name: Wait for root user setup - command: "ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null root@{{ item.public_ip }} echo root user is setup" - register: result - until: result.rc == 0 - retries: 20 - delay: 10 - with_items: gce.instance_data - - -# Apply the configs, separate so that just the configs can be run by themselves -- include: config.yml diff --git a/playbooks/gce/openshift-node/roles b/playbooks/gce/openshift-node/roles deleted file mode 120000 index 20c4c58cf..000000000 --- a/playbooks/gce/openshift-node/roles +++ /dev/null @@ -1 +0,0 @@ -../../../roles
\ No newline at end of file diff --git a/playbooks/gce/openshift-node/terminate.yml b/playbooks/gce/openshift-node/terminate.yml deleted file mode 100644 index 357e0c295..000000000 --- a/playbooks/gce/openshift-node/terminate.yml +++ /dev/null @@ -1,35 +0,0 @@ ---- -- name: Populate oo_nodes_to_terminate host group if needed - hosts: localhost - gather_facts: no - tasks: - - name: Evaluate oo_nodes_to_terminate - add_host: name={{ item }} groups=oo_nodes_to_terminate - with_items: oo_host_group_exp | default([]) - -- name: Terminate node instances - hosts: localhost - connection: local - gather_facts: no - tasks: - - name: Terminate node instances - gce: - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - state: 'absent' - instance_names: "{{ groups['oo_nodes_to_terminate'] }}" - disks: "{{ groups['oo_nodes_to_terminate'] }}" - register: gce - when: "'oo_nodes_to_terminate' in groups" - - - name: Remove disks of instances - gce_pd: - service_account_email: "{{ gce_service_account_email }}" - pem_file: "{{ gce_pem_file }}" - project_id: "{{ gce_project_id }}" - name: "{{ item }}" - zone: "{{ gce.zone }}" - state: absent - with_items: gce.instance_names - when: "'oo_nodes_to_terminate' in groups" diff --git a/playbooks/libvirt/openshift-cluster/config.yml b/playbooks/libvirt/openshift-cluster/config.yml index 75e2005a2..c208eee81 100644 --- a/playbooks/libvirt/openshift-cluster/config.yml +++ b/playbooks/libvirt/openshift-cluster/config.yml @@ -3,37 +3,22 @@ # is localhost, so no hostname value (or public_hostname) value is getting # assigned -- name: Populate oo_masters_to_config host group - hosts: localhost +- hosts: localhost gather_facts: no vars_files: - vars.yml tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_masters_to_config - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | default([]) - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_nodes_to_config - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-node"] | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type-' ~ cluster_id ~ '-openshift-master'][0] }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_first_master - when: "'tag_env-host-type-{{ cluster_id }}-openshift-master' in groups" + - set_fact: + g_ssh_user_tmp: "{{ deployment_vars[deployment_type].ssh_user }}" + g_sudo_tmp: "{{ deployment_vars[deployment_type].sudo }}" - include: ../../common/openshift-cluster/config.yml vars: + g_etcd_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-etcd' }}" + g_masters_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-master' }}" + g_nodes_group: "{{ 'tag_env-host-type-' ~ cluster_id ~ '-openshift-node' }}" + g_ssh_user: "{{ hostvars.localhost.g_ssh_user_tmp }}" + g_sudo: "{{ hostvars.localhost.g_sudo_tmp }}" openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 + openshift_debug_level: 2 openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" diff --git a/playbooks/libvirt/openshift-cluster/launch.yml b/playbooks/libvirt/openshift-cluster/launch.yml index a7ddc1e7e..d3e768de5 100644 --- a/playbooks/libvirt/openshift-cluster/launch.yml +++ b/playbooks/libvirt/openshift-cluster/launch.yml @@ -13,23 +13,47 @@ image_name: "{{ deployment_vars[deployment_type].image.name }}" tasks: - fail: msg="Deployment type not supported for libvirt provider yet" - when: deployment_type in ['online', 'enterprise'] + when: deployment_type == 'online' - include: tasks/configure_libvirt.yml + - include: ../../common/openshift-cluster/set_etcd_launch_facts_tasks.yml + - include: tasks/launch_instances.yml + vars: + instances: "{{ etcd_names }}" + cluster: "{{ cluster_id }}" + type: "{{ k8s_type }}" + g_sub_host_type: "default" + - include: ../../common/openshift-cluster/set_master_launch_facts_tasks.yml - include: tasks/launch_instances.yml vars: instances: "{{ master_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "default" + + - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "compute" + count: "{{ num_nodes }}" + - include: tasks/launch_instances.yml + vars: + instances: "{{ node_names }}" + cluster: "{{ cluster_id }}" + type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml + vars: + type: "infra" + count: "{{ num_infra }}" - include: tasks/launch_instances.yml vars: instances: "{{ node_names }}" cluster: "{{ cluster_id }}" type: "{{ k8s_type }}" + g_sub_host_type: "{{ sub_host_type }}" - include: update.yml diff --git a/playbooks/libvirt/openshift-cluster/lookup_plugins b/playbooks/libvirt/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/libvirt/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/libvirt/openshift-cluster/tasks/launch_instances.yml b/playbooks/libvirt/openshift-cluster/tasks/launch_instances.yml index 8291192ab..4b91c6da8 100644 --- a/playbooks/libvirt/openshift-cluster/tasks/launch_instances.yml +++ b/playbooks/libvirt/openshift-cluster/tasks/launch_instances.yml @@ -14,6 +14,7 @@ url: '{{ image_url }}' sha256sum: '{{ image_sha256 }}' dest: '{{ os_libvirt_storage_pool_path }}/{{ image_name }}' + when: '{{ ( lookup("oo_option", "skip_image_download") | default("no", True) | lower ) in ["false", "no"] }}' - name: Create the cloud-init config drive path file: @@ -62,8 +63,9 @@ shell: 'virsh -c {{ libvirt_uri }} net-dhcp-leases openshift-ansible | egrep -c ''{{ instances | join("|") }}''' register: nb_allocated_ips until: nb_allocated_ips.stdout == '{{ instances | length }}' - retries: 30 - delay: 1 + retries: 60 + delay: 3 + when: instances | length != 0 - name: Collect IP addresses of the VMs shell: 'virsh -c {{ libvirt_uri }} net-dhcp-leases openshift-ansible | awk ''$6 == "{{ item }}" {gsub(/\/.*/, "", $5); print $5}''' @@ -71,7 +73,7 @@ with_items: instances - set_fact: - ips: "{{ scratch_ip.results | oo_collect('stdout') }}" + ips: "{{ scratch_ip.results | default([]) | oo_collect('stdout') }}" - name: Add new instances add_host: diff --git a/playbooks/libvirt/openshift-cluster/templates/network.xml b/playbooks/libvirt/openshift-cluster/templates/network.xml index 86dcd62bb..050bc7ab9 100644 --- a/playbooks/libvirt/openshift-cluster/templates/network.xml +++ b/playbooks/libvirt/openshift-cluster/templates/network.xml @@ -8,7 +8,7 @@ <!-- TODO: query for first available virbr interface available --> <bridge name='virbr3' stp='on' delay='0'/> <!-- TODO: make overridable --> - <domain name='example.com'/> + <domain name='example.com' localOnly='yes' /> <dns> <!-- TODO: automatically add host entries --> </dns> diff --git a/playbooks/libvirt/openshift-cluster/templates/user-data b/playbooks/libvirt/openshift-cluster/templates/user-data index 77b788109..eacae7c7e 100644 --- a/playbooks/libvirt/openshift-cluster/templates/user-data +++ b/playbooks/libvirt/openshift-cluster/templates/user-data @@ -19,5 +19,5 @@ system_info: ssh_authorized_keys: - {{ lookup('file', '~/.ssh/id_rsa.pub') }} -bootcmd: +runcmd: - NETWORK_CONFIG=/etc/sysconfig/network-scripts/ifcfg-eth0; if ! grep DHCP_HOSTNAME ${NETWORK_CONFIG}; then echo 'DHCP_HOSTNAME="{{ item[0] }}.example.com"' >> ${NETWORK_CONFIG}; fi; pkill -9 dhclient; service network restart diff --git a/playbooks/libvirt/openshift-cluster/terminate.yml b/playbooks/libvirt/openshift-cluster/terminate.yml index b173a09dd..8f00812a9 100644 --- a/playbooks/libvirt/openshift-cluster/terminate.yml +++ b/playbooks/libvirt/openshift-cluster/terminate.yml @@ -15,6 +15,23 @@ ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" with_items: groups[cluster_group] | default([]) +- name: Unsubscribe VMs + hosts: oo_hosts_to_terminate + vars_files: + - vars.yml + roles: + - role: rhel_unsubscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] + +- name: Terminate instance(s) + hosts: localhost + gather_facts: no + vars_files: + - vars.yml + tasks: - name: Destroy VMs virt: name: '{{ item[0] }}' diff --git a/playbooks/libvirt/openshift-cluster/update.yml b/playbooks/libvirt/openshift-cluster/update.yml index 57e36db9e..d09832c16 100644 --- a/playbooks/libvirt/openshift-cluster/update.yml +++ b/playbooks/libvirt/openshift-cluster/update.yml @@ -11,7 +11,9 @@ groups: oo_hosts_to_update ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-node"]) | default([]) + with_items: (groups["tag_env-host-type-{{ cluster_id }}-openshift-master"] | default([])) + | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-node"] | default([])) + | union(groups["tag_env-host-type-{{ cluster_id }}-openshift-etcd"] | default([])) - include: ../../common/openshift-cluster/update_repos_and_packages.yml diff --git a/playbooks/libvirt/openshift-cluster/vars.yml b/playbooks/libvirt/openshift-cluster/vars.yml index 65d954fee..c77a0797e 100644 --- a/playbooks/libvirt/openshift-cluster/vars.yml +++ b/playbooks/libvirt/openshift-cluster/vars.yml @@ -7,9 +7,12 @@ libvirt_uri: 'qemu:///system' deployment_vars: origin: image: - url: "http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2" - name: CentOS-7-x86_64-GenericCloud.qcow2 - sha256: e324e3ab1d24a1bbf035ddb365e7f9058c0b454acf48d7aa15c5519fae5998ab + url: "{{ lookup('oo_option', 'image_url') | + default('http://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2', True) }}" + name: "{{ lookup('oo_option', 'image_name') | + default('CentOS-7-x86_64-GenericCloud.qcow2', True) }}" + sha256: "{{ lookup('oo_option', 'image_sha256') | + default('e324e3ab1d24a1bbf035ddb365e7f9058c0b454acf48d7aa15c5519fae5998ab', True) }}" ssh_user: openshift sudo: yes online: @@ -21,9 +24,12 @@ deployment_vars: sudo: no enterprise: image: - url: - name: - sha256: + url: "{{ lookup('oo_option', 'image_url') | + default('https://access.cdn.redhat.com//content/origin/files/sha256/ff/ff8198653cfd9c39411fc57077451ac291b3a605d305e905932fd6d5b1890bf3/rhel-guest-image-7.1-20150224.0.x86_64.qcow2', True) }}" + name: "{{ lookup('oo_option', 'image_name') | + default('rhel-guest-image-7.1-20150224.0.x86_64.qcow2', True) }}" + sha256: "{{ lookup('oo_option', 'image_sha256') | + default('ff8198653cfd9c39411fc57077451ac291b3a605d305e905932fd6d5b1890bf3', True) }}" ssh_user: openshift sudo: yes # origin: diff --git a/playbooks/openstack/openshift-cluster/config.yml b/playbooks/openstack/openshift-cluster/config.yml index abadaf5ca..a5ee2d6a5 100644 --- a/playbooks/openstack/openshift-cluster/config.yml +++ b/playbooks/openstack/openshift-cluster/config.yml @@ -1,35 +1,20 @@ -- name: Populate oo_masters_to_config host group - hosts: localhost +- hosts: localhost gather_facts: no vars_files: - vars.yml tasks: - - name: Evaluate oo_masters_to_config - add_host: - name: "{{ item }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_masters_to_config - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | default([]) - - name: Evaluate oo_nodes_to_config - add_host: - name: "{{ item }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_nodes_to_config - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-node"] | default([]) - - name: Evaluate oo_first_master - add_host: - name: "{{ groups['tag_env-host-type_' ~ cluster_id ~ '-openshift-master'][0] }}" - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: oo_first_master - when: "'tag_env-host-type_{{ cluster_id }}-openshift-master' in groups" + - set_fact: + g_ssh_user_tmp: "{{ deployment_vars[deployment_type].ssh_user }}" + g_sudo_tmp: "{{ deployment_vars[deployment_type].sudo }}" - include: ../../common/openshift-cluster/config.yml vars: + g_etcd_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-etcd' }}" + g_masters_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-master' }}" + g_nodes_group: "{{ 'tag_env-host-type_' ~ cluster_id ~ '-openshift-node' }}" + g_ssh_user: "{{ hostvars.localhost.g_ssh_user_tmp }}" + g_sudo: "{{ hostvars.localhost.g_sudo_tmp }}" openshift_cluster_id: "{{ cluster_id }}" - openshift_debug_level: 4 + openshift_debug_level: 2 openshift_deployment_type: "{{ deployment_type }}" - openshift_first_master: "{{ groups.oo_first_master.0 }}" openshift_hostname: "{{ ansible_default_ipv4.address }}" diff --git a/playbooks/openstack/openshift-cluster/files/heat_stack.yaml b/playbooks/openstack/openshift-cluster/files/heat_stack.yaml new file mode 100644 index 000000000..40e4ab22c --- /dev/null +++ b/playbooks/openstack/openshift-cluster/files/heat_stack.yaml @@ -0,0 +1,370 @@ +heat_template_version: 2014-10-16 + +description: OpenShift cluster + +parameters: + + cluster_id: + type: string + label: Cluster ID + description: Identifier of the cluster + + cidr: + type: string + label: CIDR + description: CIDR of the network of the cluster + + dns_nameservers: + type: comma_delimited_list + label: DNS nameservers list + description: List of DNS nameservers + + external_net: + type: string + label: External network + description: Name of the external network + default: external + + floating_ip_pool: + type: string + label: Floating IP pool + description: Floating IP pools + default: external + + ssh_public_key: + type: string + label: SSH public key + description: SSH public key + hidden: true + + ssh_incoming: + type: string + label: Source of ssh connections + description: Source of legitimate ssh connections + default: 0.0.0.0/0 + + num_masters: + type: number + label: Number of masters + description: Number of masters + + num_nodes: + type: number + label: Number of compute nodes + description: Number of compute nodes + + num_infra: + type: number + label: Number of infrastructure nodes + description: Number of infrastructure nodes + + master_image: + type: string + label: Master image + description: Name of the image for the master servers + + node_image: + type: string + label: Node image + description: Name of the image for the compute node servers + + infra_image: + type: string + label: Infra image + description: Name of the image for the infra node servers + + master_flavor: + type: string + label: Master flavor + description: Flavor of the master servers + + node_flavor: + type: string + label: Node flavor + description: Flavor of the compute node servers + + infra_flavor: + type: string + label: Infra flavor + description: Flavor of the infra node servers + +outputs: + + master_names: + description: Name of the masters + value: { get_attr: [ masters, name ] } + + master_ips: + description: IPs of the masters + value: { get_attr: [ masters, private_ip ] } + + master_floating_ips: + description: Floating IPs of the masters + value: { get_attr: [ masters, floating_ip ] } + + node_names: + description: Name of the nodes + value: { get_attr: [ compute_nodes, name ] } + + node_ips: + description: IPs of the nodes + value: { get_attr: [ compute_nodes, private_ip ] } + + node_floating_ips: + description: Floating IPs of the nodes + value: { get_attr: [ compute_nodes, floating_ip ] } + + infra_names: + description: Name of the nodes + value: { get_attr: [ infra_nodes, name ] } + + infra_ips: + description: IPs of the nodes + value: { get_attr: [ infra_nodes, private_ip ] } + + infra_floating_ips: + description: Floating IPs of the nodes + value: { get_attr: [ infra_nodes, floating_ip ] } + +resources: + + net: + type: OS::Neutron::Net + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-net + params: + cluster_id: { get_param: cluster_id } + + subnet: + type: OS::Neutron::Subnet + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-subnet + params: + cluster_id: { get_param: cluster_id } + network: { get_resource: net } + cidr: { get_param: cidr } + dns_nameservers: { get_param: dns_nameservers } + + router: + type: OS::Neutron::Router + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-router + params: + cluster_id: { get_param: cluster_id } + external_gateway_info: + network: { get_param: external_net } + + interface: + type: OS::Neutron::RouterInterface + properties: + router_id: { get_resource: router } + subnet_id: { get_resource: subnet } + + keypair: + type: OS::Nova::KeyPair + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-keypair + params: + cluster_id: { get_param: cluster_id } + public_key: { get_param: ssh_public_key } + + master-secgrp: + type: OS::Neutron::SecurityGroup + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-master-secgrp + params: + cluster_id: { get_param: cluster_id } + description: + str_replace: + template: Security group for cluster_id OpenShift cluster master + params: + cluster_id: { get_param: cluster_id } + rules: + - direction: ingress + protocol: tcp + port_range_min: 22 + port_range_max: 22 + remote_ip_prefix: { get_param: ssh_incoming } + - direction: ingress + protocol: tcp + port_range_min: 4001 + port_range_max: 4001 + - direction: ingress + protocol: tcp + port_range_min: 8443 + port_range_max: 8443 + - direction: ingress + protocol: tcp + port_range_min: 53 + port_range_max: 53 + - direction: ingress + protocol: udp + port_range_min: 53 + port_range_max: 53 + - direction: ingress + protocol: tcp + port_range_min: 24224 + port_range_max: 24224 + - direction: ingress + protocol: udp + port_range_min: 24224 + port_range_max: 24224 + + node-secgrp: + type: OS::Neutron::SecurityGroup + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-node-secgrp + params: + cluster_id: { get_param: cluster_id } + description: + str_replace: + template: Security group for cluster_id OpenShift cluster nodes + params: + cluster_id: { get_param: cluster_id } + rules: + - direction: ingress + protocol: tcp + port_range_min: 22 + port_range_max: 22 + remote_ip_prefix: { get_param: ssh_incoming } + - direction: ingress + protocol: udp + port_range_min: 4789 + port_range_max: 4789 + remote_mode: remote_group_id + - direction: ingress + protocol: tcp + port_range_min: 10250 + port_range_max: 10250 + remote_mode: remote_group_id + remote_group_id: { get_resource: master-secgrp } + + infra-secgrp: + type: OS::Neutron::SecurityGroup + properties: + name: + str_replace: + template: openshift-ansible-cluster_id-infra-secgrp + params: + cluster_id: { get_param: cluster_id } + description: + str_replace: + template: Security group for cluster_id OpenShift infrastructure cluster nodes + params: + cluster_id: { get_param: cluster_id } + rules: + - direction: ingress + protocol: tcp + port_range_min: 80 + port_range_max: 80 + - direction: ingress + protocol: tcp + port_range_min: 443 + port_range_max: 443 + + masters: + type: OS::Heat::ResourceGroup + properties: + count: { get_param: num_masters } + resource_def: + type: heat_stack_server.yaml + properties: + name: + str_replace: + template: cluster_id-k8s_type-%index% + params: + cluster_id: { get_param: cluster_id } + k8s_type: master + cluster_id: { get_param: cluster_id } + type: master + image: { get_param: master_image } + flavor: { get_param: master_flavor } + key_name: { get_resource: keypair } + net: { get_resource: net } + subnet: { get_resource: subnet } + secgrp: + - { get_resource: master-secgrp } + floating_network: { get_param: floating_ip_pool } + net_name: + str_replace: + template: openshift-ansible-cluster_id-net + params: + cluster_id: { get_param: cluster_id } + depends_on: interface + + compute_nodes: + type: OS::Heat::ResourceGroup + properties: + count: { get_param: num_nodes } + resource_def: + type: heat_stack_server.yaml + properties: + name: + str_replace: + template: cluster_id-k8s_type-sub_host_type-%index% + params: + cluster_id: { get_param: cluster_id } + k8s_type: node + sub_host_type: compute + cluster_id: { get_param: cluster_id } + type: node + subtype: compute + image: { get_param: node_image } + flavor: { get_param: node_flavor } + key_name: { get_resource: keypair } + net: { get_resource: net } + subnet: { get_resource: subnet } + secgrp: + - { get_resource: node-secgrp } + floating_network: { get_param: floating_ip_pool } + net_name: + str_replace: + template: openshift-ansible-cluster_id-net + params: + cluster_id: { get_param: cluster_id } + depends_on: interface + + infra_nodes: + type: OS::Heat::ResourceGroup + properties: + count: { get_param: num_infra } + resource_def: + type: heat_stack_server.yaml + properties: + name: + str_replace: + template: cluster_id-k8s_type-sub_host_type-%index% + params: + cluster_id: { get_param: cluster_id } + k8s_type: node + sub_host_type: infra + cluster_id: { get_param: cluster_id } + type: node + subtype: infra + image: { get_param: infra_image } + flavor: { get_param: infra_flavor } + key_name: { get_resource: keypair } + net: { get_resource: net } + subnet: { get_resource: subnet } + secgrp: + - { get_resource: node-secgrp } + - { get_resource: infra-secgrp } + floating_network: { get_param: floating_ip_pool } + net_name: + str_replace: + template: openshift-ansible-cluster_id-net + params: + cluster_id: { get_param: cluster_id } + depends_on: interface diff --git a/playbooks/openstack/openshift-cluster/files/heat_stack.yml b/playbooks/openstack/openshift-cluster/files/heat_stack.yml deleted file mode 100644 index c5f95d87d..000000000 --- a/playbooks/openstack/openshift-cluster/files/heat_stack.yml +++ /dev/null @@ -1,149 +0,0 @@ -heat_template_version: 2014-10-16 - -description: OpenShift cluster - -parameters: - cluster-id: - type: string - label: Cluster ID - description: Identifier of the cluster - - network-prefix: - type: string - label: Network prefix - description: Prefix of the network objects - - cidr: - type: string - label: CIDR - description: CIDR of the network of the cluster - - dns-nameservers: - type: comma_delimited_list - label: DNS nameservers list - description: List of DNS nameservers - - external-net: - type: string - label: External network - description: Name of the external network - default: external - - ssh-incoming: - type: string - label: Source of ssh connections - description: Source of legitimate ssh connections - -resources: - net: - type: OS::Neutron::Net - properties: - name: - str_replace: - template: network-prefix-net - params: - network-prefix: { get_param: network-prefix } - - subnet: - type: OS::Neutron::Subnet - properties: - name: - str_replace: - template: network-prefix-subnet - params: - network-prefix: { get_param: network-prefix } - network: { get_resource: net } - cidr: { get_param: cidr } - dns_nameservers: { get_param: dns-nameservers } - - router: - type: OS::Neutron::Router - properties: - name: - str_replace: - template: network-prefix-router - params: - network-prefix: { get_param: network-prefix } - external_gateway_info: - network: { get_param: external-net } - - interface: - type: OS::Neutron::RouterInterface - properties: - router_id: { get_resource: router } - subnet_id: { get_resource: subnet } - - node-secgrp: - type: OS::Neutron::SecurityGroup - properties: - name: - str_replace: - template: network-prefix-node-secgrp - params: - network-prefix: { get_param: network-prefix } - description: - str_replace: - template: Security group for cluster-id OpenShift cluster nodes - params: - cluster-id: { get_param: cluster-id } - rules: - - direction: ingress - protocol: tcp - port_range_min: 22 - port_range_max: 22 - remote_ip_prefix: { get_param: ssh-incoming } - - direction: ingress - protocol: udp - port_range_min: 4789 - port_range_max: 4789 - remote_mode: remote_group_id - - direction: ingress - protocol: tcp - port_range_min: 10250 - port_range_max: 10250 - remote_mode: remote_group_id - remote_group_id: { get_resource: master-secgrp } - - master-secgrp: - type: OS::Neutron::SecurityGroup - properties: - name: - str_replace: - template: network-prefix-master-secgrp - params: - network-prefix: { get_param: network-prefix } - description: - str_replace: - template: Security group for cluster-id OpenShift cluster master - params: - cluster-id: { get_param: cluster-id } - rules: - - direction: ingress - protocol: tcp - port_range_min: 22 - port_range_max: 22 - remote_ip_prefix: { get_param: ssh-incoming } - - direction: ingress - protocol: tcp - port_range_min: 4001 - port_range_max: 4001 - - direction: ingress - protocol: tcp - port_range_min: 8443 - port_range_max: 8443 - - direction: ingress - protocol: tcp - port_range_min: 53 - port_range_max: 53 - - direction: ingress - protocol: udp - port_range_min: 53 - port_range_max: 53 - - direction: ingress - protocol: tcp - port_range_min: 24224 - port_range_max: 24224 - - direction: ingress - protocol: udp - port_range_min: 24224 - port_range_max: 24224 diff --git a/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml b/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml new file mode 100644 index 000000000..9dcab3e60 --- /dev/null +++ b/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml @@ -0,0 +1,130 @@ +heat_template_version: 2014-10-16 + +description: OpenShift cluster server + +parameters: + + name: + type: string + label: Name + description: Name + + cluster_id: + type: string + label: Cluster ID + description: Identifier of the cluster + + type: + type: string + label: Type + description: Type master or node + + subtype: + type: string + label: Sub-type + description: Sub-type compute or infra for nodes, default otherwise + default: default + + key_name: + type: string + label: Key name + description: Key name of keypair + + image: + type: string + label: Image + description: Name of the image + + flavor: + type: string + label: Flavor + description: Name of the flavor + + net: + type: string + label: Net ID + description: Net resource + + net_name: + type: string + label: Net name + description: Net name + + subnet: + type: string + label: Subnet ID + description: Subnet resource + + secgrp: + type: comma_delimited_list + label: Security groups + description: Security group resources + + floating_network: + type: string + label: Floating network + description: Network to allocate floating IP from + +outputs: + + name: + description: Name of the server + value: { get_attr: [ server, name ] } + + private_ip: + description: Private IP of the server + value: + get_attr: + - server + - addresses + - { get_param: net_name } + - 0 + - addr + + floating_ip: + description: Floating IP of the server + value: + get_attr: + - server + - addresses + - { get_param: net_name } + - 1 + - addr + +resources: + + server: + type: OS::Nova::Server + properties: + name: { get_param: name } + key_name: { get_param: key_name } + image: { get_param: image } + flavor: { get_param: flavor } + networks: + - port: { get_resource: port } + user_data: { get_file: user-data } + user_data_format: RAW + metadata: + env: { get_param: cluster_id } + host-type: { get_param: type } + env-host-type: + str_replace: + template: cluster_id-openshift-type + params: + cluster_id: { get_param: cluster_id } + type: { get_param: type } + sub-host-type: { get_param: subtype } + + port: + type: OS::Neutron::Port + properties: + network: { get_param: net } + fixed_ips: + - subnet: { get_param: subnet } + security_groups: { get_param: secgrp } + + floating-ip: + type: OS::Neutron::FloatingIP + properties: + floating_network: { get_param: floating_network } + port_id: { get_resource: port } diff --git a/playbooks/openstack/openshift-cluster/launch.yml b/playbooks/openstack/openshift-cluster/launch.yml index 5c86ade3f..651aef40b 100644 --- a/playbooks/openstack/openshift-cluster/launch.yml +++ b/playbooks/openstack/openshift-cluster/launch.yml @@ -8,23 +8,114 @@ tasks: - fail: msg: "Deployment type not supported for OpenStack provider yet" - when: deployment_type in ['online', 'enterprise'] - - - include: tasks/configure_openstack.yml - - - include: ../../common/openshift-cluster/set_master_launch_facts_tasks.yml - - include: tasks/launch_instances.yml - vars: - instances: "{{ master_names }}" - cluster: "{{ cluster_id }}" - type: "{{ k8s_type }}" - - - include: ../../common/openshift-cluster/set_node_launch_facts_tasks.yml - - include: tasks/launch_instances.yml - vars: - instances: "{{ node_names }}" - cluster: "{{ cluster_id }}" - type: "{{ k8s_type }}" + when: deployment_type == 'online' + + # TODO: Write an Ansible module for dealing with HEAT stacks + # Dealing with the outputs is currently terrible + + - name: Check OpenStack stack + command: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack' + register: stack_show_result + changed_when: false + failed_when: stack_show_result.rc != 0 and 'Stack not found' not in stack_show_result.stderr + + - set_fact: + heat_stack_action: 'stack-create' + when: stack_show_result.rc == 1 + - set_fact: + heat_stack_action: 'stack-update' + when: stack_show_result.rc == 0 + + - name: Create or Update OpenStack Stack + command: 'heat {{ heat_stack_action }} -f {{ openstack_infra_heat_stack }} + -P cluster_id={{ cluster_id }} + -P cidr={{ openstack_network_cidr }} + -P dns_nameservers={{ openstack_network_dns | join(",") }} + -P external_net={{ openstack_network_external_net }} + -P floating_ip_pool={{ openstack_floating_ip_pool }} + -P ssh_public_key="{{ openstack_ssh_public_key }}" + -P ssh_incoming={{ openstack_ssh_access_from }} + -P num_masters={{ num_masters }} + -P num_nodes={{ num_nodes }} + -P num_infra={{ num_infra }} + -P master_image={{ deployment_vars[deployment_type].image }} + -P node_image={{ deployment_vars[deployment_type].image }} + -P infra_image={{ deployment_vars[deployment_type].image }} + -P master_flavor={{ openstack_flavor["master"] }} + -P node_flavor={{ openstack_flavor["node"] }} + -P infra_flavor={{ openstack_flavor["infra"] }} + openshift-ansible-{{ cluster_id }}-stack' + + - name: Wait for OpenStack Stack readiness + shell: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack | awk ''$2 == "stack_status" {print $4}''' + register: stack_show_status_result + until: stack_show_status_result.stdout not in ['CREATE_IN_PROGRESS', 'UPDATE_IN_PROGRESS'] + retries: 30 + delay: 1 + failed_when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE'] + + - name: Read OpenStack Stack outputs + command: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack' + register: stack_show_result + + - set_fact: + parsed_outputs: "{{ stack_show_result | oo_parse_heat_stack_outputs }}" + + - name: Add new master instances groups and variables + add_host: + hostname: '{{ item[0] }}' + ansible_ssh_host: '{{ item[2] }}' + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + groups: 'tag_env_{{ cluster_id }}, tag_host-type_master, tag_env-host-type_{{ cluster_id }}-openshift-master, tag_sub-host-type_default' + with_together: + - parsed_outputs.master_names + - parsed_outputs.master_ips + - parsed_outputs.master_floating_ips + + - name: Add new node instances groups and variables + add_host: + hostname: '{{ item[0] }}' + ansible_ssh_host: '{{ item[2] }}' + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + groups: 'tag_env_{{ cluster_id }}, tag_host-type_node, tag_env-host-type_{{ cluster_id }}-openshift-node, tag_sub-host-type_compute' + with_together: + - parsed_outputs.node_names + - parsed_outputs.node_ips + - parsed_outputs.node_floating_ips + + - name: Add new infra instances groups and variables + add_host: + hostname: '{{ item[0] }}' + ansible_ssh_host: '{{ item[2] }}' + ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" + ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" + groups: 'tag_env_{{ cluster_id }}, tag_host-type_node, tag_env-host-type_{{ cluster_id }}-openshift-node, tag_sub-host-type_infra' + with_together: + - parsed_outputs.infra_names + - parsed_outputs.infra_ips + - parsed_outputs.infra_floating_ips + + - name: Wait for ssh + wait_for: + host: '{{ item }}' + port: 22 + with_flattened: + - parsed_outputs.master_floating_ips + - parsed_outputs.node_floating_ips + - parsed_outputs.infra_floating_ips + + - name: Wait for user setup + command: 'ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null {{ deployment_vars[deployment_type].ssh_user }}@{{ item }} echo {{ deployment_vars[deployment_type].ssh_user }} user is setup' + register: result + until: result.rc == 0 + retries: 30 + delay: 1 + with_flattened: + - parsed_outputs.master_floating_ips + - parsed_outputs.node_floating_ips + - parsed_outputs.infra_floating_ips - include: update.yml diff --git a/playbooks/openstack/openshift-cluster/lookup_plugins b/playbooks/openstack/openshift-cluster/lookup_plugins new file mode 120000 index 000000000..ac79701db --- /dev/null +++ b/playbooks/openstack/openshift-cluster/lookup_plugins @@ -0,0 +1 @@ +../../../lookup_plugins
\ No newline at end of file diff --git a/playbooks/openstack/openshift-cluster/tasks/configure_openstack.yml b/playbooks/openstack/openshift-cluster/tasks/configure_openstack.yml deleted file mode 100644 index 2cbdb4805..000000000 --- a/playbooks/openstack/openshift-cluster/tasks/configure_openstack.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -- name: Check infra - command: 'heat stack-show {{ openstack_network_prefix }}-stack' - register: stack_show_result - changed_when: false - failed_when: stack_show_result.rc != 0 and 'Stack not found' not in stack_show_result.stderr - -- name: Create infra - command: 'heat stack-create -f {{ openstack_infra_heat_stack }} -P cluster-id={{ cluster_id }} -P network-prefix={{ openstack_network_prefix }} -P dns-nameservers={{ openstack_network_dns | join(",") }} -P cidr={{ openstack_network_cidr }} -P ssh-incoming={{ openstack_ssh_access_from }} {{ openstack_network_prefix }}-stack' - when: stack_show_result.rc == 1 - -- name: Update infra - command: 'heat stack-update -f {{ openstack_infra_heat_stack }} -P cluster-id={{ cluster_id }} -P network-prefix={{ openstack_network_prefix }} -P dns-nameservers={{ openstack_network_dns | join(",") }} -P cidr={{ openstack_network_cidr }} -P ssh-incoming={{ openstack_ssh_access_from }} {{ openstack_network_prefix }}-stack' - when: stack_show_result.rc == 0 - -- name: Wait for infra readiness - shell: 'heat stack-show {{ openstack_network_prefix }}-stack | awk ''$2 == "stack_status" {print $4}''' - register: stack_show_status_result - until: stack_show_status_result.stdout not in ['CREATE_IN_PROGRESS', 'UPDATE_IN_PROGRESS'] - retries: 30 - delay: 1 - failed_when: stack_show_status_result.stdout not in ['CREATE_COMPLETE', 'UPDATE_COMPLETE'] - -- name: Create ssh keypair - nova_keypair: - name: "{{ openstack_ssh_keypair }}" - public_key: "{{ openstack_ssh_public_key }}" diff --git a/playbooks/openstack/openshift-cluster/tasks/launch_instances.yml b/playbooks/openstack/openshift-cluster/tasks/launch_instances.yml deleted file mode 100644 index 1b9696aac..000000000 --- a/playbooks/openstack/openshift-cluster/tasks/launch_instances.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -- name: Get net id - shell: 'neutron net-show {{ openstack_network_prefix }}-net | awk "/\\<id\\>/ {print \$4}"' - register: net_id_result - -- name: Launch instance(s) - nova_compute: - name: '{{ item }}' - image_name: '{{ deployment_vars[deployment_type].image.name | default(omit, true) }}' - image_id: '{{ deployment_vars[deployment_type].image.id | default(omit, true) }}' - flavor_ram: '{{ openstack_flavor[k8s_type].ram | default(omit, true) }}' - flavor_id: '{{ openstack_flavor[k8s_type].id | default(omit, true) }}' - flavor_include: '{{ openstack_flavor[k8s_type].include | default(omit, true) }}' - key_name: '{{ openstack_ssh_keypair }}' - security_groups: '{{ openstack_network_prefix }}-{{ k8s_type }}-secgrp' - nics: - - net-id: '{{ net_id_result.stdout }}' - user_data: "{{ lookup('file','files/user-data') }}" - meta: - env: '{{ cluster }}' - host-type: '{{ type }}' - env-host-type: '{{ cluster }}-openshift-{{ type }}' - floating_ip_pools: '{{ openstack_floating_ip_pools }}' - with_items: instances - register: nova_compute_result - -- name: Add new instances groups and variables - add_host: - hostname: '{{ item.item }}' - ansible_ssh_host: '{{ item.public_ip }}' - ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" - ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - groups: 'tag_env_{{ cluster }}, tag_host-type_{{ type }}, tag_env-host-type_{{ cluster }}-openshift-{{ type }}' - with_items: nova_compute_result.results - -- name: Wait for ssh - wait_for: - host: '{{ item.public_ip }}' - port: 22 - with_items: nova_compute_result.results - -- name: Wait for user setup - command: 'ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null {{ hostvars[item.item].ansible_ssh_user }}@{{ item.public_ip }} echo {{ hostvars[item.item].ansible_ssh_user }} user is setup' - register: result - until: result.rc == 0 - retries: 30 - delay: 1 - with_items: nova_compute_result.results diff --git a/playbooks/openstack/openshift-cluster/terminate.yml b/playbooks/openstack/openshift-cluster/terminate.yml index 2f05f0992..62df2be73 100644 --- a/playbooks/openstack/openshift-cluster/terminate.yml +++ b/playbooks/openstack/openshift-cluster/terminate.yml @@ -13,7 +13,16 @@ ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" with_items: groups[cluster_group] | default([]) -- hosts: oo_hosts_to_terminate +- name: Unsubscribe VMs + hosts: oo_hosts_to_terminate + vars_files: + - vars.yml + roles: + - role: rhel_unsubscribe + when: deployment_type == "enterprise" and + ansible_distribution == "RedHat" and + lookup('oo_option', 'rhel_skip_subscription') | default(rhsub_skip, True) | + default('no', True) | lower in ['no', 'false'] - hosts: localhost connection: local @@ -21,23 +30,18 @@ vars_files: - vars.yml tasks: - - name: Retrieve the floating IPs - shell: "neutron floatingip-list | awk '/{{ hostvars[item].ansible_default_ipv4.address }}/ {print $2}'" - with_items: groups['oo_hosts_to_terminate'] | default([]) - register: floating_ips_to_delete - - - name: Terminate instance(s) - nova_compute: - name: "{{ hostvars[item].os_name }}" - state: absent - with_items: groups['oo_hosts_to_terminate'] | default([]) - - - name: Delete floating IPs - command: "neutron floatingip-delete {{ item.stdout }}" - with_items: floating_ips_to_delete.results | default([]) - - - name: Destroy the network - command: "heat stack-delete {{ openstack_network_prefix }}-stack" + - name: Delete the OpenStack Stack + command: 'heat stack-delete openshift-ansible-{{ cluster_id }}-stack' register: stack_delete_result changed_when: stack_delete_result.rc == 0 failed_when: stack_delete_result.rc != 0 and 'could not be found' not in stack_delete_result.stdout + + - name: Wait for the completion of the OpenStack Stack deletion + shell: 'heat stack-show openshift-ansible-{{ cluster_id }}-stack | awk ''$2 == "stack_status" {print $4}''' + when: stack_delete_result.changed + register: stack_show_result + until: stack_show_result.stdout != 'DELETE_IN_PROGRESS' + retries: 60 + delay: 1 + failed_when: '"Stack not found" not in stack_show_result.stderr and + stack_show_result.stdout != "DELETE_COMPLETE"' diff --git a/playbooks/openstack/openshift-cluster/update.yml b/playbooks/openstack/openshift-cluster/update.yml index 5e7ab4e58..e006aa74a 100644 --- a/playbooks/openstack/openshift-cluster/update.yml +++ b/playbooks/openstack/openshift-cluster/update.yml @@ -11,7 +11,9 @@ groups: oo_hosts_to_update ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}" ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" - with_items: groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-node"]) | default([]) + with_items: (groups["tag_env-host-type_{{ cluster_id }}-openshift-master"] | default([])) + | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-node"] | default([])) + | union(groups["tag_env-host-type_{{ cluster_id }}-openshift-etcd"] | default([])) - include: ../../common/openshift-cluster/update_repos_and_packages.yml diff --git a/playbooks/openstack/openshift-cluster/vars.yml b/playbooks/openstack/openshift-cluster/vars.yml index c754f19fc..262d3f4ed 100644 --- a/playbooks/openstack/openshift-cluster/vars.yml +++ b/playbooks/openstack/openshift-cluster/vars.yml @@ -1,39 +1,33 @@ --- -openstack_infra_heat_stack: "{{ opt_infra_heat_stack | default('files/heat_stack.yml') }}" -openstack_network_prefix: "{{ opt_network_prefix | default('openshift-ansible-'+cluster_id) }}" -openstack_network_cidr: "{{ opt_net_cidr | default('192.168.' + ( ( 1048576 | random % 256 ) | string() ) + '.0/24') }}" -openstack_network_external_net: "{{ opt_external_net | default('external') }}" -openstack_floating_ip_pools: "{{ opt_floating_ip_pools | default('external') | oo_split() }}" -openstack_network_dns: "{{ opt_dns | default('8.8.8.8,8.8.4.4') | oo_split() }}" -openstack_ssh_keypair: "{{ opt_keypair | default(lookup('env', 'LOGNAME')+'_key') }}" -openstack_ssh_public_key: "{{ lookup('file', opt_public_key | default('~/.ssh/id_rsa.pub')) }}" -openstack_ssh_access_from: "{{ opt_ssh_from | default('0.0.0.0/0') }}" +openstack_infra_heat_stack: "{{ lookup('oo_option', 'infra_heat_stack' ) | + default('files/heat_stack.yaml', True) }}" +openstack_network_cidr: "{{ lookup('oo_option', 'net_cidr' ) | + default('192.168.' + ( ( 1048576 | random % 256 ) | string() ) + '.0/24', True) }}" +openstack_network_external_net: "{{ lookup('oo_option', 'external_net' ) | + default('external', True) }}" +openstack_floating_ip_pool: "{{ lookup('oo_option', 'floating_ip_pool' ) | + default('external', True) }}" +openstack_network_dns: "{{ lookup('oo_option', 'dns' ) | + default('8.8.8.8,8.8.4.4', True) | oo_split() }}" +openstack_ssh_public_key: "{{ lookup('file', lookup('oo_option', 'public_key') | + default('~/.ssh/id_rsa.pub', True)) }}" +openstack_ssh_access_from: "{{ lookup('oo_option', 'ssh_from') | + default('0.0.0.0/0', True) }}" openstack_flavor: - master: - ram: "{{ opt_master_flavor_ram | default(2048) }}" - id: "{{ opt_master_flavor_id | default() }}" - include: "{{ opt_master_flavor_include | default() }}" - node: - ram: "{{ opt_node_flavor_ram | default(4096) }}" - id: "{{ opt_node_flavor_id | default() }}" - include: "{{ opt_node_flavor_include | default() }}" + master: "{{ lookup('oo_option', 'master_flavor' ) | default('m1.small', True) }}" + infra: "{{ lookup('oo_option', 'infra_flavor' ) | default('m1.small', True) }}" + node: "{{ lookup('oo_option', 'node_flavor' ) | default('m1.medium', True) }}" deployment_vars: origin: - image: - name: "{{ opt_image_name | default('centos-70-raw') }}" - id: + image: "{{ lookup('oo_option', 'image_name') | default('centos-70-raw', True) }}" ssh_user: openshift sudo: yes online: image: - name: - id: ssh_user: root sudo: no enterprise: - image: - name: "{{ opt_image_name | default('centos-70-raw') }}" - id: + image: "{{ lookup('oo_option', 'image_name') | default('rhel-guest-image-7.1-20150224.0.x86_64', True) }}" ssh_user: openshift sudo: yes diff --git a/rel-eng/packages/openshift-ansible-bin b/rel-eng/packages/openshift-ansible-bin index 2a8225740..11c2906f0 100644 --- a/rel-eng/packages/openshift-ansible-bin +++ b/rel-eng/packages/openshift-ansible-bin @@ -1 +1 @@ -0.0.18-1 bin/ +0.0.19-1 bin/ diff --git a/rel-eng/packages/openshift-ansible-inventory b/rel-eng/packages/openshift-ansible-inventory index 4851be122..733c626cf 100644 --- a/rel-eng/packages/openshift-ansible-inventory +++ b/rel-eng/packages/openshift-ansible-inventory @@ -1 +1 @@ -0.0.8-1 inventory/ +0.0.9-1 inventory/ diff --git a/roles/ansible_tower/tasks/main.yaml b/roles/ansible_tower/tasks/main.yaml index c110a3b70..b7757214d 100644 --- a/roles/ansible_tower/tasks/main.yaml +++ b/roles/ansible_tower/tasks/main.yaml @@ -9,6 +9,7 @@ - ansible - telnet - ack + - pylint - name: download Tower setup get_url: url=http://releases.ansible.com/ansible-tower/setup/ansible-tower-setup-2.1.1.tar.gz dest=/opt/ force=no @@ -38,5 +39,3 @@ regexp: "^({{ item.option }})( *)=" line: '\1\2= {{ item.value }}' with_items: config_changes | default([], true) - - diff --git a/roles/cockpit/defaults/main.yml b/roles/cockpit/defaults/main.yml new file mode 100644 index 000000000..ffd55f1dd --- /dev/null +++ b/roles/cockpit/defaults/main.yml @@ -0,0 +1,5 @@ +--- +os_firewall_use_firewalld: false +os_firewall_allow: +- service: cockpit-ws + port: 9090/tcp diff --git a/roles/cockpit/meta/main.yml b/roles/cockpit/meta/main.yml new file mode 100644 index 000000000..1e3948b19 --- /dev/null +++ b/roles/cockpit/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Scott Dodson + description: Deploy and Enable cockpit-ws plus optional plugins + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.7 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud +dependencies: + - { role: os_firewall } diff --git a/roles/cockpit/tasks/main.yml b/roles/cockpit/tasks/main.yml new file mode 100644 index 000000000..875cbad21 --- /dev/null +++ b/roles/cockpit/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: Install cockpit-ws + yum: + name: "{{ item }}" + state: present + with_items: + - cockpit-ws + - cockpit-shell + - cockpit-bridge + - "{{ cockpit_plugins }}" + +- name: Enable cockpit-ws + service: + name: cockpit.socket + enabled: true + state: started diff --git a/roles/docker_storage/README.md b/roles/docker_storage/README.md index 0d8f31afc..bf0158623 100644 --- a/roles/docker_storage/README.md +++ b/roles/docker_storage/README.md @@ -36,4 +36,4 @@ ASL 2.0 Author Information ------------------ -Openshift operations, Red Hat, Inc +OpenShift operations, Red Hat, Inc diff --git a/roles/docker_storage/meta/main.yml b/roles/docker_storage/meta/main.yml index a5d51cd3a..f5b2d53cb 100644 --- a/roles/docker_storage/meta/main.yml +++ b/roles/docker_storage/meta/main.yml @@ -1,6 +1,6 @@ --- galaxy_info: - author: Openshift + author: OpenShift description: Setup docker_storage options company: Red Hat, Inc license: ASL 2.0 diff --git a/roles/etcd/README.md b/roles/etcd/README.md new file mode 100644 index 000000000..49207c428 --- /dev/null +++ b/roles/etcd/README.md @@ -0,0 +1,39 @@ +Role Name +========= + +Configures an etcd cluster for an arbitrary number of hosts + +Requirements +------------ + +This role assumes it's being deployed on a RHEL/Fedora based host with package +named 'etcd' available via yum. + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +None + +Example Playbook +---------------- + + - hosts: etcd + roles: + - { etcd } + +License +------- + +MIT + +Author Information +------------------ + +Scott Dodson <sdodson@redhat.com> +Adapted from https://github.com/retr0h/ansible-etcd for use on RHEL/Fedora. We +should at some point submit a PR to merge this with that module. diff --git a/roles/etcd/defaults/main.yaml b/roles/etcd/defaults/main.yaml new file mode 100644 index 000000000..0f216b84e --- /dev/null +++ b/roles/etcd/defaults/main.yaml @@ -0,0 +1,31 @@ +--- +etcd_interface: "{{ ansible_default_ipv4.interface }}" +etcd_client_port: 2379 +etcd_peer_port: 2380 +etcd_peers_group: etcd +etcd_url_scheme: http +etcd_peer_url_scheme: http +etcd_conf_dir: /etc/etcd +etcd_ca_file: "{{ etcd_conf_dir }}/ca.crt" +etcd_cert_file: "{{ etcd_conf_dir }}/server.crt" +etcd_key_file: "{{ etcd_conf_dir }}/server.key" +etcd_peer_ca_file: "{{ etcd_conf_dir }}/ca.crt" +etcd_peer_cert_file: "{{ etcd_conf_dir }}/peer.crt" +etcd_peer_key_file: "{{ etcd_conf_dir }}/peer.key" + +etcd_initial_cluster_state: new +etcd_initial_cluster_token: etcd-cluster-1 + +etcd_initial_advertise_peer_urls: "{{ etcd_peer_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}" +etcd_listen_peer_urls: "{{ etcd_peer_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}" +etcd_advertise_client_urls: "{{ etcd_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_client_port }}" +etcd_listen_client_urls: "{{ etcd_url_scheme }}://{{ hostvars[inventory_hostname]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_client_port }}" + +etcd_data_dir: /var/lib/etcd/ + +os_firewall_use_firewalld: False +os_firewall_allow: +- service: etcd + port: "{{etcd_client_port}}/tcp" +- service: etcd peering + port: "{{ etcd_peer_port }}/tcp" diff --git a/roles/etcd/handlers/main.yml b/roles/etcd/handlers/main.yml new file mode 100644 index 000000000..b897913f9 --- /dev/null +++ b/roles/etcd/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: restart etcd + service: name=etcd state=restarted diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml new file mode 100644 index 000000000..92d44ef4d --- /dev/null +++ b/roles/etcd/meta/main.yml @@ -0,0 +1,20 @@ +--- +# This module is based on https://github.com/retr0h/ansible-etcd with most +# changes centered around installing from a pre-existing rpm +# TODO: Extend https://github.com/retr0h/ansible-etcd rather than forking +galaxy_info: + author: Scott Dodson + description: etcd management + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.2 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: os_firewall } +- { role: openshift_repos } diff --git a/roles/etcd/tasks/main.yml b/roles/etcd/tasks/main.yml new file mode 100644 index 000000000..656901409 --- /dev/null +++ b/roles/etcd/tasks/main.yml @@ -0,0 +1,53 @@ +--- +- name: Install etcd + yum: pkg=etcd-2.* state=present + +- name: Validate permissions on the config dir + file: + path: "{{ etcd_conf_dir }}" + state: directory + owner: etcd + group: etcd + mode: 0700 + +- name: Validate permissions on certificate files + file: + path: "{{ item }}" + mode: 0600 + group: etcd + owner: etcd + when: etcd_url_scheme == 'https' + with_items: + - "{{ etcd_ca_file }}" + - "{{ etcd_cert_file }}" + - "{{ etcd_key_file }}" + +- name: Validate permissions on peer certificate files + file: + path: "{{ item }}" + mode: 0600 + group: etcd + owner: etcd + when: etcd_peer_url_scheme == 'https' + with_items: + - "{{ etcd_peer_ca_file }}" + - "{{ etcd_peer_cert_file }}" + - "{{ etcd_peer_key_file }}" + +- name: Write etcd global config file + template: + src: etcd.conf.j2 + dest: /etc/etcd/etcd.conf + backup: true + notify: + - restart etcd + +- name: Enable etcd + service: + name: etcd + state: started + enabled: yes + register: start_result + +- pause: seconds=30 + when: start_result | changed diff --git a/roles/etcd/templates/etcd.conf.j2 b/roles/etcd/templates/etcd.conf.j2 new file mode 100644 index 000000000..9ac23b1dd --- /dev/null +++ b/roles/etcd/templates/etcd.conf.j2 @@ -0,0 +1,52 @@ +{% macro initial_cluster() -%} +{% for host in groups[etcd_peers_group] -%} +{% if loop.last -%} +{{ host }}={{ etcd_peer_url_scheme }}://{{ hostvars[host]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }} +{%- else -%} +{{ host }}={{ etcd_peer_url_scheme }}://{{ hostvars[host]['ansible_' + etcd_interface]['ipv4']['address'] }}:{{ etcd_peer_port }}, +{%- endif -%} +{% endfor -%} +{% endmacro -%} + +{% if groups[etcd_peers_group] and groups[etcd_peers_group] | length > 1 %} +ETCD_NAME={{ inventory_hostname }} +ETCD_LISTEN_PEER_URLS={{ etcd_listen_peer_urls }} +{% else %} +ETCD_NAME=default +{% endif %} +ETCD_DATA_DIR={{ etcd_data_dir }} +#ETCD_SNAPSHOT_COUNTER="10000" +ETCD_HEARTBEAT_INTERVAL="500" +ETCD_ELECTION_TIMEOUT="2500" +ETCD_LISTEN_CLIENT_URLS={{ etcd_listen_client_urls }} +#ETCD_MAX_SNAPSHOTS="5" +#ETCD_MAX_WALS="5" +#ETCD_CORS="" + +{% if groups[etcd_peers_group] and groups[etcd_peers_group] | length > 1 %} +#[cluster] +ETCD_INITIAL_ADVERTISE_PEER_URLS={{ etcd_initial_advertise_peer_urls }} +ETCD_INITIAL_CLUSTER={{ initial_cluster() }} +ETCD_INITIAL_CLUSTER_STATE={{ etcd_initial_cluster_state }} +ETCD_INITIAL_CLUSTER_TOKEN={{ etcd_initial_cluster_token }} +#ETCD_DISCOVERY="" +#ETCD_DISCOVERY_SRV="" +#ETCD_DISCOVERY_FALLBACK="proxy" +#ETCD_DISCOVERY_PROXY="" +{% endif %} +ETCD_ADVERTISE_CLIENT_URLS={{ etcd_advertise_client_urls }} + +#[proxy] +#ETCD_PROXY="off" + +#[security] +{% if etcd_url_scheme == 'https' -%} +ETCD_CA_FILE={{ etcd_ca_file }} +ETCD_CERT_FILE={{ etcd_cert_file }} +ETCD_KEY_FILE={{ etcd_key_file }} +{% endif -%} +{% if etcd_peer_url_scheme == 'https' -%} +ETCD_PEER_CA_FILE={{ etcd_peer_ca_file }} +ETCD_PEER_CERT_FILE={{ etcd_peer_cert_file }} +ETCD_PEER_KEY_FILE={{ etcd_peer_key_file }} +{% endif -%} diff --git a/roles/etcd_ca/README.md b/roles/etcd_ca/README.md new file mode 100644 index 000000000..60a880e30 --- /dev/null +++ b/roles/etcd_ca/README.md @@ -0,0 +1,34 @@ +etcd_ca +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Scott Dodson (sdodson@redhat.com) diff --git a/roles/etcd_ca/meta/main.yml b/roles/etcd_ca/meta/main.yml new file mode 100644 index 000000000..fb9280c9e --- /dev/null +++ b/roles/etcd_ca/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.9 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_repos } diff --git a/roles/etcd_ca/tasks/main.yml b/roles/etcd_ca/tasks/main.yml new file mode 100644 index 000000000..625756867 --- /dev/null +++ b/roles/etcd_ca/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- file: + path: "{{ etcd_ca_dir }}/{{ item }}" + state: directory + mode: 0700 + owner: root + group: root + with_items: + - certs + - crl + - fragments + +- command: cp /etc/pki/tls/openssl.cnf ./ + args: + chdir: "{{ etcd_ca_dir }}/fragments" + creates: "{{ etcd_ca_dir }}/fragments/openssl.cnf" + +- template: + dest: "{{ etcd_ca_dir }}/fragments/openssl_append.cnf" + src: openssl_append.j2 + backup: true + +- assemble: + src: "{{ etcd_ca_dir }}/fragments" + dest: "{{ etcd_ca_dir }}/openssl.cnf" + +- command: touch index.txt + args: + chdir: "{{ etcd_ca_dir }}" + creates: "{{ etcd_ca_dir }}/index.txt" + +- copy: + dest: "{{ etcd_ca_dir }}/serial" + content: "01" + force: no + +- command: > + openssl req -config openssl.cnf -newkey rsa:4096 + -keyout ca.key -new -out ca.crt -x509 -extensions etcd_v3_ca_self + -batch -nodes -subj /CN=etcd-signer@{{ ansible_date_time.epoch }} + -days 365 + args: + chdir: "{{ etcd_ca_dir }}" + creates: "{{ etcd_ca_dir }}/ca.crt" + environment: + SAN: '' diff --git a/roles/etcd_ca/templates/openssl_append.j2 b/roles/etcd_ca/templates/openssl_append.j2 new file mode 100644 index 000000000..de2adaead --- /dev/null +++ b/roles/etcd_ca/templates/openssl_append.j2 @@ -0,0 +1,51 @@ + +[ etcd_v3_req ] +basicConstraints = critical,CA:FALSE +keyUsage = digitalSignature,keyEncipherment +subjectAltName = ${ENV::SAN} + +[ etcd_ca ] +dir = {{ etcd_ca_dir }} +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir/certs +certificate = $dir/ca.crt +serial = $dir/serial +private_key = $dir/ca.key +crl_number = $dir/crlnumber +x509_extensions = etcd_v3_ca_client +default_days = 365 +default_md = sha256 +preserve = no +name_opt = ca_default +cert_opt = ca_default +policy = policy_anything +unique_subject = no +copy_extensions = copy + +[ etcd_v3_ca_self ] +authorityKeyIdentifier = keyid,issuer +basicConstraints = critical,CA:TRUE,pathlen:0 +keyUsage = critical,digitalSignature,keyEncipherment,keyCertSign +subjectKeyIdentifier = hash + +[ etcd_v3_ca_peer ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = clientAuth,serverAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash + +[ etcd_v3_ca_server ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = serverAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash + +[ etcd_v3_ca_client ] +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = critical,CA:FALSE +extendedKeyUsage = clientAuth +keyUsage = digitalSignature,keyEncipherment +subjectKeyIdentifier = hash diff --git a/roles/etcd_ca/vars/main.yml b/roles/etcd_ca/vars/main.yml new file mode 100644 index 000000000..901e95027 --- /dev/null +++ b/roles/etcd_ca/vars/main.yml @@ -0,0 +1,3 @@ +--- +etcd_conf_dir: /etc/etcd +etcd_ca_dir: /etc/etcd/ca diff --git a/roles/etcd_certificates/README.md b/roles/etcd_certificates/README.md new file mode 100644 index 000000000..95f8f8aab --- /dev/null +++ b/roles/etcd_certificates/README.md @@ -0,0 +1,34 @@ +OpenShift etcd certificates +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Scott Dodson (sdodson@redhat.com) diff --git a/roles/etcd_certificates/meta/main.yml b/roles/etcd_certificates/meta/main.yml new file mode 100644 index 000000000..41370fab4 --- /dev/null +++ b/roles/etcd_certificates/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: etcd_ca } diff --git a/roles/etcd_certificates/tasks/client.yml b/roles/etcd_certificates/tasks/client.yml new file mode 100644 index 000000000..28f33f442 --- /dev/null +++ b/roles/etcd_certificates/tasks/client.yml @@ -0,0 +1,42 @@ +--- +- name: Ensure generated_certs directory present + file: + path: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + state: directory + mode: 0700 + with_items: etcd_needing_client_certs + +- name: Create the client csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}client.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}client.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'client.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_client_certs + +- name: Sign and create the client crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}client.crt + -in {{ item.etcd_cert_prefix }}client.csr + -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'client.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_client_certs + +- file: + src: "{{ etcd_ca_cert }}" + dest: "{{ etcd_generated_certs_dir}}/{{ item.etcd_cert_subdir }}/{{ item.etcd_cert_prefix }}ca.crt" + state: hard + with_items: etcd_needing_client_certs diff --git a/roles/etcd_certificates/tasks/main.yml b/roles/etcd_certificates/tasks/main.yml new file mode 100644 index 000000000..da875e8ea --- /dev/null +++ b/roles/etcd_certificates/tasks/main.yml @@ -0,0 +1,9 @@ +--- +- include: client.yml + when: etcd_needing_client_certs is defined and etcd_needing_client_certs + +- include: server.yml + when: etcd_needing_server_certs is defined and etcd_needing_server_certs + + + diff --git a/roles/etcd_certificates/tasks/server.yml b/roles/etcd_certificates/tasks/server.yml new file mode 100644 index 000000000..727b7fa2c --- /dev/null +++ b/roles/etcd_certificates/tasks/server.yml @@ -0,0 +1,73 @@ +--- +- name: Ensure generated_certs directory present + file: + path: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + state: directory + mode: 0700 + with_items: etcd_needing_server_certs + +- name: Create the server csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}server.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}server.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'server.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_server_certs + +- name: Sign and create the server crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}server.crt + -in {{ item.etcd_cert_prefix }}server.csr + -extensions {{ etcd_ca_exts_server }} -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'server.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_server_certs + +- name: Create the peer csr + command: > + openssl req -new -keyout {{ item.etcd_cert_prefix }}peer.key + -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}peer.csr + -reqexts {{ etcd_req_ext }} -batch -nodes + -subj /CN={{ item.openshift.common.hostname }} + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'peer.csr' }}" + environment: + SAN: "IP:{{ item.openshift.common.ip }}" + with_items: etcd_needing_server_certs + +- name: Sign and create the peer crt + command: > + openssl ca -name {{ etcd_ca_name }} -config {{ etcd_openssl_conf }} + -out {{ item.etcd_cert_prefix }}peer.crt + -in {{ item.etcd_cert_prefix }}peer.csr + -extensions {{ etcd_ca_exts_peer }} -batch + args: + chdir: "{{ etcd_generated_certs_dir }}/{{ item.etcd_cert_subdir }}" + creates: "{{ etcd_generated_certs_dir ~ '/' ~ item.etcd_cert_subdir ~ '/' + ~ item.etcd_cert_prefix ~ 'peer.crt' }}" + environment: + SAN: '' + with_items: etcd_needing_server_certs + +- file: + src: "{{ etcd_ca_cert }}" + dest: "{{ etcd_generated_certs_dir}}/{{ item.etcd_cert_subdir }}/{{ item.etcd_cert_prefix }}ca.crt" + state: hard + with_items: etcd_needing_server_certs + + diff --git a/roles/etcd_certificates/vars/main.yml b/roles/etcd_certificates/vars/main.yml new file mode 100644 index 000000000..0eaeeb82b --- /dev/null +++ b/roles/etcd_certificates/vars/main.yml @@ -0,0 +1,11 @@ +--- +etcd_conf_dir: /etc/etcd +etcd_ca_dir: /etc/etcd/ca +etcd_generated_certs_dir: /etc/etcd/generated_certs +etcd_ca_cert: "{{ etcd_ca_dir }}/ca.crt" +etcd_ca_key: "{{ etcd_ca_dir }}/ca.key" +etcd_openssl_conf: "{{ etcd_ca_dir }}/openssl.cnf" +etcd_ca_name: etcd_ca +etcd_req_ext: etcd_v3_req +etcd_ca_exts_peer: etcd_v3_ca_peer +etcd_ca_exts_server: etcd_v3_ca_server diff --git a/roles/fluentd_master/tasks/main.yml b/roles/fluentd_master/tasks/main.yml index d828db52a..55cd94460 100644 --- a/roles/fluentd_master/tasks/main.yml +++ b/roles/fluentd_master/tasks/main.yml @@ -39,9 +39,16 @@ owner: 'td-agent' mode: 0444 +- name: wait for etcd to start up + wait_for: port=4001 delay=10 + when: embedded_etcd | bool + +- name: wait for etcd peer to start up + wait_for: port=7001 delay=10 + when: embedded_etcd | bool + - name: ensure td-agent is running service: name: 'td-agent' state: started enabled: yes - diff --git a/roles/lib_zabbix/README.md b/roles/lib_zabbix/README.md new file mode 100644 index 000000000..69debc698 --- /dev/null +++ b/roles/lib_zabbix/README.md @@ -0,0 +1,38 @@ +zabbix +========= + +Automate zabbix tasks. + +Requirements +------------ + +This requires the openshift_tools rpm be installed for the zbxapi.py library. It can be found here: https://github.com/openshift/openshift-tools under openshift_tools/monitoring/zbxapi.py for now. + +Role Variables +-------------- + +None + +Dependencies +------------ + +This depeonds on the zbxapi.py library located here: https://github.com/openshift/openshift-tools under openshift_tools/monitoring/zbxapi.py for now. + +Example Playbook +---------------- + + - zbx_host: + server: zab_server + user: zab_user + password: zab_password + name: 'myhost' + +License +------- + +ASL 2.0 + +Author Information +------------------ + +OpenShift operations, Red Hat, Inc diff --git a/roles/lib_zabbix/library/__init__.py b/roles/lib_zabbix/library/__init__.py new file mode 100644 index 000000000..0c7e19e41 --- /dev/null +++ b/roles/lib_zabbix/library/__init__.py @@ -0,0 +1,3 @@ +''' +ZabbixAPI ansible module +''' diff --git a/roles/lib_zabbix/library/zbx_action.py b/roles/lib_zabbix/library/zbx_action.py new file mode 100644 index 000000000..d64cebae1 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_action.py @@ -0,0 +1,538 @@ +#!/usr/bin/env python +''' + Ansible module for zabbix actions +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix action ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection, ZabbixAPIError + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def conditions_equal(zab_conditions, user_conditions): + '''Compare two lists of conditions''' + c_type = 'conditiontype' + _op = 'operator' + val = 'value' + if len(user_conditions) != len(zab_conditions): + return False + + for zab_cond, user_cond in zip(zab_conditions, user_conditions): + if zab_cond[c_type] != str(user_cond[c_type]) or zab_cond[_op] != str(user_cond[_op]) or \ + zab_cond[val] != str(user_cond[val]): + return False + + return True + +def filter_differences(zabbix_filters, user_filters): + '''Determine the differences from user and zabbix for operations''' + rval = {} + for key, val in user_filters.items(): + + if key == 'conditions': + if not conditions_equal(zabbix_filters[key], val): + rval[key] = val + + elif zabbix_filters[key] != str(val): + rval[key] = val + + return rval + +# This logic is quite complex. We are comparing two lists of dictionaries. +# The outer for-loops allow us to descend down into both lists at the same time +# and then walk over the key,val pairs of the incoming user dict's changes +# or updates. The if-statements are looking at different sub-object types and +# comparing them. The other suggestion on how to write this is to write a recursive +# compare function but for the time constraints and for complexity I decided to go +# this route. +# pylint: disable=too-many-branches +def operation_differences(zabbix_ops, user_ops): + '''Determine the differences from user and zabbix for operations''' + + # if they don't match, take the user options + if len(zabbix_ops) != len(user_ops): + return user_ops + + rval = {} + for zab, user in zip(zabbix_ops, user_ops): + for key, val in user.items(): + if key == 'opconditions': + for z_cond, u_cond in zip(zab[key], user[key]): + if not all([str(u_cond[op_key]) == z_cond[op_key] for op_key in \ + ['conditiontype', 'operator', 'value']]): + rval[key] = val + break + elif key == 'opmessage': + # Verify each passed param matches + for op_msg_key, op_msg_val in val.items(): + if zab[key][op_msg_key] != str(op_msg_val): + rval[key] = val + break + + elif key == 'opmessage_grp': + zab_grp_ids = set([ugrp['usrgrpid'] for ugrp in zab[key]]) + usr_grp_ids = set([ugrp['usrgrpid'] for ugrp in val]) + if usr_grp_ids != zab_grp_ids: + rval[key] = val + + elif key == 'opmessage_usr': + zab_usr_ids = set([usr['userid'] for usr in zab[key]]) + usr_ids = set([usr['userid'] for usr in val]) + if usr_ids != zab_usr_ids: + rval[key] = val + + elif zab[key] != str(val): + rval[key] = val + return rval + +def get_users(zapi, users): + '''get the mediatype id from the mediatype name''' + rval_users = [] + + for user in users: + content = zapi.get_content('user', + 'get', + {'filter': {'alias': user}}) + rval_users.append({'userid': content['result'][0]['userid']}) + + return rval_users + +def get_user_groups(zapi, groups): + '''get the mediatype id from the mediatype name''' + user_groups = [] + + content = zapi.get_content('usergroup', + 'get', + {'search': {'name': groups}}) + + for usr_grp in content['result']: + user_groups.append({'usrgrpid': usr_grp['usrgrpid']}) + + return user_groups + +def get_mediatype_id_by_name(zapi, m_name): + '''get the mediatype id from the mediatype name''' + content = zapi.get_content('mediatype', + 'get', + {'filter': {'description': m_name}}) + + return content['result'][0]['mediatypeid'] + +def get_priority(priority): + ''' determine priority + ''' + prior = 0 + if 'info' in priority: + prior = 1 + elif 'warn' in priority: + prior = 2 + elif 'avg' == priority or 'ave' in priority: + prior = 3 + elif 'high' in priority: + prior = 4 + elif 'dis' in priority: + prior = 5 + + return prior + +def get_event_source(from_src): + '''Translate even str into value''' + choices = ['trigger', 'discovery', 'auto', 'internal'] + rval = 0 + try: + rval = choices.index(from_src) + except ValueError as _: + ZabbixAPIError('Value not found for event source [%s]' % from_src) + + return rval + +def get_status(inc_status): + '''determine status for action''' + rval = 1 + if inc_status == 'enabled': + rval = 0 + + return rval + +def get_condition_operator(inc_operator): + ''' determine the condition operator''' + vals = {'=': 0, + '<>': 1, + 'like': 2, + 'not like': 3, + 'in': 4, + '>=': 5, + '<=': 6, + 'not in': 7, + } + + return vals[inc_operator] + +def get_host_id_by_name(zapi, host_name): + '''Get host id by name''' + content = zapi.get_content('host', + 'get', + {'filter': {'name': host_name}}) + + return content['result'][0]['hostid'] + +def get_trigger_value(inc_trigger): + '''determine the proper trigger value''' + rval = 1 + if inc_trigger == 'PROBLEM': + rval = 1 + else: + rval = 0 + + return rval + +def get_template_id_by_name(zapi, t_name): + '''get the template id by name''' + content = zapi.get_content('template', + 'get', + {'filter': {'host': t_name}}) + + return content['result'][0]['templateid'] + + +def get_host_group_id_by_name(zapi, hg_name): + '''Get hostgroup id by name''' + content = zapi.get_content('hostgroup', + 'get', + {'filter': {'name': hg_name}}) + + return content['result'][0]['groupid'] + +def get_condition_type(event_source, inc_condition): + '''determine the condition type''' + c_types = {} + if event_source == 'trigger': + c_types = {'host group': 0, + 'host': 1, + 'trigger': 2, + 'trigger name': 3, + 'trigger severity': 4, + 'trigger value': 5, + 'time period': 6, + 'host template': 13, + 'application': 15, + 'maintenance status': 16, + } + + elif event_source == 'discovery': + c_types = {'host IP': 7, + 'discovered service type': 8, + 'discovered service port': 9, + 'discovery status': 10, + 'uptime or downtime duration': 11, + 'received value': 12, + 'discovery rule': 18, + 'discovery check': 19, + 'proxy': 20, + 'discovery object': 21, + } + + elif event_source == 'auto': + c_types = {'proxy': 20, + 'host name': 22, + 'host metadata': 24, + } + + elif event_source == 'internal': + c_types = {'host group': 0, + 'host': 1, + 'host template': 13, + 'application': 15, + 'event type': 23, + } + else: + raise ZabbixAPIError('Unkown event source %s' % event_source) + + return c_types[inc_condition] + +def get_operation_type(inc_operation): + ''' determine the correct operation type''' + o_types = {'send message': 0, + 'remote command': 1, + 'add host': 2, + 'remove host': 3, + 'add to host group': 4, + 'remove from host group': 5, + 'link to template': 6, + 'unlink from template': 7, + 'enable host': 8, + 'disable host': 9, + } + + return o_types[inc_operation] + +def get_action_operations(zapi, inc_operations): + '''Convert the operations into syntax for api''' + for operation in inc_operations: + operation['operationtype'] = get_operation_type(operation['operationtype']) + if operation['operationtype'] == 0: # send message. Need to fix the + operation['opmessage']['mediatypeid'] = \ + get_mediatype_id_by_name(zapi, operation['opmessage']['mediatypeid']) + operation['opmessage_grp'] = get_user_groups(zapi, operation.get('opmessage_grp', [])) + operation['opmessage_usr'] = get_users(zapi, operation.get('opmessage_usr', [])) + if operation['opmessage']['default_msg']: + operation['opmessage']['default_msg'] = 1 + else: + operation['opmessage']['default_msg'] = 0 + + # NOT supported for remote commands + elif operation['operationtype'] == 1: + continue + + # Handle Operation conditions: + # Currently there is only 1 available which + # is 'event acknowledged'. In the future + # if there are any added we will need to pass this + # option to a function and return the correct conditiontype + if operation.has_key('opconditions'): + for condition in operation['opconditions']: + if condition['conditiontype'] == 'event acknowledged': + condition['conditiontype'] = 14 + + if condition['operator'] == '=': + condition['operator'] = 0 + + if condition['value'] == 'acknowledged': + condition['operator'] = 1 + else: + condition['operator'] = 0 + + + return inc_operations + +def get_operation_evaltype(inc_type): + '''get the operation evaltype''' + rval = 0 + if inc_type == 'and/or': + rval = 0 + elif inc_type == 'and': + rval = 1 + elif inc_type == 'or': + rval = 2 + elif inc_type == 'custom': + rval = 3 + + return rval + +def get_action_conditions(zapi, event_source, inc_conditions): + '''Convert the conditions into syntax for api''' + + calc_type = inc_conditions.pop('calculation_type') + inc_conditions['evaltype'] = get_operation_evaltype(calc_type) + for cond in inc_conditions['conditions']: + + cond['operator'] = get_condition_operator(cond['operator']) + # Based on conditiontype we need to set the proper value + # e.g. conditiontype = hostgroup then the value needs to be a hostgroup id + # e.g. conditiontype = host the value needs to be a host id + cond['conditiontype'] = get_condition_type(event_source, cond['conditiontype']) + if cond['conditiontype'] == 0: + cond['value'] = get_host_group_id_by_name(zapi, cond['value']) + elif cond['conditiontype'] == 1: + cond['value'] = get_host_id_by_name(zapi, cond['value']) + elif cond['conditiontype'] == 4: + cond['value'] = get_priority(cond['value']) + + elif cond['conditiontype'] == 5: + cond['value'] = get_trigger_value(cond['value']) + elif cond['conditiontype'] == 13: + cond['value'] = get_template_id_by_name(zapi, cond['value']) + elif cond['conditiontype'] == 16: + cond['value'] = '' + + return inc_conditions + + +def get_send_recovery(send_recovery): + '''Get the integer value''' + rval = 0 + if send_recovery: + rval = 1 + + return rval + +# The branches are needed for CRUD and error handling +# pylint: disable=too-many-branches +def main(): + ''' + ansible zabbix module for zbx_item + ''' + + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + + name=dict(default=None, type='str'), + event_source=dict(default='trigger', choices=['trigger', 'discovery', 'auto', 'internal'], type='str'), + action_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'), + action_message=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}\r\n" + + "Last value: {ITEM.LASTVALUE}\r\n\r\n{TRIGGER.URL}", type='str'), + reply_subject=dict(default="{TRIGGER.NAME}: {TRIGGER.STATUS}", type='str'), + reply_message=dict(default="Trigger: {TRIGGER.NAME}\r\nTrigger status: {TRIGGER.STATUS}\r\n" + + "Trigger severity: {TRIGGER.SEVERITY}\r\nTrigger URL: {TRIGGER.URL}\r\n\r\n" + + "Item values:\r\n\r\n1. {ITEM.NAME1} ({HOST.NAME1}:{ITEM.KEY1}): " + + "{ITEM.VALUE1}\r\n2. {ITEM.NAME2} ({HOST.NAME2}:{ITEM.KEY2}): " + + "{ITEM.VALUE2}\r\n3. {ITEM.NAME3} ({HOST.NAME3}:{ITEM.KEY3}): " + + "{ITEM.VALUE3}", type='str'), + send_recovery=dict(default=False, type='bool'), + status=dict(default=None, type='str'), + escalation_time=dict(default=60, type='int'), + conditions_filter=dict(default=None, type='dict'), + operations=dict(default=None, type='list'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'action' + state = module.params['state'] + + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'name': module.params['name']}, + 'selectFilter': 'extend', + 'selectOperations': 'extend', + }) + + #******# + # GET + #******# + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + #******# + # DELETE + #******# + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0]['itemid']]) + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + + conditions = get_action_conditions(zapi, module.params['event_source'], module.params['conditions_filter']) + operations = get_action_operations(zapi, module.params['operations']) + params = {'name': module.params['name'], + 'esc_period': module.params['escalation_time'], + 'eventsource': get_event_source(module.params['event_source']), + 'status': get_status(module.params['status']), + 'def_shortdata': module.params['action_subject'], + 'def_longdata': module.params['action_message'], + 'r_shortdata': module.params['reply_subject'], + 'r_longdata': module.params['reply_message'], + 'recovery_msg': get_send_recovery(module.params['send_recovery']), + 'filter': conditions, + 'operations': operations, + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=True, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + + ######## + # UPDATE + ######## + _ = params.pop('hostid', None) + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if key == 'operations': + ops = operation_differences(zab_results[key], value) + if ops: + differences[key] = ops + + elif key == 'filter': + filters = filter_differences(zab_results[key], value) + if filters: + differences[key] = filters + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update. + # action update requires an id, filters, and operations + differences['actionid'] = zab_results['actionid'] + differences['operations'] = params['operations'] + differences['filter'] = params['filter'] + content = zapi.get_content(zbx_class_name, 'update', differences) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_application.py b/roles/lib_zabbix/library/zbx_application.py new file mode 100644 index 000000000..21e3d91f4 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_application.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +''' +Ansible module for application +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix application ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_template_ids(zapi, template_name): + ''' + get related templates + ''' + template_ids = [] + # Fetch templates by name + content = zapi.get_content('template', + 'get', + {'search': {'host': template_name}}) + if content.has_key('result'): + template_ids.append(content['result'][0]['templateid']) + return template_ids + +def main(): + ''' Ansible module for application + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str', required=True), + template_name=dict(default=None, type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the application for the rest of the calls + zbx_class_name = 'application' + idname = 'applicationid' + aname = module.params['name'] + state = module.params['state'] + # get a applicationid, see if it exists + tids = get_template_ids(zapi, module.params['template_name']) + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'name': aname}, + 'templateids': tids[0], + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + params = {'hostid': tids[0], + 'name': aname, + } + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + if key == 'templates' and zab_results.has_key('parentTemplates'): + if zab_results['parentTemplates'] != value: + differences[key] = value + elif zab_results[key] != str(value) and zab_results[key] != value: + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=content['result'], state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_discoveryrule.py b/roles/lib_zabbix/library/zbx_discoveryrule.py new file mode 100644 index 000000000..f52f350a5 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_discoveryrule.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python +''' +Zabbix discovery rule ansible module +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_template(zapi, template_name): + '''get a template by name + ''' + content = zapi.get_content('template', + 'get', + {'search': {'host': template_name}, + 'output': 'extend', + 'selectInterfaces': 'interfaceid', + }) + if not content['result']: + return None + return content['result'][0] + +def get_type(vtype): + ''' + Determine which type of discoverrule this is + ''' + _types = {'agent': 0, + 'SNMPv1': 1, + 'trapper': 2, + 'simple': 3, + 'SNMPv2': 4, + 'internal': 5, + 'SNMPv3': 6, + 'active': 7, + 'external': 10, + 'database monitor': 11, + 'ipmi': 12, + 'ssh': 13, + 'telnet': 14, + 'JMX': 16, + } + + for typ in _types.keys(): + if vtype in typ or vtype == typ: + _vtype = _types[typ] + break + else: + _vtype = 2 + + return _vtype + +def main(): + ''' + Ansible module for zabbix discovery rules + ''' + + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + key=dict(default=None, type='str'), + description=dict(default=None, type='str'), + interfaceid=dict(default=None, type='int'), + ztype=dict(default='trapper', type='str'), + delay=dict(default=60, type='int'), + lifetime=dict(default=30, type='int'), + template_name=dict(default=[], type='list'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'discoveryrule' + idname = "itemid" + dname = module.params['name'] + state = module.params['state'] + template = get_template(zapi, module.params['template_name']) + + # selectInterfaces doesn't appear to be working but is needed. + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'name': dname}, + 'templateids': template['templateid'], + #'selectDServices': 'extend', + #'selectDChecks': 'extend', + #'selectDhosts': 'dhostid', + }) + + #******# + # GET + #******# + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + #******# + # DELETE + #******# + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + + # Create and Update + if state == 'present': + params = {'name': dname, + 'key_': module.params['key'], + 'hostid': template['templateid'], + 'interfaceid': module.params['interfaceid'], + 'lifetime': module.params['lifetime'], + 'type': get_type(module.params['ztype']), + 'description': module.params['description'], + } + if params['type'] in [2, 5, 7, 11]: + params.pop('interfaceid') + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=True, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + ######## + # UPDATE + ######## + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_host.py b/roles/lib_zabbix/library/zbx_host.py new file mode 100644 index 000000000..e26c9caf3 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_host.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +''' +Zabbix host ansible module +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_group_ids(zapi, hostgroup_names): + ''' + get hostgroups + ''' + # Fetch groups by name + group_ids = [] + for hgr in hostgroup_names: + content = zapi.get_content('hostgroup', 'get', {'search': {'name': hgr}}) + if content.has_key('result'): + group_ids.append({'groupid': content['result'][0]['groupid']}) + + return group_ids + +def get_template_ids(zapi, template_names): + ''' + get related templates + ''' + template_ids = [] + # Fetch templates by name + for template_name in template_names: + content = zapi.get_content('template', 'get', {'search': {'host': template_name}}) + if content.has_key('result'): + template_ids.append({'templateid': content['result'][0]['templateid']}) + return template_ids + +def main(): + ''' + Ansible module for zabbix host + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + hostgroup_names=dict(default=[], type='list'), + template_names=dict(default=[], type='list'), + state=dict(default='present', type='str'), + interfaces=dict(default=None, type='list'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'host' + idname = "hostid" + hname = module.params['name'] + state = module.params['state'] + + # selectInterfaces doesn't appear to be working but is needed. + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'host': hname}, + 'selectGroups': 'groupid', + 'selectParentTemplates': 'templateid', + 'selectInterfaces': 'interfaceid', + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + ifs = module.params['interfaces'] or [{'type': 1, # interface type, 1 = agent + 'main': 1, # default interface? 1 = true + 'useip': 1, # default interface? 1 = true + 'ip': '127.0.0.1', # default interface? 1 = true + 'dns': '', # dns for host + 'port': '10050', # port for interface? 10050 + }] + params = {'host': hname, + 'groups': get_group_ids(zapi, module.params['hostgroup_names']), + 'templates': get_template_ids(zapi, module.params['template_names']), + 'interfaces': ifs, + } + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if key == 'templates' and zab_results.has_key('parentTemplates'): + if zab_results['parentTemplates'] != value: + differences[key] = value + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_hostgroup.py b/roles/lib_zabbix/library/zbx_hostgroup.py new file mode 100644 index 000000000..7f080af24 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_hostgroup.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +''' Ansible module for hostgroup +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix hostgroup ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def main(): + ''' ansible module for hostgroup + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'hostgroup' + idname = "groupid" + hname = module.params['name'] + state = module.params['state'] + + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'name': hname}, + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + params = {'name': hname} + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + if zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_item.py b/roles/lib_zabbix/library/zbx_item.py new file mode 100644 index 000000000..5dc3cff9b --- /dev/null +++ b/roles/lib_zabbix/library/zbx_item.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +''' + Ansible module for zabbix items +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix item ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_value_type(value_type): + ''' + Possible values: + 0 - numeric float; + 1 - character; + 2 - log; + 3 - numeric unsigned; + 4 - text + ''' + vtype = 0 + if 'int' in value_type: + vtype = 3 + elif 'log' in value_type: + vtype = 2 + elif 'char' in value_type: + vtype = 1 + elif 'str' in value_type: + vtype = 4 + + return vtype + +def get_app_ids(application_names, app_name_ids): + ''' get application ids from names + ''' + applications = [] + if application_names: + for app in application_names: + applications.append(app_name_ids[app]) + + return applications + +def get_template_id(zapi, template_name): + ''' + get related templates + ''' + template_ids = [] + app_ids = {} + # Fetch templates by name + content = zapi.get_content('template', + 'get', + {'search': {'host': template_name}, + 'selectApplications': ['applicationid', 'name']}) + if content.has_key('result'): + template_ids.append(content['result'][0]['templateid']) + for app in content['result'][0]['applications']: + app_ids[app['name']] = app['applicationid'] + + return template_ids, app_ids + +def get_multiplier(inval): + ''' Determine the multiplier + ''' + if inval == None or inval == '': + return None, 0 + + rval = None + try: + rval = int(inval) + except ValueError: + pass + + if rval: + return rval, 1 + + return rval, 0 + +def get_zabbix_type(ztype): + ''' + Determine which type of discoverrule this is + ''' + _types = {'agent': 0, + 'SNMPv1': 1, + 'trapper': 2, + 'simple': 3, + 'SNMPv2': 4, + 'internal': 5, + 'SNMPv3': 6, + 'active': 7, + 'aggregate': 8, + 'web': 9, + 'external': 10, + 'database monitor': 11, + 'ipmi': 12, + 'ssh': 13, + 'telnet': 14, + 'calculated': 15, + 'JMX': 16, + 'SNMP trap': 17, + } + + for typ in _types.keys(): + if ztype in typ or ztype == typ: + _vtype = _types[typ] + break + else: + _vtype = 2 + + return _vtype + +# The branches are needed for CRUD and error handling +# pylint: disable=too-many-branches +def main(): + ''' + ansible zabbix module for zbx_item + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + key=dict(default=None, type='str'), + template_name=dict(default=None, type='str'), + zabbix_type=dict(default='trapper', type='str'), + value_type=dict(default='int', type='str'), + interval=dict(default=60, type='int'), + delta=dict(default=0, type='int'), + multiplier=dict(default=None, type='str'), + description=dict(default=None, type='str'), + units=dict(default=None, type='str'), + applications=dict(default=None, type='list'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'item' + state = module.params['state'] + + templateid, app_name_ids = get_template_id(zapi, module.params['template_name']) + + # Fail if a template was not found matching the name + if not templateid: + module.exit_json(failed=True, + changed=False, + results='Error: Could find template with name %s for item.' % module.params['template_name'], + state="Unkown") + + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'key_': module.params['key']}, + 'selectApplications': 'applicationid', + 'templateids': templateid, + }) + + #******# + # GET + #******# + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + #******# + # DELETE + #******# + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0]['itemid']]) + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + + formula, use_multiplier = get_multiplier(module.params['multiplier']) + params = {'name': module.params.get('name', module.params['key']), + 'key_': module.params['key'], + 'hostid': templateid[0], + 'type': get_zabbix_type(module.params['zabbix_type']), + 'value_type': get_value_type(module.params['value_type']), + 'applications': get_app_ids(module.params['applications'], app_name_ids), + 'formula': formula, + 'multiplier': use_multiplier, + 'description': module.params['description'], + 'units': module.params['units'], + 'delay': module.params['interval'], + 'delta': module.params['delta'], + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=True, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + + ######## + # UPDATE + ######## + _ = params.pop('hostid', None) + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if key == 'applications': + app_ids = [item['applicationid'] for item in zab_results[key]] + if set(app_ids) != set(value): + differences[key] = value + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences['itemid'] = zab_results['itemid'] + content = zapi.get_content(zbx_class_name, 'update', differences) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_itemprototype.py b/roles/lib_zabbix/library/zbx_itemprototype.py new file mode 100644 index 000000000..e7fd6fa21 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_itemprototype.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python +''' +Zabbix discovery rule ansible module +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_rule_id(zapi, discoveryrule_key, templateid): + '''get a discoveryrule by name + ''' + content = zapi.get_content('discoveryrule', + 'get', + {'search': {'key_': discoveryrule_key}, + 'output': 'extend', + 'templateids': templateid, + }) + if not content['result']: + return None + return content['result'][0]['itemid'] + +def get_template(zapi, template_name): + '''get a template by name + ''' + if not template_name: + return None + + content = zapi.get_content('template', + 'get', + {'search': {'host': template_name}, + 'output': 'extend', + 'selectInterfaces': 'interfaceid', + }) + if not content['result']: + return None + return content['result'][0] + +def get_type(ztype): + ''' + Determine which type of discoverrule this is + ''' + _types = {'agent': 0, + 'SNMPv1': 1, + 'trapper': 2, + 'simple': 3, + 'SNMPv2': 4, + 'internal': 5, + 'SNMPv3': 6, + 'active': 7, + 'aggregate': 8, + 'external': 10, + 'database monitor': 11, + 'ipmi': 12, + 'ssh': 13, + 'telnet': 14, + 'calculated': 15, + 'JMX': 16, + } + + for typ in _types.keys(): + if ztype in typ or ztype == typ: + _vtype = _types[typ] + break + else: + _vtype = 2 + + return _vtype + +def get_value_type(value_type): + ''' + Possible values: + 0 - numeric float; + 1 - character; + 2 - log; + 3 - numeric unsigned; + 4 - text + ''' + vtype = 0 + if 'int' in value_type: + vtype = 3 + elif 'char' in value_type: + vtype = 1 + elif 'str' in value_type: + vtype = 4 + + return vtype + +def get_status(status): + ''' Determine status + ''' + _status = 0 + if status == 'disabled': + _status = 1 + elif status == 'unsupported': + _status = 3 + + return _status + +def get_app_ids(zapi, application_names, templateid): + ''' get application ids from names + ''' + app_ids = [] + for app_name in application_names: + content = zapi.get_content('application', 'get', {'filter': {'name': app_name}, 'templateids': templateid}) + if content.has_key('result'): + app_ids.append(content['result'][0]['applicationid']) + return app_ids + +# pylint: disable=too-many-branches +def main(): + ''' + Ansible module for zabbix discovery rules + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + key=dict(default=None, type='str'), + description=dict(default=None, type='str'), + interfaceid=dict(default=None, type='int'), + ztype=dict(default='trapper', type='str'), + value_type=dict(default='float', type='str'), + delay=dict(default=60, type='int'), + lifetime=dict(default=30, type='int'), + state=dict(default='present', type='str'), + status=dict(default='enabled', type='str'), + applications=dict(default=[], type='list'), + template_name=dict(default=None, type='str'), + discoveryrule_key=dict(default=None, type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'itemprototype' + idname = "itemid" + state = module.params['state'] + template = get_template(zapi, module.params['template_name']) + + # selectInterfaces doesn't appear to be working but is needed. + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'key_': module.params['key']}, + 'selectApplications': 'applicationid', + 'selectDiscoveryRule': 'itemid', + 'templated': True, + }) + + #******# + # GET + #******# + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + #******# + # DELETE + #******# + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + params = {'name': module.params['name'], + 'key_': module.params['key'], + 'hostid': template['templateid'], + 'interfaceid': module.params['interfaceid'], + 'ruleid': get_rule_id(zapi, module.params['discoveryrule_key'], template['templateid']), + 'type': get_type(module.params['ztype']), + 'value_type': get_value_type(module.params['value_type']), + 'applications': get_app_ids(zapi, module.params['applications'], template['templateid']), + 'description': module.params['description'], + } + + if params['type'] in [2, 5, 7, 8, 11, 15]: + params.pop('interfaceid') + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + #******# + # UPDATE + #******# + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if key == 'ruleid': + if value != zab_results['discoveryRule']['itemid']: + differences[key] = value + + elif key == 'applications': + app_ids = [app['applicationid'] for app in zab_results[key]] + if set(app_ids) - set(value): + differences[key] = value + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_mediatype.py b/roles/lib_zabbix/library/zbx_mediatype.py new file mode 100644 index 000000000..3be232ecf --- /dev/null +++ b/roles/lib_zabbix/library/zbx_mediatype.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +''' + Ansible module for mediatype +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix mediatype ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_mtype(mtype): + ''' + Transport used by the media type. + Possible values: + 0 - email; + 1 - script; + 2 - SMS; + 3 - Jabber; + 100 - Ez Texting. + ''' + mtype = mtype.lower() + media_type = None + if mtype == 'script': + media_type = 1 + elif mtype == 'sms': + media_type = 2 + elif mtype == 'jabber': + media_type = 3 + elif mtype == 'script': + media_type = 100 + else: + media_type = 0 + + return media_type + +def main(): + ''' + Ansible zabbix module for mediatype + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + description=dict(default=None, type='str'), + mtype=dict(default=None, type='str'), + smtp_server=dict(default=None, type='str'), + smtp_helo=dict(default=None, type='str'), + smtp_email=dict(default=None, type='str'), + passwd=dict(default=None, type='str'), + path=dict(default=None, type='str'), + username=dict(default=None, type='str'), + status=dict(default='enabled', type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'mediatype' + idname = "mediatypeid" + description = module.params['description'] + state = module.params['state'] + + content = zapi.get_content(zbx_class_name, 'get', {'search': {'description': description}}) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + status = 1 + if module.params['status']: + status = 0 + params = {'description': description, + 'type': get_mtype(module.params['mtype']), + 'smtp_server': module.params['smtp_server'], + 'smtp_helo': module.params['smtp_helo'], + 'smtp_email': module.params['smtp_email'], + 'passwd': module.params['passwd'], + 'exec_path': module.params['path'], + 'username': module.params['username'], + 'status': status, + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + if zab_results[key] != value and \ + zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_template.py b/roles/lib_zabbix/library/zbx_template.py new file mode 100644 index 000000000..ff5714bdc --- /dev/null +++ b/roles/lib_zabbix/library/zbx_template.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +''' +Ansible module for template +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix template ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def main(): + ''' Ansible module for template + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'template' + idname = 'templateid' + tname = module.params['name'] + state = module.params['state'] + # get a template, see if it exists + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'host': tname}, + 'selectParentTemplates': 'templateid', + 'selectGroups': 'groupid', + 'selectApplications': 'applicationid', + 'selectDiscoveries': 'extend', + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + if not tname: + module.exit_json(failed=True, + changed=False, + results='Must specifiy a template name.', + state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + params = {'groups': module.params.get('groups', [{'groupid': '1'}]), + 'host': tname, + } + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + if key == 'templates' and zab_results.has_key('parentTemplates'): + if zab_results['parentTemplates'] != value: + differences[key] = value + elif zab_results[key] != str(value) and zab_results[key] != value: + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=content['result'], state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_trigger.py b/roles/lib_zabbix/library/zbx_trigger.py new file mode 100644 index 000000000..ab7731faa --- /dev/null +++ b/roles/lib_zabbix/library/zbx_trigger.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python +''' +ansible module for zabbix triggers +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix trigger ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_priority(priority): + ''' determine priority + ''' + prior = 0 + if 'info' in priority: + prior = 1 + elif 'warn' in priority: + prior = 2 + elif 'avg' == priority or 'ave' in priority: + prior = 3 + elif 'high' in priority: + prior = 4 + elif 'dis' in priority: + prior = 5 + + return prior + +def get_deps(zapi, deps): + ''' get trigger dependencies + ''' + results = [] + for desc in deps: + content = zapi.get_content('trigger', + 'get', + {'filter': {'description': desc}, + 'expandExpression': True, + 'selectDependencies': 'triggerid', + }) + if content.has_key('result'): + results.append({'triggerid': content['result'][0]['triggerid']}) + + return results + + +def get_trigger_status(inc_status): + ''' Determine the trigger's status + 0 is enabled + 1 is disabled + ''' + r_status = 0 + if inc_status == 'disabled': + r_status = 1 + + return r_status + +def get_template_id(zapi, template_name): + ''' + get related templates + ''' + template_ids = [] + app_ids = {} + # Fetch templates by name + content = zapi.get_content('template', + 'get', + {'search': {'host': template_name}, + 'selectApplications': ['applicationid', 'name']}) + if content.has_key('result'): + template_ids.append(content['result'][0]['templateid']) + for app in content['result'][0]['applications']: + app_ids[app['name']] = app['applicationid'] + + return template_ids, app_ids + +def main(): + ''' + Create a trigger in zabbix + + Example: + "params": { + "description": "Processor load is too high on {HOST.NAME}", + "expression": "{Linux server:system.cpu.load[percpu,avg1].last()}>5", + "dependencies": [ + { + "triggerid": "14062" + } + ] + }, + + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + expression=dict(default=None, type='str'), + name=dict(default=None, type='str'), + description=dict(default=None, type='str'), + dependencies=dict(default=[], type='list'), + priority=dict(default='avg', type='str'), + url=dict(default=None, type='str'), + status=dict(default=None, type='str'), + state=dict(default='present', type='str'), + template_name=dict(default=None, type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'trigger' + idname = "triggerid" + state = module.params['state'] + tname = module.params['name'] + + templateid = None + if module.params['template_name']: + templateid, _ = get_template_id(zapi, module.params['template_name']) + + content = zapi.get_content(zbx_class_name, + 'get', + {'filter': {'description': tname}, + 'expandExpression': True, + 'selectDependencies': 'triggerid', + 'templateids': templateid, + }) + + # Get + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + # Delete + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + params = {'description': tname, + 'comments': module.params['description'], + 'expression': module.params['expression'], + 'dependencies': get_deps(zapi, module.params['dependencies']), + 'priority': get_priority(module.params['priority']), + 'url': module.params['url'], + 'status': get_trigger_status(module.params['status']), + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=True, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + ######## + # UPDATE + ######## + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_triggerprototype.py b/roles/lib_zabbix/library/zbx_triggerprototype.py new file mode 100644 index 000000000..c1224b268 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_triggerprototype.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +''' +ansible module for zabbix triggerprototypes +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix triggerprototypes ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_priority(priority): + ''' determine priority + ''' + prior = 0 + if 'info' in priority: + prior = 1 + elif 'warn' in priority: + prior = 2 + elif 'avg' == priority or 'ave' in priority: + prior = 3 + elif 'high' in priority: + prior = 4 + elif 'dis' in priority: + prior = 5 + + return prior + +def get_trigger_status(inc_status): + ''' Determine the trigger's status + 0 is enabled + 1 is disabled + ''' + r_status = 0 + if inc_status == 'disabled': + r_status = 1 + + return r_status + + +def main(): + ''' + Create a triggerprototype in zabbix + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + name=dict(default=None, type='str'), + expression=dict(default=None, type='str'), + description=dict(default=None, type='str'), + priority=dict(default='avg', type='str'), + url=dict(default=None, type='str'), + status=dict(default=None, type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'triggerprototype' + idname = "triggerid" + state = module.params['state'] + tname = module.params['name'] + + content = zapi.get_content(zbx_class_name, + 'get', + {'filter': {'description': tname}, + 'expandExpression': True, + 'selectDependencies': 'triggerid', + }) + + # Get + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + # Delete + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + params = {'description': tname, + 'comments': module.params['description'], + 'expression': module.params['expression'], + 'priority': get_priority(module.params['priority']), + 'url': module.params['url'], + 'status': get_trigger_status(module.params['status']), + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + #******# + # CREATE + #******# + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=True, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + ######## + # UPDATE + ######## + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + + if zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_user.py b/roles/lib_zabbix/library/zbx_user.py new file mode 100644 index 000000000..62c85c1bf --- /dev/null +++ b/roles/lib_zabbix/library/zbx_user.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +''' +ansible module for zabbix users +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix user ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_usergroups(zapi, usergroups): + ''' Get usergroups + ''' + ugroups = [] + for ugr in usergroups: + content = zapi.get_content('usergroup', + 'get', + {'search': {'name': ugr}, + #'selectUsers': 'userid', + #'getRights': 'extend' + }) + if content['result']: + ugroups.append({'usrgrpid': content['result'][0]['usrgrpid']}) + + return ugroups or None + +def get_passwd(passwd): + '''Determine if password is set, if not, return 'zabbix' + ''' + if passwd: + return passwd + + return 'zabbix' + +def get_usertype(user_type): + ''' + Determine zabbix user account type + ''' + if not user_type: + return None + + utype = 1 + if 'super' in user_type: + utype = 3 + elif 'admin' in user_type or user_type == 'admin': + utype = 2 + + return utype + +def main(): + ''' + ansible zabbix module for users + ''' + + ##def user(self, name, state='present', params=None): + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + login=dict(default=None, type='str'), + first_name=dict(default=None, type='str'), + last_name=dict(default=None, type='str'), + user_type=dict(default=None, type='str'), + password=dict(default=None, type='str'), + update_password=dict(default=False, type='bool'), + user_groups=dict(default=[], type='list'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + ## before we can create a user media and users with media types we need media + zbx_class_name = 'user' + idname = "userid" + state = module.params['state'] + + content = zapi.get_content(zbx_class_name, + 'get', + {'output': 'extend', + 'search': {'alias': module.params['login']}, + "selectUsrgrps": 'usergrpid', + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content) or len(content['result']) == 0: + module.exit_json(changed=False, state="absent") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + + params = {'alias': module.params['login'], + 'passwd': get_passwd(module.params['password']), + 'usrgrps': get_usergroups(zapi, module.params['user_groups']), + 'name': module.params['first_name'], + 'surname': module.params['last_name'], + 'type': get_usertype(module.params['user_type']), + } + + # Remove any None valued params + _ = [params.pop(key, None) for key in params.keys() if params[key] is None] + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + + if content.has_key('Error'): + module.exit_json(failed=True, changed=False, results=content, state='present') + + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + + # Update password + if not module.params['update_password']: + params.pop('passwd', None) + + zab_results = content['result'][0] + for key, value in params.items(): + + if key == 'usrgrps': + # this must be done as a list of ordered dictionaries fails comparison + if not all([_ in value for _ in zab_results[key]]): + differences[key] = value + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_user_media.py b/roles/lib_zabbix/library/zbx_user_media.py new file mode 100644 index 000000000..8895c78c3 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_user_media.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +''' + Ansible module for user media +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix user media ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_mtype(zapi, mtype): + '''Get mediatype + + If passed an int, return it as the mediatypeid + if its a string, then try to fetch through a description + ''' + if isinstance(mtype, int): + return mtype + try: + return int(mtype) + except ValueError: + pass + + content = zapi.get_content('mediatype', 'get', {'filter': {'description': mtype}}) + if content.has_key('result') and content['result']: + return content['result'][0]['mediatypeid'] + + return None + +def get_user(zapi, user): + ''' Get userids from user aliases + ''' + content = zapi.get_content('user', 'get', {'filter': {'alias': user}}) + if content['result']: + return content['result'][0] + + return None + +def get_severity(severity): + ''' determine severity + ''' + if isinstance(severity, int) or \ + isinstance(severity, str): + return severity + + val = 0 + sev_map = { + 'not': 2**0, + 'inf': 2**1, + 'war': 2**2, + 'ave': 2**3, + 'avg': 2**3, + 'hig': 2**4, + 'dis': 2**5, + } + for level in severity: + val |= sev_map[level[:3].lower()] + return val + +def get_zbx_user_query_data(zapi, user_name): + ''' If name exists, retrieve it, and build query params. + ''' + query = {} + if user_name: + zbx_user = get_user(zapi, user_name) + query = {'userid': zbx_user['userid']} + + return query + +def find_media(medias, user_media): + ''' Find the user media in the list of medias + ''' + for media in medias: + if all([media[key] == str(user_media[key]) for key in user_media.keys()]): + return media + return None + +def get_active(is_active): + '''Determine active value + 0 - enabled + 1 - disabled + ''' + active = 1 + if is_active: + active = 0 + + return active + +def get_mediatype(zapi, mediatype, mediatype_desc): + ''' Determine mediatypeid + ''' + mtypeid = None + if mediatype: + mtypeid = get_mtype(zapi, mediatype) + elif mediatype_desc: + mtypeid = get_mtype(zapi, mediatype_desc) + + return mtypeid + +def preprocess_medias(zapi, medias): + ''' Insert the correct information when processing medias ''' + for media in medias: + # Fetch the mediatypeid from the media desc (name) + if media.has_key('mediatype'): + media['mediatypeid'] = get_mediatype(zapi, mediatype=None, mediatype_desc=media.pop('mediatype')) + + media['active'] = get_active(media.get('active')) + media['severity'] = int(get_severity(media['severity'])) + + return medias + +# Disabling branching as the logic requires branches. +# I've also added a few safeguards which required more branches. +# pylint: disable=too-many-branches +def main(): + ''' + Ansible zabbix module for mediatype + ''' + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + login=dict(default=None, type='str'), + active=dict(default=False, type='bool'), + medias=dict(default=None, type='list'), + mediaid=dict(default=None, type='int'), + mediatype=dict(default=None, type='str'), + mediatype_desc=dict(default=None, type='str'), + #d-d,hh:mm-hh:mm;d-d,hh:mm-hh:mm... + period=dict(default=None, type='str'), + sendto=dict(default=None, type='str'), + severity=dict(default=None, type='str'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + #Set the instance and the template for the rest of the calls + zbx_class_name = 'user' + idname = "mediaid" + state = module.params['state'] + + # User media is fetched through the usermedia.get + zbx_user_query = get_zbx_user_query_data(zapi, module.params['login']) + content = zapi.get_content('usermedia', 'get', + {'userids': [uid for user, uid in zbx_user_query.items()]}) + ##### + # Get + ##### + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + ######## + # Delete + ######## + if state == 'absent': + if not exists(content) or len(content['result']) == 0: + module.exit_json(changed=False, state="absent") + + if not module.params['login']: + module.exit_json(failed=True, changed=False, results='Must specifiy a user login.', state="absent") + + content = zapi.get_content(zbx_class_name, 'deletemedia', [res[idname] for res in content['result']]) + + if content.has_key('error'): + module.exit_json(changed=False, results=content['error'], state="absent") + + module.exit_json(changed=True, results=content['result'], state="absent") + + # Create and Update + if state == 'present': + active = get_active(module.params['active']) + mtypeid = get_mediatype(zapi, module.params['mediatype'], module.params['mediatype_desc']) + + medias = module.params['medias'] + if medias == None: + medias = [{'mediatypeid': mtypeid, + 'sendto': module.params['sendto'], + 'active': active, + 'severity': int(get_severity(module.params['severity'])), + 'period': module.params['period'], + }] + else: + medias = preprocess_medias(zapi, medias) + + params = {'users': [zbx_user_query], + 'medias': medias, + 'output': 'extend', + } + + ######## + # Create + ######## + if not exists(content): + if not params['medias']: + module.exit_json(changed=False, results=content['result'], state='present') + + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'addmedia', params) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state='present') + + # mediaid signifies an update + # If user params exists, check to see if they already exist in zabbix + # if they exist, then return as no update + # elif they do not exist, then take user params only + ######## + # Update + ######## + diff = {'medias': [], 'users': {}} + _ = [diff['medias'].append(media) for media in params['medias'] if not find_media(content['result'], media)] + + if not diff['medias']: + module.exit_json(changed=False, results=content['result'], state="present") + + for user in params['users']: + diff['users']['userid'] = user['userid'] + + # Medias have no real unique key so therefore we need to make it like the incoming user's request + diff['medias'] = medias + + # We have differences and need to update + content = zapi.get_content(zbx_class_name, 'updatemedia', diff) + + if content.has_key('error'): + module.exit_json(failed=True, changed=False, results=content['error'], state="present") + + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/library/zbx_usergroup.py b/roles/lib_zabbix/library/zbx_usergroup.py new file mode 100644 index 000000000..297d8ef91 --- /dev/null +++ b/roles/lib_zabbix/library/zbx_usergroup.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +''' +zabbix ansible module for usergroups +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +# Zabbix usergroup ansible module +# +# +# Copyright 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): + ''' Check if key exists in content or the size of content[key] > 0 + ''' + if not content.has_key(key): + return False + + if not content[key]: + return False + + return True + +def get_rights(zapi, rights): + '''Get rights + ''' + if rights == None: + return None + + perms = [] + for right in rights: + hstgrp = right.keys()[0] + perm = right.values()[0] + content = zapi.get_content('hostgroup', 'get', {'search': {'name': hstgrp}}) + if content['result']: + permission = 0 + if perm == 'ro': + permission = 2 + elif perm == 'rw': + permission = 3 + perms.append({'id': content['result'][0]['groupid'], + 'permission': permission}) + return perms + +def get_gui_access(access): + ''' Return the gui_access for a usergroup + ''' + access = access.lower() + if access == 'internal': + return 1 + elif access == 'disabled': + return 2 + + return 0 + +def get_debug_mode(mode): + ''' Return the debug_mode for a usergroup + ''' + mode = mode.lower() + if mode == 'enabled': + return 1 + + return 0 + +def get_user_status(status): + ''' Return the user_status for a usergroup + ''' + status = status.lower() + if status == 'enabled': + return 0 + + return 1 + + +#def get_userids(zapi, users): +# ''' Get userids from user aliases +# ''' +# if not users: +# return None +# +# userids = [] +# for alias in users: +# content = zapi.get_content('user', 'get', {'search': {'alias': alias}}) +# if content['result']: +# userids.append(content['result'][0]['userid']) +# +# return userids + +def main(): + ''' Ansible module for usergroup + ''' + + ##def usergroup(self, name, rights=None, users=None, state='present', params=None): + + module = AnsibleModule( + argument_spec=dict( + zbx_server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), + zbx_user=dict(default=os.environ.get('ZABBIX_USER', None), type='str'), + zbx_password=dict(default=os.environ.get('ZABBIX_PASSWORD', None), type='str'), + zbx_debug=dict(default=False, type='bool'), + debug_mode=dict(default='disabled', type='str'), + gui_access=dict(default='default', type='str'), + status=dict(default='enabled', type='str'), + name=dict(default=None, type='str', required=True), + rights=dict(default=None, type='list'), + #users=dict(default=None, type='list'), + state=dict(default='present', type='str'), + ), + #supports_check_mode=True + ) + + zapi = ZabbixAPI(ZabbixConnection(module.params['zbx_server'], + module.params['zbx_user'], + module.params['zbx_password'], + module.params['zbx_debug'])) + + zbx_class_name = 'usergroup' + idname = "usrgrpid" + uname = module.params['name'] + state = module.params['state'] + + content = zapi.get_content(zbx_class_name, + 'get', + {'search': {'name': uname}, + 'selectUsers': 'userid', + }) + if state == 'list': + module.exit_json(changed=False, results=content['result'], state="list") + + if state == 'absent': + if not exists(content): + module.exit_json(changed=False, state="absent") + + if not uname: + module.exit_json(failed=True, changed=False, results='Need to pass in a user.', state="error") + + content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) + module.exit_json(changed=True, results=content['result'], state="absent") + + if state == 'present': + + params = {'name': uname, + 'rights': get_rights(zapi, module.params['rights']), + 'users_status': get_user_status(module.params['status']), + 'gui_access': get_gui_access(module.params['gui_access']), + 'debug_mode': get_debug_mode(module.params['debug_mode']), + #'userids': get_userids(zapi, module.params['users']), + } + + _ = [params.pop(key, None) for key in params.keys() if params[key] == None] + + if not exists(content): + # if we didn't find it, create it + content = zapi.get_content(zbx_class_name, 'create', params) + module.exit_json(changed=True, results=content['result'], state='present') + # already exists, we need to update it + # let's compare properties + differences = {} + zab_results = content['result'][0] + for key, value in params.items(): + if key == 'rights': + differences['rights'] = value + + #elif key == 'userids' and zab_results.has_key('users'): + #if zab_results['users'] != value: + #differences['userids'] = value + + elif zab_results[key] != value and zab_results[key] != str(value): + differences[key] = value + + if not differences: + module.exit_json(changed=False, results=zab_results, state="present") + + # We have differences and need to update + differences[idname] = zab_results[idname] + content = zapi.get_content(zbx_class_name, 'update', differences) + module.exit_json(changed=True, results=content['result'], state="present") + + module.exit_json(failed=True, + changed=False, + results='Unknown state passed. %s' % state, + state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets. This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/lib_zabbix/tasks/create_template.yml b/roles/lib_zabbix/tasks/create_template.yml new file mode 100644 index 000000000..ac9cf756b --- /dev/null +++ b/roles/lib_zabbix/tasks/create_template.yml @@ -0,0 +1,101 @@ +--- +- name: Template Create Template + zbx_template: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ template.name }}" + register: created_template + + +- set_fact: + lzbx_item_applications: "{{ template.zitems | default([], True) | oo_select_keys_from_list(['applications']) | oo_flatten | unique }}" + lzbx_itemprototype_applications: "{{ template.zitemprototypes | default([], True) | oo_select_keys_from_list(['applications']) | oo_flatten | unique }}" + +- name: Create Application + zbx_application: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ item }}" + template_name: "{{ template.name }}" + with_items: + - "{{ lzbx_item_applications }}" + - "{{ lzbx_itemprototype_applications }}" + register: created_application + when: template.zitems is defined or template.zitemprototypes is defined + +- name: Create Items + zbx_item: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + key: "{{ item.key }}" + name: "{{ item.name | default(item.key, true) }}" + value_type: "{{ item.value_type | default('int') }}" + description: "{{ item.description | default('', True) }}" + multiplier: "{{ item.multiplier | default('', True) }}" + units: "{{ item.units | default('', True) }}" + template_name: "{{ template.name }}" + applications: "{{ item.applications }}" + zabbix_type: "{{ item.zabbix_type | default('trapper') }}" + interval: "{{ item.interval | default(60, True) }}" + delta: "{{ item.delta | default(0, True) }}" + with_items: template.zitems + register: created_items + when: template.zitems is defined + +- name: Create Triggers + zbx_trigger: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ item.name }}" + description: "{{ item.description | default('', True) }}" + dependencies: "{{ item.dependencies | default([], True) }}" + expression: "{{ item.expression }}" + priority: "{{ item.priority }}" + url: "{{ item.url | default(None, True) }}" + with_items: template.ztriggers + when: template.ztriggers is defined + +- name: Create Discoveryrules + zbx_discoveryrule: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ item.name }}" + key: "{{ item.key }}" + lifetime: "{{ item.lifetime }}" + template_name: "{{ template.name }}" + description: "{{ item.description | default('', True) }}" + with_items: template.zdiscoveryrules + when: template.zdiscoveryrules is defined + +- name: Create Item Prototypes + zbx_itemprototype: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ item.name }}" + key: "{{ item.key }}" + discoveryrule_key: "{{ item.discoveryrule_key }}" + value_type: "{{ item.value_type }}" + template_name: "{{ template.name }}" + applications: "{{ item.applications }}" + description: "{{ item.description | default('', True) }}" + with_items: template.zitemprototypes + when: template.zitemprototypes is defined + +- name: Create Trigger Prototypes + zbx_triggerprototype: + zbx_server: "{{ server }}" + zbx_user: "{{ user }}" + zbx_password: "{{ password }}" + name: "{{ item.name }}" + expression: "{{ item.expression }}" + url: "{{ item.url | default('', True) }}" + priority: "{{ item.priority | default('average', True) }}" + description: "{{ item.description | default('', True) }}" + with_items: template.ztriggerprototypes + when: template.ztriggerprototypes is defined diff --git a/roles/lib_zabbix/tasks/create_user.yml b/roles/lib_zabbix/tasks/create_user.yml new file mode 100644 index 000000000..1f752a9e1 --- /dev/null +++ b/roles/lib_zabbix/tasks/create_user.yml @@ -0,0 +1,11 @@ +--- +- name: Update zabbix credentialss for a user + zbx_user: + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + alias: "{{ ozb_username }}" + passwd: "{{ ozb_new_password | default(ozb_password, true) }}" + register: user + +- debug: var=user.results diff --git a/roles/nickhammond.logrotate/.travis.yml b/roles/nickhammond.logrotate/.travis.yml new file mode 100644 index 000000000..161023def --- /dev/null +++ b/roles/nickhammond.logrotate/.travis.yml @@ -0,0 +1,14 @@ +--- +language: python +python: "2.7" +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq python-apt python-pycurl +install: + - pip install ansible +script: + - "printf '[defaults]\nroles_path = ../' > ansible.cfg" + - ansible-playbook -i tests/inventory --syntax-check tests/test.yml + - ansible-playbook -i tests/inventory --connection=local --sudo -vvvv tests/test.yml +notifications: + email: false diff --git a/roles/nickhammond.logrotate/README.md b/roles/nickhammond.logrotate/README.md new file mode 100644 index 000000000..602b5ef6c --- /dev/null +++ b/roles/nickhammond.logrotate/README.md @@ -0,0 +1,71 @@ +[![Build Status](https://travis-ci.org/nickhammond/ansible-logrotate.svg?branch=master)](https://travis-ci.org/nickhammond/ansible-logrotate) + +Role Name +======== + +Installs logrotate and provides an easy way to setup additional logrotate scripts by specifying a list of directives. + +Requirements +------------ + +None + +Role Variables +-------------- + +**logrotate_scripts**: A list of logrotate scripts and the directives to use for the rotation. + +* name - The name of the script that goes into /etc/logrotate.d/ +* path - Path to point logrotate to for the log rotation +* options - List of directives for logrotate, view the logrotate man page for specifics +* scripts - Dict of scripts for logrotate (see Example below) + +``` +logrotate_scripts: + - name: rails + path: "/srv/current/log/*.log" + options: + - weekly + - size 25M + - missingok + - compress + - delaycompress + - copytruncate +``` + +Dependencies +------------ + +None + +Example Playbook +------------------------- + +Setting up logrotate for additional Nginx logs, with postrotate script. + +``` +logrotate_scripts: + - name: nginx + path: /var/log/nginx/*.log + options: + - weekly + - size 25M + - rotate 7 + - missingok + - compress + - delaycompress + - copytruncate + scripts: + postrotate: "[ -s /run/nginx.pid ] && kill USR1 `cat /run/nginx.pid`" + +``` + +License +------- + +BSD + +Author Information +------------------ + +Find [Nick Hammond]( http://www.nickhammond.com ) on [Twitter](http://twitter.com/nickhammond). diff --git a/roles/nickhammond.logrotate/meta/.galaxy_install_info b/roles/nickhammond.logrotate/meta/.galaxy_install_info new file mode 100644 index 000000000..0d76708c9 --- /dev/null +++ b/roles/nickhammond.logrotate/meta/.galaxy_install_info @@ -0,0 +1 @@ +{install_date: 'Thu Aug 27 15:26:31 2015', version: master} diff --git a/roles/nickhammond.logrotate/meta/main.yml b/roles/nickhammond.logrotate/meta/main.yml new file mode 100644 index 000000000..1717b6d3d --- /dev/null +++ b/roles/nickhammond.logrotate/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Nick Hammond + description: Role to configure logrotate scripts + license: BSD + min_ansible_version: 1.5 + platforms: + - name: Ubuntu + versions: + - lucid + - precise + - trusty + categories: + - system +dependencies: [] diff --git a/roles/nickhammond.logrotate/tasks/main.yml b/roles/nickhammond.logrotate/tasks/main.yml new file mode 100644 index 000000000..fda23e05e --- /dev/null +++ b/roles/nickhammond.logrotate/tasks/main.yml @@ -0,0 +1,10 @@ +--- +- name: nickhammond.logrotate | Install logrotate + action: "{{ansible_pkg_mgr}} pkg=logrotate state=present" + +- name: nickhammond.logrotate | Setup logrotate.d scripts + template: + src: logrotate.d.j2 + dest: /etc/logrotate.d/{{ item.name }} + with_items: logrotate_scripts + when: logrotate_scripts is defined diff --git a/roles/nickhammond.logrotate/templates/logrotate.d.j2 b/roles/nickhammond.logrotate/templates/logrotate.d.j2 new file mode 100644 index 000000000..6453be6b2 --- /dev/null +++ b/roles/nickhammond.logrotate/templates/logrotate.d.j2 @@ -0,0 +1,16 @@ +# {{ ansible_managed }} + +{{ item.path }} { + {% if item.options is defined -%} + {% for option in item.options -%} + {{ option }} + {% endfor -%} + {% endif %} + {%- if item.scripts is defined -%} + {%- for name, script in item.scripts.iteritems() -%} + {{ name }} + {{ script }} + endscript + {% endfor -%} + {% endif -%} +} diff --git a/roles/nickhammond.logrotate/tests/inventory b/roles/nickhammond.logrotate/tests/inventory new file mode 100644 index 000000000..2fbb50c4a --- /dev/null +++ b/roles/nickhammond.logrotate/tests/inventory @@ -0,0 +1 @@ +localhost diff --git a/roles/nickhammond.logrotate/tests/test.yml b/roles/nickhammond.logrotate/tests/test.yml new file mode 100644 index 000000000..e806b0a02 --- /dev/null +++ b/roles/nickhammond.logrotate/tests/test.yml @@ -0,0 +1,18 @@ +--- +- hosts: all + sudo: True + roles: + - ansible-logrotate + - role: ansible-logrotate + logrotate_scripts: + - name: nginx-options + path: /var/log/nginx/options.log + options: + - daily + + - role: ansible-logrotate + logrotate_scripts: + - name: nginx-scripts + path: /var/log/nginx/scripts.log + scripts: + postrotate: "echo test" diff --git a/roles/openshift_ansible_inventory/README.md b/roles/openshift_ansible_inventory/README.md index 69a07effd..b62287c12 100644 --- a/roles/openshift_ansible_inventory/README.md +++ b/roles/openshift_ansible_inventory/README.md @@ -1,4 +1,4 @@ -Openshift Ansible Inventory +OpenShift Ansible Inventory ========= Install and configure openshift-ansible-inventory. @@ -38,4 +38,4 @@ ASL 2.0 Author Information ------------------ -Openshift operations, Red Hat, Inc +OpenShift operations, Red Hat, Inc diff --git a/roles/openshift_ansible_inventory/meta/main.yml b/roles/openshift_ansible_inventory/meta/main.yml index ff3df0a7d..7f7387e80 100644 --- a/roles/openshift_ansible_inventory/meta/main.yml +++ b/roles/openshift_ansible_inventory/meta/main.yml @@ -1,6 +1,6 @@ --- galaxy_info: - author: Openshift + author: OpenShift description: Install and configure openshift-ansible-inventory company: Red Hat, Inc license: ASL 2.0 diff --git a/roles/openshift_ansible_inventory/templates/multi_ec2.yaml.j2 b/roles/openshift_ansible_inventory/templates/multi_ec2.yaml.j2 index 8228ab915..ce8515e17 100644 --- a/roles/openshift_ansible_inventory/templates/multi_ec2.yaml.j2 +++ b/roles/openshift_ansible_inventory/templates/multi_ec2.yaml.j2 @@ -15,10 +15,10 @@ accounts: env_vars: AWS_ACCESS_KEY_ID: {{ account.env_vars.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: {{ account.env_vars.AWS_SECRET_ACCESS_KEY }} -{% if account.all_group is defined and account.hostvars is defined%} +{% if account.all_group is defined and account.extra_vars is defined%} all_group: {{ account.all_group }} - hostvars: -{% for property, value in account.hostvars.items() %} + extra_vars: +{% for property, value in account.extra_vars.items() %} {{ property }}: {{ value }} {% endfor %} {% endif %} diff --git a/roles/openshift_cluster_metrics/README.md b/roles/openshift_cluster_metrics/README.md new file mode 100644 index 000000000..9fdfab8e3 --- /dev/null +++ b/roles/openshift_cluster_metrics/README.md @@ -0,0 +1,36 @@ +#openshift_cluster_metrics + +This role configures Cluster wide metrics. It does setting up three services: +* Metrics are stored in InfluxDB for querying. +* Heapster reads all nodes and pods from the master, then connects to eachs node's kubelet to retrieve pod metrics. +* Grafan allows users to create dashboards of metrics from InfluxDB + +## Requirements + +Running OpenShift cluster + +## Role Variables + +``` +# Enable cluster metrics +use_cluster_metrics=true +``` + +## Dependencies + +None + +## Example Playbook + +TODO + +## Security Note +Opening up the read-only port exposes information about the running pods (such as namespace, pod name, labels, etc.) to unauthenticated clients. The requirement to open up this read-only port will be fixed in future versions. + +##License + +Apache License, Version 2.0 + +## Author Information + +Diego Castro (diego.castro@getupcloud.com) diff --git a/roles/openshift_cluster_metrics/files/cluster-metrics/grafana.yaml b/roles/openshift_cluster_metrics/files/cluster-metrics/grafana.yaml new file mode 100644 index 000000000..bff422efc --- /dev/null +++ b/roles/openshift_cluster_metrics/files/cluster-metrics/grafana.yaml @@ -0,0 +1,53 @@ +apiVersion: "v1" +kind: "List" +items: + - + apiVersion: "v1" + kind: "Service" + metadata: + labels: + provider: "fabric8" + component: "grafana" + name: "grafana" + spec: + ports: + - + port: 80 + targetPort: "http" + selector: + provider: "fabric8" + component: "grafana" + - + apiVersion: "v1" + kind: "ReplicationController" + metadata: + labels: + provider: "fabric8" + component: "grafana" + name: "grafana" + spec: + replicas: 1 + selector: + provider: "fabric8" + component: "grafana" + template: + metadata: + labels: + provider: "fabric8" + component: "grafana" + spec: + containers: + - + env: + - + name: "INFLUXDB_SERVICE_NAME" + value: "INFLUXDB_MONITORING" + - + name: "GRAFANA_DEFAULT_DASHBOARD" + value: "/dashboard/file/kubernetes.json" + image: "fabric8/grafana:1.9.1_2" + name: "grafana" + ports: + - + containerPort: 3000 + name: "http"
\ No newline at end of file diff --git a/roles/openshift_cluster_metrics/files/cluster-metrics/heapster-serviceaccount.yaml b/roles/openshift_cluster_metrics/files/cluster-metrics/heapster-serviceaccount.yaml new file mode 100644 index 000000000..1de2ad699 --- /dev/null +++ b/roles/openshift_cluster_metrics/files/cluster-metrics/heapster-serviceaccount.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: heapster
\ No newline at end of file diff --git a/roles/openshift_cluster_metrics/files/cluster-metrics/heapster.yaml b/roles/openshift_cluster_metrics/files/cluster-metrics/heapster.yaml new file mode 100644 index 000000000..83e314074 --- /dev/null +++ b/roles/openshift_cluster_metrics/files/cluster-metrics/heapster.yaml @@ -0,0 +1,30 @@ +apiVersion: "v1" +kind: "List" +items: + - + apiVersion: "v1" + kind: "ReplicationController" + metadata: + labels: + provider: "fabric8" + component: "heapster" + name: "heapster" + spec: + replicas: 1 + selector: + provider: "fabric8" + component: "heapster" + template: + metadata: + labels: + provider: "fabric8" + component: "heapster" + spec: + containers: + - + args: + - "-source=kubernetes:https://kubernetes.default.svc.cluster.local?auth=&insecure=true&useServiceAccount=true" + - "-sink=influxdb:http://influxdb-monitoring.default.svc.cluster.local:8086" + image: "kubernetes/heapster:V0.14.2" + name: "heapster" + serviceAccount: "heapster"
\ No newline at end of file diff --git a/roles/openshift_cluster_metrics/files/cluster-metrics/influxdb.yaml b/roles/openshift_cluster_metrics/files/cluster-metrics/influxdb.yaml new file mode 100644 index 000000000..6f67c3d7c --- /dev/null +++ b/roles/openshift_cluster_metrics/files/cluster-metrics/influxdb.yaml @@ -0,0 +1,67 @@ +apiVersion: "v1" +kind: "List" +items: + - + apiVersion: "v1" + kind: "Service" + metadata: + labels: + provider: "fabric8" + component: "influxdb-monitoring" + name: "influxdb-monitoring" + spec: + ports: + - + port: 8086 + targetPort: "http" + selector: + provider: "fabric8" + component: "influxdb-monitoring" + - + apiVersion: "v1" + kind: "ReplicationController" + metadata: + labels: + provider: "fabric8" + component: "influxdb-monitoring" + name: "influxdb-monitoring" + spec: + replicas: 1 + selector: + provider: "fabric8" + component: "influxdb-monitoring" + template: + metadata: + labels: + provider: "fabric8" + component: "influxdb-monitoring" + spec: + containers: + - + env: + - + name: "PRE_CREATE_DB" + value: "k8s;grafana" + image: "fabric8/influxdb:0.8.8" + name: "influxdb" + ports: + - + containerPort: 8090 + name: "raft" + - + containerPort: 8099 + name: "protobuf" + - + containerPort: 8083 + name: "admin" + - + containerPort: 8086 + name: "http" + volumeMounts: + - + mountPath: "/data" + name: "influxdb-data" + volumes: + - + emptyDir: + name: "influxdb-data"
\ No newline at end of file diff --git a/roles/openshift_cluster_metrics/tasks/main.yml b/roles/openshift_cluster_metrics/tasks/main.yml new file mode 100644 index 000000000..3938aba4c --- /dev/null +++ b/roles/openshift_cluster_metrics/tasks/main.yml @@ -0,0 +1,50 @@ +--- + +- name: Install cluster metrics templates + copy: + src: cluster-metrics + dest: /etc/openshift/ + +- name: Create InfluxDB Services + command: > + {{ openshift.common.client_binary }} create -f + /etc/openshift/cluster-metrics/influxdb.yaml + register: oex_influxdb_services + failed_when: "'already exists' not in oex_influxdb_services.stderr and oex_influxdb_services.rc != 0" + changed_when: false + +- name: Create Heapster Service Account + command: > + {{ openshift.common.client_binary }} create -f + /etc/openshift/cluster-metrics/heapster-serviceaccount.yaml + register: oex_heapster_serviceaccount + failed_when: "'already exists' not in oex_heapster_serviceaccount.stderr and oex_heapster_serviceaccount.rc != 0" + changed_when: false + +- name: Add cluster-reader role to Heapster + command: > + {{ openshift.common.admin_binary }} policy + add-cluster-role-to-user + cluster-reader + system:serviceaccount:default:heapster + register: oex_cluster_header_role + register: oex_cluster_header_role + failed_when: "'already exists' not in oex_cluster_header_role.stderr and oex_cluster_header_role.rc != 0" + changed_when: false + +- name: Create Heapster Services + command: > + {{ openshift.common.client_binary }} create -f + /etc/openshift/cluster-metrics/heapster.yaml + register: oex_heapster_services + failed_when: "'already exists' not in oex_heapster_services.stderr and oex_heapster_services.rc != 0" + changed_when: false + +- name: Create Grafana Services + command: > + {{ openshift.common.client_binary }} create -f + /etc/openshift/cluster-metrics/grafana.yaml + register: oex_grafana_services + failed_when: "'already exists' not in oex_grafana_services.stderr and oex_grafana_services.rc != 0" + changed_when: false + diff --git a/roles/openshift_common/README.md b/roles/openshift_common/README.md index 14c2037e4..87306d4a6 100644 --- a/roles/openshift_common/README.md +++ b/roles/openshift_common/README.md @@ -1,13 +1,13 @@ -OpenShift Common -================ +OpenShift/Atomic Enterprise Common +=================================== -OpenShift common installation and configuration tasks. +OpenShift/Atomic Enterprise common installation and configuration tasks. Requirements ------------ A RHEL 7.1 host pre-configured with access to the rhel-7-server-rpms, -rhel-7-server-extra-rpms, and rhel-7-server-ose-beta-rpms repos. +rhel-7-server-extra-rpms, and rhel-7-server-ose-3.0-rpms repos. Role Variables -------------- @@ -15,7 +15,7 @@ Role Variables | Name | Default value | | |---------------------------|-------------------|---------------------------------------------| | openshift_cluster_id | default | Cluster name if multiple OpenShift clusters | -| openshift_debug_level | 0 | Global openshift debug log verbosity | +| openshift_debug_level | 2 | Global openshift debug log verbosity | | openshift_hostname | UNDEF | Internal hostname to use for this host (this value will set the hostname on the system) | | openshift_ip | UNDEF | Internal IP address to use for this host | | openshift_public_hostname | UNDEF | Public hostname to use for this host | diff --git a/roles/openshift_common/defaults/main.yml b/roles/openshift_common/defaults/main.yml index 4d3e0fe9e..267c03605 100644 --- a/roles/openshift_common/defaults/main.yml +++ b/roles/openshift_common/defaults/main.yml @@ -1,3 +1,3 @@ --- openshift_cluster_id: 'default' -openshift_debug_level: 0 +openshift_debug_level: 2 diff --git a/roles/openshift_common/tasks/main.yml b/roles/openshift_common/tasks/main.yml index f76dd84ed..73bd28630 100644 --- a/roles/openshift_common/tasks/main.yml +++ b/roles/openshift_common/tasks/main.yml @@ -1,10 +1,10 @@ --- -- name: Set common OpenShift facts +- name: Set common Cluster facts openshift_facts: role: common local_facts: cluster_id: "{{ openshift_cluster_id | default('default') }}" - debug_level: "{{ openshift_debug_level | default(0) }}" + debug_level: "{{ openshift_debug_level | default(2) }}" hostname: "{{ openshift_hostname | default(None) }}" ip: "{{ openshift_ip | default(None) }}" public_hostname: "{{ openshift_public_hostname | default(None) }}" @@ -12,7 +12,7 @@ use_openshift_sdn: "{{ openshift_use_openshift_sdn | default(None) }}" sdn_network_plugin_name: "{{ os_sdn_network_plugin_name | default(None) }}" deployment_type: "{{ openshift_deployment_type }}" + use_fluentd: "{{ openshift_use_fluentd | default(None) }}" - name: Set hostname hostname: name={{ openshift.common.hostname }} - diff --git a/roles/openshift_common/vars/main.yml b/roles/openshift_common/vars/main.yml index 8e7d71154..50816d319 100644 --- a/roles/openshift_common/vars/main.yml +++ b/roles/openshift_common/vars/main.yml @@ -5,5 +5,3 @@ # chains with the public zone (or the zone associated with the correct # interfaces) os_firewall_use_firewalld: False - -openshift_data_dir: /var/lib/openshift diff --git a/roles/openshift_examples/README.md b/roles/openshift_examples/README.md new file mode 100644 index 000000000..7d8735a0a --- /dev/null +++ b/roles/openshift_examples/README.md @@ -0,0 +1,49 @@ +OpenShift Examples +================ + +Installs example image streams, db-templates, and quickstart-templates by copying +examples from this module to your first master and importing them with oc create -n into the openshift namespace + +The examples-sync.sh script can be used to pull the latest content from github +and stage it for updating the ansible repo. This script is not used directly by +ansible. + +Requirements +------------ + +Role Variables +-------------- + +| Name | Default value | | +|-------------------------------------|-----------------------------------------------------|------------------------------------------| +| openshift_examples_load_centos | true when openshift_deployment_typenot 'enterprise' | Load centos image streams | +| openshift_examples_load_rhel | true if openshift_deployment_type is 'enterprise' | Load rhel image streams | +| openshift_examples_load_db_templates| true | Loads databcase templates | +| openshift_examples_load_quickstarts | true | Loads quickstarts ie: nodejs, rails, etc | +| openshift_examples_load_xpaas | false | Loads xpass streams and templates | + + +Dependencies +------------ + +Example Playbook +---------------- + +TODO +---- +Currently we use `oc create -f` against various files and we accept non zero return code as a success +if (and only iff) stderr also contains the string 'already exists'. This means that if one object in the file exists already +but others fail to create you won't be aware of the failure. This also means that we do not currently support +updating existing objects. + +We should add the ability to compare existing image streams against those we're being asked to load and update if necessary. + +License +------- + +Apache License, Version 2.0 + +Author Information +------------------ + +Scott Dodson (sdodson@redhat.com) diff --git a/roles/openshift_examples/defaults/main.yml b/roles/openshift_examples/defaults/main.yml new file mode 100644 index 000000000..2043985ec --- /dev/null +++ b/roles/openshift_examples/defaults/main.yml @@ -0,0 +1,18 @@ +--- +# By default install rhel and xpaas streams on enterprise installs +openshift_examples_load_centos: "{{ openshift_deployment_type not in ['enterprise','openshift-enterprise','atomic-enterprise','online'] }}" +openshift_examples_load_rhel: "{{ openshift_deployment_type in ['enterprise','openshift-enterprise','atomic-enterprise','online'] }}" +openshift_examples_load_db_templates: true +openshift_examples_load_xpaas: "{{ openshift_deployment_type in ['enterprise','openshift-enterprise','atomic-enterprise','online'] }}" +openshift_examples_load_quickstarts: true + +examples_base: /usr/share/openshift/examples +image_streams_base: "{{ examples_base }}/image-streams" +centos_image_streams: "{{ image_streams_base}}/image-streams-centos7.json" +rhel_image_streams: "{{ image_streams_base}}/image-streams-rhel7.json" +db_templates_base: "{{ examples_base }}/db-templates" +xpaas_image_streams: "{{ examples_base }}/xpaas-streams/jboss-image-streams.json" +xpaas_templates_base: "{{ examples_base }}/xpaas-templates" +quickstarts_base: "{{ examples_base }}/quickstart-templates" + +openshift_examples_import_command: "create" diff --git a/roles/openshift_examples/examples-sync.sh b/roles/openshift_examples/examples-sync.sh new file mode 100755 index 000000000..21137e31b --- /dev/null +++ b/roles/openshift_examples/examples-sync.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Utility script to update the ansible repo with the latest templates and image +# streams from several github repos +# +# This script should be run from openshift-ansible/roles/openshift_examples + +EXAMPLES_BASE=$(pwd)/files/examples +find files/examples -name '*.json' -delete +TEMP=`mktemp -d` +pushd $TEMP +wget https://github.com/openshift/origin/archive/master.zip -O origin-master.zip +wget https://github.com/openshift/django-ex/archive/master.zip -O django-ex-master.zip +wget https://github.com/openshift/rails-ex/archive/master.zip -O rails-ex-master.zip +wget https://github.com/openshift/nodejs-ex/archive/master.zip -O nodejs-ex-master.zip +wget https://github.com/openshift/dancer-ex/archive/master.zip -O dancer-ex-master.zip +wget https://github.com/openshift/cakephp-ex/archive/master.zip -O cakephp-ex-master.zip +wget https://github.com/jboss-openshift/application-templates/archive/ose-v1.0.2.zip -O application-templates-master.zip +unzip origin-master.zip +unzip django-ex-master.zip +unzip rails-ex-master.zip +unzip nodejs-ex-master.zip +unzip dancer-ex-master.zip +unzip cakephp-ex-master.zip +unzip application-templates-master.zip +cp origin-master/examples/db-templates/* ${EXAMPLES_BASE}/db-templates/ +cp origin-master/examples/jenkins/jenkins-*template.json ${EXAMPLES_BASE}/quickstart-templates/ +cp origin-master/examples/image-streams/* ${EXAMPLES_BASE}/image-streams/ +cp django-ex-master/openshift/templates/* ${EXAMPLES_BASE}/quickstart-templates/ +cp rails-ex-master/openshift/templates/* ${EXAMPLES_BASE}/quickstart-templates/ +cp nodejs-ex-master/openshift/templates/* ${EXAMPLES_BASE}/quickstart-templates/ +cp dancer-ex-master/openshift/templates/* ${EXAMPLES_BASE}/quickstart-templates/ +cp cakephp-ex-master/openshift/templates/* ${EXAMPLES_BASE}/quickstart-templates/ +mv application-templates-master/jboss-image-streams.json ${EXAMPLES_BASE}/xpaas-streams/ +find application-templates-master/ -name '*.json' ! -wholename '*secret*' -exec mv {} ${EXAMPLES_BASE}/xpaas-templates/ \; +popd +git diff files/examples diff --git a/roles/openshift_examples/files/examples/db-templates/mongodb-ephemeral-template.json b/roles/openshift_examples/files/examples/db-templates/mongodb-ephemeral-template.json new file mode 100644 index 000000000..6b90fa54e --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/mongodb-ephemeral-template.json @@ -0,0 +1,184 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "mongodb-ephemeral", + "creationTimestamp": null, + "annotations": { + "description": "MongoDB database service, without persistent storage. WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing", + "iconClass": "icon-mongodb", + "tags": "database,mongodb" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "mongo", + "protocol": "TCP", + "port": 27017, + "targetPort": 27017, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mongodb:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mongodb", + "image": "mongodb", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${MONGODB_USER}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${MONGODB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${MONGODB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${MONGODB_ADMIN_PASSWORD}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/mongodb/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mongodb", + "required": true + }, + { + "name": "MONGODB_USER", + "description": "Username for MongoDB user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "MONGODB_PASSWORD", + "description": "Password for the MongoDB user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "MONGODB_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "description": "Password for the database admin user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + } + ], + "labels": { + "template": "mongodb-ephemeral-template" + } +} diff --git a/roles/openshift_examples/files/examples/db-templates/mongodb-persistent-template.json b/roles/openshift_examples/files/examples/db-templates/mongodb-persistent-template.json new file mode 100644 index 000000000..97b315600 --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/mongodb-persistent-template.json @@ -0,0 +1,207 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "mongodb-persistent", + "creationTimestamp": null, + "annotations": { + "description": "MongoDB database service, with persistent storage. Scaling to more than one replica is not supported", + "iconClass": "icon-mongodb", + "tags": "database,mongodb" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "mongo", + "protocol": "TCP", + "port": 27017, + "targetPort": 27017, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mongodb:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mongodb", + "image": "mongodb", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${MONGODB_USER}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${MONGODB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${MONGODB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${MONGODB_ADMIN_PASSWORD}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/mongodb/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mongodb", + "required": true + }, + { + "name": "MONGODB_USER", + "description": "Username for MongoDB user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "MONGODB_PASSWORD", + "description": "Password for the MongoDB user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "MONGODB_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "description": "Password for the database admin user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "VOLUME_CAPACITY", + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "value": "512Mi", + "required": true + } + ], + "labels": { + "template": "mongodb-persistent-template" + } +} diff --git a/roles/openshift_examples/files/examples/db-templates/mysql-ephemeral-template.json b/roles/openshift_examples/files/examples/db-templates/mysql-ephemeral-template.json new file mode 100644 index 000000000..b384a5992 --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/mysql-ephemeral-template.json @@ -0,0 +1,173 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "mysql-ephemeral", + "creationTimestamp": null, + "annotations": { + "description": "MySQL database service, without persistent storage. WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing", + "iconClass": "icon-mysql-database", + "tags": "database,mysql" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "mysql", + "protocol": "TCP", + "port": 3306, + "targetPort": 3306, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mysql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mysql:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${MYSQL_USER}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${MYSQL_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/mysql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mysql", + "required": true + }, + { + "name": "MYSQL_USER", + "description": "Username for MySQL user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "MYSQL_PASSWORD", + "description": "Password for the MySQL user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "MYSQL_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + } + ], + "labels": { + "template": "mysql-ephemeral-template" + } +} diff --git a/roles/openshift_examples/files/examples/db-templates/mysql-persistent-template.json b/roles/openshift_examples/files/examples/db-templates/mysql-persistent-template.json new file mode 100644 index 000000000..6e19f48f5 --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/mysql-persistent-template.json @@ -0,0 +1,196 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "mysql-persistent", + "creationTimestamp": null, + "annotations": { + "description": "MySQL database service, with persistent storage. Scaling to more than one replica is not supported", + "iconClass": "icon-mysql-database", + "tags": "database,mysql" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "mysql", + "protocol": "TCP", + "port": 3306, + "targetPort": 3306, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mysql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mysql:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${MYSQL_USER}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${MYSQL_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/mysql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mysql", + "required": true + }, + { + "name": "MYSQL_USER", + "description": "Username for MySQL user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "MYSQL_PASSWORD", + "description": "Password for the MySQL user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "MYSQL_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + }, + { + "name": "VOLUME_CAPACITY", + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "value": "512Mi", + "required": true + } + ], + "labels": { + "template": "mysql-persistent-template" + } +} diff --git a/roles/openshift_examples/files/examples/db-templates/postgresql-ephemeral-template.json b/roles/openshift_examples/files/examples/db-templates/postgresql-ephemeral-template.json new file mode 100644 index 000000000..60d6b8519 --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/postgresql-ephemeral-template.json @@ -0,0 +1,173 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "postgresql-ephemeral", + "creationTimestamp": null, + "annotations": { + "description": "PostgreSQL database service, without persistent storage. WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing", + "iconClass": "icon-postgresql", + "tags": "database,postgresql" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "postgresql", + "protocol": "TCP", + "port": 5432, + "targetPort": 5432, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "postgresql:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${POSTGRESQL_USER}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${POSTGRESQL_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${POSTGRESQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/pgsql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "postgresql", + "required": true + }, + { + "name": "POSTGRESQL_USER", + "description": "Username for PostgreSQL user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "POSTGRESQL_PASSWORD", + "description": "Password for the PostgreSQL user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "POSTGRESQL_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + } + ], + "labels": { + "template": "postgresql-ephemeral-template" + } +} diff --git a/roles/openshift_examples/files/examples/db-templates/postgresql-persistent-template.json b/roles/openshift_examples/files/examples/db-templates/postgresql-persistent-template.json new file mode 100644 index 000000000..91cd7453e --- /dev/null +++ b/roles/openshift_examples/files/examples/db-templates/postgresql-persistent-template.json @@ -0,0 +1,196 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "postgresql-persistent", + "creationTimestamp": null, + "annotations": { + "description": "PostgreSQL database service, with persistent storage. Scaling to more than one replica is not supported", + "iconClass": "icon-postgresql", + "tags": "database,postgresql" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "postgresql", + "protocol": "TCP", + "port": 5432, + "targetPort": 5432, + "nodePort": 0 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "postgresql:latest", + "namespace": "openshift" + }, + "lastTriggeredImage": "" + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${POSTGRESQL_USER}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${POSTGRESQL_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${POSTGRESQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "mountPath": "/var/lib/pgsql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + }, + "status": {} + } + ], + "parameters": [ + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "postgresql", + "required": true + }, + { + "name": "POSTGRESQL_USER", + "description": "Username for PostgreSQL user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "POSTGRESQL_PASSWORD", + "description": "Password for the PostgreSQL user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}", + "required": true + }, + { + "name": "POSTGRESQL_DATABASE", + "description": "Database name", + "value": "sampledb", + "required": true + }, + { + "name": "VOLUME_CAPACITY", + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "value": "512Mi", + "required": true + } + ], + "labels": { + "template": "postgresql-persistent-template" + } +} diff --git a/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json b/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json new file mode 100644 index 000000000..268d680f4 --- /dev/null +++ b/roles/openshift_examples/files/examples/image-streams/image-streams-centos7.json @@ -0,0 +1,285 @@ +{ + "kind": "ImageStreamList", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "ruby", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/ruby-20-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "2.0", + "annotations": { + "description": "Build and run Ruby 2.0 applications", + "iconClass": "icon-ruby", + "tags": "builder,ruby", + "supports": "ruby:2.0,ruby", + "version": "2.0", + "sampleRepo": "https://github.com/openshift/ruby-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "nodejs", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/nodejs-010-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "0.10", + "annotations": { + "description": "Build and run NodeJS 0.10 applications", + "iconClass": "icon-nodejs", + "tags": "builder,nodejs", + "supports":"nodejs:0.10,nodejs:0.1,nodejs", + "version": "0.10", + "sampleRepo": "https://github.com/openshift/nodejs-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "perl", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/perl-516-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.16", + "annotations": { + "description": "Build and run Perl 5.16 applications", + "iconClass": "icon-perl", + "tags": "builder,perl", + "supports":"perl:5.16,perl", + "version": "5.16", + "sampleRepo": "https://github.com/openshift/dancer-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "php", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/php-55-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.5", + "annotations": { + "description": "Build and run PHP 5.5 applications", + "iconClass": "icon-php", + "tags": "builder,php", + "supports":"php:5.5,php", + "version": "5.5", + "sampleRepo": "https://github.com/openshift/cakephp-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "python", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/python-33-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "3.3", + "annotations": { + "description": "Build and run Python 3.3 applications", + "iconClass": "icon-python", + "tags": "builder,python", + "supports":"python:3.3,python", + "version": "3.3", + "sampleRepo": "https://github.com/openshift/django-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "wildfly", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/wildfly-81-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "8.1", + "annotations": { + "description": "Build and run Java applications on Wildfly 8.1", + "iconClass": "icon-wildfly", + "tags": "builder,wildfly,java", + "supports":"wildfly:8.1,jee,java", + "version": "8.1", + "sampleRepo": "https://github.com/bparees/openshift-jee-sample.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "mysql", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/mysql-55-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.5", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "postgresql", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/postgresql-92-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "9.2", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "mongodb", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/mongodb-24-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "2.4", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jenkins", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "openshift/jenkins-1-centos7", + "tags": [ + { + "name": "latest" + }, + { + "name": "1", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json b/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json new file mode 100644 index 000000000..aa62ebd53 --- /dev/null +++ b/roles/openshift_examples/files/examples/image-streams/image-streams-rhel7.json @@ -0,0 +1,254 @@ +{ + "kind": "ImageStreamList", + "apiVersion": "v1", + "metadata": {}, + "items": [ + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "ruby", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/ruby-20-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "2.0", + "annotations": { + "description": "Build and run Ruby 2.0 applications", + "iconClass": "icon-ruby", + "tags": "builder,ruby", + "supports": "ruby:2.0,ruby", + "version": "2.0", + "sampleRepo": "https://github.com/openshift/ruby-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "nodejs", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/nodejs-010-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "0.10", + "annotations": { + "description": "Build and run NodeJS 0.10 applications", + "iconClass": "icon-nodejs", + "tags": "builder,nodejs", + "supports":"nodejs:0.10,nodejs:0.1,nodejs", + "version": "0.10", + "sampleRepo": "https://github.com/openshift/nodejs-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "perl", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/perl-516-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.16", + "annotations": { + "description": "Build and run Perl 5.16 applications", + "iconClass": "icon-perl", + "tags": "builder,perl", + "supports":"perl:5.16,perl", + "version": "5.16", + "sampleRepo": "https://github.com/openshift/dancer-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "php", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/php-55-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.5", + "annotations": { + "description": "Build and run PHP 5.5 applications", + "iconClass": "icon-php", + "tags": "builder,php", + "supports":"php:5.5,php", + "version": "5.5", + "sampleRepo": "https://github.com/openshift/cakephp-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "python", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/python-33-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "3.3", + "annotations": { + "description": "Build and run Python 3.3 applications", + "iconClass": "icon-python", + "tags": "builder,python", + "supports":"python:3.3,python", + "version": "3.3", + "sampleRepo": "https://github.com/openshift/django-ex.git" + }, + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "mysql", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/mysql-55-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "5.5", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "postgresql", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/postgresql-92-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "9.2", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "mongodb", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/mongodb-24-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "2.4", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jenkins", + "creationTimestamp": null + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/openshift3/jenkins-1-rhel7", + "tags": [ + { + "name": "latest" + }, + { + "name": "1", + "from": { + "Kind": "ImageStreamTag", + "Name": "latest" + } + } + ] + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json b/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json new file mode 100644 index 000000000..da5679444 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/cakephp-mysql.json @@ -0,0 +1,378 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example", + "annotations": { + "description": "An example CakePHP application with a MySQL database", + "tags": "instant-app,php,cakephp,mysql", + "iconClass": "icon-php" + } + }, + "labels": { + "template": "cakephp-mysql-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "cakephp-mysql-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "cakephp-mysql-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "php:5.5" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "cakephp-mysql-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-mysql-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling", + "recreateParams": { + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "./migrate-database.sh" + ], + "containerName": "cakephp-mysql-example" + } + } + } + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "cakephp-mysql-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "cakephp-mysql-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "cakephp-mysql-example" + }, + "template": { + "metadata": { + "name": "cakephp-mysql-example", + "labels": { + "name": "cakephp-mysql-example" + } + }, + "spec": { + "containers": [ + { + "name": "cakephp-mysql-example", + "image": "cakephp-mysql-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "DATABASE_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "CAKEPHP_SECRET_TOKEN", + "value": "${CAKEPHP_SECRET_TOKEN}" + }, + { + "name": "CAKEPHP_SECURITY_SALT", + "value": "${CAKEPHP_SECURITY_SALT}" + }, + { + "name": "CAKEPHP_SECURITY_CIPHER_SEED", + "value": "${CAKEPHP_SECURITY_CIPHER_SEED}" + }, + { + "name": "OPCACHE_REVALIDATE_FREQ", + "value": "${OPCACHE_REVALIDATE_FREQ}" + } + ] + } + ] + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Exposes the database server" + } + }, + "spec": { + "ports": [ + { + "name": "mysql", + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Defines how to deploy the database" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "${MYSQL_IMAGE}", + "ports": [ + { + "containerPort": 3306 + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DATABASE_NAME}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/cakephp-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the CakePHP service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mysql" + }, + { + "name": "DATABASE_ENGINE", + "description": "Database engine: postgresql, mysql or sqlite (default)", + "value": "mysql" + }, + { + "name": "DATABASE_NAME", + "description": "Database name", + "value": "default" + }, + { + "name": "DATABASE_USER", + "description": "Database user name", + "value": "cakephp" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Database user password", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}" + }, + { + "name": "MYSQL_IMAGE", + "description": "Image to use for mysql", + "value": "openshift/mysql-55-centos7" + }, + { + "name": "CAKEPHP_SECRET_TOKEN", + "description": "Set this to a long random string", + "generate": "expression", + "from": "[\\w]{50}" + }, + { + "name": "CAKEPHP_SECURITY_SALT", + "description": "Security salt for session hash", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "CAKEPHP_SECURITY_CIPHER_SEED", + "description": "Security cipher seed for session hash", + "generate": "expression", + "from": "[0-9]{30}" + }, + { + "name": "OPCACHE_REVALIDATE_FREQ", + "description": "The How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.", + "value": "2" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json b/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json new file mode 100644 index 000000000..f426e1dd6 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/cakephp.json @@ -0,0 +1,275 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example", + "annotations": { + "description": "An example CakePHP application with no database", + "tags": "instant-app,php,cakephp", + "iconClass": "icon-php" + } + }, + "labels": { + "template": "cakephp-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "cakephp-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "cakephp-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "php:5.5" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "cakephp-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "cakephp-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "cakephp-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "cakephp-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "cakephp-example" + }, + "template": { + "metadata": { + "name": "cakephp-example", + "labels": { + "name": "cakephp-example" + } + }, + "spec": { + "containers": [ + { + "name": "cakephp-example", + "image": "cakephp-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "DATABASE_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "CAKEPHP_SECRET_TOKEN", + "value": "${CAKEPHP_SECRET_TOKEN}" + }, + { + "name": "CAKEPHP_SECURITY_SALT", + "value": "${CAKEPHP_SECURITY_SALT}" + }, + { + "name": "CAKEPHP_SECURITY_CIPHER_SEED", + "value": "${CAKEPHP_SECURITY_CIPHER_SEED}" + }, + { + "name": "OPCACHE_REVALIDATE_FREQ", + "value": "${OPCACHE_REVALIDATE_FREQ}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/cakephp-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the CakePHP service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name" + }, + { + "name": "DATABASE_ENGINE", + "description": "Database engine: postgresql, mysql or sqlite (default)" + }, + { + "name": "DATABASE_NAME", + "description": "Database name" + }, + { + "name": "DATABASE_USER", + "description": "Database user name" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Database user password" + }, + { + "name": "CAKEPHP_SECRET_TOKEN", + "description": "Set this to a long random string", + "generate": "expression", + "from": "[\\w]{50}" + }, + { + "name": "CAKEPHP_SECURITY_SALT", + "description": "Security salt for session hash", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "CAKEPHP_SECURITY_CIPHER_SEED", + "description": "Security cipher seed for session hash", + "generate": "expression", + "from": "[0-9]{30}" + }, + { + "name": "OPCACHE_REVALIDATE_FREQ", + "description": "The How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.", + "value": "2" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json b/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json new file mode 100644 index 000000000..55f655102 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/dancer-mysql.json @@ -0,0 +1,348 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example", + "annotations": { + "description": "An example Dancer application with a MySQL database", + "tags": "instant-app,perl,dancer,mysql", + "iconClass": "icon-perl" + } + }, + "labels": { + "template": "dancer-mysql-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "dancer-mysql-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "dancer-mysql-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "perl:5.16" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "dancer-mysql-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "dancer-mysql-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "dancer-mysql-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "dancer-mysql-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "dancer-mysql-example" + }, + "template": { + "metadata": { + "name": "dancer-mysql-example", + "labels": { + "name": "dancer-mysql-example" + } + }, + "spec": { + "containers": [ + { + "name": "dancer-mysql-example", + "image": "dancer-mysql-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "MYSQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DATABASE_NAME}" + }, + { + "name": "SECRET_KEY_BASE", + "value": "${SECRET_KEY_BASE}" + }, + { + "name": "PERL_APACHE2_RELOAD", + "value": "${PERL_APACHE2_RELOAD}" + } + ] + } + ] + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Exposes the database server" + } + }, + "spec": { + "ports": [ + { + "name": "mysql", + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Defines how to deploy the database" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mysql", + "image": "${MYSQL_IMAGE}", + "ports": [ + { + "containerPort": 3306 + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DATABASE_NAME}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/dancer-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Dancer service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "ADMIN_USERNAME", + "description": "administrator username", + "generate": "expression", + "from": "admin[A-Z0-9]{3}" + }, + { + "name": "ADMIN_PASSWORD", + "description": "administrator password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "database" + }, + { + "name": "DATABASE_USER", + "description": "database username", + "generate": "expression", + "from": "user[A-Z0-9]{3}" + }, + { + "name": "DATABASE_PASSWORD", + "description": "database password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "DATABASE_NAME", + "description": "database name", + "value": "sampledb" + }, + { + "name": "MYSQL_IMAGE", + "description": "Image to use for mysql", + "value": "openshift/mysql-55-centos7" + }, + { + "name": "PERL_APACHE2_RELOAD", + "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules", + "value": "" + }, + { + "name": "SECRET_KEY_BASE", + "description": "Your secret key for verifying the integrity of signed cookies", + "generate": "expression", + "from": "[a-z0-9]{127}" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/dancer.json b/roles/openshift_examples/files/examples/quickstart-templates/dancer.json new file mode 100644 index 000000000..3ee19be83 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/dancer.json @@ -0,0 +1,211 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example", + "annotations": { + "description": "An example Dancer application with no database", + "tags": "instant-app,perl,dancer", + "iconClass": "icon-perl" + } + }, + "labels": { + "template": "dancer-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "dancer-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "dancer-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "perl:5.16" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "dancer-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "dancer-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "dancer-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "dancer-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "dancer-example" + }, + "template": { + "metadata": { + "name": "dancer-example", + "labels": { + "name": "dancer-example" + } + }, + "spec": { + "containers": [ + { + "name": "dancer-example", + "image": "dancer-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "PERL_APACHE2_RELOAD", + "value": "${PERL_APACHE2_RELOAD}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/dancer-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Dancer service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "SECRET_KEY_BASE", + "description": "Your secret key for verifying the integrity of signed cookies", + "generate": "expression", + "from": "[a-z0-9]{127}" + }, + { + "name": "PERL_APACHE2_RELOAD", + "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules", + "value": "" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/django-postgresql.json b/roles/openshift_examples/files/examples/quickstart-templates/django-postgresql.json new file mode 100644 index 000000000..749064e98 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/django-postgresql.json @@ -0,0 +1,346 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example", + "annotations": { + "description": "An example Django application with a PostgreSQL database", + "tags": "instant-app,python,django,postgresql", + "iconClass": "icon-python" + } + }, + "labels": { + "template": "django-psql-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "django-psql-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "django-psql-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "python:3.3" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "django-psql-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "django-psql-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "django-psql-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "django-psql-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "django-psql-example" + }, + "template": { + "metadata": { + "name": "django-psql-example", + "labels": { + "name": "django-psql-example" + } + }, + "spec": { + "containers": [ + { + "name": "django-psql-example", + "image": "django-psql-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "DATABASE_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "APP_CONFIG", + "value": "${APP_CONFIG}" + }, + { + "name": "DJANGO_SECRET_KEY", + "value": "${DJANGO_SECRET_KEY}" + } + ] + } + ] + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Exposes the database server" + } + }, + "spec": { + "ports": [ + { + "name": "postgresql", + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Defines how to deploy the database" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "postgresql", + "image": "${POSTGRESQL_IMAGE}", + "ports": [ + { + "containerPort": 5432 + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DATABASE_NAME}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/django-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Django service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "postgresql" + }, + { + "name": "DATABASE_ENGINE", + "description": "Database engine: postgresql, mysql or sqlite (default)", + "value": "postgresql" + }, + { + "name": "DATABASE_NAME", + "description": "Database name", + "value": "default" + }, + { + "name": "DATABASE_USER", + "description": "Database user name", + "value": "django" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Database user password", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}" + }, + { + "name": "POSTGRESQL_IMAGE", + "description": "Image to use for postgresql", + "value": "openshift/postgresql-92-centos7" + }, + { + "name": "APP_CONFIG", + "description": "Relative path to Gunicorn configuration file (optional)" + }, + { + "name": "DJANGO_SECRET_KEY", + "description": "Set this to a long random string", + "generate": "expression", + "from": "[\\w]{50}" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/django.json b/roles/openshift_examples/files/examples/quickstart-templates/django.json new file mode 100644 index 000000000..143a942ab --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/django.json @@ -0,0 +1,254 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "django-example", + "annotations": { + "description": "An example Django application with no database", + "tags": "instant-app,python,django", + "iconClass": "icon-python" + } + }, + "labels": { + "template": "django-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "django-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "django-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "django-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "django-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "django-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "django-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "python:3.3" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "django-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "django-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "django-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "django-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "django-example" + }, + "template": { + "metadata": { + "name": "django-example", + "labels": { + "name": "django-example" + } + }, + "spec": { + "containers": [ + { + "name": "django-example", + "image": "django-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "DATABASE_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "APP_CONFIG", + "value": "${APP_CONFIG}" + }, + { + "name": "DJANGO_SECRET_KEY", + "value": "${DJANGO_SECRET_KEY}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/django-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Django service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name" + }, + { + "name": "DATABASE_ENGINE", + "description": "Database engine: postgresql, mysql or sqlite (default)" + }, + { + "name": "DATABASE_NAME", + "description": "Database name" + }, + { + "name": "DATABASE_USER", + "description": "Database user name" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Database user password" + }, + { + "name": "APP_CONFIG", + "description": "Relative path to Gunicorn configuration file (optional)" + }, + { + "name": "DJANGO_SECRET_KEY", + "description": "Set this to a long random string", + "generate": "expression", + "from": "[\\w]{50}" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/jenkins-ephemeral-template.json b/roles/openshift_examples/files/examples/quickstart-templates/jenkins-ephemeral-template.json new file mode 100644 index 000000000..14bd032af --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/jenkins-ephemeral-template.json @@ -0,0 +1,150 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "jenkins-ephemeral", + "creationTimestamp": null, + "annotations": { + "description": "Jenkins service, without persistent storage. WARNING: Any data stored will be lost upon pod destruction. Only use this template for testing", + "iconClass": "icon-jenkins", + "tags": "database,jenkins" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${JENKINS_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "web", + "protocol": "TCP", + "port": 8080, + "targetPort": 8080, + "nodePort": 0 + } + ], + "selector": { + "name": "${JENKINS_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "jenkins", + "creationTimestamp": null + }, + "spec": { + "to": { + "kind": "Service", + "name": "${JENKINS_SERVICE_NAME}" + }, + "tls": { + "termination": "edge", + "certificate": "-----BEGIN CERTIFICATE-----\nMIIDIjCCAgqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCVVMx\nCzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0ExGjAYBgNVBAMMEXd3\ndy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu\nY29tMB4XDTE1MDExMjE0MTk0MVoXDTE2MDExMjE0MTk0MVowfDEYMBYGA1UEAwwP\nd3d3LmV4YW1wbGUuY29tMQswCQYDVQQIDAJTQzELMAkGA1UEBhMCVVMxIjAgBgkq\nhkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUx\nEDAOBgNVBAsMB0V4YW1wbGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrv\ngu6ZTTefNN7jjiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm\n47VRx5Qrf/YLXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1M\nmNrQUgZyQC6XIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAGjDTALMAkGA1UdEwQC\nMAAwDQYJKoZIhvcNAQEFBQADggEBAFCi7ZlkMnESvzlZCvv82Pq6S46AAOTPXdFd\nTMvrh12E1sdVALF1P1oYFJzG1EiZ5ezOx88fEDTW+Lxb9anw5/KJzwtWcfsupf1m\nV7J0D3qKzw5C1wjzYHh9/Pz7B1D0KthQRATQCfNf8s6bbFLaw/dmiIUhHLtIH5Qc\nyfrejTZbOSP77z8NOWir+BWWgIDDB2//3AkDIQvT20vmkZRhkqSdT7et4NmXOX/j\njhPti4b2Fie0LeuvgaOdKjCpQQNrYthZHXeVlOLRhMTSk3qUczenkKTOhvP7IS9q\n+Dzv5hqgSfvMG392KWh5f8xXfJNs4W5KLbZyl901MeReiLrPH3w=\n-----END CERTIFICATE-----", + "key": "-----BEGIN PRIVATE KEY-----\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMrvgu6ZTTefNN7j\njiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm47VRx5Qrf/YL\nXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1MmNrQUgZyQC6X\nIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAECgYEAnxOjEj/vrLNLMZE1Q9H7PZVF\nWdP/JQVNvQ7tCpZ3ZdjxHwkvf//aQnuxS5yX2Rnf37BS/TZu+TIkK4373CfHomSx\nUTAn2FsLmOJljupgGcoeLx5K5nu7B7rY5L1NHvdpxZ4YjeISrRtEPvRakllENU5y\ngJE8c2eQOx08ZSRE4TkCQQD7dws2/FldqwdjJucYijsJVuUdoTqxP8gWL6bB251q\nelP2/a6W2elqOcWId28560jG9ZS3cuKvnmu/4LG88vZFAkEAzphrH3673oTsHN+d\nuBd5uyrlnGjWjuiMKv2TPITZcWBjB8nJDSvLneHF59MYwejNNEof2tRjgFSdImFH\nmi995wJBAMtPjW6wiqRz0i41VuT9ZgwACJBzOdvzQJfHgSD9qgFb1CU/J/hpSRIM\nkYvrXK9MbvQFvG6x4VuyT1W8mpe1LK0CQAo8VPpffhFdRpF7psXLK/XQ/0VLkG3O\nKburipLyBg/u9ZkaL0Ley5zL5dFBjTV2Qkx367Ic2b0u9AYTCcgi2DsCQQD3zZ7B\nv7BOm7MkylKokY2MduFFXU0Bxg6pfZ7q3rvg8gqhUFbaMStPRYg6myiDiW/JfLhF\nTcFT4touIo7oriFJ\n-----END PRIVATE KEY-----", + "caCertificate": "-----BEGIN CERTIFICATE-----\nMIIEFzCCAv+gAwIBAgIJALK1iUpF2VQLMA0GCSqGSIb3DQEBBQUAMIGhMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCU0MxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoG\nA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UECwwHVGVzdCBDQTEaMBgG\nA1UEAwwRd3d3LmV4YW1wbGVjYS5jb20xIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVA\nZXhhbXBsZS5jb20wHhcNMTUwMTEyMTQxNTAxWhcNMjUwMTA5MTQxNTAxWjCBoTEL\nMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkx\nHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0Ex\nGjAYBgNVBAMMEXd3dy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFt\ncGxlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\nw2rK1J2NMtQj0KDug7g7HRKl5jbf0QMkMKyTU1fBtZ0cCzvsF4CqV11LK4BSVWaK\nrzkaXe99IVJnH8KdOlDl5Dh/+cJ3xdkClSyeUT4zgb6CCBqg78ePp+nN11JKuJlV\nIG1qdJpB1J5O/kCLsGcTf7RS74MtqMFo96446Zvt7YaBhWPz6gDaO/TUzfrNcGLA\nEfHVXkvVWqb3gqXUztZyVex/gtP9FXQ7gxTvJml7UkmT0VAFjtZnCqmFxpLZFZ15\n+qP9O7Q2MpsGUO/4vDAuYrKBeg1ZdPSi8gwqUP2qWsGd9MIWRv3thI2903BczDc7\nr8WaIbm37vYZAS9G56E4+wIDAQABo1AwTjAdBgNVHQ4EFgQUugLrSJshOBk5TSsU\nANs4+SmJUGwwHwYDVR0jBBgwFoAUugLrSJshOBk5TSsUANs4+SmJUGwwDAYDVR0T\nBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaMJ33zAMV4korHo5aPfayV3uHoYZ\n1ChzP3eSsF+FjoscpoNSKs91ZXZF6LquzoNezbfiihK4PYqgwVD2+O0/Ty7UjN4S\nqzFKVR4OS/6lCJ8YncxoFpTntbvjgojf1DEataKFUN196PAANc3yz8cWHF4uvjPv\nWkgFqbIjb+7D1YgglNyovXkRDlRZl0LD1OQ0ZWhd4Ge1qx8mmmanoBeYZ9+DgpFC\nj9tQAbS867yeOryNe7sEOIpXAAqK/DTu0hB6+ySsDfMo4piXCc2aA/eI2DCuw08e\nw17Dz9WnupZjVdwTKzDhFgJZMLDqn37HQnT6EemLFqbcR0VPEnfyhDtZIQ==\n-----END CERTIFICATE-----" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${JENKINS_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${JENKINS_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${JENKINS_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "jenkins", + "image": "${JENKINS_IMAGE}", + "env": [ + { + "name": "JENKINS_PASSWORD", + "value": "${JENKINS_PASSWORD}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${JENKINS_SERVICE_NAME}-data", + "mountPath": "/var/lib/jenkins" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${JENKINS_SERVICE_NAME}-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + } + } + ], + "parameters": [ + { + "name": "JENKINS_SERVICE_NAME", + "description": "Jenkins service name", + "value": "jenkins" + }, + { + "name": "JENKINS_IMAGE", + "description": "Jenkins Docker image to use", + "value": "openshift/jenkins-1-centos7" + }, + { + "name": "JENKINS_PASSWORD", + "description": "Password for the Jenkins user", + "generate": "expression", + "value": "password" + } + ], + "labels": { + "template": "jenkins-ephemeral-template" + } +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/jenkins-persistent-template.json b/roles/openshift_examples/files/examples/quickstart-templates/jenkins-persistent-template.json new file mode 100644 index 000000000..fa31de486 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/jenkins-persistent-template.json @@ -0,0 +1,173 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "jenkins-persistent", + "creationTimestamp": null, + "annotations": { + "description": "Jenkins service, with persistent storage.", + "iconClass": "icon-jenkins", + "tags": "database,jenkins" + } + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${JENKINS_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "name": "web", + "protocol": "TCP", + "port": 8080, + "targetPort": 8080, + "nodePort": 0 + } + ], + "selector": { + "name": "${JENKINS_SERVICE_NAME}" + }, + "portalIP": "", + "type": "ClusterIP", + "sessionAffinity": "None" + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "jenkins", + "creationTimestamp": null + }, + "spec": { + "to": { + "kind": "Service", + "name": "${JENKINS_SERVICE_NAME}" + }, + "tls": { + "termination": "edge", + "certificate": "-----BEGIN CERTIFICATE-----\nMIIDIjCCAgqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCVVMx\nCzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0ExGjAYBgNVBAMMEXd3\ndy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu\nY29tMB4XDTE1MDExMjE0MTk0MVoXDTE2MDExMjE0MTk0MVowfDEYMBYGA1UEAwwP\nd3d3LmV4YW1wbGUuY29tMQswCQYDVQQIDAJTQzELMAkGA1UEBhMCVVMxIjAgBgkq\nhkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUx\nEDAOBgNVBAsMB0V4YW1wbGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrv\ngu6ZTTefNN7jjiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm\n47VRx5Qrf/YLXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1M\nmNrQUgZyQC6XIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAGjDTALMAkGA1UdEwQC\nMAAwDQYJKoZIhvcNAQEFBQADggEBAFCi7ZlkMnESvzlZCvv82Pq6S46AAOTPXdFd\nTMvrh12E1sdVALF1P1oYFJzG1EiZ5ezOx88fEDTW+Lxb9anw5/KJzwtWcfsupf1m\nV7J0D3qKzw5C1wjzYHh9/Pz7B1D0KthQRATQCfNf8s6bbFLaw/dmiIUhHLtIH5Qc\nyfrejTZbOSP77z8NOWir+BWWgIDDB2//3AkDIQvT20vmkZRhkqSdT7et4NmXOX/j\njhPti4b2Fie0LeuvgaOdKjCpQQNrYthZHXeVlOLRhMTSk3qUczenkKTOhvP7IS9q\n+Dzv5hqgSfvMG392KWh5f8xXfJNs4W5KLbZyl901MeReiLrPH3w=\n-----END CERTIFICATE-----", + "key": "-----BEGIN PRIVATE KEY-----\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMrvgu6ZTTefNN7j\njiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm47VRx5Qrf/YL\nXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1MmNrQUgZyQC6X\nIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAECgYEAnxOjEj/vrLNLMZE1Q9H7PZVF\nWdP/JQVNvQ7tCpZ3ZdjxHwkvf//aQnuxS5yX2Rnf37BS/TZu+TIkK4373CfHomSx\nUTAn2FsLmOJljupgGcoeLx5K5nu7B7rY5L1NHvdpxZ4YjeISrRtEPvRakllENU5y\ngJE8c2eQOx08ZSRE4TkCQQD7dws2/FldqwdjJucYijsJVuUdoTqxP8gWL6bB251q\nelP2/a6W2elqOcWId28560jG9ZS3cuKvnmu/4LG88vZFAkEAzphrH3673oTsHN+d\nuBd5uyrlnGjWjuiMKv2TPITZcWBjB8nJDSvLneHF59MYwejNNEof2tRjgFSdImFH\nmi995wJBAMtPjW6wiqRz0i41VuT9ZgwACJBzOdvzQJfHgSD9qgFb1CU/J/hpSRIM\nkYvrXK9MbvQFvG6x4VuyT1W8mpe1LK0CQAo8VPpffhFdRpF7psXLK/XQ/0VLkG3O\nKburipLyBg/u9ZkaL0Ley5zL5dFBjTV2Qkx367Ic2b0u9AYTCcgi2DsCQQD3zZ7B\nv7BOm7MkylKokY2MduFFXU0Bxg6pfZ7q3rvg8gqhUFbaMStPRYg6myiDiW/JfLhF\nTcFT4touIo7oriFJ\n-----END PRIVATE KEY-----", + "caCertificate": "-----BEGIN CERTIFICATE-----\nMIIEFzCCAv+gAwIBAgIJALK1iUpF2VQLMA0GCSqGSIb3DQEBBQUAMIGhMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCU0MxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoG\nA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UECwwHVGVzdCBDQTEaMBgG\nA1UEAwwRd3d3LmV4YW1wbGVjYS5jb20xIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVA\nZXhhbXBsZS5jb20wHhcNMTUwMTEyMTQxNTAxWhcNMjUwMTA5MTQxNTAxWjCBoTEL\nMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkx\nHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0Ex\nGjAYBgNVBAMMEXd3dy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFt\ncGxlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\nw2rK1J2NMtQj0KDug7g7HRKl5jbf0QMkMKyTU1fBtZ0cCzvsF4CqV11LK4BSVWaK\nrzkaXe99IVJnH8KdOlDl5Dh/+cJ3xdkClSyeUT4zgb6CCBqg78ePp+nN11JKuJlV\nIG1qdJpB1J5O/kCLsGcTf7RS74MtqMFo96446Zvt7YaBhWPz6gDaO/TUzfrNcGLA\nEfHVXkvVWqb3gqXUztZyVex/gtP9FXQ7gxTvJml7UkmT0VAFjtZnCqmFxpLZFZ15\n+qP9O7Q2MpsGUO/4vDAuYrKBeg1ZdPSi8gwqUP2qWsGd9MIWRv3thI2903BczDc7\nr8WaIbm37vYZAS9G56E4+wIDAQABo1AwTjAdBgNVHQ4EFgQUugLrSJshOBk5TSsU\nANs4+SmJUGwwHwYDVR0jBBgwFoAUugLrSJshOBk5TSsUANs4+SmJUGwwDAYDVR0T\nBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaMJ33zAMV4korHo5aPfayV3uHoYZ\n1ChzP3eSsF+FjoscpoNSKs91ZXZF6LquzoNezbfiihK4PYqgwVD2+O0/Ty7UjN4S\nqzFKVR4OS/6lCJ8YncxoFpTntbvjgojf1DEataKFUN196PAANc3yz8cWHF4uvjPv\nWkgFqbIjb+7D1YgglNyovXkRDlRZl0LD1OQ0ZWhd4Ge1qx8mmmanoBeYZ9+DgpFC\nj9tQAbS867yeOryNe7sEOIpXAAqK/DTu0hB6+ySsDfMo4piXCc2aA/eI2DCuw08e\nw17Dz9WnupZjVdwTKzDhFgJZMLDqn37HQnT6EemLFqbcR0VPEnfyhDtZIQ==\n-----END CERTIFICATE-----" + } + } + }, + { + "kind": "PersistentVolumeClaim", + "apiVersion": "v1", + "metadata": { + "name": "${JENKINS_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${JENKINS_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${JENKINS_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${JENKINS_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "jenkins", + "image": "${JENKINS_IMAGE}", + "env": [ + { + "name": "JENKINS_PASSWORD", + "value": "${JENKINS_PASSWORD}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "${JENKINS_SERVICE_NAME}-data", + "mountPath": "/var/lib/jenkins" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "${JENKINS_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${JENKINS_SERVICE_NAME}" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + } + } + ], + "parameters": [ + { + "name": "JENKINS_SERVICE_NAME", + "description": "Jenkins service name", + "value": "jenkins" + }, + { + "name": "JENKINS_PASSWORD", + "description": "Password for the Jenkins user", + "generate": "expression", + "value": "password" + }, + { + "name": "JENKINS_IMAGE", + "description": "Jenkins Docker image to use", + "value": "openshift/jenkins-1-centos7" + }, + { + "name": "VOLUME_CAPACITY", + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "value": "512Mi", + "required": true + } + ], + "labels": { + "template": "jenkins-persistent-template" + } +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json b/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json new file mode 100644 index 000000000..8760b074c --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/nodejs-mongodb.json @@ -0,0 +1,346 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example", + "annotations": { + "description": "An example Node.js application with a MongoDB database", + "tags": "instant-app,nodejs,mongodb", + "iconClass": "icon-nodejs" + } + }, + "labels": { + "template": "nodejs-mongodb-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "nodejs-mongodb-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "nodejs-mongodb-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "nodejs:0.10" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "nodejs-mongodb-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-mongodb-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "nodejs-mongodb-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "nodejs-mongodb-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "nodejs-mongodb-example" + }, + "template": { + "metadata": { + "name": "nodejs-mongodb-example", + "labels": { + "name": "nodejs-mongodb-example" + } + }, + "spec": { + "containers": [ + { + "name": "nodejs-mongodb-example", + "image": "nodejs-mongodb-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "MONGODB_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DATABASE_NAME}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DATABASE_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Exposes the database server" + } + }, + "spec": { + "ports": [ + { + "name": "mongodb", + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Defines how to deploy the database" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "mongodb", + "image": "${MONGODB_IMAGE}", + "ports": [ + { + "containerPort": 27017 + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DATABASE_NAME}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DATABASE_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/nodejs-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Node.js service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "GENERIC_WEBHOOK_SECRET", + "description": "A secret string used to configure the Generic webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "mongodb" + }, + { + "name": "DATABASE_USER", + "description": "Username for MongoDB user that will be used for accessing the database", + "generate": "expression", + "from": "user[A-Z0-9]{3}" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Password for the MongoDB user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}" + }, + { + "name": "DATABASE_NAME", + "description": "Database name", + "value": "sampledb" + }, + { + "name": "DATABASE_ADMIN_PASSWORD", + "description": "Password for the database admin user", + "generate": "expression", + "from": "[a-zA-Z0-9]{16}" + }, + { + "name": "MONGODB_IMAGE", + "description": "Image to use for mongodb", + "value": "openshift/mongodb-24-centos7" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json b/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json new file mode 100644 index 000000000..e047266e3 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/nodejs.json @@ -0,0 +1,248 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example", + "annotations": { + "description": "An example Node.js application with no database", + "tags": "instant-app,nodejs", + "iconClass": "icon-nodejs" + } + }, + "labels": { + "template": "nodejs-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "nodejs-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "nodejs-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "nodejs:0.10" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "nodejs-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "nodejs-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Rolling" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "nodejs-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "nodejs-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "nodejs-example" + }, + "template": { + "metadata": { + "name": "nodejs-example", + "labels": { + "name": "nodejs-example" + } + }, + "spec": { + "containers": [ + { + "name": "nodejs-example", + "image": "nodejs-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "MONGODB_USER", + "value": "${MONGODB_USER}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${MONGODB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${MONGODB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${MONGODB_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/nodejs-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Node.js service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "GENERIC_WEBHOOK_SECRET", + "description": "A secret string used to configure the Generic webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name" + }, + { + "name": "MONGODB_USER", + "description": "Username for MongoDB user that will be used for accessing the database" + }, + { + "name": "MONGODB_PASSWORD", + "description": "Password for the MongoDB user" + }, + { + "name": "MONGODB_DATABASE", + "description": "Database name" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "description": "Password for the database admin user" + } + ] +} diff --git a/roles/openshift_examples/files/examples/quickstart-templates/rails-postgresql.json b/roles/openshift_examples/files/examples/quickstart-templates/rails-postgresql.json new file mode 100644 index 000000000..b98282528 --- /dev/null +++ b/roles/openshift_examples/files/examples/quickstart-templates/rails-postgresql.json @@ -0,0 +1,402 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example", + "annotations": { + "description": "An example Rails application with a PostgreSQL database", + "tags": "instant-app,ruby,rails,postgresql", + "iconClass": "icon-ruby" + } + }, + "labels": { + "template": "rails-postgresql-example" + }, + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example", + "annotations": { + "description": "Exposes and load balances the application pods" + } + }, + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "name": "rails-postgresql-example" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "rails-postgresql-example" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example", + "annotations": { + "description": "Keeps track of changes in the application image" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example", + "annotations": { + "description": "Defines how to build the application" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${SOURCE_REPOSITORY_URL}", + "ref": "${SOURCE_REPOSITORY_REF}" + }, + "contextDir": "${CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "ruby:2.0" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "rails-postgresql-example:latest" + } + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + } + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "rails-postgresql-example", + "annotations": { + "description": "Defines how to deploy the application server" + } + }, + "spec": { + "strategy": { + "type": "Recreate", + "recreateParams": { + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "./migrate-database.sh" + ], + "containerName": "rails-postgresql-example" + } + } + } + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "rails-postgresql-example" + ], + "from": { + "kind": "ImageStreamTag", + "name": "rails-postgresql-example:latest" + } + } + }, + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "rails-postgresql-example" + }, + "template": { + "metadata": { + "name": "rails-postgresql-example", + "labels": { + "name": "rails-postgresql-example" + } + }, + "spec": { + "containers": [ + { + "name": "rails-postgresql-example", + "image": "rails-postgresql-example", + "ports": [ + { + "containerPort": 8080 + } + ], + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "POSTGRESQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DATABASE_NAME}" + }, + { + "name": "SECRET_KEY_BASE", + "value": "${SECRET_KEY_BASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + }, + { + "name": "SECRET_KEY_BASE", + "value": "${SECRET_KEY_BASE}" + }, + { + "name": "APPLICATION_DOMAIN", + "value": "${APPLICATION_DOMAIN}" + }, + { + "name": "APPLICATION_USER", + "value": "${APPLICATION_USER}" + }, + { + "name": "APPLICATION_PASSWORD", + "value": "${APPLICATION_PASSWORD}" + }, + { + "name": "RAILS_ENV", + "value": "${RAILS_ENV}" + } + ] + } + ] + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Exposes the database server" + } + }, + "spec": { + "ports": [ + { + "name": "postgresql", + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "annotations": { + "description": "Defines how to deploy the database" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "name": "${DATABASE_SERVICE_NAME}", + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "postgresql", + "image": "${POSTGRESQL_IMAGE}", + "ports": [ + { + "containerPort": 5432 + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DATABASE_USER}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DATABASE_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DATABASE_NAME}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ] + } + } + } + } + ], + "parameters": [ + { + "name": "SOURCE_REPOSITORY_URL", + "description": "The URL of the repository with your application source code", + "value": "https://github.com/openshift/rails-ex.git" + }, + { + "name": "SOURCE_REPOSITORY_REF", + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch" + }, + { + "name": "CONTEXT_DIR", + "description": "Set this to the relative path to your project if it is not in the root of your repository" + }, + { + "name": "APPLICATION_DOMAIN", + "description": "The exposed hostname that will route to the Rails service, if left blank a value will be defaulted.", + "value": "" + }, + { + "name": "GITHUB_WEBHOOK_SECRET", + "description": "A secret string used to configure the GitHub webhook", + "generate": "expression", + "from": "[a-zA-Z0-9]{40}" + }, + { + "name": "SECRET_KEY_BASE", + "description": "Your secret key for verifying the integrity of signed cookies", + "generate": "expression", + "from": "[a-z0-9]{127}" + }, + { + "name": "APPLICATION_USER", + "description": "The application user that is used within the sample application to authorize access on pages", + "value": "openshift" + }, + { + "name": "APPLICATION_PASSWORD", + "description": "The application password that is used within the sample application to authorize access on pages", + "value": "secret" + }, + { + "name": "RAILS_ENV", + "description": "Environment under which the sample application will run. Could be set to production, development or test", + "value": "production" + }, + { + "name": "DATABASE_SERVICE_NAME", + "description": "Database service name", + "value": "postgresql" + }, + { + "name": "DATABASE_USER", + "description": "database username", + "generate": "expression", + "from": "user[A-Z0-9]{3}" + }, + { + "name": "DATABASE_PASSWORD", + "description": "database password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "DATABASE_NAME", + "description": "database name", + "value": "root" + }, + { + "name": "POSTGRESQL_IMAGE", + "description": "Image to use for postgresql", + "value": "openshift/postgresql-92-centos7" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "description": "database max connections", + "value": "10" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "description": "database shared buffers", + "value": "12MB" + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-streams/jboss-image-streams.json b/roles/openshift_examples/files/examples/xpaas-streams/jboss-image-streams.json new file mode 100644 index 000000000..37e6269fe --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-streams/jboss-image-streams.json @@ -0,0 +1,100 @@ +{ + "kind": "List", + "apiVersion": "v1", + "metadata": { + "name": "jboss-image-streams", + "annotations": { + "description": "ImageStream definitions for JBoss Middleware products." + } + }, + "items": [ + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jboss-webserver3-tomcat7-openshift" + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/jboss-webserver-3/tomcat7-openshift", + "tags": [ + { + "name": "3.0", + "annotations": { + "description": "JBoss Web Server v3 Tomcat 7 STI images.", + "iconClass": "icon-jboss", + "tags": "java", + "supports":"tomcat7:3.0,java", + "version": "3.0" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jboss-webserver3-tomcat8-openshift" + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/jboss-webserver-3/tomcat8-openshift", + "tags": [ + { + "name": "3.0", + "annotations": { + "description": "JBoss Web Server v3 Tomcat 8 STI images.", + "iconClass": "icon-jboss", + "tags": "java", + "supports":"tomcat8:3.0,java", + "version": "3.0" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jboss-eap6-openshift" + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/jboss-eap-6/eap-openshift", + "tags": [ + { + "name": "6.4", + "annotations": { + "description": "JBoss EAP 6 STI images.", + "iconClass": "icon-jboss", + "tags": "javaee", + "supports":"eap:6.4,jee,java", + "version": "6.4" + } + } + ] + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "jboss-amq-6" + }, + "spec": { + "dockerImageRepository": "registry.access.redhat.com/jboss-amq-6/amq-openshift", + "tags": [ + { + "name": "6.2", + "annotations": { + "description": "JBoss ActiveMQ 6 broker image.", + "iconClass": "icon-jboss", + "tags": "javaee", + "supports":"amq:6.2,jee,java", + "version": "6.2" + } + } + ] + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/amq6-persistent.json b/roles/openshift_examples/files/examples/xpaas-templates/amq6-persistent.json new file mode 100644 index 000000000..5cbc7ee7e --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/amq6-persistent.json @@ -0,0 +1,439 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for ActiveMQ brokers using persistent storage." + }, + "name": "amq6-persistent" + }, + "labels": { + "template": "amq6-persistent" + }, + "parameters": [ + { + "description": "ActiveMQ Release version, e.g. 6.2, etc.", + "name": "AMQ_RELEASE", + "value": "6.2" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "broker" + }, + { + "description": "Protocol to configure. Only openwire is supported by EAP. amqp, amqp+ssl, mqtt, stomp, stomp+ssl, and ssl are not supported by EAP", + "name": "MQ_PROTOCOL", + "value": "openwire" + }, + { + "description": "Queue names", + "name": "MQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "MQ_TOPICS", + "value": "" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "Broker user name", + "name": "MQ_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Broker user password", + "name": "MQ_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin User", + "name": "AMQ_ADMIN_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin Password", + "name": "AMQ_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Name of a secret containing SSL related files", + "name": "AMQ_SECRET", + "value": "amq-app-secret" + }, + { + "description": "SSL trust store filename", + "name": "AMQ_TRUSTSTORE", + "value": "broker.ts" + }, + { + "description": "SSL key store filename", + "name": "AMQ_KEYSTORE", + "value": "broker.ks" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5672, + "targetPort": 5672 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-amqp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's amqp port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5671, + "targetPort": 5671 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-amqp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's amqp ssl port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 1883, + "targetPort": 1883 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-mqtt", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's mqtt port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61613, + "targetPort": 61613 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-stomp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's stomp port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61612, + "targetPort": 61612 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-stomp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's stomp ssl port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61616, + "targetPort": 61616 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp (openwire) port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61617, + "targetPort": 61617 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp ssl (openwire) port." + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-amq" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-amq-6:${AMQ_RELEASE}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-amq", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "amq-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}-amq", + "image": "jboss-amq-6", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "broker-secret-volume", + "mountPath": "/etc/amq-secret-volume", + "readOnly": true + }, + { + "mountPath": "/opt/amq/data/kahadb", + "name": "${APPLICATION_NAME}-amq-pvol" + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -L -u ${AMQ_ADMIN_USERNAME}:${AMQ_ADMIN_PASSWORD} 'http://localhost:8161/hawtio/jolokia/read/org.apache.activemq:type=Broker,brokerName=*,service=Health/CurrentStatus' | grep -q '\"CurrentStatus\" *: *\"Good\"'" + ] + } + }, + "ports": [ + { + "name": "amqp", + "containerPort": 5672, + "protocol": "TCP" + }, + { + "name": "amqp-ssl", + "containerPort": 5671, + "protocol": "TCP" + }, + { + "name": "mqtt", + "containerPort": 1883, + "protocol": "TCP" + }, + { + "name": "stomp", + "containerPort": 61613, + "protocol": "TCP" + }, + { + "name": "stomp-ssl", + "containerPort": 61612, + "protocol": "TCP" + }, + { + "name": "tcp", + "containerPort": 61616, + "protocol": "TCP" + }, + { + "name": "tcp-ssl", + "containerPort": 61617, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "AMQ_USER", + "value": "${MQ_USERNAME}" + }, + { + "name": "AMQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "AMQ_PROTOCOLS", + "value": "${MQ_PROTOCOL}" + }, + { + "name": "AMQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "AMQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "AMQ_ADMIN_USERNAME", + "value": "${AMQ_ADMIN_USERNAME}" + }, + { + "name": "AMQ_ADMIN_PASSWORD", + "value": "${AMQ_ADMIN_PASSWORD}" + }, + { + "name": "AMQ_KEYSTORE_TRUSTSTORE_DIR", + "value": "/etc/amq-secret-volume" + }, + { + "name": "AMQ_TRUSTSTORE", + "value": "${AMQ_TRUSTSTORE}" + }, + { + "name": "AMQ_KEYSTORE", + "value": "${AMQ_KEYSTORE}" + } + ] + } + ], + "volumes": [ + { + "name": "broker-secret-volume", + "secret": { + "secretName": "${AMQ_SECRET}" + } + }, + { + "name": "${APPLICATION_NAME}-amq-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-amq-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-amq-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/amq6.json b/roles/openshift_examples/files/examples/xpaas-templates/amq6.json new file mode 100644 index 000000000..7decdfe52 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/amq6.json @@ -0,0 +1,410 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for ActiveMQ brokers." + }, + "name": "amq6" + }, + "labels": { + "template": "amq6" + }, + "parameters": [ + { + "description": "ActiveMQ Release version, e.g. 6.2, etc.", + "name": "AMQ_RELEASE", + "value": "6.2" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "broker" + }, + { + "description": "Protocol to configure. Only openwire is supported by EAP. amqp, amqp+ssl, mqtt, stomp, stomp+ssl, and ssl are not supported by EAP", + "name": "MQ_PROTOCOL", + "value": "openwire" + }, + { + "description": "Queue names", + "name": "MQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "MQ_TOPICS", + "value": "" + }, + { + "description": "Broker user name", + "name": "MQ_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Broker user password", + "name": "MQ_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin User", + "name": "AMQ_ADMIN_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin Password", + "name": "AMQ_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Name of a secret containing SSL related files", + "name": "AMQ_SECRET", + "value": "amq-app-secret" + }, + { + "description": "SSL trust store filename", + "name": "AMQ_TRUSTSTORE", + "value": "broker.ts" + }, + { + "description": "SSL key store filename", + "name": "AMQ_KEYSTORE", + "value": "broker.ks" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5672, + "targetPort": 5672 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-amqp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's amqp port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5671, + "targetPort": 5671 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-amqp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's amqp ssl port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 1883, + "targetPort": 1883 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-mqtt", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's mqtt port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61613, + "targetPort": 61613 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-stomp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's stomp port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61612, + "targetPort": 61612 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-stomp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's stomp ssl port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61616, + "targetPort": 61616 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp (openwire) port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61617, + "targetPort": 61617 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp-ssl", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp ssl (openwire) port." + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-amq" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-amq-6:${AMQ_RELEASE}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-amq", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "amq-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}-amq", + "image": "jboss-amq-6", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "broker-secret-volume", + "mountPath": "/etc/amq-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -L -u ${AMQ_ADMIN_USERNAME}:${AMQ_ADMIN_PASSWORD} 'http://localhost:8161/hawtio/jolokia/read/org.apache.activemq:type=Broker,brokerName=*,service=Health/CurrentStatus' | grep -q '\"CurrentStatus\" *: *\"Good\"'" + ] + } + }, + "ports": [ + { + "name": "amqp", + "containerPort": 5672, + "protocol": "TCP" + }, + { + "name": "amqp-ssl", + "containerPort": 5671, + "protocol": "TCP" + }, + { + "name": "mqtt", + "containerPort": 1883, + "protocol": "TCP" + }, + { + "name": "stomp", + "containerPort": 61613, + "protocol": "TCP" + }, + { + "name": "stomp-ssl", + "containerPort": 61612, + "protocol": "TCP" + }, + { + "name": "tcp", + "containerPort": 61616, + "protocol": "TCP" + }, + { + "name": "tcp-ssl", + "containerPort": 61617, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "AMQ_USER", + "value": "${MQ_USERNAME}" + }, + { + "name": "AMQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "AMQ_PROTOCOLS", + "value": "${MQ_PROTOCOL}" + }, + { + "name": "AMQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "AMQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "AMQ_ADMIN_USERNAME", + "value": "${AMQ_ADMIN_USERNAME}" + }, + { + "name": "AMQ_ADMIN_PASSWORD", + "value": "${AMQ_ADMIN_PASSWORD}" + }, + { + "name": "AMQ_MESH_SERVICE_NAME", + "value": "${APPLICATION_NAME}-amq-tcp" + }, + { + "name": "AMQ_KEYSTORE_TRUSTSTORE_DIR", + "value": "/etc/amq-secret-volume" + }, + { + "name": "AMQ_TRUSTSTORE", + "value": "${AMQ_TRUSTSTORE}" + }, + { + "name": "AMQ_KEYSTORE", + "value": "${AMQ_KEYSTORE}" + } + ] + } + ], + "volumes": [ + { + "name": "broker-secret-volume", + "secret": { + "secretName": "${AMQ_SECRET}" + } + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-persistent-sti.json new file mode 100644 index 000000000..b64acae8b --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-persistent-sti.json @@ -0,0 +1,646 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 A-MQ applications with persistent storage built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-amq-persistent-sti" + }, + "labels": { + "template": "eap6-amq-persistent-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "ActiveMQ Release version, e.g. 6.2, etc.", + "name": "AMQ_RELEASE", + "value": "6.2" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "JNDI name for connection factory used by applications to connect to the broker, e.g. java:/ConnectionFactory", + "name": "MQ_JNDI", + "value": "java:/ConnectionFactory" + }, + { + "description": "Protocol to configure. Only openwire is supported by EAP. amqp, amqp+ssl, mqtt, stomp, stomp+ssl, and ssl are not supported by EAP", + "name": "MQ_PROTOCOL", + "value": "openwire" + }, + { + "description": "Queue names", + "name": "MQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "MQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Broker user name", + "name": "MQ_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Broker user password", + "name": "MQ_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin User", + "name": "AMQ_ADMIN_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin Password", + "name": "AMQ_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61616, + "targetPort": 61616 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp (openwire) port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MQ_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-amq=MQ" + }, + { + "name": "MQ_JNDI", + "value": "${MQ_JNDI}" + }, + { + "name": "MQ_USERNAME", + "value": "${MQ_USERNAME}" + }, + { + "name": "MQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "MQ_PROTOCOL", + "value": "tcp" + }, + { + "name": "MQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "MQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-amq" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-amq-6:${AMQ_RELEASE}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-amq", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-amq", + "image": "jboss-amq-6", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -L -u ${AMQ_ADMIN_USERNAME}:${AMQ_ADMIN_PASSWORD} 'http://localhost:8161/hawtio/jolokia/read/org.apache.activemq:type=Broker,brokerName=*,service=Health/CurrentStatus' | grep -q '\"CurrentStatus\" *: *\"Good\"'" + ] + } + }, + "ports": [ + { + "name": "amqp", + "containerPort": 5672, + "protocol": "TCP" + }, + { + "name": "amqp-ssl", + "containerPort": 5671, + "protocol": "TCP" + }, + { + "name": "mqtt", + "containerPort": 1883, + "protocol": "TCP" + }, + { + "name": "stomp", + "containerPort": 61613, + "protocol": "TCP" + }, + { + "name": "stomp-ssl", + "containerPort": 61612, + "protocol": "TCP" + }, + { + "name": "tcp", + "containerPort": 61616, + "protocol": "TCP" + }, + { + "name": "tcp-ssl", + "containerPort": 61617, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/opt/amq/data/kahadb", + "name": "${APPLICATION_NAME}-amq-pvol" + } + ], + "env": [ + { + "name": "AMQ_USER", + "value": "${MQ_USERNAME}" + }, + { + "name": "AMQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "AMQ_PROTOCOLS", + "value": "${MQ_PROTOCOL}" + }, + { + "name": "AMQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "AMQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "AMQ_ADMIN_USERNAME", + "value": "${AMQ_ADMIN_USERNAME}" + }, + { + "name": "AMQ_ADMIN_PASSWORD", + "value": "${AMQ_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-amq-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-amq-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-amq-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-sti.json new file mode 100644 index 000000000..20b234bd0 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-amq-sti.json @@ -0,0 +1,609 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 A-MQ applications built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-amq-sti" + }, + "labels": { + "template": "eap6-amq-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "ActiveMQ Release version, e.g. 6.2, etc.", + "name": "AMQ_RELEASE", + "value": "6.2" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "JNDI name for connection factory used by applications to connect to the broker, e.g. java:/ConnectionFactory", + "name": "MQ_JNDI", + "value": "java:/ConnectionFactory" + }, + { + "description": "Protocol to configure. Only openwire is supported by EAP. amqp, amqp+ssl, mqtt, stomp, stomp+ssl, and ssl are not supported by EAP", + "name": "MQ_PROTOCOL", + "value": "openwire" + }, + { + "description": "Queue names", + "name": "MQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "MQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Broker user name", + "name": "MQ_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Broker user password", + "name": "MQ_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin User", + "name": "AMQ_ADMIN_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "ActiveMQ Admin Password", + "name": "AMQ_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 61616, + "targetPort": 61616 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-amq-tcp", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The broker's tcp (openwire) port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MQ_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-amq=MQ" + }, + { + "name": "MQ_JNDI", + "value": "${MQ_JNDI}" + }, + { + "name": "MQ_USERNAME", + "value": "${MQ_USERNAME}" + }, + { + "name": "MQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "MQ_PROTOCOL", + "value": "tcp" + }, + { + "name": "MQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "MQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-amq" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-amq-6:${AMQ_RELEASE}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-amq" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-amq", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-amq", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-amq", + "image": "jboss-amq-6", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -L -u ${AMQ_ADMIN_USERNAME}:${AMQ_ADMIN_PASSWORD} 'http://localhost:8161/hawtio/jolokia/read/org.apache.activemq:type=Broker,brokerName=*,service=Health/CurrentStatus' | grep -q '\"CurrentStatus\" *: *\"Good\"'" + ] + } + }, + "ports": [ + { + "name": "amqp", + "containerPort": 5672, + "protocol": "TCP" + }, + { + "name": "amqp-ssl", + "containerPort": 5671, + "protocol": "TCP" + }, + { + "name": "mqtt", + "containerPort": 1883, + "protocol": "TCP" + }, + { + "name": "stomp", + "containerPort": 61613, + "protocol": "TCP" + }, + { + "name": "stomp-ssl", + "containerPort": 61612, + "protocol": "TCP" + }, + { + "name": "tcp", + "containerPort": 61616, + "protocol": "TCP" + }, + { + "name": "tcp-ssl", + "containerPort": 61617, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "AMQ_USER", + "value": "${MQ_USERNAME}" + }, + { + "name": "AMQ_PASSWORD", + "value": "${MQ_PASSWORD}" + }, + { + "name": "AMQ_PROTOCOLS", + "value": "${MQ_PROTOCOL}" + }, + { + "name": "AMQ_QUEUES", + "value": "${MQ_QUEUES}" + }, + { + "name": "AMQ_TOPICS", + "value": "${MQ_TOPICS}" + }, + { + "name": "AMQ_ADMIN_USERNAME", + "value": "${AMQ_ADMIN_USERNAME}" + }, + { + "name": "AMQ_ADMIN_PASSWORD", + "value": "${AMQ_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-basic-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-basic-sti.json new file mode 100644 index 000000000..146bfb1ee --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-basic-sti.json @@ -0,0 +1,304 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-jboss", + "description": "Application template for EAP 6 applications built using STI." + }, + "name": "eap6-basic-sti" + }, + "labels": { + "template": "eap6-basic-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI", + "value": "https://github.com/jboss-developer/jboss-eap-quickstarts" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "6.4.x" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "kitchensink" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-https-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-https-sti.json new file mode 100644 index 000000000..5df36ccc2 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-https-sti.json @@ -0,0 +1,408 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-jboss", + "description": "Application template for EAP 6 applications built using STI." + }, + "name": "eap6-https-sti" + }, + "labels": { + "template": "eap6-https-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI", + "value": "https://github.com/jboss-developer/jboss-eap-quickstarts" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "6.4.x" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "kitchensink" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-persistent-sti.json new file mode 100644 index 000000000..289ab284f --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-persistent-sti.json @@ -0,0 +1,645 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 MongDB applications with persistent storage built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-mongodb-persistent-sti" + }, + "labels": { + "template": "eap6-mongodb-persistent-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mongodb/data", + "name": "${APPLICATION_NAME}-mongodb-pvol" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mongodb-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mongodb-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-sti.json new file mode 100644 index 000000000..22b301aa9 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mongodb-sti.json @@ -0,0 +1,608 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 MongDB applications built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-mongodb-sti" + }, + "labels": { + "template": "eap6-mongodb-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-persistent-sti.json new file mode 100644 index 000000000..648a53199 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-persistent-sti.json @@ -0,0 +1,651 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 MySQL applications with persistent storage built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-mysql-persistent-sti" + }, + "labels": { + "template": "eap6-mysql-persistent-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mysql", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "TX_DATABASE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mysql/data", + "name": "${APPLICATION_NAME}-mysql-pvol" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mysql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mysql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mysql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-sti.json new file mode 100644 index 000000000..83d5c8b18 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-mysql-sti.json @@ -0,0 +1,614 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 MySQL applications built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-mysql-sti" + }, + "labels": { + "template": "eap6-mysql-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mysql", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "TX_DATABASE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-persistent-sti.json new file mode 100644 index 000000000..53b953b7e --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-persistent-sti.json @@ -0,0 +1,627 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 PostgreSQL applications with persistent storage built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-postgresql-persistent-sti" + }, + "labels": { + "template": "eap6-postgresql-persistent-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/postgresql", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "TX_DATABASE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/pgsql/data", + "name": "${APPLICATION_NAME}-postgresql-pvol" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-postgresql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-postgresql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-sti.json new file mode 100644 index 000000000..9d660cb42 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/eap6-postgresql-sti.json @@ -0,0 +1,590 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "description": "Application template for EAP 6 PostgreSQL applications built using STI.", + "iconClass" : "icon-jboss" + }, + "name": "eap6-postgresql-sti" + }, + "labels": { + "template": "eap6-postgresql-sti" + }, + "parameters": [ + { + "description": "EAP Release version, e.g. 6.4, etc.", + "name": "EAP_RELEASE", + "value": "6.4" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "eap-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/postgresql", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Queue names", + "name": "HORNETQ_QUEUES", + "value": "" + }, + { + "description": "Topic names", + "name": "HORNETQ_TOPICS", + "value": "" + }, + { + "description": "The name of the secret containing the keystore file", + "name": "EAP_HTTPS_SECRET", + "value": "eap-app-secret" + }, + { + "description": "The name of the keystore file within the secret", + "name": "EAP_HTTPS_KEYSTORE", + "value": "keystore.jks" + }, + { + "description": "The name associated with the server certificate", + "name": "EAP_HTTPS_NAME", + "value": "" + }, + { + "description": "The password for the keystore and certificate", + "name": "EAP_HTTPS_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "HornetQ cluster admin password", + "name": "HORNETQ_CLUSTER_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8888, + "targetPort": 8888 + } + ], + "portalIP": "None", + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-ping", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Ping service for clustered applications." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-eap6-openshift:${EAP_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "eap-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "volumeMounts": [ + { + "name": "eap-keystore-volume", + "mountPath": "/etc/eap-secret-volume", + "readOnly": true + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "/opt/eap/bin/readinessProbe.sh" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + }, + { + "name": "ping", + "containerPort": 8888, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "TX_DATABASE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_NAME", + "value": "${APPLICATION_NAME}-ping" + }, + { + "name": "OPENSHIFT_DNS_PING_SERVICE_PORT", + "value": "8888" + }, + { + "name": "EAP_HTTPS_KEYSTORE_DIR", + "value": "/etc/eap-secret-volume" + }, + { + "name": "EAP_HTTPS_KEYSTORE", + "value": "${EAP_HTTPS_KEYSTORE}" + }, + { + "name": "EAP_HTTPS_NAME", + "value": "${EAP_HTTPS_NAME}" + }, + { + "name": "EAP_HTTPS_PASSWORD", + "value": "${EAP_HTTPS_PASSWORD}" + }, + { + "name": "HORNETQ_CLUSTER_PASSWORD", + "value": "${HORNETQ_CLUSTER_PASSWORD}" + }, + { + "name": "HORNETQ_QUEUES", + "value": "${HORNETQ_QUEUES}" + }, + { + "name": "HORNETQ_TOPICS", + "value": "${HORNETQ_TOPICS}" + } + ] + } + ], + "volumes": [ + { + "name": "eap-keystore-volume", + "secret": { + "secretName": "${EAP_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-basic-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-basic-sti.json new file mode 100644 index 000000000..d74c2dfe3 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-basic-sti.json @@ -0,0 +1,257 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS applications built using STI." + }, + "name": "jws-tomcat7-basic-sti" + }, + "labels": { + "template": "jws-tomcat7-basic-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-https-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-https-sti.json new file mode 100644 index 000000000..b94142135 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-https-sti.json @@ -0,0 +1,361 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS applications built using STI." + }, + "name": "jws-tomcat7-basic-sti" + }, + "labels": { + "template": "jws-tomcat7-basic-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-persistent-sti.json new file mode 100644 index 000000000..0c7b7d8e3 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-persistent-sti.json @@ -0,0 +1,599 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MongoDB applications with persistent storage built using STI." + }, + "name": "jws-tomcat7-mongodb-persistent-sti" + }, + "labels": { + "template": "jws-tomcat7-mongodb-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mongodb/data", + "name": "${APPLICATION_NAME}-mongodb-pvol" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mongodb-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mongodb-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-sti.json new file mode 100644 index 000000000..892f27fe3 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mongodb-sti.json @@ -0,0 +1,562 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MongoDB applications built using STI." + }, + "name": "jws-tomcat7-mongodb-sti" + }, + "labels": { + "template": "jws-tomcat7-mongodb-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-persistent-sti.json new file mode 100644 index 000000000..547449010 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-persistent-sti.json @@ -0,0 +1,600 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MySQL applications with persistent storage built using STI." + }, + "name": "jws-tomcat7-mysql-persistent-sti" + }, + "labels": { + "template": "jws-tomcat7-mysql-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mysql/data", + "name": "${APPLICATION_NAME}-mysql-pvol" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mysql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mysql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mysql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-sti.json new file mode 100644 index 000000000..2ae59ec71 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-mysql-sti.json @@ -0,0 +1,563 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MySQL applications built using STI." + }, + "name": "jws-tomcat7-mysql-sti" + }, + "labels": { + "template": "jws-tomcat7-mysql-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-persistent-sti.json new file mode 100644 index 000000000..b871b48d0 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-persistent-sti.json @@ -0,0 +1,576 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS PostgreSQL applications with persistent storage built using STI." + }, + "name": "jws-tomcat7-postgresql-persistent-sti" + }, + "labels": { + "template": "jws-tomcat7-postgresql-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/pgsql/data", + "name": "${APPLICATION_NAME}-postgresql-pvol" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-postgresql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-postgresql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-sti.json new file mode 100644 index 000000000..384ff1b8f --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat7-postgresql-sti.json @@ -0,0 +1,539 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS PostgreSQL applications built using STI." + }, + "name": "jws-tomcat7-postgresql-sti" + }, + "labels": { + "template": "jws-tomcat7-postgresql-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat7-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-basic-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-basic-sti.json new file mode 100644 index 000000000..3c7812b69 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-basic-sti.json @@ -0,0 +1,257 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS applications built using STI." + }, + "name": "jws-tomcat8-basic-sti" + }, + "labels": { + "template": "jws-tomcat8-basic-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-https-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-https-sti.json new file mode 100644 index 000000000..d725e0606 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-https-sti.json @@ -0,0 +1,361 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS applications built using STI." + }, + "name": "jws-tomcat8-basic-sti" + }, + "labels": { + "template": "jws-tomcat8-basic-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-persistent-sti.json new file mode 100644 index 000000000..cf35d0024 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-persistent-sti.json @@ -0,0 +1,599 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MongoDB applications with persistent storage built using STI." + }, + "name": "jws-tomcat8-mongodb-persistent-sti" + }, + "labels": { + "template": "jws-tomcat8-mongodb-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mongodb/data", + "name": "${APPLICATION_NAME}-mongodb-pvol" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mongodb-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mongodb-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-sti.json new file mode 100644 index 000000000..a993024f4 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mongodb-sti.json @@ -0,0 +1,562 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MongoDB applications built using STI." + }, + "name": "jws-tomcat8-mongodb-sti" + }, + "labels": { + "template": "jws-tomcat8-mongodb-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Disable data file preallocation.", + "name": "MONGODB_NOPREALLOC" + }, + { + "description": "Set MongoDB to use a smaller default data file size.", + "name": "MONGODB_SMALLFILES" + }, + { + "description": "Runs MongoDB in a quiet mode that attempts to limit the amount of output.", + "name": "MONGODB_QUIET" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Database admin password", + "name": "DB_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 27017, + "targetPort": 27017 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mongodb=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mongodb" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mongodb:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mongodb", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mongodb", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mongodb", + "image": "mongodb", + "imagePullPolicy": "Always", + "ports": [ + { + "containerPort": 27017, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MONGODB_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MONGODB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MONGODB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MONGODB_ADMIN_PASSWORD", + "value": "${DB_ADMIN_PASSWORD}" + }, + { + "name": "MONGODB_NOPREALLOC", + "value": "${MONGODB_NOPREALLOC}" + }, + { + "name": "MONGODB_SMALLFILES", + "value": "${MONGODB_SMALLFILES}" + }, + { + "name": "MONGODB_QUIET", + "value": "${MONGODB_QUIET}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-persistent-sti.json new file mode 100644 index 000000000..0692817bf --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-persistent-sti.json @@ -0,0 +1,600 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MySQL applications with persistent storage built using STI." + }, + "name": "jws-tomcat8-mysql-persistent-sti" + }, + "labels": { + "template": "jws-tomcat8-mysql-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/mysql/data", + "name": "${APPLICATION_NAME}-mysql-pvol" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-mysql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-mysql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-mysql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-sti.json new file mode 100644 index 000000000..226a983b7 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-mysql-sti.json @@ -0,0 +1,563 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS MySQL applications built using STI." + }, + "name": "jws-tomcat8-mysql-sti" + }, + "labels": { + "template": "jws-tomcat8-mysql-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "Sets how the table names are stored and compared.", + "name": "MYSQL_LOWER_CASE_TABLE_NAMES" + }, + { + "description": "The maximum permitted number of simultaneous client connections.", + "name": "MYSQL_MAX_CONNECTIONS" + }, + { + "description": "The minimum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MIN_WORD_LEN" + }, + { + "description": "The maximum length of the word to be included in a FULLTEXT index.", + "name": "MYSQL_FT_MAX_WORD_LEN" + }, + { + "description": "Controls the innodb_use_native_aio setting value if the native AIO is broken.", + "name": "MYSQL_AIO" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 3306, + "targetPort": 3306 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-mysql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-mysql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "mysql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-mysql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-mysql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-mysql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-mysql", + "image": "mysql", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "MYSQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "MYSQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "MYSQL_LOWER_CASE_TABLE_NAMES", + "value": "${MYSQL_LOWER_CASE_TABLE_NAMES}" + }, + { + "name": "MYSQL_MAX_CONNECTIONS", + "value": "${MYSQL_MAX_CONNECTIONS}" + }, + { + "name": "MYSQL_FT_MIN_WORD_LEN", + "value": "${MYSQL_FT_MIN_WORD_LEN}" + }, + { + "name": "MYSQL_FT_MAX_WORD_LEN", + "value": "${MYSQL_FT_MAX_WORD_LEN}" + }, + { + "name": "MYSQL_AIO", + "value": "${MYSQL_AIO}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-persistent-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-persistent-sti.json new file mode 100644 index 000000000..b4644ac08 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-persistent-sti.json @@ -0,0 +1,576 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS PostgreSQL applications with persistent storage built using STI." + }, + "name": "jws-tomcat8-postgresql-persistent-sti" + }, + "labels": { + "template": "jws-tomcat8-postgresql-persistent-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "Size of persistent storage for database volume.", + "name": "VOLUME_CAPACITY", + "value": "512Mi" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "volumeMounts": [ + { + "mountPath": "/var/lib/pgsql/data", + "name": "${APPLICATION_NAME}-postgresql-pvol" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ], + "volumes": [ + { + "name": "${APPLICATION_NAME}-postgresql-pvol", + "persistentVolumeClaim": { + "claimName": "${APPLICATION_NAME}-postgresql-claim" + } + } + ] + } + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql-claim", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "accessModes": [ "ReadWriteOnce" ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + } + ] +} diff --git a/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-sti.json b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-sti.json new file mode 100644 index 000000000..b46f23225 --- /dev/null +++ b/roles/openshift_examples/files/examples/xpaas-templates/jws-tomcat8-postgresql-sti.json @@ -0,0 +1,539 @@ +{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "annotations": { + "iconClass" : "icon-tomcat", + "description": "Application template for JWS PostgreSQL applications built using STI." + }, + "name": "jws-tomcat8-postgresql-sti" + }, + "labels": { + "template": "jws-tomcat8-postgresql-sti" + }, + "parameters": [ + { + "description": "JWS Release version, e.g. 3.0, 2.1, etc.", + "name": "JWS_RELEASE", + "value": "3.0" + }, + { + "description": "The name for the application.", + "name": "APPLICATION_NAME", + "value": "jws-app" + }, + { + "description": "Custom hostname for service routes. Leave blank for default hostname, e.g.: <application-name>.<project>.<default-domain-suffix>", + "name": "APPLICATION_HOSTNAME", + "value": "" + }, + { + "description": "Git source URI for application", + "name": "GIT_URI" + }, + { + "description": "Git branch/tag reference", + "name": "GIT_REF", + "value": "master" + }, + { + "description": "Path within Git project to build; empty for root project directory.", + "name": "GIT_CONTEXT_DIR", + "value": "" + }, + { + "description": "Database JNDI name used by application to resolve the datasource, e.g. java:/jboss/datasources/mongodb", + "name": "DB_JNDI", + "value": "" + }, + { + "description": "Database name", + "name": "DB_DATABASE", + "value": "root" + }, + { + "description": "The name of the secret containing the certificate files", + "name": "JWS_HTTPS_SECRET", + "value": "jws-app-secret" + }, + { + "description": "The name of the certificate file within the secret", + "name": "JWS_HTTPS_CERTIFICATE", + "value": "server.crt" + }, + { + "description": "The name of the certificate key file within the secret", + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "server.key" + }, + { + "description": "The certificate password", + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "" + }, + { + "description": "Sets xa-pool/min-pool-size for the configured datasource.", + "name": "DB_MIN_POOL_SIZE" + }, + { + "description": "Sets xa-pool/max-pool-size for the configured datasource.", + "name": "DB_MAX_POOL_SIZE" + }, + { + "description": "Sets transaction-isolation for the configured datasource.", + "name": "DB_TX_ISOLATION" + }, + { + "description": "The maximum number of client connections allowed. This also sets the maximum number of prepared transactions.", + "name": "POSTGRESQL_MAX_CONNECTIONS" + }, + { + "description": "Configures how much memory is dedicated to PostgreSQL for caching data.", + "name": "POSTGRESQL_SHARED_BUFFERS" + }, + { + "description": "Database user name", + "name": "DB_USERNAME", + "from": "user[a-zA-Z0-9]{3}", + "generate": "expression" + }, + { + "description": "Database user password", + "name": "DB_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin User", + "name": "JWS_ADMIN_USERNAME", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "JWS Admin Password", + "name": "JWS_ADMIN_PASSWORD", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Github trigger secret", + "name": "GITHUB_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + }, + { + "description": "Generic build trigger secret", + "name": "GENERIC_TRIGGER_SECRET", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression" + } + ], + "objects": [ + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8080, + "targetPort": 8080 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's http port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 8443, + "targetPort": 8443 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + } + }, + "metadata": { + "name": "secure-${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The web server's https port." + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "spec": { + "ports": [ + { + "port": 5432, + "targetPort": 5432 + } + ], + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + } + }, + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "The database server's port." + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-http-route", + "metadata": { + "name": "${APPLICATION_NAME}-http-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's http service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "Route", + "apiVersion": "v1", + "id": "${APPLICATION_NAME}-https-route", + "metadata": { + "name": "${APPLICATION_NAME}-https-route", + "labels": { + "application": "${APPLICATION_NAME}" + }, + "annotations": { + "description": "Route for application's https service." + } + }, + "spec": { + "host": "${APPLICATION_HOSTNAME}", + "to": { + "name": "secure-${APPLICATION_NAME}" + }, + "tls": { + "termination" : "passthrough" + } + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "source": { + "type": "Git", + "git": { + "uri": "${GIT_URI}", + "ref": "${GIT_REF}" + }, + "contextDir":"${GIT_CONTEXT_DIR}" + }, + "strategy": { + "type": "Source", + "sourceStrategy": { + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "jboss-webserver3-tomcat8-openshift:${JWS_RELEASE}" + } + } + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${APPLICATION_NAME}:latest" + } + }, + "triggers": [ + { + "type": "GitHub", + "github": { + "secret": "${GITHUB_TRIGGER_SECRET}" + } + }, + { + "type": "Generic", + "generic": { + "secret": "${GENERIC_TRIGGER_SECRET}" + } + }, + { + "type": "ImageChange", + "imageChange": {} + } + ] + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}" + ], + "from": { + "kind": "ImageStream", + "name": "${APPLICATION_NAME}" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "serviceAccount": "jws-service-account", + "containers": [ + { + "name": "${APPLICATION_NAME}", + "image": "${APPLICATION_NAME}", + "imagePullPolicy": "Always", + "readinessProbe": { + "exec": { + "command": [ + "/bin/bash", + "-c", + "curl -s -u ${JWS_ADMIN_USERNAME}:${JWS_ADMIN_PASSWORD} 'http://localhost:8080/manager/jmxproxy/?get=Catalina%3Atype%3DServer&att=stateName' |grep -iq 'stateName *= *STARTED'" + ] + } + }, + "volumeMounts": [ + { + "name": "jws-certificate-volume", + "mountPath": "/etc/jws-secret-volume", + "readOnly": true + } + ], + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + }, + { + "name": "https", + "containerPort": 8443, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "DB_SERVICE_PREFIX_MAPPING", + "value": "${APPLICATION_NAME}-postgresql=DB" + }, + { + "name": "DB_JNDI", + "value": "${DB_JNDI}" + }, + { + "name": "DB_USERNAME", + "value": "${DB_USERNAME}" + }, + { + "name": "DB_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "DB_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "DB_MIN_POOL_SIZE", + "value": "${DB_MIN_POOL_SIZE}" + }, + { + "name": "DB_MAX_POOL_SIZE", + "value": "${DB_MAX_POOL_SIZE}" + }, + { + "name": "DB_TX_ISOLATION", + "value": "${DB_TX_ISOLATION}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_DIR", + "value": "/etc/jws-secret-volume" + }, + { + "name": "JWS_HTTPS_CERTIFICATE", + "value": "${JWS_HTTPS_CERTIFICATE}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_KEY", + "value": "${JWS_HTTPS_CERTIFICATE_KEY}" + }, + { + "name": "JWS_HTTPS_CERTIFICATE_PASSWORD", + "value": "${JWS_HTTPS_CERTIFICATE_PASSWORD}" + }, + { + "name": "JWS_ADMIN_USERNAME", + "value": "${JWS_ADMIN_USERNAME}" + }, + { + "name": "JWS_ADMIN_PASSWORD", + "value": "${JWS_ADMIN_PASSWORD}" + } + ] + } + ], + "volumes": [ + { + "name": "jws-certificate-volume", + "secret": { + "secretName": "${JWS_HTTPS_SECRET}" + } + } + ] + } + } + } + }, + { + "kind": "DeploymentConfig", + "apiVersion": "v1", + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "strategy": { + "type": "Recreate" + }, + "triggers": [ + { + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "${APPLICATION_NAME}-postgresql" + ], + "from": { + "kind": "ImageStreamTag", + "namespace": "openshift", + "name": "postgresql:latest" + } + } + } + ], + "replicas": 1, + "selector": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql" + }, + "template": { + "metadata": { + "name": "${APPLICATION_NAME}-postgresql", + "labels": { + "deploymentConfig": "${APPLICATION_NAME}-postgresql", + "application": "${APPLICATION_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "${APPLICATION_NAME}-postgresql", + "image": "postgresql", + "ports": [ + { + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "POSTGRESQL_USER", + "value": "${DB_USERNAME}" + }, + { + "name": "POSTGRESQL_PASSWORD", + "value": "${DB_PASSWORD}" + }, + { + "name": "POSTGRESQL_DATABASE", + "value": "${DB_DATABASE}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" + } + ] + } + ] + } + } + } + } + ] +} diff --git a/roles/openshift_examples/meta/main.yml b/roles/openshift_examples/meta/main.yml new file mode 100644 index 000000000..5cfda1c89 --- /dev/null +++ b/roles/openshift_examples/meta/main.yml @@ -0,0 +1,15 @@ +--- +galaxy_info: + author: Scott Dodson + description: OpenShift Examples + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.7 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud +dependencies: +- role: openshift_common diff --git a/roles/openshift_examples/tasks/main.yml b/roles/openshift_examples/tasks/main.yml new file mode 100644 index 000000000..40b7a5d6e --- /dev/null +++ b/roles/openshift_examples/tasks/main.yml @@ -0,0 +1,55 @@ +--- +- name: Copy openshift examples + copy: + src: examples + dest: /usr/share/openshift + +# RHEL and Centos image streams are mutually exclusive +- name: Import RHEL streams + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ rhel_image_streams }} + when: openshift_examples_load_rhel + register: oex_import_rhel_streams + failed_when: "'already exists' not in oex_import_rhel_streams.stderr and oex_import_rhel_streams.rc != 0" + changed_when: false + +- name: Import Centos Image streams + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ centos_image_streams }} + when: openshift_examples_load_centos | bool + register: oex_import_centos_streams + failed_when: "'already exists' not in oex_import_centos_streams.stderr and oex_import_centos_streams.rc != 0" + changed_when: false + +- name: Import db templates + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ db_templates_base }} + when: openshift_examples_load_db_templates | bool + register: oex_import_db_templates + failed_when: "'already exists' not in oex_import_db_templates.stderr and oex_import_db_templates.rc != 0" + changed_when: false + +- name: Import quickstart-templates + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ quickstarts_base }} + when: openshift_examples_load_quickstarts | bool + register: oex_import_quickstarts + failed_when: "'already exists' not in oex_import_quickstarts.stderr and oex_import_quickstarts.rc != 0" + changed_when: false + + +- name: Import xPaas image streams + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ xpaas_image_streams }} + when: openshift_examples_load_xpaas | bool + register: oex_import_xpaas_streams + failed_when: "'already exists' not in oex_import_xpaas_streams.stderr and oex_import_xpaas_streams.rc != 0" + changed_when: false + +- name: Import xPaas templates + command: > + {{ openshift.common.client_binary }} {{ openshift_examples_import_command }} -n openshift -f {{ xpaas_templates_base }} + when: openshift_examples_load_xpaas | bool + register: oex_import_xpaas_templates + failed_when: "'already exists' not in oex_import_xpaas_templates.stderr and oex_import_xpaas_templates.rc != 0" + changed_when: false diff --git a/roles/openshift_expand_partition/README.md b/roles/openshift_expand_partition/README.md new file mode 100644 index 000000000..cd394e1ba --- /dev/null +++ b/roles/openshift_expand_partition/README.md @@ -0,0 +1,87 @@ +# openshift_expand_partition + +This role is useful to expand a partition, and it's file system to +fully utilize the disk it is on. It does this by first expanding the +partition, and then expanding the file system on the partition. + +## Requirements + +* A machine with a disk that is not fully utilized + +* cloud-utils-growpart rpm (either installed or avialable via yum) + +* The partition you are expanding needs to be at the end of the partition list + +## Role Variables + +``` +# The following variables are if you want to expand +# /dev/xvda3 that has a filesystem xfs + +# oep_drive +# Drive that has the partition we wish to expand. +oep_drive: "/dev/xvda" + +# oep_partition +# Partition that we wish to expand. +oep_partition: 3 + +# oep_file_system +# What file system is on the partition +# Currently only xfs, and ext(2,3,4) are supported +# For ext2, ext3, or ext4 just use ext +oep_file_system: "xfs" + +``` + +## Dependencies + +growpart + +## Example Playbook + +With this playbook, the partition /dev/xvda3 will expand to fill the free +space on /dev/xvda, and the file system will be expanded to fill the new +partition space. + + - hosts: mynodes + sudo: no + remote_user: root + gather_facts: no + roles: + - role: openshift_expand_partition + oep_drive: "/dev/xvda" + oep_partition: 3 + oep_file_system: "xfs" + + +## Full example + + +* Create an `inventory` file: + ``` + [mynodes] + 10.0.0.1 + 10.0.0.2 + ``` + +* Create an ansible playbook, say `expandvar.yaml`: + ``` + - hosts: mynodes + sudo: no + remote_user: root + gather_facts: no + roles: + - role: openshift_expand_partition + oep_drive: "/dev/xvda" + oep_partition: 3 + oep_file_system: "xfs" + +* Run the playbook: + ``` + ansible-playbook -i inventory expandvar.yml + ``` + +## License + +Apache 2.0 diff --git a/roles/openshift_expand_partition/defaults/main.yml b/roles/openshift_expand_partition/defaults/main.yml new file mode 100644 index 000000000..cce9bd951 --- /dev/null +++ b/roles/openshift_expand_partition/defaults/main.yml @@ -0,0 +1,18 @@ +--- +# oep_drive +# Drive that has the partition we wish to expand. +oep_drive: "/dev/xvda" + +# oep_partition +# Partition that we wish to expand. +oep_partition: 3 + +# oep_partition_mount_point +# Where the partition is mounted +oep_partition_mount_point: /var + +# oep_file_system +# What file system is on the partition +# Currently only xfs, and ext(2,3,4) are supported +# For ext2, ext3, or ext4 just use ext +oep_file_system: "xfs" diff --git a/roles/openshift_expand_partition/meta/main.yml b/roles/openshift_expand_partition/meta/main.yml new file mode 100644 index 000000000..c2a38be17 --- /dev/null +++ b/roles/openshift_expand_partition/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: + author: Troy Dawson + description: Expand partition and filesystem to fill free space on disks. + company: Red Hat, Inc. + license: license (Apache) + min_ansible_version: 1.4 + platforms: + - name: EL + versions: + - 7 + - name: Fedora + versions: + - all + categories: + - openshift + - cloud diff --git a/roles/openshift_expand_partition/tasks/main.yml b/roles/openshift_expand_partition/tasks/main.yml new file mode 100644 index 000000000..8bc399070 --- /dev/null +++ b/roles/openshift_expand_partition/tasks/main.yml @@ -0,0 +1,14 @@ +--- +- name: Ensure growpart is installed + yum: pkg=cloud-utils-growpart state=present + +- name: Grow the partitions + command: "growpart {{oep_drive}} {{oep_partition}}" + +- name: Expand the filesystem - xfs + command: "xfs_growfs {{oep_drive}}{{oep_partition}}" + when: oep_file_system == "xfs" + +- name: Expand the filesystem - ext(2,3,4) + command: "resize2fs {{oep_drive}}{{oep_partition}}" + when: oep_file_system == "ext" diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index cb67a13de..795f38341 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -1,12 +1,16 @@ #!/usr/bin/python +# pylint: disable=too-many-lines # -*- coding: utf-8 -*- # vim: expandtab:tabstop=4:shiftwidth=4 +# Reason: Disable pylint too-many-lines because we don't want to split up this file. +# Status: Permanently disabled to keep this module as self-contained as possible. + """Ansible module for retrieving and setting openshift related facts""" DOCUMENTATION = ''' --- module: openshift_facts -short_description: OpenShift Facts +short_description: Cluster Facts author: Jason DeTiberus requirements: [ ] ''' @@ -16,6 +20,8 @@ EXAMPLES = ''' import ConfigParser import copy import os +from distutils.util import strtobool +from distutils.version import LooseVersion def hostname_valid(hostname): @@ -242,8 +248,8 @@ def normalize_openstack_facts(metadata, facts): # metadata api, should be updated if neutron exposes this. facts['zone'] = metadata['availability_zone'] - - facts['network']['ip'] = metadata['ec2_compat']['local-ipv4'] + local_ipv4 = metadata['ec2_compat']['local-ipv4'].split(',')[0] + facts['network']['ip'] = local_ipv4 facts['network']['public_ip'] = metadata['ec2_compat']['public-ipv4'] # TODO: verify local hostname makes sense and is resolvable @@ -283,45 +289,105 @@ def normalize_provider_facts(provider, metadata): facts = normalize_openstack_facts(metadata, facts) return facts -def set_registry_url_if_unset(facts): - """ Set registry_url fact if not already present in facts dict +def set_fluentd_facts_if_unset(facts): + """ Set fluentd facts if not already present in facts dict + dict: the facts dict updated with the generated fluentd facts if + missing + Args: + facts (dict): existing facts + Returns: + dict: the facts dict updated with the generated fluentd + facts if they were not already present + + """ + if 'common' in facts: + if 'use_fluentd' not in facts['common']: + use_fluentd = False + facts['common']['use_fluentd'] = use_fluentd + return facts +def set_node_schedulability(facts): + """ Set schedulable facts if not already present in facts dict Args: facts (dict): existing facts Returns: - dict: the facts dict updated with the generated identity providers + dict: the facts dict updated with the generated schedulable facts if they were not already present + """ - for role in ('master', 'node'): - if role in facts: + if 'node' in facts: + if 'schedulable' not in facts['node']: + if 'master' in facts: + facts['node']['schedulable'] = False + else: + facts['node']['schedulable'] = True + return facts + +def set_master_selectors(facts): + """ Set selectors facts if not already present in facts dict + Args: + facts (dict): existing facts + Returns: + dict: the facts dict updated with the generated selectors + facts if they were not already present + + """ + if 'master' in facts: + if 'infra_nodes' in facts['master']: deployment_type = facts['common']['deployment_type'] - if 'registry_url' not in facts[role]: - registry_url = "openshift/origin-${component}:${version}" - if deployment_type == 'enterprise': - registry_url = "openshift3_beta/ose-${component}:${version}" - elif deployment_type == 'online': - registry_url = ("docker-registry.ops.rhcloud.com/" - "openshift3_beta/ose-${component}:${version}") - facts[role]['registry_url'] = registry_url + if deployment_type == 'online': + selector = "type=infra" + else: + selector = "region=infra" + if 'router_selector' not in facts['master']: + facts['master']['router_selector'] = selector + if 'registry_selector' not in facts['master']: + facts['master']['registry_selector'] = selector return facts -def set_fluentd_facts_if_unset(facts): - """ Set fluentd facts if not already present in facts dict - dict: the facts dict updated with the generated fluentd facts if +def set_metrics_facts_if_unset(facts): + """ Set cluster metrics facts if not already present in facts dict + dict: the facts dict updated with the generated cluster metrics facts if missing Args: facts (dict): existing facts Returns: - dict: the facts dict updated with the generated fluentd + dict: the facts dict updated with the generated cluster metrics facts if they were not already present """ if 'common' in facts: - deployment_type = facts['common']['deployment_type'] - if 'use_fluentd' not in facts['common']: - use_fluentd = True if deployment_type == 'online' else False - facts['common']['use_fluentd'] = use_fluentd + if 'use_cluster_metrics' not in facts['common']: + use_cluster_metrics = False + facts['common']['use_cluster_metrics'] = use_cluster_metrics + return facts + +def set_project_cfg_facts_if_unset(facts): + """ Set Project Configuration facts if not already present in facts dict + dict: + Args: + facts (dict): existing facts + Returns: + dict: the facts dict updated with the generated Project Configuration + facts if they were not already present + + """ + + config = { + 'default_node_selector': '', + 'project_request_message': '', + 'project_request_template': '', + 'mcs_allocator_range': 's0:/2', + 'mcs_labels_per_project': 5, + 'uid_allocator_range': '1000000000-1999999999/10000' + } + + if 'master' in facts: + for key, value in config.items(): + if key not in facts['master']: + facts['master'][key] = value + return facts def set_identity_providers_if_unset(facts): @@ -366,32 +432,135 @@ def set_url_facts_if_unset(facts): console_port = facts['master']['console_port'] console_path = facts['master']['console_path'] etcd_use_ssl = facts['master']['etcd_use_ssl'] - etcd_port = facts['master']['etcd_port'], + etcd_hosts = facts['master']['etcd_hosts'] + etcd_port = facts['master']['etcd_port'] hostname = facts['common']['hostname'] public_hostname = facts['common']['public_hostname'] + cluster_hostname = facts['master'].get('cluster_hostname') + cluster_public_hostname = facts['master'].get('cluster_public_hostname') if 'etcd_urls' not in facts['master']: - facts['master']['etcd_urls'] = [format_url(etcd_use_ssl, hostname, - etcd_port)] + etcd_urls = [] + if etcd_hosts != '': + facts['master']['etcd_port'] = etcd_port + facts['master']['embedded_etcd'] = False + for host in etcd_hosts: + etcd_urls.append(format_url(etcd_use_ssl, host, + etcd_port)) + else: + etcd_urls = [format_url(etcd_use_ssl, hostname, + etcd_port)] + facts['master']['etcd_urls'] = etcd_urls if 'api_url' not in facts['master']: - facts['master']['api_url'] = format_url(api_use_ssl, hostname, + api_hostname = cluster_hostname if cluster_hostname else hostname + facts['master']['api_url'] = format_url(api_use_ssl, api_hostname, api_port) if 'public_api_url' not in facts['master']: + api_public_hostname = cluster_public_hostname if cluster_public_hostname else public_hostname facts['master']['public_api_url'] = format_url(api_use_ssl, - public_hostname, + api_public_hostname, api_port) if 'console_url' not in facts['master']: + console_hostname = cluster_hostname if cluster_hostname else hostname facts['master']['console_url'] = format_url(console_use_ssl, - hostname, + console_hostname, console_port, console_path) if 'public_console_url' not in facts['master']: + console_public_hostname = cluster_public_hostname if cluster_public_hostname else public_hostname facts['master']['public_console_url'] = format_url(console_use_ssl, - public_hostname, + console_public_hostname, console_port, console_path) return facts +def set_aggregate_facts(facts): + """ Set aggregate facts + + Args: + facts (dict): existing facts + Returns: + dict: the facts dict updated with aggregated facts + """ + all_hostnames = set() + if 'common' in facts: + all_hostnames.add(facts['common']['hostname']) + all_hostnames.add(facts['common']['public_hostname']) + + if 'master' in facts: + if 'cluster_hostname' in facts['master']: + all_hostnames.add(facts['master']['cluster_hostname']) + if 'cluster_public_hostname' in facts['master']: + all_hostnames.add(facts['master']['cluster_public_hostname']) + + facts['common']['all_hostnames'] = list(all_hostnames) + + return facts + +def set_deployment_facts_if_unset(facts): + """ Set Facts that vary based on deployment_type. This currently + includes common.service_type, common.config_base, master.registry_url, + node.registry_url, node.storage_plugin_deps + + Args: + facts (dict): existing facts + Returns: + dict: the facts dict updated with the generated deployment_type + facts + """ + # Perhaps re-factor this as a map? + # pylint: disable=too-many-branches + if 'common' in facts: + deployment_type = facts['common']['deployment_type'] + if 'service_type' not in facts['common']: + service_type = 'atomic-openshift' + if deployment_type == 'origin': + service_type = 'origin' + elif deployment_type in ['enterprise', 'online']: + service_type = 'openshift' + facts['common']['service_type'] = service_type + if 'config_base' not in facts['common']: + config_base = '/etc/origin' + if deployment_type in ['enterprise', 'online']: + config_base = '/etc/openshift' + facts['common']['config_base'] = config_base + if 'data_dir' not in facts['common']: + data_dir = '/var/lib/origin' + if deployment_type in ['enterprise', 'online']: + data_dir = '/var/lib/openshift' + facts['common']['data_dir'] = data_dir + facts['common']['version'] = version = get_openshift_version() + if version is not None: + if deployment_type == 'origin': + version_gt_3_1_or_1_1 = LooseVersion(version) > LooseVersion('1.0.6') + else: + version_gt_3_1_or_1_1 = LooseVersion(version) > LooseVersion('3.0.2') + else: + version_gt_3_1_or_1_1 = True + facts['common']['version_greater_than_3_1_or_1_1'] = version_gt_3_1_or_1_1 + + for role in ('master', 'node'): + if role in facts: + deployment_type = facts['common']['deployment_type'] + if 'registry_url' not in facts[role]: + registry_url = 'openshift/origin-${component}:${version}' + if deployment_type in ['enterprise', 'online', 'openshift-enterprise']: + registry_url = 'openshift3/ose-${component}:${version}' + elif deployment_type == 'atomic-enterprise': + registry_url = 'aep3/aep-${component}:${version}' + facts[role]['registry_url'] = registry_url + + if 'node' in facts: + deployment_type = facts['common']['deployment_type'] + if 'storage_plugin_deps' not in facts['node']: + if deployment_type in ['openshift-enterprise', 'atomic-enterprise']: + facts['node']['storage_plugin_deps'] = ['ceph', 'glusterfs'] + else: + facts['node']['storage_plugin_deps'] = [] + + return facts + + def set_sdn_facts_if_unset(facts): """ Set sdn facts if not already present in facts dict @@ -402,8 +571,10 @@ def set_sdn_facts_if_unset(facts): were not already present """ if 'common' in facts: + use_sdn = facts['common']['use_openshift_sdn'] + if not (use_sdn == '' or isinstance(use_sdn, bool)): + facts['common']['use_openshift_sdn'] = bool(strtobool(str(use_sdn))) if 'sdn_network_plugin_name' not in facts['common']: - use_sdn = facts['common']['use_openshift_sdn'] plugin = 'redhat/openshift-ovs-subnet' if use_sdn else '' facts['common']['sdn_network_plugin_name'] = plugin @@ -413,6 +584,10 @@ def set_sdn_facts_if_unset(facts): if 'sdn_host_subnet_length' not in facts['master']: facts['master']['sdn_host_subnet_length'] = '8' + if 'node' in facts: + if 'sdn_mtu' not in facts['node']: + facts['node']['sdn_mtu'] = '1450' + return facts def format_url(use_ssl, hostname, port, path=''): @@ -450,9 +625,11 @@ def get_current_config(facts): # TODO: parse the /etc/sysconfig/openshift-{master,node} config to # determine the location of files. - + # TODO: I suspect this isn't working right now, but it doesn't prevent + # anything from working properly as far as I can tell, perhaps because + # we override the kubeconfig path everywhere we use it? # Query kubeconfig settings - kubeconfig_dir = '/var/lib/openshift/openshift.local.certificates' + kubeconfig_dir = '/var/lib/origin/openshift.local.certificates' if role == 'node': kubeconfig_dir = os.path.join( kubeconfig_dir, "node-%s" % facts['common']['hostname'] @@ -485,7 +662,7 @@ def get_current_config(facts): current_config['kubeconfig'] = config # override pylint broad-except warning, since we do not want - # to bubble up any exceptions if openshift ex config view + # to bubble up any exceptions if oc config view # fails # pylint: disable=broad-except except Exception: @@ -493,6 +670,21 @@ def get_current_config(facts): return current_config +def get_openshift_version(): + """ Get current version of openshift on the host + + Returns: + version: the current openshift version + """ + version = None + + if os.path.isfile('/usr/bin/openshift'): + _, output, _ = module.run_command(['/usr/bin/openshift', 'version']) + versions = dict(e.split(' v') for e in output.splitlines() if ' v' in e) + version = versions.get('openshift', '') + + #TODO: acknowledge the possility of a containerized install + return version def apply_provider_facts(facts, provider_facts): """ Apply provider facts to supplied facts dict @@ -538,7 +730,7 @@ def merge_facts(orig, new): facts = dict() for key, value in orig.iteritems(): if key in new: - if isinstance(value, dict): + if isinstance(value, dict) and isinstance(new[key], dict): facts[key] = merge_facts(value, new[key]) else: facts[key] = copy.copy(new[key]) @@ -599,25 +791,25 @@ def get_local_facts_from_file(filename): class OpenShiftFactsUnsupportedRoleError(Exception): - """OpenShift Facts Unsupported Role Error""" + """Origin Facts Unsupported Role Error""" pass class OpenShiftFactsFileWriteError(Exception): - """OpenShift Facts File Write Error""" + """Origin Facts File Write Error""" pass class OpenShiftFactsMetadataUnavailableError(Exception): - """OpenShift Facts Metadata Unavailable Error""" + """Origin Facts Metadata Unavailable Error""" pass class OpenShiftFacts(object): - """ OpenShift Facts + """ Origin Facts Attributes: - facts (dict): OpenShift facts for the host + facts (dict): facts for the host Args: role (str): role for setting local facts @@ -659,10 +851,15 @@ class OpenShiftFacts(object): facts = merge_facts(facts, local_facts) facts['current_config'] = get_current_config(facts) facts = set_url_facts_if_unset(facts) + facts = set_project_cfg_facts_if_unset(facts) facts = set_fluentd_facts_if_unset(facts) + facts = set_node_schedulability(facts) + facts = set_master_selectors(facts) + facts = set_metrics_facts_if_unset(facts) facts = set_identity_providers_if_unset(facts) - facts = set_registry_url_if_unset(facts) facts = set_sdn_facts_if_unset(facts) + facts = set_deployment_facts_if_unset(facts) + facts = set_aggregate_facts(facts) return dict(openshift=facts) def get_defaults(self, roles): @@ -681,7 +878,7 @@ class OpenShiftFacts(object): hostname_f = output.strip() if exit_code == 0 else '' hostname_values = [hostname_f, self.system_facts['nodename'], self.system_facts['fqdn']] - hostname = choose_hostname(hostname_values) + hostname = choose_hostname(hostname_values, ip_addr) common = dict(use_openshift_sdn=True, ip=ip_addr, public_ip=ip_addr, deployment_type='origin', hostname=hostname, @@ -693,7 +890,7 @@ class OpenShiftFacts(object): if 'master' in roles: master = dict(api_use_ssl=True, api_port='8443', console_use_ssl=True, console_path='/console', - console_port='8443', etcd_use_ssl=True, + console_port='8443', etcd_use_ssl=True, etcd_hosts='', etcd_port='4001', portal_net='172.30.0.0/16', embedded_etcd=True, embedded_kube=True, embedded_dns=True, dns_port='53', @@ -701,15 +898,11 @@ class OpenShiftFacts(object): session_name='ssn', session_secrets_file='', access_token_max_seconds=86400, auth_token_max_seconds=500, - oauth_grant_method='auto') + oauth_grant_method='auto', cluster_defer_ha=False) defaults['master'] = master if 'node' in roles: - node = dict(pod_cidr='', labels={}, annotations={}, portal_net='172.30.0.0/16') - node['resources_cpu'] = self.system_facts['processor_cores'] - node['resources_memory'] = int( - int(self.system_facts['memtotal_mb']) * 1024 * 1024 * 0.75 - ) + node = dict(labels={}, annotations={}, portal_net='172.30.0.0/16') defaults['node'] = node return defaults diff --git a/roles/openshift_facts/tasks/main.yml b/roles/openshift_facts/tasks/main.yml index d71e6d019..6301d4fc0 100644 --- a/roles/openshift_facts/tasks/main.yml +++ b/roles/openshift_facts/tasks/main.yml @@ -1,9 +1,10 @@ --- -- name: Verify Ansible version is greater than 1.8.0 and not 1.9.0 +- name: Verify Ansible version is greater than 1.8.0 and not 1.9.0 and not 1.9.0.1 assert: that: - ansible_version | version_compare('1.8.0', 'ge') - ansible_version | version_compare('1.9.0', 'ne') + - ansible_version | version_compare('1.9.0.1', 'ne') -- name: Gather OpenShift facts +- name: Gather Cluster facts openshift_facts: diff --git a/roles/openshift_manage_node/tasks/main.yml b/roles/openshift_manage_node/tasks/main.yml new file mode 100644 index 000000000..637e494ea --- /dev/null +++ b/roles/openshift_manage_node/tasks/main.yml @@ -0,0 +1,21 @@ +- name: Wait for Node Registration + command: > + {{ openshift.common.client_binary }} get node {{ item | lower }} + register: omd_get_node + until: omd_get_node.rc == 0 + retries: 20 + delay: 5 + with_items: openshift_nodes + +- name: Set node schedulability + command: > + {{ openshift.common.admin_binary }} manage-node {{ item.openshift.common.hostname | lower }} --schedulable={{ 'true' if item.openshift.node.schedulable | bool else 'false' }} + with_items: + - "{{ openshift_node_vars }}" + +- name: Label nodes + command: > + {{ openshift.common.client_binary }} label --overwrite node {{ item.openshift.common.hostname | lower }} {{ item.openshift.node.labels | oo_combine_dict }} + with_items: + - "{{ openshift_node_vars }}" + when: "'labels' in item.openshift.node and item.openshift.node.labels != {}" diff --git a/roles/openshift_master/README.md b/roles/openshift_master/README.md index 3178e318c..155bdb58b 100644 --- a/roles/openshift_master/README.md +++ b/roles/openshift_master/README.md @@ -1,13 +1,13 @@ -OpenShift Master -================ +OpenShift/Atomic Enterprise Master +================================== -OpenShift Master service installation +Master service installation Requirements ------------ A RHEL 7.1 host pre-configured with access to the rhel-7-server-rpms, -rhel-7-server-extras-rpms, and rhel-server-7-ose-beta-rpms repos. +rhel-7-server-extras-rpms, and rhel-7-server-ose-3.0-rpms repos. Role Variables -------------- @@ -15,8 +15,8 @@ Role Variables From this role: | Name | Default value | | |-------------------------------------|-----------------------|--------------------------------------------------| -| openshift_master_debug_level | openshift_debug_level | Verbosity of the debug logs for openshift-master | -| openshift_node_ips | [] | List of the openshift node ip addresses to pre-register when openshift-master starts up | +| openshift_master_debug_level | openshift_debug_level | Verbosity of the debug logs for master | +| openshift_node_ips | [] | List of the openshift node ip addresses to pre-register when master starts up | | oreg_url | UNDEF | Default docker registry to use | | openshift_master_api_port | UNDEF | | | openshift_master_console_port | UNDEF | | @@ -28,7 +28,7 @@ From this role: From openshift_common: | Name | Default Value | | |-------------------------------|----------------|----------------------------------------| -| openshift_debug_level | 0 | Global openshift debug log verbosity | +| openshift_debug_level | 2 | Global openshift debug log verbosity | | openshift_public_ip | UNDEF | Public IP address to use for this host | | openshift_hostname | UNDEF | hostname to use for this instance | diff --git a/roles/openshift_master/defaults/main.yml b/roles/openshift_master/defaults/main.yml index 11195e83e..9766d01ae 100644 --- a/roles/openshift_master/defaults/main.yml +++ b/roles/openshift_master/defaults/main.yml @@ -5,20 +5,26 @@ openshift_node_ips: [] os_firewall_allow: - service: etcd embedded port: 4001/tcp -- service: OpenShift api https +- service: api server https port: 8443/tcp -- service: OpenShift dns tcp +- service: dns tcp port: 53/tcp -- service: OpenShift dns udp +- service: dns udp port: 53/udp - service: Fluentd td-agent tcp port: 24224/tcp - service: Fluentd td-agent udp port: 24224/udp +- service: pcsd + port: 2224/tcp +- service: Corosync UDP + port: 5404/udp +- service: Corosync UDP + port: 5405/udp os_firewall_deny: -- service: OpenShift api http +- service: api server http port: 8080/tcp -- service: former OpenShift web console port +- service: former web console port port: 8444/tcp - service: former etcd peer port port: 7001/tcp diff --git a/roles/openshift_master/handlers/main.yml b/roles/openshift_master/handlers/main.yml index 6fd4dfb51..37028e0f6 100644 --- a/roles/openshift_master/handlers/main.yml +++ b/roles/openshift_master/handlers/main.yml @@ -1,3 +1,4 @@ --- -- name: restart openshift-master - service: name=openshift-master state=restarted +- name: restart master + service: name={{ openshift.common.service_type }}-master state=restarted + when: (not openshift_master_ha | bool) and (not master_service_status_changed | default(false)) diff --git a/roles/openshift_master/meta/main.yml b/roles/openshift_master/meta/main.yml index 41a183c3b..c125cb5d0 100644 --- a/roles/openshift_master/meta/main.yml +++ b/roles/openshift_master/meta/main.yml @@ -1,7 +1,7 @@ --- galaxy_info: author: Jhon Honce - description: OpenShift Master + description: Master company: Red Hat, Inc. license: Apache License, Version 2.0 min_ansible_version: 1.7 diff --git a/roles/openshift_master/tasks/main.yml b/roles/openshift_master/tasks/main.yml index 23f8b4649..94eb73346 100644 --- a/roles/openshift_master/tasks/main.yml +++ b/roles/openshift_master/tasks/main.yml @@ -8,10 +8,17 @@ - openshift_master_oauth_grant_method in openshift_master_valid_grant_methods when: openshift_master_oauth_grant_method is defined -- name: Set master OpenShift facts +- fail: + msg: "openshift_master_cluster_password must be set for multi-master installations" + when: openshift_master_ha | bool and not openshift.master.cluster_defer_ha | bool and openshift_master_cluster_password is not defined + +- name: Set master facts openshift_facts: role: master local_facts: + cluster_hostname: "{{ openshift_master_cluster_hostname | default(None) }}" + cluster_public_hostname: "{{ openshift_master_cluster_public_hostname | default(None) }}" + cluster_defer_ha: "{{ openshift_master_cluster_defer_ha | default(None) }}" debug_level: "{{ openshift_master_debug_level | default(openshift.common.debug_level) }}" api_port: "{{ openshift_master_api_port | default(None) }}" api_url: "{{ openshift_master_api_url | default(None) }}" @@ -22,6 +29,7 @@ console_url: "{{ openshift_master_console_url | default(None) }}" console_use_ssl: "{{ openshift_master_console_use_ssl | default(None) }}" public_console_url: "{{ openshift_master_public_console_url | default(None) }}" + etcd_hosts: "{{ openshift_master_etcd_hosts | default(None)}}" etcd_port: "{{ openshift_master_etcd_port | default(None) }}" etcd_use_ssl: "{{ openshift_master_etcd_use_ssl | default(None) }}" etcd_urls: "{{ openshift_master_etcd_urls | default(None) }}" @@ -41,39 +49,38 @@ oauth_grant_method: "{{ openshift_master_oauth_grant_method | default(None) }}" sdn_cluster_network_cidr: "{{ osm_cluster_network_cidr | default(None) }}" sdn_host_subnet_length: "{{ osm_host_subnet_length | default(None) }}" + default_subdomain: "{{ osm_default_subdomain | default(None) }}" + custom_cors_origins: "{{ osm_custom_cors_origins | default(None) }}" + default_node_selector: "{{ osm_default_node_selector | default(None) }}" + project_request_message: "{{ osm_project_request_message | default(None) }}" + project_request_template: "{{ osm_project_request_template | default(None) }}" + mcs_allocator_range: "{{ osm_mcs_allocator_range | default(None) }}" + mcs_labels_per_project: "{{ osm_mcs_labels_per_project | default(None) }}" + uid_allocator_range: "{{ osm_uid_allocator_range | default(None) }}" + router_selector: "{{ openshift_router_selector | default(None) }}" + 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: "{{ num_infra | default(None) }}" + +- name: Install Master package + yum: pkg={{ openshift.common.service_type }}-master{{ openshift_version }} state=present + register: install_result # TODO: These values need to be configurable -- name: Set dns OpenShift facts +- name: Set dns facts openshift_facts: role: dns local_facts: - ip: "{{ openshift.common.ip }}" + ip: "{{ openshift_master_cluster_vip | default(openshift.common.ip, true) | default(None) }}" domain: cluster.local when: openshift.master.embedded_dns -- name: Install OpenShift Master package - yum: pkg=openshift-master state=present - register: install_result - -- name: Reload systemd units - command: systemctl daemon-reload - when: install_result | changed - - name: Create config parent directory if it doesn't exist file: path: "{{ openshift_master_config_dir }}" state: directory -- name: Create the master certificates if they do not already exist - command: > - {{ openshift.common.admin_binary }} create-master-certs - --hostnames={{ openshift.common.hostname }},{{ openshift.common.public_hostname }} - --master={{ openshift.master.api_url }} - --public-master={{ openshift.master.public_api_url }} - --cert-dir={{ openshift_master_config_dir }} --overwrite=false - args: - creates: "{{ openshift_master_config_dir }}/master.server.key" - - name: Create the policy file if it does not already exist command: > {{ openshift.common.admin_binary }} create-bootstrap-policy-file @@ -81,20 +88,28 @@ args: creates: "{{ openshift_master_policy }}" notify: - - restart openshift-master + - restart master - name: Create the scheduler config template: dest: "{{ openshift_master_scheduler_conf }}" src: scheduler.json.j2 + backup: true notify: - - restart openshift-master + - restart master - name: Install httpd-tools if needed yum: pkg=httpd-tools state=present when: item.kind == 'HTPasswdPasswordIdentityProvider' with_items: openshift.master.identity_providers +- name: Ensure htpasswd directory exists + file: + path: "{{ item.filename | dirname }}" + state: directory + when: item.kind == 'HTPasswdPasswordIdentityProvider' + with_items: openshift.master.identity_providers + - name: Create the htpasswd file if needed copy: dest: "{{ item.filename }}" @@ -109,12 +124,13 @@ template: dest: "{{ openshift_master_config_file }}" src: master.yaml.v1.j2 + backup: true notify: - - restart openshift-master + - restart master -- name: Configure OpenShift settings +- name: Configure master settings lineinfile: - dest: /etc/sysconfig/openshift-master + dest: /etc/sysconfig/{{ openshift.common.service_type }}-master regexp: "{{ item.regex }}" line: "{{ item.line }}" with_items: @@ -123,39 +139,61 @@ - regex: '^CONFIG_FILE=' line: "CONFIG_FILE={{ openshift_master_config_file }}" notify: - - restart openshift-master + - restart master + +- name: Start and enable master + service: name={{ openshift.common.service_type }}-master enabled=yes state=started + when: not openshift_master_ha | bool + register: start_result + +- set_fact: + master_service_status_changed = start_result | changed + +- name: Install cluster packages + yum: pkg=pcs state=present + when: openshift_master_ha | bool and not openshift.master.cluster_defer_ha | bool + register: install_result + +- name: Start and enable cluster service + service: name=pcsd enabled=yes state=started + when: openshift_master_ha | bool and not openshift.master.cluster_defer_ha | bool + +- name: Set the cluster user password + shell: echo {{ openshift_master_cluster_password | quote }} | passwd --stdin hacluster + when: install_result | changed -- name: Start and enable openshift-master - service: name=openshift-master enabled=yes state=started +- name: Lookup default group for ansible_ssh_user + command: "/usr/bin/id -g {{ ansible_ssh_user }}" + register: _ansible_ssh_user_gid -- name: Create the OpenShift client config dir(s) +- name: Create the client config dir(s) file: - path: "~{{ item }}/.config/openshift" + path: "~{{ item }}/.kube" state: directory mode: 0700 owner: "{{ item }}" - group: "{{ item }}" + group: "{{ 'root' if item == 'root' else _ansible_ssh_user_gid.stdout }}" with_items: - root - "{{ ansible_ssh_user }}" # TODO: Update this file if the contents of the source file are not present in # the dest file, will need to make sure to ignore things that could be added -- name: Copy the OpenShift admin client config(s) - command: cp {{ openshift_master_config_dir }}/admin.kubeconfig ~{{ item }}/.config/openshift/.config +- name: Copy the admin client config(s) + command: cp {{ openshift_master_config_dir }}/admin.kubeconfig ~{{ item }}/.kube/config args: - creates: ~{{ item }}/.config/openshift/.config + creates: ~{{ item }}/.kube/config with_items: - root - "{{ ansible_ssh_user }}" -- name: Update the permissions on the OpenShift admin client config(s) +- name: Update the permissions on the admin client config(s) file: - path: "~{{ item }}/.config/openshift/.config" + path: "~{{ item }}/.kube/config" state: file mode: 0700 owner: "{{ item }}" - group: "{{ item }}" + group: "{{ 'root' if item == 'root' else _ansible_ssh_user_gid.stdout }}" with_items: - root - "{{ ansible_ssh_user }}" diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2 index 1c2d37b63..3e4f78b17 100644 --- a/roles/openshift_master/templates/master.yaml.v1.j2 +++ b/roles/openshift_master/templates/master.yaml.v1.j2 @@ -1,3 +1,6 @@ +apiLevels: +- v1beta3 +- v1 apiVersion: v1 assetConfig: logoutURL: "" @@ -8,24 +11,28 @@ assetConfig: certFile: master.server.crt clientCA: "" keyFile: master.server.key + maxRequestsInFlight: 0 + requestTimeoutSeconds: 0 corsAllowedOrigins: -{# TODO: add support for user specified corsAllowedOrigins #} {% for origin in ['127.0.0.1', 'localhost', openshift.common.hostname, openshift.common.ip, openshift.common.public_hostname, openshift.common.public_ip] %} - {{ origin }} {% endfor %} -{% if openshift.master.embedded_dns %} +{% for custom_origin in openshift.master.custom_cors_origins | default("") %} + - {{ custom_origin }} +{% endfor %} +{% if openshift.master.embedded_dns | bool %} dnsConfig: bindAddress: {{ openshift.master.bind_addr }}:{{ openshift.master.dns_port }} {% endif %} etcdClientInfo: - ca: ca.crt + ca: {{ "ca.crt" if (openshift.master.embedded_etcd | bool) else "master.etcd-ca.crt" }} certFile: master.etcd-client.crt keyFile: master.etcd-client.key urls: {% for etcd_url in openshift.master.etcd_urls %} - {{ etcd_url }} {% endfor %} -{% if openshift.master.embedded_etcd %} +{% if openshift.master.embedded_etcd | bool %} etcdConfig: address: {{ openshift.common.hostname }}:{{ openshift.master.etcd_port }} peerAddress: {{ openshift.common.hostname }}:7001 @@ -39,13 +46,13 @@ etcdConfig: certFile: etcd.server.crt clientCA: ca.crt keyFile: etcd.server.key - storageDirectory: {{ openshift_data_dir }}/openshift.local.etcd + storageDirectory: {{ openshift.common.data_dir }}/openshift.local.etcd {% endif %} etcdStorageConfig: kubernetesStoragePrefix: kubernetes.io - kubernetesStorageVersion: v1beta3 - kubernetesStoragePrefix: kubernetes.io - openShiftStorageVersion: v1beta3 + kubernetesStorageVersion: v1 + openShiftStoragePrefix: openshift.io + openShiftStorageVersion: v1 imageConfig: format: {{ openshift.master.registry_url }} latest: false @@ -56,38 +63,59 @@ kubeletClientInfo: certFile: master.kubelet-client.crt keyFile: master.kubelet-client.key port: 10250 -{% if openshift.master.embedded_kube %} +{% if openshift.master.embedded_kube | bool %} kubernetesMasterConfig: + apiLevels: + - v1beta3 + - v1 + apiServerArguments: {{ api_server_args if api_server_args is defined else 'null' }} + controllerArguments: {{ controller_args if controller_args is defined else 'null' }} {# TODO: support overriding masterCount #} masterCount: 1 masterIP: "" + podEvictionTimeout: "" + proxyClientInfo: + certFile: master.proxy-client.crt + keyFile: master.proxy-client.key schedulerConfigFile: {{ openshift_master_scheduler_conf }} + servicesNodePortRange: "" servicesSubnet: {{ openshift.master.portal_net }} staticNodeNames: {{ openshift_node_ips | default([], true) }} {% endif %} masterClients: {# TODO: allow user to set externalKubernetesKubeConfig #} - deployerKubeConfig: openshift-deployer.kubeconfig externalKubernetesKubeConfig: "" - openshiftLoopbackKubeConfig: openshift-client.kubeconfig + openshiftLoopbackKubeConfig: openshift-master.kubeconfig masterPublicURL: {{ openshift.master.public_api_url }} networkConfig: clusterNetworkCIDR: {{ openshift.master.sdn_cluster_network_cidr }} hostSubnetLength: {{ openshift.master.sdn_host_subnet_length }} +{% if openshift.common.use_openshift_sdn %} networkPluginName: {{ openshift.common.sdn_network_plugin_name }} +{% endif %} +# serviceNetworkCIDR must match kubernetesMasterConfig.servicesSubnet + serviceNetworkCIDR: {{ openshift.master.portal_net }} {% include 'v1_partials/oauthConfig.j2' %} policyConfig: bootstrapPolicyFile: {{ openshift_master_policy }} + openshiftInfrastructureNamespace: openshift-infra openshiftSharedResourcesNamespace: openshift -{# TODO: Allow users to override projectConfig items #} projectConfig: - defaultNodeSelector: "" - projectRequestMessage: "" - projectRequestTemplate: "" + defaultNodeSelector: "{{ openshift.master.default_node_selector }}" + projectRequestMessage: "{{ openshift.master.project_request_message }}" + projectRequestTemplate: "{{ openshift.master.project_request_template }}" + securityAllocator: + mcsAllocatorRange: "{{ openshift.master.mcs_allocator_range }}" + mcsLabelsPerProject: {{ openshift.master.mcs_labels_per_project }} + uidAllocatorRange: "{{ openshift.master.uid_allocator_range }}" +routingConfig: + subdomain: "{{ openshift.master.default_subdomain | default("") }}" serviceAccountConfig: managedNames: - default - builder + - deployer + masterCA: ca.crt privateKeyFile: serviceaccounts.private.key publicKeyFiles: - serviceaccounts.public.key @@ -96,3 +124,5 @@ servingInfo: certFile: master.server.crt clientCA: ca.crt keyFile: master.server.key + maxRequestsInFlight: 500 + requestTimeoutSeconds: 3600 diff --git a/roles/openshift_master/templates/scheduler.json.j2 b/roles/openshift_master/templates/scheduler.json.j2 index 833e7f3e1..cb5f43bb2 100644 --- a/roles/openshift_master/templates/scheduler.json.j2 +++ b/roles/openshift_master/templates/scheduler.json.j2 @@ -1,5 +1,8 @@ { + "kind": "Policy", + "apiVersion": "v1", "predicates": [ + {"name": "MatchNodeSelector"}, {"name": "PodFitsResources"}, {"name": "PodFitsPorts"}, {"name": "NoDiskConflict"}, diff --git a/roles/openshift_master/templates/v1_partials/oauthConfig.j2 b/roles/openshift_master/templates/v1_partials/oauthConfig.j2 index f6fd88c65..8a4f5a746 100644 --- a/roles/openshift_master/templates/v1_partials/oauthConfig.j2 +++ b/roles/openshift_master/templates/v1_partials/oauthConfig.j2 @@ -7,9 +7,23 @@ url: {{ identity_provider.url }} {% for key in ('ca', 'certFile', 'keyFile') %} {% if key in identity_provider %} - {{ key }}: {{ identity_provider[key] }}" + {{ key }}: "{{ identity_provider[key] }}" {% endif %} {% endfor %} +{% elif identity_provider.kind == 'LDAPPasswordIdentityProvider' %} + attributes: +{% for attribute_key in identity_provider.attributes %} + {{ attribute_key }}: +{% for attribute_value in identity_provider.attributes[attribute_key] %} + - {{ attribute_value }} +{% endfor %} +{% endfor %} +{% for key in ('bindDN', 'bindPassword', 'ca') %} + {{ key }}: "{{ identity_provider[key] }}" +{% endfor %} +{% for key in ('insecure', 'url') %} + {{ key }}: {{ identity_provider[key] }} +{% endfor %} {% elif identity_provider.kind == 'RequestHeaderIdentityProvider' %} headers: {{ identity_provider.headers }} {% if 'clientCA' in identity_provider %} @@ -66,6 +80,7 @@ oauthConfig: provider: {{ identity_provider_config(identity_provider) }} {%- endfor %} + masterCA: ca.crt masterPublicURL: {{ openshift.master.public_api_url }} masterURL: {{ openshift.master.api_url }} sessionConfig: diff --git a/roles/openshift_master/vars/main.yml b/roles/openshift_master/vars/main.yml index f6f69966a..ecdb4f883 100644 --- a/roles/openshift_master/vars/main.yml +++ b/roles/openshift_master/vars/main.yml @@ -1,8 +1,9 @@ --- -openshift_master_config_dir: /etc/openshift/master +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" openshift_master_config_file: "{{ openshift_master_config_dir }}/master-config.yaml" openshift_master_scheduler_conf: "{{ openshift_master_config_dir }}/scheduler.json" openshift_master_policy: "{{ openshift_master_config_dir }}/policy.json" +openshift_version: "{{ openshift_pkg_version | default('') }}" openshift_master_valid_grant_methods: - auto diff --git a/roles/openshift_register_nodes/README.md b/roles/openshift_master_ca/README.md index b96faa044..5b2d3601b 100644 --- a/roles/openshift_register_nodes/README.md +++ b/roles/openshift_master_ca/README.md @@ -1,4 +1,4 @@ -OpenShift Register Nodes +OpenShift Master CA ======================== TODO diff --git a/roles/openshift_master_ca/meta/main.yml b/roles/openshift_master_ca/meta/main.yml new file mode 100644 index 000000000..0c8881521 --- /dev/null +++ b/roles/openshift_master_ca/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_repos } diff --git a/roles/openshift_master_ca/tasks/main.yml b/roles/openshift_master_ca/tasks/main.yml new file mode 100644 index 000000000..cfd1ceabf --- /dev/null +++ b/roles/openshift_master_ca/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Install the base package for admin tooling + yum: pkg={{ openshift.common.service_type }}{{ openshift_version }} state=present + register: install_result + +- name: Reload generated facts + openshift_facts: + +- name: Create openshift_master_config_dir if it doesn't exist + file: + path: "{{ openshift_master_config_dir }}" + state: directory + +- name: Create the master certificates if they do not already exist + command: > + {{ openshift.common.admin_binary }} create-master-certs + --hostnames={{ openshift.common.all_hostnames | join(',') }} + --master={{ openshift.master.api_url }} + --public-master={{ openshift.master.public_api_url }} + --cert-dir={{ openshift_master_config_dir }} --overwrite=false + when: master_certs_missing diff --git a/roles/openshift_register_nodes/vars/main.yml b/roles/openshift_master_ca/vars/main.yml index 3801b8427..b35339b18 100644 --- a/roles/openshift_register_nodes/vars/main.yml +++ b/roles/openshift_master_ca/vars/main.yml @@ -1,8 +1,6 @@ --- -openshift_node_config_dir: /etc/openshift/node -openshift_master_config_dir: /etc/openshift/master -openshift_generated_configs_dir: /etc/openshift/generated-configs +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" openshift_master_ca_cert: "{{ openshift_master_config_dir }}/ca.crt" openshift_master_ca_key: "{{ openshift_master_config_dir }}/ca.key" openshift_master_ca_serial: "{{ openshift_master_config_dir }}/ca.serial.txt" -openshift_kube_api_version: v1beta3 +openshift_version: "{{ openshift_pkg_version | default('') }}" diff --git a/roles/openshift_master_certificates/README.md b/roles/openshift_master_certificates/README.md new file mode 100644 index 000000000..ba3d5f28c --- /dev/null +++ b/roles/openshift_master_certificates/README.md @@ -0,0 +1,34 @@ +OpenShift Master Certificates +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Jason DeTiberus (jdetiber@redhat.com) diff --git a/roles/openshift_master_certificates/meta/main.yml b/roles/openshift_master_certificates/meta/main.yml new file mode 100644 index 000000000..fd7b73b0f --- /dev/null +++ b/roles/openshift_master_certificates/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_master_ca } diff --git a/roles/openshift_master_certificates/tasks/main.yml b/roles/openshift_master_certificates/tasks/main.yml new file mode 100644 index 000000000..e4602337e --- /dev/null +++ b/roles/openshift_master_certificates/tasks/main.yml @@ -0,0 +1,47 @@ +--- +- name: Ensure the generated_configs directory present + file: + path: "{{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }}" + state: directory + mode: 0700 + with_items: masters_needing_certs + +- file: + src: "{{ openshift_master_config_dir }}/{{ item.1 }}" + dest: "{{ openshift_generated_configs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}" + state: hard + with_nested: + - masters_needing_certs + - - ca.crt + - ca.key + - ca.serial.txt + - admin.crt + - admin.key + - admin.kubeconfig + - master.kubelet-client.crt + - master.kubelet-client.key + - "{{ 'master.proxy-client.crt' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}" + - "{{ 'master.proxy-client.key' if openshift.common.version_greater_than_3_1_or_1_1 else omit }}" + - openshift-master.crt + - openshift-master.key + - openshift-master.kubeconfig + - openshift-registry.crt + - openshift-registry.key + - openshift-registry.kubeconfig + - openshift-router.crt + - openshift-router.key + - openshift-router.kubeconfig + - serviceaccounts.private.key + - serviceaccounts.public.key + + +- name: Create the master certificates if they do not already exist + command: > + {{ openshift.common.admin_binary }} create-master-certs + --hostnames={{ item.openshift.common.all_hostnames | join(',') }} + --master={{ item.openshift.master.api_url }} + --public-master={{ item.openshift.master.public_api_url }} + --cert-dir={{ openshift_generated_configs_dir }}/{{ item.master_cert_subdir }} + --overwrite=false + when: master_certs_missing + with_items: masters_needing_certs diff --git a/roles/openshift_master_certificates/vars/main.yml b/roles/openshift_master_certificates/vars/main.yml new file mode 100644 index 000000000..3f18ddc79 --- /dev/null +++ b/roles/openshift_master_certificates/vars/main.yml @@ -0,0 +1,3 @@ +--- +openshift_generated_configs_dir: "{{ openshift.common.config_base }}/generated-configs" +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" diff --git a/roles/openshift_master_cluster/README.md b/roles/openshift_master_cluster/README.md new file mode 100644 index 000000000..f150981fa --- /dev/null +++ b/roles/openshift_master_cluster/README.md @@ -0,0 +1,34 @@ +OpenShift Master Cluster +======================== + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Jason DeTiberus (jdetiber@redhat.com) diff --git a/roles/openshift_master_cluster/meta/main.yml b/roles/openshift_master_cluster/meta/main.yml new file mode 100644 index 000000000..0c8881521 --- /dev/null +++ b/roles/openshift_master_cluster/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jason DeTiberus + description: + company: Red Hat, Inc. + license: Apache License, Version 2.0 + min_ansible_version: 1.8 + platforms: + - name: EL + versions: + - 7 + categories: + - cloud + - system +dependencies: +- { role: openshift_repos } diff --git a/roles/openshift_master_cluster/tasks/configure.yml b/roles/openshift_master_cluster/tasks/configure.yml new file mode 100644 index 000000000..7ab9afb51 --- /dev/null +++ b/roles/openshift_master_cluster/tasks/configure.yml @@ -0,0 +1,44 @@ +--- +- fail: + msg: This role requires that openshift_master_cluster_vip is set + when: openshift_master_cluster_vip is not defined or not openshift_master_cluster_vip +- fail: + msg: This role requires that openshift_master_cluster_public_vip is set + when: openshift_master_cluster_public_vip is not defined or not openshift_master_cluster_public_vip + +- name: Authenticate to the cluster + command: pcs cluster auth -u hacluster -p {{ openshift_master_cluster_password }} {{ omc_cluster_hosts }} + +- name: Create the cluster + command: pcs cluster setup --name openshift_master {{ omc_cluster_hosts }} + +- name: Start the cluster + command: pcs cluster start --all + +- name: Enable the cluster on all nodes + command: pcs cluster enable --all + +- name: Set default resource stickiness + command: pcs resource defaults resource-stickiness=100 + +- name: Add the cluster VIP resource + command: pcs resource create virtual-ip IPaddr2 ip={{ openshift_master_cluster_vip }} --group {{ openshift.common.service_type }}-master + +- name: Add the cluster public VIP resource + command: pcs resource create virtual-ip IPaddr2 ip={{ openshift_master_cluster_public_vip }} --group {{ openshift.common.service_type }}-master + when: openshift_master_cluster_public_vip != openshift_master_cluster_vip + +- name: Add the cluster master service resource + command: pcs resource create master systemd:{{ openshift.common.service_type }}-master op start timeout=90s stop timeout=90s --group {{ openshift.common.service_type }}-master + +- name: Disable stonith + command: pcs property set stonith-enabled=false + +# TODO: handle case where api port is not 8443 +- name: Wait for the clustered master service to be available + wait_for: + host: "{{ openshift_master_cluster_vip }}" + port: 8443 + state: started + timeout: 180 + delay: 90 diff --git a/roles/openshift_master_cluster/tasks/configure_deferred.yml b/roles/openshift_master_cluster/tasks/configure_deferred.yml new file mode 100644 index 000000000..3b416005b --- /dev/null +++ b/roles/openshift_master_cluster/tasks/configure_deferred.yml @@ -0,0 +1,8 @@ +--- +- debug: msg="Deferring config" + +- name: Start and enable the master + service: + name: "{{ openshift.common.service_type }}-master" + state: started + enabled: yes diff --git a/roles/openshift_master_cluster/tasks/main.yml b/roles/openshift_master_cluster/tasks/main.yml new file mode 100644 index 000000000..315947183 --- /dev/null +++ b/roles/openshift_master_cluster/tasks/main.yml @@ -0,0 +1,13 @@ +--- +- name: Test if cluster is already configured + command: pcs status + register: pcs_status + changed_when: false + failed_when: false + when: not openshift.master.cluster_defer_ha | bool + +- include: configure.yml + when: "pcs_status | failed and 'Error: cluster is not currently running on this node' in pcs_status.stderr" + +- include: configure_deferred.yml + when: openshift.master.cluster_defer_ha | bool diff --git a/roles/openshift_node/README.md b/roles/openshift_node/README.md index c3c17b848..3aff81274 100644 --- a/roles/openshift_node/README.md +++ b/roles/openshift_node/README.md @@ -1,28 +1,28 @@ -OpenShift Node -============== +OpenShift/Atomic Enterprise Node +================================ -OpenShift Node service installation +Node service installation Requirements ------------ -One or more OpenShift Master servers. +One or more Master servers. A RHEL 7.1 host pre-configured with access to the rhel-7-server-rpms, -rhel-7-server-extras-rpms, and rhel-server-7-ose-beta-rpms repos. +rhel-7-server-extras-rpms, and rhel-7-server-ose-3.0-rpms repos. Role Variables -------------- From this role: -| Name | Default value | | -|------------------------------------------|-----------------------|----------------------------------------| -| openshift_node_debug_level | openshift_debug_level | Verbosity of the debug logs for openshift-node | -| oreg_url | UNDEF (Optional) | Default docker registry to use | +| Name | Default value | | +|------------------------------------------|-----------------------|--------------------------------------------------------| +| openshift_node_debug_level | openshift_debug_level | Verbosity of the debug logs for node | +| oreg_url | UNDEF (Optional) | Default docker registry to use | From openshift_common: -| Name | Default Value | | +| Name | Default Value | | |-------------------------------|---------------------|---------------------| -| openshift_debug_level | 0 | Global openshift debug log verbosity | +| openshift_debug_level | 2 | Global openshift debug log verbosity | | openshift_public_ip | UNDEF (Required) | Public IP address to use for this host | | openshift_hostname | UNDEF (Required) | hostname to use for this instance | @@ -34,6 +34,18 @@ openshift_common Example Playbook ---------------- +Notes +----- + +Currently we support re-labeling nodes but we don't re-schedule running pods nor remove existing labels. That means you will have to trigger the re-schedulling manually. To re-schedule your pods, just follow the steps below: + +``` +oadm manage-node --schedulable=false ${NODE} +oadm manage-node --evacuate ${NODE} +oadm manage-node --schedulable=true ${NODE} +```` + + TODO License diff --git a/roles/openshift_node/defaults/main.yml b/roles/openshift_node/defaults/main.yml index be51195f2..fffbf2994 100644 --- a/roles/openshift_node/defaults/main.yml +++ b/roles/openshift_node/defaults/main.yml @@ -1,8 +1,15 @@ --- os_firewall_allow: -- service: OpenShift kubelet +- service: Kubernetes kubelet port: 10250/tcp - service: http port: 80/tcp - service: https port: 443/tcp +- service: Openshift kubelet ReadOnlyPort + port: 10255/tcp +- service: Openshift kubelet ReadOnlyPort udp + port: 10255/udp +- service: OpenShift OVS sdn + port: 4789/udp + when: openshift.node.use_openshift_sdn | bool diff --git a/roles/openshift_node/handlers/main.yml b/roles/openshift_node/handlers/main.yml index 953a1421b..447ca85f3 100644 --- a/roles/openshift_node/handlers/main.yml +++ b/roles/openshift_node/handlers/main.yml @@ -1,3 +1,7 @@ --- -- name: restart openshift-node - service: name=openshift-node state=restarted +- name: restart node + service: name={{ openshift.common.service_type }}-node state=restarted + when: not node_service_status_changed | default(false) + +- name: restart docker + service: name=docker state=restarted diff --git a/roles/openshift_node/tasks/main.yml b/roles/openshift_node/tasks/main.yml index 15d18f510..aea60b75c 100644 --- a/roles/openshift_node/tasks/main.yml +++ b/roles/openshift_node/tasks/main.yml @@ -1,7 +1,16 @@ --- # TODO: allow for overriding default ports where possible +- fail: + msg: This role requres that osn_cluster_dns_domain is set + when: osn_cluster_dns_domain is not defined or not osn_cluster_dns_domain +- fail: + msg: This role requres that osn_cluster_dns_ip is set + when: osn_cluster_dns_ip is not defined or not osn_cluster_dns_ip +- fail: + msg: "SELinux is disabled, This deployment type requires that SELinux is enabled." + when: (not ansible_selinux or ansible_selinux.status != 'enabled') and deployment_type in ['enterprise', 'online'] -- name: Set node OpenShift facts +- name: Set node facts openshift_facts: role: "{{ item.role }}" local_facts: "{{ item.local_facts }}" @@ -13,40 +22,41 @@ deployment_type: "{{ openshift_deployment_type }}" - role: node local_facts: - resources_cpu: "{{ openshift_node_resources_cpu | default(none) }}" - resources_memory: "{{ openshift_node_resources_memory | default(none) }}" - pod_cidr: "{{ openshift_node_pod_cidr | default(none) }}" - labels: "{{ openshift_node_labels | default(none) }}" + labels: "{{ lookup('oo_option', 'openshift_node_labels') | default( openshift_node_labels | default(none), true) }}" annotations: "{{ openshift_node_annotations | default(none) }}" registry_url: "{{ oreg_url | default(none) }}" debug_level: "{{ openshift_node_debug_level | default(openshift.common.debug_level) }}" portal_net: "{{ openshift_master_portal_net | default(None) }}" + kubelet_args: "{{ openshift_node_kubelet_args | default(None) }}" + sdn_mtu: "{{ openshift_node_sdn_mtu | default(None) }}" + schedulable: "{{ openshift_schedulable | default(openshift_scheduleable) | default(None) }}" + docker_log_driver: "{{ lookup( 'oo_option' , 'docker_log_driver' ) | default('',True) }}" + docker_log_options: "{{ lookup( 'oo_option' , 'docker_log_options' ) | default('',True) }}" + storage_plugin_deps: "{{ osn_storage_plugin_deps | default(None) }}" -- name: Install OpenShift Node package - yum: pkg=openshift-node state=present +# We have to add tuned-profiles in the same transaction otherwise we run into depsolving +# problems because the rpms don't pin the version properly. +- name: Install Node package + yum: pkg={{ openshift.common.service_type }}-node{{ openshift_version }},tuned-profiles-{{ openshift.common.service_type }}-node{{ openshift_version }} state=present register: node_install_result -- name: Install openshift-sdn-ovs - yum: pkg=openshift-sdn-ovs state=present +- name: Install sdn-ovs package + yum: pkg={{ openshift.common.service_type }}-sdn-ovs{{ openshift_version }} state=present register: sdn_install_result when: openshift.common.use_openshift_sdn -- name: Reload systemd units - command: systemctl daemon-reload - when: (node_install_result | changed or (openshift.common.use_openshift_sdn - and sdn_install_result | changed)) - # TODO: add the validate parameter when there is a validation command to run - name: Create the Node config template: dest: "{{ openshift_node_config_file }}" src: node.yaml.v1.j2 + backup: true notify: - - restart openshift-node + - restart node -- name: Configure OpenShift Node settings +- name: Configure Node settings lineinfile: - dest: /etc/sysconfig/openshift-node + dest: /etc/sysconfig/{{ openshift.common.service_type }}-node regexp: "{{ item.regex }}" line: "{{ item.line }}" with_items: @@ -55,21 +65,72 @@ - regex: '^CONFIG_FILE=' line: "CONFIG_FILE={{ openshift_node_config_file }}" notify: - - restart openshift-node + - restart node - stat: path=/etc/sysconfig/docker register: docker_check # TODO: Enable secure registry when code available in origin -- name: Secure OpenShift Registry +- name: Secure Registry and Logs Options lineinfile: dest: /etc/sysconfig/docker - regexp: '^OPTIONS=.*' - line: "OPTIONS='--insecure-registry={{ openshift.node.portal_net }} --selinux-enabled'" + regexp: '^OPTIONS=.*$' + line: "OPTIONS='--insecure-registry={{ openshift.node.portal_net }} \ +{% if ansible_selinux and ansible_selinux.status == '''enabled''' %}--selinux-enabled{% endif %} \ +{% if openshift.node.docker_log_driver is defined %} --log-driver {{ openshift.node.docker_log_driver }} {% endif %} \ +{% if openshift.node.docker_log_options is defined %} {{ openshift.node.docker_log_options | oo_split() | oo_prepend_strings_in_list('--log-opt ') | join(' ')}} {% endif %} '" when: docker_check.stat.isreg + notify: + - restart docker + +- set_fact: + docker_additional_registries: "{{ lookup('oo_option', 'docker_additional_registries') + | oo_split() | union(['registry.access.redhat.com']) + | difference(['']) }}" + when: openshift.common.deployment_type == 'enterprise' +- set_fact: + docker_additional_registries: "{{ lookup('oo_option', 'docker_additional_registries') + | oo_split() | difference(['']) }}" + when: openshift.common.deployment_type != 'enterprise' + +- name: Add personal registries + lineinfile: + dest: /etc/sysconfig/docker + regexp: '^ADD_REGISTRY=.*$' + line: "ADD_REGISTRY='{{ docker_additional_registries + | oo_prepend_strings_in_list('--add-registry ') | join(' ') }}'" + when: docker_check.stat.isreg and docker_additional_registries + notify: + - restart docker + +- name: Block registries + lineinfile: + dest: /etc/sysconfig/docker + regexp: '^BLOCK_REGISTRY=.*$' + line: "BLOCK_REGISTRY='{{ lookup('oo_option', 'docker_blocked_registries') | oo_split() + | oo_prepend_strings_in_list('--block-registry ') | join(' ') }}'" + when: docker_check.stat.isreg and + lookup('oo_option', 'docker_blocked_registries') != '' + notify: + - restart docker + +- name: Grant access to additional insecure registries + lineinfile: + dest: /etc/sysconfig/docker + regexp: '^INSECURE_REGISTRY=.*' + line: "INSECURE_REGISTRY='{{ lookup('oo_option', 'docker_insecure_registries') | oo_split() + | oo_prepend_strings_in_list('--insecure-registry ') | join(' ') }}'" + when: docker_check.stat.isreg and + lookup('oo_option', 'docker_insecure_registries') != '' + notify: + - restart docker + +- name: Additional storage plugin configuration + include: storage_plugins/main.yml -- name: Allow NFS access for VMs - seboolean: name=virt_use_nfs state=yes persistent=yes +- name: Start and enable node + service: name={{ openshift.common.service_type }}-node enabled=yes state=started + register: start_result -- name: Start and enable openshift-node - service: name=openshift-node enabled=yes state=started +- set_fact: + node_service_status_changed = start_result | changed diff --git a/roles/openshift_node/tasks/storage_plugins/ceph.yml b/roles/openshift_node/tasks/storage_plugins/ceph.yml new file mode 100644 index 000000000..b6936618a --- /dev/null +++ b/roles/openshift_node/tasks/storage_plugins/ceph.yml @@ -0,0 +1,5 @@ +--- +- name: Install Ceph storage plugin dependencies + yum: + pkg: ceph-common + state: installed diff --git a/roles/openshift_node/tasks/storage_plugins/glusterfs.yml b/roles/openshift_node/tasks/storage_plugins/glusterfs.yml new file mode 100644 index 000000000..b812e81df --- /dev/null +++ b/roles/openshift_node/tasks/storage_plugins/glusterfs.yml @@ -0,0 +1,12 @@ +--- +- name: Install GlusterFS storage plugin dependencies + yum: + pkg: glusterfs-fuse + state: installed + +- name: Set seboolean to allow gluster storage plugin access from containers + seboolean: + name: virt_use_fusefs + state: yes + persistent: yes + when: ansible_selinux and ansible_selinux.status == "enabled" diff --git a/roles/openshift_node/tasks/storage_plugins/main.yml b/roles/openshift_node/tasks/storage_plugins/main.yml new file mode 100644 index 000000000..39c7b9390 --- /dev/null +++ b/roles/openshift_node/tasks/storage_plugins/main.yml @@ -0,0 +1,13 @@ +--- +# The NFS storage plugin is always enabled since it doesn't require any +# additional package dependencies +- name: NFS storage plugin configuration + include: nfs.yml + +- name: GlusterFS storage plugin configuration + include: glusterfs.yml + when: "'glusterfs' in openshift.node.storage_plugin_deps" + +- name: Ceph storage plugin configuration + include: ceph.yml + when: "'ceph' in openshift.node.storage_plugin_deps" diff --git a/roles/openshift_node/tasks/storage_plugins/nfs.yml b/roles/openshift_node/tasks/storage_plugins/nfs.yml new file mode 100644 index 000000000..1edf21d9b --- /dev/null +++ b/roles/openshift_node/tasks/storage_plugins/nfs.yml @@ -0,0 +1,7 @@ +--- +- name: Set seboolean to allow nfs storage plugin access from containers + seboolean: + name: virt_use_nfs + state: yes + persistent: yes + when: ansible_selinux and ansible_selinux.status == "enabled" diff --git a/roles/openshift_node/templates/node.yaml.v1.j2 b/roles/openshift_node/templates/node.yaml.v1.j2 index cab75cd49..4931d127e 100644 --- a/roles/openshift_node/templates/node.yaml.v1.j2 +++ b/roles/openshift_node/templates/node.yaml.v1.j2 @@ -1,18 +1,33 @@ allowDisabledDocker: false apiVersion: v1 -dnsDomain: {{ hostvars[openshift_first_master].openshift.dns.domain }} -dnsIP: {{ hostvars[openshift_first_master].openshift.dns.ip }} +dnsDomain: {{ osn_cluster_dns_domain }} +dnsIP: {{ osn_cluster_dns_ip }} +dockerConfig: + execHandlerName: "" imageConfig: format: {{ openshift.node.registry_url }} latest: false kind: NodeConfig -masterKubeConfig: node.kubeconfig +{% if openshift.node.kubelet_args is defined and openshift.node.kubelet_args %} +kubeletArguments: {{ openshift.node.kubelet_args | to_json }} +{% endif %} +masterKubeConfig: system:node:{{ openshift.common.hostname }}.kubeconfig +{% if openshift.common.use_openshift_sdn %} networkPluginName: {{ openshift.common.sdn_network_plugin_name }} -nodeName: {{ openshift.common.hostname }} -podManifestConfig: null +{% endif %} +# networkConfig struct introduced in origin 1.0.6 and OSE 3.0.2 which +# deprecates networkPluginName above. The two should match. +networkConfig: + mtu: {{ openshift.node.sdn_mtu }} +{% if openshift.common.use_openshift_sdn %} + networkPluginName: {{ openshift.common.sdn_network_plugin_name }} +{% endif %} +nodeName: {{ openshift.common.hostname | lower }} +podManifestConfig: servingInfo: bindAddress: 0.0.0.0:10250 certFile: server.crt clientCA: ca.crt keyFile: server.key -volumeDirectory: {{ openshift_data_dir }}/openshift.local.volumes +volumeDirectory: {{ openshift.common.data_dir }}/openshift.local.volumes +{% include 'partials/kubeletArguments.j2' %} diff --git a/roles/openshift_node/templates/partials/kubeletArguments.j2 b/roles/openshift_node/templates/partials/kubeletArguments.j2 new file mode 100644 index 000000000..6c3bd04c5 --- /dev/null +++ b/roles/openshift_node/templates/partials/kubeletArguments.j2 @@ -0,0 +1,5 @@ +{% if openshift.common.use_cluster_metrics | bool %} +kubeletArguments: + "read-only-port": + - "10255" +{% endif %}
\ No newline at end of file diff --git a/roles/openshift_node/vars/main.yml b/roles/openshift_node/vars/main.yml index cf47f8354..43dc50ca8 100644 --- a/roles/openshift_node/vars/main.yml +++ b/roles/openshift_node/vars/main.yml @@ -1,3 +1,4 @@ --- -openshift_node_config_dir: /etc/openshift/node +openshift_node_config_dir: "{{ openshift.common.config_base }}/node" openshift_node_config_file: "{{ openshift_node_config_dir }}/node-config.yaml" +openshift_version: "{{ openshift_pkg_version | default('') }}" diff --git a/roles/openshift_node_certificates/README.md b/roles/openshift_node_certificates/README.md new file mode 100644 index 000000000..6264d253a --- /dev/null +++ b/roles/openshift_node_certificates/README.md @@ -0,0 +1,34 @@ +OpenShift/Atomic Enterprise Node Certificates +============================================= + +TODO + +Requirements +------------ + +TODO + +Role Variables +-------------- + +TODO + +Dependencies +------------ + +TODO + +Example Playbook +---------------- + +TODO + +License +------- + +Apache License Version 2.0 + +Author Information +------------------ + +Jason DeTiberus (jdetiber@redhat.com) diff --git a/roles/openshift_register_nodes/meta/main.yml b/roles/openshift_node_certificates/meta/main.yml index e40a152c1..f3236e850 100644 --- a/roles/openshift_register_nodes/meta/main.yml +++ b/roles/openshift_node_certificates/meta/main.yml @@ -14,4 +14,3 @@ galaxy_info: - system dependencies: - { role: openshift_facts } - diff --git a/roles/openshift_register_nodes/tasks/main.yml b/roles/openshift_node_certificates/tasks/main.yml index 11097a7cf..57f71887b 100644 --- a/roles/openshift_register_nodes/tasks/main.yml +++ b/roles/openshift_node_certificates/tasks/main.yml @@ -3,6 +3,7 @@ file: path: "{{ openshift_generated_configs_dir }}" state: directory + when: nodes_needing_certs | length > 0 - name: Generate the node client config command: > @@ -14,18 +15,17 @@ --signer-cert={{ openshift_master_ca_cert }} --signer-key={{ openshift_master_ca_key }} --signer-serial={{ openshift_master_ca_serial }} - --user=system:node-{{ item.openshift.common.hostname }} + --user=system:node:{{ item.openshift.common.hostname }} args: chdir: "{{ openshift_generated_configs_dir }}" creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}" with_items: nodes_needing_certs - name: Generate the node server certificate - delegate_to: "{{ openshift_first_master }}" command: > {{ openshift.common.admin_binary }} create-server-cert --cert=server.crt --key=server.key --overwrite=true - --hostnames={{ [item.openshift.common.hostname, item.openshift.common.public_hostname]|unique|join(",") }} + --hostnames={{ item.openshift.common.all_hostnames |join(",") }} --signer-cert={{ openshift_master_ca_cert }} --signer-key={{ openshift_master_ca_key }} --signer-serial={{ openshift_master_ca_serial }} @@ -33,18 +33,3 @@ chdir: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}" creates: "{{ openshift_generated_configs_dir }}/node-{{ item.openshift.common.hostname }}/server.crt" with_items: nodes_needing_certs - -- name: Register unregistered nodes - kubernetes_register_node: - kubectl_cmd: "{{ [openshift.common.client_binary] }}" - default_client_config: '~/.config/openshift/.config' - name: "{{ item.openshift.common.hostname }}" - api_version: "{{ openshift_kube_api_version }}" - cpu: "{{ item.openshift.node.resources_cpu | default(None) }}" - memory: "{{ item.openshift.node.resources_memory | default(None) }}" - pod_cidr: "{{ item.openshift.node.pod_cidr | default(None) }}" - host_ip: "{{ item.openshift.common.ip }}" - labels: "{{ item.openshift.node.labels | default({}) }}" - annotations: "{{ item.openshift.node.annotations | default({}) }}" - with_items: openshift_nodes - register: register_result diff --git a/roles/openshift_node_certificates/vars/main.yml b/roles/openshift_node_certificates/vars/main.yml new file mode 100644 index 000000000..61fbb1e51 --- /dev/null +++ b/roles/openshift_node_certificates/vars/main.yml @@ -0,0 +1,7 @@ +--- +openshift_node_config_dir: "{{ openshift.common.config_base }}/node" +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" +openshift_generated_configs_dir: "{{ openshift.common.config_base }}/generated-configs" +openshift_master_ca_cert: "{{ openshift_master_config_dir }}/ca.crt" +openshift_master_ca_key: "{{ openshift_master_config_dir }}/ca.key" +openshift_master_ca_serial: "{{ openshift_master_config_dir }}/ca.serial.txt" diff --git a/roles/openshift_register_nodes/library/kubernetes_register_node.py b/roles/openshift_register_nodes/library/kubernetes_register_node.py deleted file mode 100755 index a8c38627b..000000000 --- a/roles/openshift_register_nodes/library/kubernetes_register_node.py +++ /dev/null @@ -1,513 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim: expandtab:tabstop=4:shiftwidth=4 -# -# disable pylint checks -# permanently disabled unless someone wants to refactor the object model: -# too-few-public-methods -# no-self-use -# too-many-arguments -# too-many-locals -# too-many-branches -# pylint:disable=too-many-arguments, no-self-use -# pylint:disable=too-many-locals, too-many-branches, too-few-public-methods -"""Ansible module to register a kubernetes node to the cluster""" - -import os - -DOCUMENTATION = ''' ---- -module: kubernetes_register_node -short_description: Registers a kubernetes node with a master -description: - - Registers a kubernetes node with a master -options: - name: - default: null - description: - - Identifier for this node (usually the node fqdn). - required: true - api_verison: - choices: ['v1beta1', 'v1beta3'] - default: 'v1beta1' - description: - - Kubernetes API version to use - required: true - host_ip: - default: null - description: - - IP Address to associate with the node when registering. - Available in the following API versions: v1beta1. - required: false - cpu: - default: null - description: - - Number of CPUs to allocate for this node. When using the v1beta1 - API, you must specify the CPU count as a floating point number - with no more than 3 decimal places. API version v1beta3 and newer - accepts arbitrary float values. - required: false - memory: - default: null - description: - - Memory available for this node. When using the v1beta1 API, you - must specify the memory size in bytes. API version v1beta3 and - newer accepts binary SI and decimal SI values. - required: false -''' -EXAMPLES = ''' -# Minimal node registration -- openshift_register_node: name=ose3.node.example.com - -# Node registration using the v1beta1 API and assigning 1 CPU core and 10 GB of -# Memory -- openshift_register_node: - name: ose3.node.example.com - api_version: v1beta1 - hostIP: 192.168.1.1 - cpu: 1 - memory: 500000000 -''' - - -class ClientConfigException(Exception): - """Client Configuration Exception""" - pass - -class ClientConfig(object): - """ Representation of a client config - - Attributes: - config (dict): dictionary representing the client configuration - - Args: - client_opts (list of str): client options to use - module (AnsibleModule): - - Raises: - ClientConfigException: - """ - def __init__(self, client_opts, module): - kubectl = module.params['kubectl_cmd'] - _, output, _ = module.run_command((kubectl + - ["config", "view", "-o", "json"] + - client_opts), check_rc=True) - self.config = json.loads(output) - - if not (bool(self.config['clusters']) or - bool(self.config['contexts']) or - bool(self.config['current-context']) or - bool(self.config['users'])): - raise ClientConfigException( - "Client config missing required values: %s" % output - ) - - def current_context(self): - """ Gets the current context for the client config - - Returns: - str: The current context as set in the config - """ - return self.config['current-context'] - - def section_has_value(self, section_name, value): - """ Test if specified section contains a value - - Args: - section_name (str): config section to test - value (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - section = self.config[section_name] - if isinstance(section, dict): - return value in section - else: - val = next((item for item in section - if item['name'] == value), None) - return val is not None - - def has_context(self, context): - """ Test if specified context exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('contexts', context) - - def has_user(self, user): - """ Test if specified user exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('users', user) - - def has_cluster(self, cluster): - """ Test if specified cluster exists in config - - Args: - context (str): value to test if present - Returns: - bool: True if successful, false otherwise - """ - return self.section_has_value('clusters', cluster) - - def get_value_for_context(self, context, attribute): - """ Get the value of attribute in context - - Args: - context (str): context to search - attribute (str): attribute wanted - Returns: - str: The value for attribute in context - """ - contexts = self.config['contexts'] - if isinstance(contexts, dict): - return contexts[context][attribute] - else: - return next((c['context'][attribute] for c in contexts - if c['name'] == context), None) - - def get_user_for_context(self, context): - """ Get the user attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'user') - - def get_cluster_for_context(self, context): - """ Get the cluster attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'cluster') - - def get_namespace_for_context(self, context): - """ Get the namespace attribute in context - - Args: - context (str): context to search - Returns: - str: The value for the attribute in context - """ - return self.get_value_for_context(context, 'namespace') - -class Util(object): - """Utility methods""" - @staticmethod - def remove_empty_elements(mapping): - """ Recursively removes empty elements from a dict - - Args: - mapping (dict): dict to remove empty attributes from - Returns: - dict: A copy of the dict with empty elements removed - """ - if isinstance(mapping, dict): - copy = mapping.copy() - for key, val in mapping.iteritems(): - if not val: - del copy[key] - return copy - else: - return mapping - -class NodeResources(object): - """ Kubernetes Node Resources - - Attributes: - resources (dict): A dictionary representing the node resources - - Args: - version (str): kubernetes api version - cpu (str): string representation of the cpu resources for the node - memory (str): string representation of the memory resources for the - node - """ - def __init__(self, version, cpu=None, memory=None): - if version == 'v1beta1': - self.resources = dict(capacity=dict()) - self.resources['capacity']['cpu'] = cpu - self.resources['capacity']['memory'] = memory - - def get_resources(self): - """ Get the dict representing the node resources - - Returns: - dict: representation of the node resources with any empty - elements removed - """ - return Util.remove_empty_elements(self.resources) - -class NodeSpec(object): - """ Kubernetes Node Spec - - Attributes: - spec (dict): A dictionary representing the node resources - - Args: - version (str): kubernetes api version - cpu (str): string representation of the cpu resources for the node - memory (str): string representation of the memory resources for the - node - cidr (str): string representation of the cidr block available for - the node - externalID (str): The external id of the node - """ - def __init__(self, version, cpu=None, memory=None, cidr=None, - externalID=None): - if version == 'v1beta3': - self.spec = dict(podCIDR=cidr, externalID=externalID, - capacity=dict()) - self.spec['capacity']['cpu'] = cpu - self.spec['capacity']['memory'] = memory - - def get_spec(self): - """ Get the dict representing the node spec - - Returns: - dict: representation of the node spec with any empty elements - removed - """ - return Util.remove_empty_elements(self.spec) - -class Node(object): - """ Kubernetes Node - - Attributes: - node (dict): A dictionary representing the node - - Args: - module (AnsibleModule): - client_opts (list): client connection options - version (str, optional): kubernetes api version - node_name (str, optional): name for node - hostIP (str, optional): node host ip - cpu (str, optional): cpu resources for the node - memory (str, optional): memory resources for the node - labels (list, optional): labels for the node - annotations (list, optional): annotations for the node - podCIDR (list, optional): cidr block to use for pods - externalID (str, optional): external id of the node - """ - def __init__(self, module, client_opts, version='v1beta1', node_name=None, - hostIP=None, cpu=None, memory=None, labels=None, - annotations=None, podCIDR=None, externalID=None): - self.module = module - self.client_opts = client_opts - if version == 'v1beta1': - self.node = dict(id=node_name, - kind='Node', - apiVersion=version, - hostIP=hostIP, - resources=NodeResources(version, cpu, memory), - cidr=podCIDR, - labels=labels, - annotations=annotations, - externalID=externalID) - elif version == 'v1beta3': - metadata = dict(name=node_name, - labels=labels, - annotations=annotations) - self.node = dict(kind='Node', - apiVersion=version, - metadata=metadata, - spec=NodeSpec(version, cpu, memory, podCIDR, - externalID)) - - def get_name(self): - """ Get the name for the node - - Returns: - str: node name - """ - if self.node['apiVersion'] == 'v1beta1': - return self.node['id'] - elif self.node['apiVersion'] == 'v1beta3': - return self.node['metadata']['name'] - - def get_node(self): - """ Get the dict representing the node - - Returns: - dict: representation of the node with any empty elements - removed - """ - node = self.node.copy() - if self.node['apiVersion'] == 'v1beta1': - node['resources'] = self.node['resources'].get_resources() - elif self.node['apiVersion'] == 'v1beta3': - node['spec'] = self.node['spec'].get_spec() - return Util.remove_empty_elements(node) - - def exists(self): - """ Tests if the node already exists - - Returns: - bool: True if node exists, otherwise False - """ - kubectl = self.module.params['kubectl_cmd'] - _, output, _ = self.module.run_command((kubectl + ["get", "nodes"] + - self.client_opts), - check_rc=True) - if re.search(self.module.params['name'], output, re.MULTILINE): - return True - return False - - def create(self): - """ Creates the node - - Returns: - bool: True if node creation successful - """ - kubectl = self.module.params['kubectl_cmd'] - cmd = kubectl + self.client_opts + ['create', '-f', '-'] - exit_code, output, error = self.module.run_command( - cmd, data=self.module.jsonify(self.get_node()) - ) - if exit_code != 0: - if re.search("minion \"%s\" already exists" % self.get_name(), - error): - self.module.exit_json(msg="node definition already exists", - changed=False, node=self.get_node()) - else: - self.module.fail_json(msg="Node creation failed.", - exit_code=exit_code, - output=output, error=error, - node=self.get_node()) - else: - return True - -def generate_client_opts(module): - """ Generates the client options - - Args: - module(AnsibleModule) - - Returns: - str: client options - """ - client_config = '~/.kube/.kubeconfig' - if 'default_client_config' in module.params: - client_config = module.params['default_client_config'] - user_has_client_config = os.path.exists(os.path.expanduser(client_config)) - if not (user_has_client_config or module.params['client_config']): - module.fail_json(msg="Could not locate client configuration, " - "client_config must be specified if " - "~/.kube/.kubeconfig is not present") - - client_opts = [] - if module.params['client_config']: - kubeconfig_flag = '--kubeconfig' - if 'kubeconfig_flag' in module.params: - kubeconfig_flag = module.params['kubeconfig_flag'] - client_opts.append(kubeconfig_flag + '=' + os.path.expanduser(module.params['client_config'])) - - try: - config = ClientConfig(client_opts, module) - except ClientConfigException as ex: - module.fail_json(msg="Failed to get client configuration", - exception=str(ex)) - - client_context = module.params['client_context'] - if config.has_context(client_context): - if client_context != config.current_context(): - client_opts.append("--context=%s" % client_context) - else: - module.fail_json(msg="Context %s not found in client config" % client_context) - - client_user = module.params['client_user'] - if config.has_user(client_user): - if client_user != config.get_user_for_context(client_context): - client_opts.append("--user=%s" % client_user) - else: - module.fail_json(msg="User %s not found in client config" % client_user) - - client_cluster = module.params['client_cluster'] - if config.has_cluster(client_cluster): - if client_cluster != config.get_cluster_for_context(client_context): - client_opts.append("--cluster=%s" % client_cluster) - else: - module.fail_json(msg="Cluster %s not found in client config" % client_cluster) - - client_namespace = module.params['client_namespace'] - if client_namespace != config.get_namespace_for_context(client_context): - client_opts.append("--namespace=%s" % client_namespace) - - return client_opts - - -def main(): - """ main """ - module = AnsibleModule( - argument_spec=dict( - name=dict(required=True, type='str'), - host_ip=dict(type='str'), - api_version=dict(type='str', default='v1beta1', - choices=['v1beta1', 'v1beta3']), - cpu=dict(type='str'), - memory=dict(type='str'), - # TODO: needs documented - labels=dict(type='dict', default={}), - # TODO: needs documented - annotations=dict(type='dict', default={}), - # TODO: needs documented - pod_cidr=dict(type='str'), - # TODO: needs documented - client_config=dict(type='str'), - # TODO: needs documented - client_cluster=dict(type='str', default='master'), - # TODO: needs documented - client_context=dict(type='str', default='default'), - # TODO: needs documented - client_namespace=dict(type='str', default='default'), - # TODO: needs documented - client_user=dict(type='str', default='system:admin'), - # TODO: needs documented - kubectl_cmd=dict(type='list', default=['kubectl']), - # TODO: needs documented - kubeconfig_flag=dict(type='str'), - # TODO: needs documented - default_client_config=dict(type='str') - ), - supports_check_mode=True - ) - - labels = module.params['labels'] - kube_hostname_label = 'kubernetes.io/hostname' - if kube_hostname_label not in labels: - labels[kube_hostname_label] = module.params['name'] - - node = Node(module, generate_client_opts(module), - module.params['api_version'], module.params['name'], - module.params['host_ip'], module.params['cpu'], - module.params['memory'], labels, module.params['annotations'], - module.params['pod_cidr']) - - if node.exists(): - module.exit_json(changed=False, node=node.get_node()) - elif module.check_mode: - module.exit_json(changed=True, node=node.get_node()) - elif node.create(): - module.exit_json(changed=True, msg="Node created successfully", - node=node.get_node()) - else: - module.fail_json(msg="Unknown error creating node", node=node.get_node()) - -# ignore pylint errors related to the module_utils import -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import -# import module snippets -from ansible.module_utils.basic import * -if __name__ == '__main__': - main() diff --git a/roles/openshift_registry/README.md b/roles/openshift_registry/README.md index 202c818b8..8e66c483b 100644 --- a/roles/openshift_registry/README.md +++ b/roles/openshift_registry/README.md @@ -12,14 +12,16 @@ Role Variables -------------- From this role: + | Name | Default value | | |--------------------|-------------------------------------------------------|---------------------| | | | | From openshift_common: + | Name | Default value | | |-----------------------|---------------|--------------------------------------| -| openshift_debug_level | 0 | Global openshift debug log verbosity | +| openshift_debug_level | 2 | Global openshift debug log verbosity | Dependencies @@ -39,4 +41,3 @@ Author Information ------------------ Red Hat openshift@redhat.com - diff --git a/roles/openshift_registry/tasks/main.yml b/roles/openshift_registry/tasks/main.yml index 29387d7d5..749eea5c0 100644 --- a/roles/openshift_registry/tasks/main.yml +++ b/roles/openshift_registry/tasks/main.yml @@ -1,11 +1,14 @@ --- -- set_fact: _oreg_images="--images={{ oreg_url|quote }}" - when: oreg_url is defined +# This role is unused until we add options for configuring the backend storage + +- set_fact: _oreg_images="--images='{{ openshift.master.registry_url }}'" + +- set_fact: _oreg_selector="--selector='{{ openshift.master.registry_selector }}'" - name: Deploy OpenShift Registry command: > {{ openshift.common.admin_binary }} registry - --create - --credentials={{ openshift_master_config_dir }}/openshift-registry.kubeconfig {{ _oreg_images|default() }} + --create --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" diff --git a/roles/openshift_registry/vars/main.yml b/roles/openshift_registry/vars/main.yml index 9fb501e85..9967e26f4 100644 --- a/roles/openshift_registry/vars/main.yml +++ b/roles/openshift_registry/vars/main.yml @@ -1,3 +1,2 @@ --- -openshift_master_config_dir: /etc/openshift/master - +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" diff --git a/roles/openshift_repos/README.md b/roles/openshift_repos/README.md index 6bbedd839..95b155b29 100644 --- a/roles/openshift_repos/README.md +++ b/roles/openshift_repos/README.md @@ -7,7 +7,7 @@ Requirements ------------ A RHEL 7.1 host pre-configured with access to the rhel-7-server-rpms, -rhel-7-server-extra-rpms, and rhel-7-server-ose-beta-rpms repos. +rhel-7-server-extra-rpms, and rhel-7-server-ose-3.0-rpms repos. Role Variables -------------- diff --git a/roles/openshift_repos/files/online/repos/enterprise-v3.repo b/roles/openshift_repos/files/online/repos/enterprise-v3.repo index 69c480f0a..92bd35834 100644 --- a/roles/openshift_repos/files/online/repos/enterprise-v3.repo +++ b/roles/openshift_repos/files/online/repos/enterprise-v3.repo @@ -1,7 +1,7 @@ [enterprise-v3] -name=OpenShift Enterprise Beta4 -baseurl=https://mirror.ops.rhcloud.com/libra/libra-7-ose-beta4/ - https://gce-mirror1.ops.rhcloud.com/libra/libra-7-ose-beta4/ +name=OpenShift Enterprise +baseurl=https://mirror.ops.rhcloud.com/libra/rhui-rhel-server-7-ose/ + https://gce-mirror1.ops.rhcloud.com/libra/rhui-rhel-server-7-ose/ enabled=1 gpgcheck=0 failovermethod=priority diff --git a/roles/openshift_repos/vars/main.yml b/roles/openshift_repos/vars/main.yml index bbb4c77e7..319611a0b 100644 --- a/roles/openshift_repos/vars/main.yml +++ b/roles/openshift_repos/vars/main.yml @@ -1,2 +1,7 @@ --- -known_openshift_deployment_types: ['origin', 'online', 'enterprise'] +# origin uses community packages named 'origin' +# online currently uses 'openshift' packages +# enterprise is used for OSE 3.0 < 3.1 which uses packages named 'openshift' +# atomic-enterprise uses Red Hat packages named 'atomic-openshift' +# openshift-enterprise uses Red Hat packages named 'atomic-openshift' starting with OSE 3.1 +known_openshift_deployment_types: ['origin', 'online', 'enterprise','atomic-enterprise','openshift-enterprise'] diff --git a/roles/openshift_router/README.md b/roles/openshift_router/README.md index 6d8ee25c6..836efc443 100644 --- a/roles/openshift_router/README.md +++ b/roles/openshift_router/README.md @@ -19,7 +19,7 @@ From this role: From openshift_common: | Name | Default value | | |-----------------------|---------------|--------------------------------------| -| openshift_debug_level | 0 | Global openshift debug log verbosity | +| openshift_debug_level | 2 | Global openshift debug log verbosity | Dependencies ------------ @@ -38,4 +38,3 @@ Author Information ------------------ Red Hat openshift@redhat.com - diff --git a/roles/openshift_router/tasks/main.yml b/roles/openshift_router/tasks/main.yml index 929177262..498a65127 100644 --- a/roles/openshift_router/tasks/main.yml +++ b/roles/openshift_router/tasks/main.yml @@ -1,11 +1,14 @@ --- -- set_fact: _ortr_images="--images={{ oreg_url|quote }}" - when: oreg_url is defined + +- set_fact: _ortr_images="--images='{{ openshift.master.registry_url }}'" + +- set_fact: _ortr_selector="--selector='{{ openshift.master.router_selector }}'" - name: Deploy OpenShift Router command: > {{ openshift.common.admin_binary }} router - --create - --credentials={{ openshift_master_config_dir }}/openshift-router.kubeconfig {{ _ortr_images|default() }} + --create --replicas={{ openshift.master.infra_nodes }} + --service-account=router {{ _ortr_selector }} + --credentials={{ openshift_master_config_dir }}/openshift-router.kubeconfig {{ _ortr_images }} register: _ortr_results changed_when: "'service exists' not in _ortr_results.stdout" diff --git a/roles/openshift_router/vars/main.yml b/roles/openshift_router/vars/main.yml index 9fb501e85..9967e26f4 100644 --- a/roles/openshift_router/vars/main.yml +++ b/roles/openshift_router/vars/main.yml @@ -1,3 +1,2 @@ --- -openshift_master_config_dir: /etc/openshift/master - +openshift_master_config_dir: "{{ openshift.common.config_base }}/master" diff --git a/roles/openshift_serviceaccounts/tasks/main.yml b/roles/openshift_serviceaccounts/tasks/main.yml new file mode 100644 index 000000000..d93a25a21 --- /dev/null +++ b/roles/openshift_serviceaccounts/tasks/main.yml @@ -0,0 +1,26 @@ +- name: Create service account configs + template: + src: serviceaccount.j2 + dest: "/tmp/{{ item }}-serviceaccount.yaml" + with_items: accounts + +- name: Create {{ item }} service account + command: > + {{ openshift.common.client_binary }} create -f "/tmp/{{ item }}-serviceaccount.yaml" + with_items: accounts + register: _sa_result + failed_when: "'serviceaccounts \"{{ item }}\" already exists' not in _sa_result.stderr and _sa_result.rc != 0" + changed_when: "'serviceaccounts \"{{ item }}\" already exists' not in _sa_result.stderr and _sa_result.rc == 0" + +- name: Get current security context constraints + shell: "{{ openshift.common.client_binary }} get scc privileged -o yaml > /tmp/scc.yaml" + +- name: Add security context constraint for {{ item }} + lineinfile: + dest: /tmp/scc.yaml + line: "- system:serviceaccount:default:{{ item }}" + insertafter: "^users:$" + with_items: accounts + +- name: Apply new scc rules for service accounts + command: "{{ openshift.common.client_binary }} update -f /tmp/scc.yaml" diff --git a/roles/openshift_serviceaccounts/templates/serviceaccount.j2 b/roles/openshift_serviceaccounts/templates/serviceaccount.j2 new file mode 100644 index 000000000..931e249f9 --- /dev/null +++ b/roles/openshift_serviceaccounts/templates/serviceaccount.j2 @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ item }} diff --git a/roles/openshift_storage_nfs_lvm/README.md b/roles/openshift_storage_nfs_lvm/README.md new file mode 100644 index 000000000..1ee02e18a --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/README.md @@ -0,0 +1,108 @@ +# openshift_storage_nfs_lvm + +This role is useful to create and export nfs disks for openshift persistent volumes. +It does so by creating lvm partitions on an already setup pv/vg, creating xfs +filesystem on each partition, mounting the partitions, exporting the mounts via NFS +and creating a json file for each mount that an openshift master can use to +create persistent volumes. + +## Requirements + +* NFS server with NFS, iptables, and everything setup. + +* A lvm volume group created on the nfs server (default: openshiftvg) + +* The lvm volume needs to have as much free space as you are allocating + +## Role Variables + +``` +# Options of NFS exports. +osnl_nfs_export_options: "*(rw,sync,all_squash)" + +# Directory, where the created partitions should be mounted. They will be +# mounted as <osnl_mount_dir>/<lvm volume name> +osnl_mount_dir: /exports/openshift + +# Volume Group to use. +# This role always assumes that there is enough free space on the volume +# group for all the partitions you will be making +osnl_volume_group: openshiftvg + +# volume names +# volume names are {{osnl_volume_prefix}}{{osnl_volume_size}}g{{volume number}} +# example: stg5g0004 + +# osnl_volume_prefix +# Useful if you are using the nfs server for more than one cluster +osnl_volume_prefix: "stg" + +# osnl_volume_size +# Size of the volumes/partitions in Gigabytes. +osnl_volume_size: 5 + +# osnl_volume_num_start +# Where to start the volume number numbering. +osnl_volume_num_start: 3 + +# osnl_number_of_volumes +# How many volumes/partitions to build, with the size we stated. +osnl_number_of_volumes: 2 + +``` + +## Dependencies + +None + +## Example Playbook + +With this playbook, 2 5Gig lvm partitions are created, named stg5g0003 and stg5g0004 +Both of them are mounted into `/exports/openshift` directory. Both directories are +exported via NFS. json files are created in /root. + + - hosts: nfsservers + sudo: no + remote_user: root + gather_facts: no + roles: + - role: openshift_storage_nfs_lvm + osnl_mount_dir: /exports/openshift + osnl_volume_prefix: "stg" + osnl_volume_size: 5 + osnl_volume_num_start: 3 + osnl_number_of_volumes: 2 + + +## Full example + + +* Create an `inventory` file: + ``` + [nfsservers] + 10.0.0.1 + 10.0.0.2 + ``` + +* Create an ansible playbook, say `setupnfs.yaml`: + ``` + - hosts: nfsservers + sudo: no + remote_user: root + gather_facts: no + roles: + - role: openshift_storage_nfs_lvm + osnl_mount_dir: /exports/stg + osnl_volume_prefix: "stg" + osnl_volume_size: 5 + osnl_volume_num_start: 3 + osnl_number_of_volumes: 2 + +* Run the playbook: + ``` + ansible-playbook -i inventory setupnfs.yml + ``` + +## License + +Apache 2.0 diff --git a/roles/openshift_storage_nfs_lvm/defaults/main.yml b/roles/openshift_storage_nfs_lvm/defaults/main.yml new file mode 100644 index 000000000..f81cdc724 --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/defaults/main.yml @@ -0,0 +1,10 @@ +--- +# Options of NFS exports. +osnl_nfs_export_options: "*(rw,sync,all_squash)" + +# Directory, where the created partitions should be mounted. They will be +# mounted as <osnl_mount_dir>/test1g0001 etc. +osnl_mount_dir: /exports/openshift + +# Volume Group to use. +osnl_volume_group: openshiftvg diff --git a/roles/openshift_storage_nfs_lvm/handlers/main.yml b/roles/openshift_storage_nfs_lvm/handlers/main.yml new file mode 100644 index 000000000..52f3ceffe --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/handlers/main.yml @@ -0,0 +1,3 @@ +--- +- name: restart nfs + service: name=nfs-server state=restarted diff --git a/roles/openshift_storage_nfs_lvm/meta/main.yml b/roles/openshift_storage_nfs_lvm/meta/main.yml new file mode 100644 index 000000000..44fee47ff --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/meta/main.yml @@ -0,0 +1,16 @@ +--- +galaxy_info: + author: Jan Safranek, Troy Dawson + description: Create LVM volumes and use them as openshift persistent volumes. + company: Red Hat, Inc. + license: license (Apache) + min_ansible_version: 1.4 + platforms: + - name: EL + versions: + - 7 + - name: Fedora + versions: + - all + categories: + - openshift diff --git a/roles/openshift_storage_nfs_lvm/tasks/main.yml b/roles/openshift_storage_nfs_lvm/tasks/main.yml new file mode 100644 index 000000000..ead81b876 --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Create lvm volumes + lvol: vg={{osnl_volume_group}} lv={{ item }} size={{osnl_volume_size}}G + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + +- name: create filesystem + filesystem: fstype=xfs dev=/dev/{{osnl_volume_group}}/{{ item }} + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + +- name: mount volumes + mount: name={{osnl_mount_dir}}/{{ item }} src=/dev/{{osnl_volume_group}}/{{ item }} state=mounted fstype=xfs passno=0 + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + +- name: Make mounts owned by nfsnobody + file: path={{osnl_mount_dir}}/{{ item }} owner=nfsnobody group=nfsnobody mode=0700 + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + +- include: nfs.yml + +- name: Create volume json file + template: src=../templates/nfs.json.j2 dest=/root/persistent-volume.{{ item }}.json + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + +# TODO - Get the json files to a master, and load them. diff --git a/roles/openshift_storage_nfs_lvm/tasks/nfs.yml b/roles/openshift_storage_nfs_lvm/tasks/nfs.yml new file mode 100644 index 000000000..65ae069df --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/tasks/nfs.yml @@ -0,0 +1,16 @@ +--- +- name: Install NFS server + yum: name=nfs-utils state=present + +- name: Start rpcbind + service: name=rpcbind state=started enabled=yes + +- name: Start nfs + service: name=nfs-server state=started enabled=yes + +- name: Export the directories + lineinfile: dest=/etc/exports + regexp="^{{ osnl_mount_dir }}/{{ item }} " + line="{{ osnl_mount_dir }}/{{ item }} {{osnl_nfs_export_options}}" + with_sequence: start={{osnl_volume_num_start}} count={{osnl_number_of_volumes}} format={{osnl_volume_prefix}}{{osnl_volume_size}}g%04d + notify: restart nfs diff --git a/roles/openshift_storage_nfs_lvm/templates/nfs.json.j2 b/roles/openshift_storage_nfs_lvm/templates/nfs.json.j2 new file mode 100644 index 000000000..0f3d84e75 --- /dev/null +++ b/roles/openshift_storage_nfs_lvm/templates/nfs.json.j2 @@ -0,0 +1,21 @@ +{ + "apiVersion": "v1", + "kind": "PersistentVolume", + "metadata": { + "name": "pv-{{ inventory_hostname | regex_replace("\.", "-") }}-{{ item }}", + "labels": { + "type": "nfs" + } + }, + "spec": { + "capacity": { + "storage": "{{ osnl_volume_size }}Gi" + }, + "accessModes": [ "ReadWriteMany" ], + "persistentVolumeReclaimPolicy": "Recycle", + "nfs": { + "Server": "{{ inventory_hostname }}", + "Path": "{{ osnl_mount_dir }}/{{ item }}" + } + } +} diff --git a/roles/os_zabbix/README.md b/roles/os_zabbix/README.md new file mode 100644 index 000000000..ac3dc2833 --- /dev/null +++ b/roles/os_zabbix/README.md @@ -0,0 +1,40 @@ +os_zabbix +========= + +Automate zabbix tasks. + +Requirements +------------ + +This requires the openshift_tools rpm be installed for the zbxapi.py library. It can be found here: https://github.com/openshift/openshift-tools under openshift_tools/monitoring/zbxapi.py for now. + +Role Variables +-------------- + +zab_server +zab_username +zab_password + +Dependencies +------------ + +This depeonds on the zbxapi.py library located here: https://github.com/openshift/openshift-tools under openshift_tools/monitoring/zbxapi.py for now. + +Example Playbook +---------------- + + - zbx_host: + server: zab_server + user: zab_user + password: zab_password + name: 'myhost' + +License +------- + +ASL 2.0 + +Author Information +------------------ + +OpenShift operations, Red Hat, Inc diff --git a/roles/os_zabbix/defaults/main.yml b/roles/os_zabbix/defaults/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/os_zabbix/defaults/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/os_zabbix/handlers/main.yml b/roles/os_zabbix/handlers/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/os_zabbix/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/os_zabbix/library/zbxapi.py b/roles/os_zabbix/library/zbxapi.py deleted file mode 100755 index b5fa5ee2b..000000000 --- a/roles/os_zabbix/library/zbxapi.py +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/env python -# vim: expandtab:tabstop=4:shiftwidth=4 -''' - ZabbixAPI ansible module -''' - -# Copyright 2015 Red Hat Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Purpose: An ansible module to communicate with zabbix. -# - -# pylint: disable=line-too-long -# Disabling line length for readability - -import json -import httplib2 -import sys -import os -import re -import copy - -class ZabbixAPIError(Exception): - ''' - ZabbixAPIError - Exists to propagate errors up from the api - ''' - pass - -class ZabbixAPI(object): - ''' - ZabbixAPI class - ''' - classes = { - 'Action': ['create', 'delete', 'get', 'update'], - 'Alert': ['get'], - 'Application': ['create', 'delete', 'get', 'massadd', 'update'], - 'Configuration': ['export', 'import'], - 'Dcheck': ['get'], - 'Dhost': ['get'], - 'Drule': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Dservice': ['get'], - 'Event': ['acknowledge', 'get'], - 'Graph': ['create', 'delete', 'get', 'update'], - 'Graphitem': ['get'], - 'Graphprototype': ['create', 'delete', 'get', 'update'], - 'History': ['get'], - 'Hostgroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], - 'Hostinterface': ['create', 'delete', 'get', 'massadd', 'massremove', 'replacehostinterfaces', 'update'], - 'Host': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], - 'Hostprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Httptest': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Iconmap': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Image': ['create', 'delete', 'get', 'update'], - 'Item': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Itemprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Maintenance': ['create', 'delete', 'get', 'update'], - 'Map': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Mediatype': ['create', 'delete', 'get', 'update'], - 'Proxy': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Screen': ['create', 'delete', 'get', 'update'], - 'Screenitem': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update', 'updatebyposition'], - 'Script': ['create', 'delete', 'execute', 'get', 'getscriptsbyhosts', 'update'], - 'Service': ['adddependencies', 'addtimes', 'create', 'delete', 'deletedependencies', 'deletetimes', 'get', 'getsla', 'isreadable', 'iswritable', 'update'], - 'Template': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], - 'Templatescreen': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], - 'Templatescreenitem': ['get'], - 'Trigger': ['adddependencies', 'create', 'delete', 'deletedependencies', 'get', 'isreadable', 'iswritable', 'update'], - 'Triggerprototype': ['create', 'delete', 'get', 'update'], - 'User': ['addmedia', 'create', 'delete', 'deletemedia', 'get', 'isreadable', 'iswritable', 'login', 'logout', 'update', 'updatemedia', 'updateprofile'], - 'Usergroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massupdate', 'update'], - 'Usermacro': ['create', 'createglobal', 'delete', 'deleteglobal', 'get', 'update', 'updateglobal'], - 'Usermedia': ['get'], - } - - def __init__(self, data=None): - if not data: - data = {} - self.server = data.get('server', None) - self.username = data.get('user', None) - self.password = data.get('password', None) - if any([value == None for value in [self.server, self.username, self.password]]): - print 'Please specify zabbix server url, username, and password.' - sys.exit(1) - - self.verbose = data.get('verbose', False) - self.use_ssl = data.has_key('use_ssl') - self.auth = None - - for cname, _ in self.classes.items(): - setattr(self, cname.lower(), getattr(self, cname)(self)) - - # pylint: disable=no-member - # This method does not exist until the metaprogramming executed - # This is permanently disabled. - results = self.user.login(user=self.username, password=self.password) - - if results[0]['status'] == '200': - if results[1].has_key('result'): - self.auth = results[1]['result'] - elif results[1].has_key('error'): - print "Unable to authenticate with zabbix server. {0} ".format(results[1]['error']) - sys.exit(1) - else: - print "Error in call to zabbix. Http status: {0}.".format(results[0]['status']) - sys.exit(1) - - def perform(self, method, rpc_params): - ''' - This method calls your zabbix server. - - It requires the following parameters in order for a proper request to be processed: - jsonrpc - the version of the JSON-RPC protocol used by the API; - the Zabbix API implements JSON-RPC version 2.0; - method - the API method being called; - rpc_params - parameters that will be passed to the API method; - id - an arbitrary identifier of the request; - auth - a user authentication token; since we don't have one yet, it's set to null. - ''' - http_method = "POST" - jsonrpc = "2.0" - rid = 1 - - http = None - if self.use_ssl: - http = httplib2.Http() - else: - http = httplib2.Http(disable_ssl_certificate_validation=True,) - - headers = {} - headers["Content-type"] = "application/json" - - body = { - "jsonrpc": jsonrpc, - "method": method, - "params": rpc_params.get('params', {}), - "id": rid, - 'auth': self.auth, - } - - if method in ['user.login', 'api.version']: - del body['auth'] - - body = json.dumps(body) - - if self.verbose: - print body - print method - print headers - httplib2.debuglevel = 1 - - response, content = http.request(self.server, http_method, body, headers) - - if response['status'] not in ['200', '201']: - raise ZabbixAPIError('Error calling zabbix. Zabbix returned %s' % response['status']) - - if self.verbose: - print response - print content - - try: - content = json.loads(content) - except ValueError as err: - content = {"error": err.message} - - return response, content - - @staticmethod - def meta(cname, method_names): - ''' - This bit of metaprogramming is where the ZabbixAPI subclasses are created. - For each of ZabbixAPI.classes we create a class from the key and methods - from the ZabbixAPI.classes values. We pass a reference to ZabbixAPI class - to each subclass in order for each to be able to call the perform method. - ''' - def meta_method(_class, method_name): - ''' - This meta method allows a class to add methods to it. - ''' - # This template method is a stub method for each of the subclass - # methods. - def template_method(self, params=None, **rpc_params): - ''' - This template method is a stub method for each of the subclass methods. - ''' - if params: - rpc_params['params'] = params - else: - rpc_params['params'] = copy.deepcopy(rpc_params) - - return self.parent.perform(cname.lower()+"."+method_name, rpc_params) - - template_method.__doc__ = \ - "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s/%s" % \ - (cname.lower(), method_name) - template_method.__name__ = method_name - # this is where the template method is placed inside of the subclass - # e.g. setattr(User, "create", stub_method) - setattr(_class, template_method.__name__, template_method) - - # This class call instantiates a subclass. e.g. User - _class = type(cname, - (object,), - {'__doc__': \ - "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s" % cname.lower()}) - def __init__(self, parent): - ''' - This init method gets placed inside of the _class - to allow it to be instantiated. A reference to the parent class(ZabbixAPI) - is passed in to allow each class access to the perform method. - ''' - self.parent = parent - - # This attaches the init to the subclass. e.g. Create - setattr(_class, __init__.__name__, __init__) - # For each of our ZabbixAPI.classes dict values - # Create a method and attach it to our subclass. - # e.g. 'User': ['delete', 'get', 'updatemedia', 'updateprofile', - # 'update', 'iswritable', 'logout', 'addmedia', 'create', - # 'login', 'deletemedia', 'isreadable'], - # User.delete - # User.get - for method_name in method_names: - meta_method(_class, method_name) - # Return our subclass with all methods attached - return _class - -# Attach all ZabbixAPI.classes to ZabbixAPI class through metaprogramming -for _class_name, _method_names in ZabbixAPI.classes.items(): - setattr(ZabbixAPI, _class_name, ZabbixAPI.meta(_class_name, _method_names)) - -def exists(content, key='result'): - ''' Check if key exists in content or the size of content[key] > 0 - ''' - if not content.has_key(key): - return False - - if not content[key]: - return False - - return True - -def diff_content(from_zabbix, from_user): - ''' Compare passed in object to results returned from zabbix - ''' - terms = ['search', 'output', 'groups', 'select', 'expand'] - regex = '(' + '|'.join(terms) + ')' - retval = {} - for key, value in from_user.items(): - if re.findall(regex, key): - continue - - if from_zabbix[key] != str(value): - retval[key] = str(value) - - return retval - -def main(): - ''' - This main method runs the ZabbixAPI Ansible Module - ''' - - module = AnsibleModule( - argument_spec=dict( - server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), - user=dict(default=None, type='str'), - password=dict(default=None, type='str'), - zbx_class=dict(choices=ZabbixAPI.classes.keys()), - params=dict(), - debug=dict(default=False, type='bool'), - state=dict(default='present', type='str'), - ), - #supports_check_mode=True - ) - - user = module.params.get('user', None) - if not user: - user = os.environ['ZABBIX_USER'] - - passwd = module.params.get('password', None) - if not passwd: - passwd = os.environ['ZABBIX_PASSWORD'] - - - - api_data = { - 'user': user, - 'password': passwd, - 'server': module.params['server'], - 'verbose': module.params['debug'] - } - - if not user or not passwd or not module.params['server']: - module.fail_json(msg='Please specify the user, password, and the zabbix server.') - - zapi = ZabbixAPI(api_data) - - zbx_class = module.params.get('zbx_class') - rpc_params = module.params.get('params', {}) - state = module.params.get('state') - - # Get the instance we are trying to call - zbx_class_inst = zapi.__getattribute__(zbx_class.lower()) - - # perform get - # Get the instance's method we are trying to call - - zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['get'] - _, content = zbx_action_method(zbx_class_inst, rpc_params) - - if state == 'list': - module.exit_json(changed=False, results=content['result'], state="list") - - if state == 'absent': - if not exists(content): - module.exit_json(changed=False, state="absent") - # If we are coming from a query, we need to pass in the correct rpc_params for delete. - # specifically the zabbix class name + 'id' - # if rpc_params is a list then we need to pass it. (list of ids to delete) - idname = zbx_class.lower() + "id" - if not isinstance(rpc_params, list) and content['result'][0].has_key(idname): - rpc_params = [content['result'][0][idname]] - - zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['delete'] - _, content = zbx_action_method(zbx_class_inst, rpc_params) - module.exit_json(changed=True, results=content['result'], state="absent") - - if state == 'present': - # It's not there, create it! - if not exists(content): - zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['create'] - _, content = zbx_action_method(zbx_class_inst, rpc_params) - module.exit_json(changed=True, results=content['result'], state='present') - - # It's there and the same, do nothing! - diff_params = diff_content(content['result'][0], rpc_params) - if not diff_params: - module.exit_json(changed=False, results=content['result'], state="present") - - # Add the id to update with - idname = zbx_class.lower() + "id" - diff_params[idname] = content['result'][0][idname] - - - ## It's there and not the same, update it! - zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['update'] - _, content = zbx_action_method(zbx_class_inst, diff_params) - module.exit_json(changed=True, results=content, state="present") - - module.exit_json(failed=True, - changed=False, - results='Unknown state passed. %s' % state, - state="unknown") - -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled -# import module snippets. This are required -from ansible.module_utils.basic import * - -main() diff --git a/roles/os_zabbix/meta/main.yml b/roles/os_zabbix/meta/main.yml new file mode 100644 index 000000000..360f5aad2 --- /dev/null +++ b/roles/os_zabbix/meta/main.yml @@ -0,0 +1,9 @@ +--- +galaxy_info: + author: OpenShift + description: ZabbixAPI + company: Red Hat, Inc + license: ASL 2.0 + min_ansible_version: 1.2 +dependencies: +- lib_zabbix diff --git a/roles/os_zabbix/tasks/main.yml b/roles/os_zabbix/tasks/main.yml new file mode 100644 index 000000000..a503b24d7 --- /dev/null +++ b/roles/os_zabbix/tasks/main.yml @@ -0,0 +1,81 @@ +--- +- name: Main List all templates + zbx_template: + zbx_server: "{{ ozb_server }}" + zbx_user: "{{ ozb_user }}" + zbx_password: "{{ ozb_password }}" + state: list + register: templates + +- include_vars: template_heartbeat.yml +- include_vars: template_os_linux.yml +- include_vars: template_docker.yml +- include_vars: template_openshift_master.yml +- include_vars: template_openshift_node.yml +- include_vars: template_ops_tools.yml +- include_vars: template_app_zabbix_server.yml +- include_vars: template_app_zabbix_agent.yml + +- name: Include Template Heartbeat + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_heartbeat }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template os_linux + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_os_linux }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template docker + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_docker }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template Openshift Master + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_openshift_master }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template Openshift Node + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_openshift_node }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template Ops Tools + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_ops_tools }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template App Zabbix Server + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_app_zabbix_server }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" + +- name: Include Template App Zabbix Agent + include: ../../lib_zabbix/tasks/create_template.yml + vars: + template: "{{ g_template_app_zabbix_agent }}" + server: "{{ ozb_server }}" + user: "{{ ozb_user }}" + password: "{{ ozb_password }}" diff --git a/roles/os_zabbix/vars/main.yml b/roles/os_zabbix/vars/main.yml new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/roles/os_zabbix/vars/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/os_zabbix/vars/template_app_zabbix_agent.yml b/roles/os_zabbix/vars/template_app_zabbix_agent.yml new file mode 100644 index 000000000..d636d4822 --- /dev/null +++ b/roles/os_zabbix/vars/template_app_zabbix_agent.yml @@ -0,0 +1,23 @@ +--- +g_template_app_zabbix_agent: + name: Template App Zabbix Agent + zitems: + - key: agent.hostname + applications: + - Zabbix agent + value_type: character + zabbix_type: agent + + - key: agent.ping + applications: + - Zabbix agent + description: The agent always returns 1 for this item. It could be used in combination with nodata() for availability check. + value_type: int + zabbix_type: agent + + ztriggers: + - name: '[Reboot] Zabbix agent on {HOST.NAME} is unreachable for 15 minutes' + description: Zabbix agent is unreachable for 15 minutes. + expression: '{Template App Zabbix Agent:agent.ping.nodata(15m)}=1' + priority: high + url: https://github.com/openshift/ops-sop/blob/master/Alerts/check_ping.asciidoc diff --git a/roles/os_zabbix/vars/template_app_zabbix_server.yml b/roles/os_zabbix/vars/template_app_zabbix_server.yml new file mode 100644 index 000000000..43517113b --- /dev/null +++ b/roles/os_zabbix/vars/template_app_zabbix_server.yml @@ -0,0 +1,412 @@ +--- +g_template_app_zabbix_server: + name: Template App Zabbix Server + zitems: + - key: housekeeper_creates + applications: + - Zabbix server + description: A simple count of the number of partition creates output by the housekeeper script. + units: '' + value_type: int + zabbix_type: internal + + - key: housekeeper_drops + applications: + - Zabbix server + description: A simple count of the number of partition drops output by the housekeeper script. + units: '' + value_type: int + zabbix_type: internal + + - key: housekeeper_errors + applications: + - Zabbix server + description: A simple count of the number of errors output by the housekeeper script. + units: '' + value_type: int + zabbix_type: internal + + - key: housekeeper_total + applications: + - Zabbix server + description: A simple count of the total number of lines output by the housekeeper + script. + units: '' + value_type: int + zabbix_type: internal + + - key: zabbix[process,alerter,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,configuration syncer,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,db watchdog,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,discoverer,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,escalator,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,history syncer,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,housekeeper,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,http poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,icmp pinger,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,ipmi poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,java poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,node watcher,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,proxy poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,self-monitoring,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,snmp trapper,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,timer,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,trapper,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[process,unreachable poller,avg,busy] + applications: + - Zabbix server + description: '' + units: '%' + value_type: float + zabbix_type: internal + + - key: zabbix[queue,10m] + applications: + - Zabbix server + description: '' + units: '' + value_type: int + zabbix_type: internal + interval: 600 + + - key: zabbix[queue] + applications: + - Zabbix server + description: '' + units: '' + value_type: int + zabbix_type: internal + interval: 600 + + - key: zabbix[rcache,buffer,pfree] + applications: + - Zabbix server + description: '' + units: '' + value_type: float + zabbix_type: internal + + - key: zabbix[wcache,history,pfree] + applications: + - Zabbix server + description: '' + units: '' + value_type: float + zabbix_type: internal + + - key: zabbix[wcache,text,pfree] + applications: + - Zabbix server + description: '' + units: '' + value_type: float + zabbix_type: internal + + - key: zabbix[wcache,trend,pfree] + applications: + - Zabbix server + description: '' + units: '' + value_type: float + zabbix_type: internal + + - key: zabbix[wcache,values] + applications: + - Zabbix server + description: '' + units: '' + value_type: float + zabbix_type: internal + delta: 1 # speed per second + + ztriggers: + - description: "There has been unexpected output while running the housekeeping script\ + \ on the Zabbix. There are only three kinds of lines we expect to see in the output,\ + \ and we've gotten something enw.\r\n\r\nCheck the script's output in /var/lib/zabbix/state\ + \ for more details." + expression: '{Template App Zabbix Server:housekeeper_errors.last(0)}+{Template App Zabbix Server:housekeeper_creates.last(0)}+{Template App Zabbix Server:housekeeper_drops.last(0)}<>{Template App Zabbix Server:housekeeper_total.last(0)}' + name: Unexpected output in Zabbix DB Housekeeping + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_DB_Housekeeping.asciidoc + + - description: An error has occurred during running the housekeeping script on the Zabbix. Check the script's output in /var/lib/zabbix/state for more details. + expression: '{Template App Zabbix Server:housekeeper_errors.last(0)}>0' + name: Errors during Zabbix DB Housekeeping + priority: high + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,alerter,avg,busy].min(600)}>75' + name: Zabbix alerter processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,configuration syncer,avg,busy].min(600)}>75' + name: Zabbix configuration syncer processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,db watchdog,avg,busy].min(600)}>75' + name: Zabbix db watchdog processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,discoverer,avg,busy].min(600)}>75' + name: Zabbix discoverer processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,escalator,avg,busy].min(600)}>75' + name: Zabbix escalator processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,history syncer,avg,busy].min(600)}>75' + name: Zabbix history syncer processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,housekeeper,avg,busy].min(1800)}>75' + name: Zabbix housekeeper processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,http poller,avg,busy].min(600)}>75' + name: Zabbix http poller processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,icmp pinger,avg,busy].min(600)}>75' + name: Zabbix icmp pinger processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,ipmi poller,avg,busy].min(600)}>75' + name: Zabbix ipmi poller processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,java poller,avg,busy].min(600)}>75' + name: Zabbix java poller processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,node watcher,avg,busy].min(600)}>75' + name: Zabbix node watcher processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,poller,avg,busy].min(600)}>75' + name: Zabbix poller processes more than 75% busy + priority: high + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,proxy poller,avg,busy].min(600)}>75' + name: Zabbix proxy poller processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,self-monitoring,avg,busy].min(600)}>75' + name: Zabbix self-monitoring processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,snmp trapper,avg,busy].min(600)}>75' + name: Zabbix snmp trapper processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: Timer processes usually are busy because they have to process time + based trigger functions + expression: '{Template App Zabbix Server:zabbix[process,timer,avg,busy].min(600)}>75' + name: Zabbix timer processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,trapper,avg,busy].min(600)}>75' + name: Zabbix trapper processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[process,unreachable poller,avg,busy].min(600)}>75' + name: Zabbix unreachable poller processes more than 75% busy + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/Zabbix_state_check.asciidoc + + - description: "This alert generally indicates a performance problem or a problem\ + \ with the zabbix-server or proxy.\r\n\r\nThe first place to check for issues\ + \ is Administration > Queue. Be sure to check the general view and the per-proxy\ + \ view." + expression: '{Template App Zabbix Server:zabbix[queue,10m].min(600)}>1000' + name: More than 1000 items having missing data for more than 10 minutes + priority: high + url: https://github.com/openshift/ops-sop/blob/master/Alerts/data_lost_overview_plugin.asciidoc + + - description: Consider increasing CacheSize in the zabbix_server.conf configuration + file + expression: '{Template App Zabbix Server:zabbix[rcache,buffer,pfree].min(600)}<5' + name: Less than 5% free in the configuration cache + priority: info + url: https://github.com/openshift/ops-sop/blob/master/Alerts/check_cache.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[wcache,history,pfree].min(600)}<25' + name: Less than 25% free in the history cache + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/check_cache.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[wcache,text,pfree].min(600)}<25' + name: Less than 25% free in the text history cache + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/check_cache.asciidoc + + - description: '' + expression: '{Template App Zabbix Server:zabbix[wcache,trend,pfree].min(600)}<25' + name: Less than 25% free in the trends cache + priority: avg + url: https://github.com/openshift/ops-sop/blob/master/Alerts/check_cache.asciidoc diff --git a/roles/os_zabbix/vars/template_docker.yml b/roles/os_zabbix/vars/template_docker.yml new file mode 100644 index 000000000..bfabf50c5 --- /dev/null +++ b/roles/os_zabbix/vars/template_docker.yml @@ -0,0 +1,94 @@ +--- +g_template_docker: + name: Template Docker + zitems: + - key: docker.ping + applications: + - Docker Daemon + value_type: int + + - key: docker.info_elapsed_ms + applications: + - Docker Daemon + value_type: int + + - key: docker.storage.is_loopback + applications: + - Docker Storage + value_type: int + + - key: docker.storage.data.space.total + applications: + - Docker Storage + value_type: float + + - key: docker.storage.data.space.used + applications: + - Docker Storage + value_type: float + + - key: docker.storage.data.space.available + applications: + - Docker Storage + value_type: float + + - key: docker.storage.data.space.percent_available + applications: + - Docker Storage + value_type: float + + - key: docker.storage.metadata.space.total + applications: + - Docker Storage + value_type: float + + - key: docker.storage.metadata.space.used + applications: + - Docker Storage + value_type: float + + - key: docker.storage.metadata.space.available + applications: + - Docker Storage + value_type: float + + - key: docker.storage.metadata.space.percent_available + applications: + - Docker Storage + value_type: float + ztriggers: + - name: 'docker.ping failed on {HOST.NAME}' + expression: '{Template Docker:docker.ping.max(#3)}<1' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_ping.asciidoc' + priority: high + + - name: 'Docker storage is using LOOPBACK on {HOST.NAME}' + expression: '{Template Docker:docker.storage.is_loopback.last()}<>0' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_loopback.asciidoc' + priority: high + + - name: 'Critically low docker storage data space on {HOST.NAME}' + expression: '{Template Docker:docker.storage.data.space.percent_available.max(#3)}<5 or {Template Docker:docker.storage.data.space.available.max(#3)}<5' # < 5% or < 5GB + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_storage.asciidoc' + priority: high + + - name: 'Critically low docker storage metadata space on {HOST.NAME}' + expression: '{Template Docker:docker.storage.metadata.space.percent_available.max(#3)}<5 or {Template Docker:docker.storage.metadata.space.available.max(#3)}<0.005' # < 5% or < 5MB + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_storage.asciidoc' + priority: high + + # Put triggers that depend on other triggers here (deps must be created first) + - name: 'Low docker storage data space on {HOST.NAME}' + expression: '{Template Docker:docker.storage.data.space.percent_available.max(#3)}<10 or {Template Docker:docker.storage.data.space.available.max(#3)}<10' # < 10% or < 10GB + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_storage.asciidoc' + dependencies: + - 'Critically low docker storage data space on {HOST.NAME}' + priority: average + + - name: 'Low docker storage metadata space on {HOST.NAME}' + expression: '{Template Docker:docker.storage.metadata.space.percent_available.max(#3)}<10 or {Template Docker:docker.storage.metadata.space.available.max(#3)}<0.01' # < 10% or < 10MB + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_docker_storage.asciidoc' + dependencies: + - 'Critically low docker storage metadata space on {HOST.NAME}' + priority: average + diff --git a/roles/os_zabbix/vars/template_heartbeat.yml b/roles/os_zabbix/vars/template_heartbeat.yml new file mode 100644 index 000000000..8dbe0d0d6 --- /dev/null +++ b/roles/os_zabbix/vars/template_heartbeat.yml @@ -0,0 +1,13 @@ +--- +g_template_heartbeat: + name: Template Heartbeat + zitems: + - name: Heartbeat Ping + applications: + - Heartbeat + key: heartbeat.ping + ztriggers: + - name: 'Heartbeat.ping has failed on {HOST.NAME}' + expression: '{Template Heartbeat:heartbeat.ping.nodata(20m)}=1' + priority: avg + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_node_heartbeat.asciidoc' diff --git a/roles/os_zabbix/vars/template_openshift_master.yml b/roles/os_zabbix/vars/template_openshift_master.yml new file mode 100644 index 000000000..1de4fefbb --- /dev/null +++ b/roles/os_zabbix/vars/template_openshift_master.yml @@ -0,0 +1,58 @@ +--- +g_template_openshift_master: + name: Template Openshift Master + zitems: + - name: create_app + applications: + - Openshift Master + key: create_app + + - key: openshift.master.process.count + description: Shows number of master processes running + type: int + applications: + - Openshift Master + + - key: openshift.master.user.count + description: Shows number of users in a cluster + type: int + applications: + - Openshift Master + + - key: openshift.master.pod.running.count + description: Shows number of pods running + type: int + applications: + - Openshift Master + + - key: openshift.project.counter + description: Shows number of projects on a cluster + type: int + applications: + - Openshift Master + + ztriggers: + - name: 'Application creation has failed on {HOST.NAME}' + expression: '{Template Openshift Master:create_app.last(#1)}=1 and {Template Openshift Master:create_app.last(#2)}=1' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_create_app.asciidoc' + priority: avg + + - name: 'Openshift Master process not running on {HOST.NAME}' + expression: '{Template Openshift Master:openshift.master.process.count.max(#3)}<1' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/openshift_master.asciidoc' + priority: high + + - name: 'Too many Openshift Master processes running on {HOST.NAME}' + expression: '{Template Openshift Master:openshift.master.process.count.min(#3)}>1' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/openshift_master.asciidoc' + priority: high + + - name: 'Number of users for Openshift Master on {HOST.NAME}' + expression: '{Template Openshift Master:openshift.master.user.count.last()}=0' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/openshift_master.asciidoc' + priority: info + + - name: 'There are no projects running on {HOST.NAME}' + expression: '{Template Openshift Master:openshift.project.counter.last()}=0' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/openshift_master.asciidoc' + priority: info diff --git a/roles/os_zabbix/vars/template_openshift_node.yml b/roles/os_zabbix/vars/template_openshift_node.yml new file mode 100644 index 000000000..ce28b1048 --- /dev/null +++ b/roles/os_zabbix/vars/template_openshift_node.yml @@ -0,0 +1,44 @@ +--- +g_template_openshift_node: + name: Template Openshift Node + zitems: + - key: openshift.node.process.count + description: Shows number of OpenShift Node processes running + type: int + applications: + - Openshift Node + + - key: openshift.node.ovs.pids.count + description: Shows number of ovs process ids running + type: int + applications: + - Openshift Node + + - key: openshift.node.ovs.ports.count + description: Shows number of OVS ports defined + type: int + applications: + - Openshift Node + + ztriggers: + - name: 'Openshift Node process not running on {HOST.NAME}' + expression: '{Template Openshift Node:openshift.node.process.count.max(#3)}<1' + url: 'https://github.com/openshift/ops-sop/blob/node/V3/Alerts/openshift_node.asciidoc' + priority: high + + - name: 'Too many Openshift Node processes running on {HOST.NAME}' + expression: '{Template Openshift Node:openshift.node.process.count.min(#3)}>1' + url: 'https://github.com/openshift/ops-sop/blob/node/V3/Alerts/openshift_node.asciidoc' + priority: high + + - name: 'OVS may not be running on {HOST.NAME}' + expression: '{Template Openshift Node:openshift.node.ovs.pids.count.last()}<>4' + url: 'https://github.com/openshift/ops-sop/blob/node/V3/Alerts/openshift_node.asciidoc' + priority: high + + - name: 'Number of OVS ports is 0 on {HOST.NAME}' + expression: '{Template Openshift Node:openshift.node.ovs.ports.count.last()}=0' + url: 'https://github.com/openshift/ops-sop/blob/node/V3/Alerts/openshift_node.asciidoc' + priority: high + + diff --git a/roles/os_zabbix/vars/template_ops_tools.yml b/roles/os_zabbix/vars/template_ops_tools.yml new file mode 100644 index 000000000..d1b8a2514 --- /dev/null +++ b/roles/os_zabbix/vars/template_ops_tools.yml @@ -0,0 +1,23 @@ +--- +g_template_ops_tools: + name: Template Operations Tools + zdiscoveryrules: + - name: disc.ops.runner + key: disc.ops.runner + lifetime: 1 + description: "Dynamically register operations runner items" + + zitemprototypes: + - discoveryrule_key: disc.ops.runner + name: "Exit code of ops-runner[{#OSO_COMMAND}]" + key: "disc.ops.runner.command.exitcode[{#OSO_COMMAND}]" + value_type: int + description: "The exit code of the command run from ops-runner" + applications: + - Ops Runner + + ztriggerprototypes: + - name: 'ops-runner[{#OSO_COMMAND}]: non-zero exit code on {HOST.NAME}' + expression: '{Template Operations Tools:disc.ops.runner.command.exitcode[{#OSO_COMMAND}].last()}<>0' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_ops_runner_command.asciidoc' + priority: average diff --git a/roles/os_zabbix/vars/template_os_linux.yml b/roles/os_zabbix/vars/template_os_linux.yml new file mode 100644 index 000000000..3ae1500bc --- /dev/null +++ b/roles/os_zabbix/vars/template_os_linux.yml @@ -0,0 +1,260 @@ +--- +g_template_os_linux: + name: Template OS Linux + zitems: + - key: kernel.uname.sysname + applications: + - Kernel + value_type: string + + - key: kernel.all.cpu.wait.total + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.cpu.irq.hard + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.cpu.idle + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.uname.distro + applications: + - Kernel + value_type: string + + - key: kernel.uname.nodename + applications: + - Kernel + value_type: string + + - key: kernel.all.cpu.irq.soft + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.load.15_minute + applications: + - Kernel + value_type: float + + - key: kernel.all.cpu.sys + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.load.5_minute + applications: + - Kernel + value_type: float + + - key: kernel.all.cpu.nice + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.load.1_minute + applications: + - Kernel + value_type: float + + - key: kernel.uname.version + applications: + - Kernel + value_type: string + + - key: kernel.all.uptime + applications: + - Kernel + value_type: int + + - key: kernel.all.cpu.user + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.uname.machine + applications: + - Kernel + value_type: string + + - key: hinv.ncpu + applications: + - Kernel + value_type: int + + - key: kernel.all.cpu.steal + applications: + - Kernel + value_type: float + units: '%' + + - key: kernel.all.pswitch + applications: + - Kernel + value_type: int + + - key: kernel.uname.release + applications: + - Kernel + value_type: string + + - key: proc.nprocs + applications: + - Kernel + value_type: int + + # Memory Items + - key: mem.freemem + applications: + - Memory + value_type: int + description: "PCP: free system memory metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: mem.util.bufmem + applications: + - Memory + value_type: int + description: "PCP: Memory allocated for buffer_heads.; I/O buffers metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: swap.used + applications: + - Memory + value_type: int + description: "PCP: swap used metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: swap.length + applications: + - Memory + value_type: int + description: "PCP: total swap available metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: mem.physmem + applications: + - Memory + value_type: int + description: "PCP: The value of this metric corresponds to the \"MemTotal\" field reported by /proc/meminfo. Note that this does not necessarily correspond to actual installed physical memory - there may be areas of the physical address space mapped as ROM in various peripheral devices and the bios may be mirroring certain ROMs in RAM." + multiplier: 1024 + units: B + + - key: swap.free + applications: + - Memory + value_type: int + description: "PCP: swap free metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: mem.util.available + applications: + - Memory + value_type: int + description: "PCP: The amount of memory that is available for a new workload, without pushing the system into swap. Estimated from MemFree, Active(file), Inactive(file), and SReclaimable, as well as the \"low\" watermarks from /proc/zoneinfo.; available memory from /proc/meminfo" + multiplier: 1024 + units: B + + - key: mem.util.used + applications: + - Memory + value_type: int + description: "PCP: Used memory is the difference between mem.physmem and mem.freemem; used memory metric from /proc/meminfo" + multiplier: 1024 + units: B + + - key: mem.util.cached + applications: + - Memory + value_type: int + description: "PCP: Memory used by the page cache, including buffered file data. This is in-memory cache for files read from the disk (the pagecache) but doesn't include SwapCached.; page cache metric from /proc/meminfo" + multiplier: 1024 + units: B + + zdiscoveryrules: + - name: disc.filesys + key: disc.filesys + lifetime: 1 + description: "Dynamically register the filesystems" + + zitemprototypes: + - discoveryrule_key: disc.filesys + name: "disc.filesys.full.{#OSO_FILESYS}" + key: "disc.filesys.full[{#OSO_FILESYS}]" + value_type: float + description: "PCP filesys.full option. This is the percent full returned from pcp filesys.full" + applications: + - Disk + + - discoveryrule_key: disc.filesys + name: "Percentage of used inodes on {#OSO_FILESYS}" + key: "disc.filesys.inodes.pused[{#OSO_FILESYS}]" + value_type: float + description: "PCP derived value of percentage of used inodes on a filesystem." + applications: + - Disk + + ztriggerprototypes: + - name: 'Filesystem: {#OSO_FILESYS} has less than 15% free disk space on {HOST.NAME}' + expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>85' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc' + priority: warn + + - name: 'Filesystem: {#OSO_FILESYS} has less than 10% free disk space on {HOST.NAME}' + expression: '{Template OS Linux:disc.filesys.full[{#OSO_FILESYS}].last()}>90' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc' + priority: high + + - name: 'Filesystem: {#OSO_FILESYS} has less than 10% free inodes on {HOST.NAME}' + expression: '{Template OS Linux:disc.filesys.inodes.pused[{#OSO_FILESYS}].last()}>90' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc' + priority: warn + + - name: 'Filesystem: {#OSO_FILESYS} has less than 5% free inodes on {HOST.NAME}' + expression: '{Template OS Linux:disc.filesys.inodes.pused[{#OSO_FILESYS}].last()}>95' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_filesys_full.asciidoc' + priority: high + + ztriggers: + - name: 'Too many TOTAL processes on {HOST.NAME}' + expression: '{Template OS Linux:proc.nprocs.last()}>5000' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_proc.asciidoc' + priority: warn + + - name: 'Lack of available memory on {HOST.NAME}' + expression: '{Template OS Linux:mem.freemem.last()}<30720000' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_memory.asciidoc' + priority: warn + description: 'Alert on less than 30MegaBytes. This is 30 Million Bytes. 30000 KB x 1024' + + # CPU Utilization # + - name: 'CPU idle less than 5% on {HOST.NAME}' + expression: '{Template OS Linux:kernel.all.cpu.idle.last()}<5 and {Template OS Linux:kernel.all.cpu.idle.last(#2)}<5' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_cpu_idle.asciidoc' + priority: average + description: 'CPU is less than 5% idle' + + - name: 'CPU idle less than 10% on {HOST.NAME}' + expression: '{Template OS Linux:kernel.all.cpu.idle.last()}<10 and {Template OS Linux:kernel.all.cpu.idle.last(#2)}<10' + url: 'https://github.com/openshift/ops-sop/blob/master/V3/Alerts/check_cpu_idle.asciidoc' + priority: warn + description: 'CPU is less than 10% idle' + dependencies: + - 'CPU idle less than 5% on {HOST.NAME}' diff --git a/roles/rhel_subscribe/tasks/enterprise.yml b/roles/rhel_subscribe/tasks/enterprise.yml new file mode 100644 index 000000000..e9e6e4bd4 --- /dev/null +++ b/roles/rhel_subscribe/tasks/enterprise.yml @@ -0,0 +1,9 @@ +--- +- name: Disable all repositories + command: subscription-manager repos --disable="*" + +- name: Enable RHEL repositories + command: subscription-manager repos \ + --enable="rhel-7-server-rpms" \ + --enable="rhel-7-server-extras-rpms" \ + --enable="rhel-7-server-ose-3.0-rpms" diff --git a/roles/rhel_subscribe/tasks/main.yml b/roles/rhel_subscribe/tasks/main.yml new file mode 100644 index 000000000..8fb2fc042 --- /dev/null +++ b/roles/rhel_subscribe/tasks/main.yml @@ -0,0 +1,29 @@ +--- +# TODO: Enhance redhat_subscription module +# to make it able to attach to a pool +# to make it able to enable repositories + +- set_fact: + rhel_subscription_user: "{{ lookup('oo_option', 'rhel_subscription_user') | default(rhsub_user, True) | default(omit, True) }}" + rhel_subscription_pass: "{{ lookup('oo_option', 'rhel_subscription_pass') | default(rhsub_pass, True) | default(omit, True) }}" + +- fail: + msg: "This role is only supported for Red Hat hosts" + when: ansible_distribution != 'RedHat' + +- fail: + msg: Either rsub_user or the rhel_subscription_user env variable are required for this role. + when: rhel_subscription_user is not defined + +- fail: + msg: Either rsub_pass or the rhel_subscription_pass env variable are required for this role. + when: rhel_subscription_pass is not defined + +- name: RedHat subscriptions + redhat_subscription: + username: "{{ rhel_subscription_user }}" + password: "{{ rhel_subscription_pass }}" + autosubscribe: yes + +- include: enterprise.yml + when: deployment_type == 'enterprise' diff --git a/roles/rhel_unsubscribe/tasks/main.yml b/roles/rhel_unsubscribe/tasks/main.yml new file mode 100644 index 000000000..2aeb09d83 --- /dev/null +++ b/roles/rhel_unsubscribe/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- name: Remove RedHat subscriptions + redhat_subscription: + state: absent + when: ansible_distribution == "RedHat" diff --git a/utils/.gitignore b/utils/.gitignore new file mode 100644 index 000000000..68759c0ba --- /dev/null +++ b/utils/.gitignore @@ -0,0 +1,45 @@ +package/ + +# Backup files +*.~ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +.tox/ +.coverage +.cache +.noseids +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Sphinx documentation +docs/_build/ diff --git a/utils/README.txt b/utils/README.txt new file mode 100644 index 000000000..6a6a1d24d --- /dev/null +++ b/utils/README.txt @@ -0,0 +1,24 @@ +## Running From Source + +You will need to setup a virtualenv to run from source and execute the unit tests. + +$ virtualenv oo-install +$ source ./oo-install/bin/activate +$ virtualenv --relocatable ./oo-install/ +$ python setup.py install + +The virtualenv bin directory should now be at the start of your $PATH, and oo-install is ready to use from your shell. + +You can exit the virtualenv with: + +$ deactivate + +## Testing + +Install some testing libraries: (we cannot do this via setuptools due to the version virtualenv bundles) + +$ pip install mock nose + +Then run the tests with: + +$ oo-install/bin/nosetests diff --git a/utils/docs/config.md b/utils/docs/config.md new file mode 100644 index 000000000..9399409dd --- /dev/null +++ b/utils/docs/config.md @@ -0,0 +1,72 @@ +# oo-install Supported Configuration File + +Upon completion oo-install will write out a configuration file representing the settings that were gathered and used. This configuration file, or one crafted by hand, can be used to run or re-run the installer and add additional hosts, upgrade, or re-install. + +The default location this config file will be written to ~/.config/openshift/installer.cfg.yml. + +## Example + +``` +variant: openshift-enterprise +variant_version: 3.0 +ansible_ssh_user: root +hosts: +- ip: 10.0.0.1 + hostname: master-private.example.com + public_ip: 24.222.0.1 + public_hostname: master.example.com + master: true + node: true + containerized: true +- ip: 10.0.0.2 + hostname: node1-private.example.com + public_ip: 24.222.0.2 + public_hostname: node1.example.com + node: true +- ip: 10.0.0.3 + hostname: node2-private.example.com + public_ip: 24.222.0.3 + public_hostname: node2.example.com + node: true +``` + +## Primary Settings + +### variant + +The OpenShift variant to install. Currently valid options are: + + * openshift-enterprise + * atomic-enterprise + +### variant_version (optional) + +Default: Latest version for your chosen variant. + +A version which must be valid for your selected variant. If not specified the latest will be assumed. + +Examples: 3.0, 3.1, etc. + +### hosts + +This section defines a list of the hosts you wish to install the OpenShift master/node service on. + +*ip* or *hostname* must be specified so the installer can connect to the system to gather facts before proceeding with the install. + +If *public_ip* or *public_hostname* are not specified, this information will be gathered from the facts and the user will be asked to confirm in an editor. For an unattended install, the installer will error out. (you must provide complete host records for an unattended install) + +*master* and *node* determine the type of services that will be installed. One of these must be set to true for the configuration file to be considered valid. + +*containerized* indicates you want to run OpenShift services in a container on this host. + +### ansible_ssh_user + +Default: root + +Defines the user ansible will use to ssh to remote systems for gathering facts and the installation. + +### ansible_log_path + +Default: /tmp/ansible.log + + diff --git a/utils/etc/ansible.cfg b/utils/etc/ansible.cfg new file mode 100644 index 000000000..b7376ddfc --- /dev/null +++ b/utils/etc/ansible.cfg @@ -0,0 +1,25 @@ +# config file for ansible -- http://ansible.com/ +# ============================================== + +# This config file provides examples for running +# the OpenShift playbooks with the provided +# inventory scripts. Only global defaults are +# left uncommented + +[defaults] +# Add the roles directory to the roles path +roles_path = roles/ + +# Set the log_path +log_path = /tmp/ansible.log + +forks = 10 +host_key_checking = False +nocows = 1 +# Need to handle: +# inventory - derive from OO_ANSIBLE_DIRECTORY env var +# callback_plugins - derive from pkg_resource.resource_filename +# private_key_file - prompt if missing +# remote_tmp - set if provided by user (cli) +# ssh_args - set if provided by user (cli) +# control_path
\ No newline at end of file diff --git a/utils/setup.cfg b/utils/setup.cfg new file mode 100644 index 000000000..79bc67848 --- /dev/null +++ b/utils/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +# This flag says that the code is written to work on both Python 2 and Python +# 3. If at all possible, it is good practice to do this. If you cannot, you +# will need to generate wheels for each Python version that you support. +universal=1 diff --git a/utils/setup.py b/utils/setup.py new file mode 100644 index 000000000..6e2fdd9c0 --- /dev/null +++ b/utils/setup.py @@ -0,0 +1,85 @@ +"""A setuptools based setup module. + +""" + +# Always prefer setuptools over distutils +from setuptools import setup + +setup( + name='ooinstall', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version="3.0.0", + + description="Ansible wrapper for OpenShift Enterprise 3 installation.", + + # The project's main homepage. + url="http://github.com/openshift/openshift-extras/tree/enterprise-3.0/oo-install", + + # Author details + author="openshift@redhat.com", + author_email="OpenShift", + + # Choose your license + license="Apache 2.0", + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + + # What does your project relate to? + keywords='oo-install setuptools development', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + #packages=find_packages(exclude=['contrib', 'docs', 'tests*']), + packages=['ooinstall'], + package_dir={'ooinstall': 'src/ooinstall'}, + + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=['click', 'PyYAML'], + + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # for example: + # $ pip install -e .[dev,test] + #extras_require={ + # 'dev': ['check-manifest'], + # 'test': ['coverage'], + #}, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. + package_data={ + 'ooinstall': ['ansible.cfg', 'ansible_plugins/*'], + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. See: + # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa + # In this case, 'data_file' will be installed into '<sys.prefix>/my_data' + #data_files=[('my_data', ['data/data_file'])], + tests_require=['nose'], + + test_suite='nose.collector', + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points={ + 'console_scripts': [ + 'oo-install=ooinstall.cli_installer:main', + ], + }, +) diff --git a/utils/site_assets/oo-install-bootstrap.sh b/utils/site_assets/oo-install-bootstrap.sh new file mode 100755 index 000000000..e1b2cec90 --- /dev/null +++ b/utils/site_assets/oo-install-bootstrap.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +# Grab command-line arguments +cmdlnargs="$@" + +: ${OO_INSTALL_KEEP_ASSETS:="false"} +: ${OO_INSTALL_CONTEXT:="INSTALLCONTEXT"} +: ${TMPDIR:=/tmp} +: ${OO_INSTALL_LOG:=${TMPDIR}/INSTALLPKGNAME.log} +[[ $TMPDIR != */ ]] && TMPDIR="${TMPDIR}/" + +if [ $OO_INSTALL_CONTEXT != 'origin_vm' ] +then + clear + echo "Checking for necessary tools..." +fi +if [ -e /etc/redhat-release ] +then + for i in python python-virtualenv openssh-clients gcc + do + rpm -q $i >/dev/null 2>&1 || { echo >&2 "Missing installation dependency detected. Please run \"yum install ${i}\"."; exit 1; } + done +fi +for i in python virtualenv ssh gcc +do + command -v $i >/dev/null 2>&1 || { echo >&2 "OpenShift installation requires $i on the PATH but it does not appear to be available. Correct this and rerun the installer."; exit 1; } +done + +# All instances of INSTALLPKGNAME are replaced during packaging with the actual package name. +if [[ -e ./INSTALLPKGNAME.tgz ]] +then + if [ $OO_INSTALL_CONTEXT != 'origin_vm' ] + then + echo "Using bundled assets." + fi + cp INSTALLPKGNAME.tgz ${TMPDIR}/INSTALLPKGNAME.tgz +elif [[ $OO_INSTALL_KEEP_ASSETS == 'true' && -e ${TMPDIR}/INSTALLPKGNAME.tgz ]] +then + if [ $OO_INSTALL_CONTEXT != 'origin_vm' ] + then + echo "Using existing installer assets." + fi +else + echo "Downloading oo-install package to ${TMPDIR}INSTALLPKGNAME.tgz..." + curl -s -o ${TMPDIR}INSTALLPKGNAME.tgz https://install.openshift.com/INSTALLVERPATHINSTALLPKGNAME.tgz +fi + +if [ $OO_INSTALL_CONTEXT != 'origin_vm' ] +then + echo "Extracting oo-install to ${TMPDIR}INSTALLPKGNAME..." +fi +tar xzf ${TMPDIR}INSTALLPKGNAME.tgz -C ${TMPDIR} 2>&1 >> $OO_INSTALL_LOG + +echo "Preparing to install. This can take a minute or two..." +virtualenv ${TMPDIR}/INSTALLPKGNAME 2>&1 >> $OO_INSTALL_LOG +cd ${TMPDIR}/INSTALLPKGNAME 2>&1 >> $OO_INSTALL_LOG +source ./bin/activate 2>&1 >> $OO_INSTALL_LOG +pip install --no-index -f file:///$(readlink -f deps) ansible 2>&1 >> $OO_INSTALL_LOG + +# TODO: these deps should technically be handled as part of installing ooinstall +pip install --no-index -f file:///$(readlink -f deps) click 2>&1 >> $OO_INSTALL_LOG +pip install --no-index ./src/ 2>&1 >> $OO_INSTALL_LOG +echo "Installation preperation done!" 2>&1 >> $OO_INSTALL_LOG + +echo "Using `ansible --version`" 2>&1 >> $OO_INSTALL_LOG + +if [ $OO_INSTALL_CONTEXT != 'origin_vm' ] +then + echo "Starting oo-install..." 2>&1 >> $OO_INSTALL_LOG +else + clear +fi +oo-install $cmdlnargs --ansible-playbook-directory ${TMPDIR}/INSTALLPKGNAME/openshift-ansible-*/ --ansible-log-path $OO_INSTALL_LOG + +if [ $OO_INSTALL_KEEP_ASSETS == 'true' ] +then + echo "Keeping temporary assets in ${TMPDIR}" +else + echo "Removing temporary assets." + rm -rf ${TMPDIR}INSTALLPKGNAME + rm -rf ${TMPDIR}INSTALLPKGNAME.tgz +fi + +echo "Please see $OO_INSTALL_LOG for full output." + +exit diff --git a/utils/site_assets/oo_install_launcher.README.txt b/utils/site_assets/oo_install_launcher.README.txt new file mode 100644 index 000000000..46947b481 --- /dev/null +++ b/utils/site_assets/oo_install_launcher.README.txt @@ -0,0 +1,22 @@ += oo-install Portable Installer Package + +This package is identical to the installer package that can be downloaded +and executed directly from https://install.openshift.com/. + +NOTE: It will still be necessary for this installer to download RPMs from the +internet, unless you have already set up the necessary local repositories. + +To run the installer from this package, run the following command: + +$ ./LAUNCHERNAME + +That command script and the packaged zip file can be burned to a CD or +written to a USB drive and used to run the oo-install utility in places +where the web-based installer is not reachable. + +All of the command-line arguments supported by oo-install can be passed +to this launcher application. + +For more information for Enterprise installs, refer to the OpenShift +Enterprise Administrator Guide: +https://docs.openshift.com/enterprise/latest/welcome/index.html diff --git a/utils/src/DESCRIPTION.rst b/utils/src/DESCRIPTION.rst new file mode 100644 index 000000000..68b3a57f2 --- /dev/null +++ b/utils/src/DESCRIPTION.rst @@ -0,0 +1,13 @@ +A sample Python project +======================= + +This is the description file for the project. + +The file should use UTF-8 encoding and be written using ReStructured Text. It +will be used to generate the project webpage on PyPI, and should be written for +that purpose. + +Typical contents for this file would include an overview of the project, basic +usage examples, etc. Generally, including the project changelog in here is not +a good idea, although a simple "What's New" section for the most recent version +may be appropriate. diff --git a/utils/src/MANIFEST.in b/utils/src/MANIFEST.in new file mode 100644 index 000000000..d4153e738 --- /dev/null +++ b/utils/src/MANIFEST.in @@ -0,0 +1,9 @@ +include DESCRIPTION.rst + +# Include the test suite (FIXME: does not work yet) +# recursive-include tests * + +# If using Python 2.6 or less, then have to include package data, even though +# it's already declared in setup.py +include ooinstall/* +include ansible.cfg diff --git a/utils/src/data/data_file b/utils/src/data/data_file new file mode 100644 index 000000000..7c0646bfd --- /dev/null +++ b/utils/src/data/data_file @@ -0,0 +1 @@ +some data
\ No newline at end of file diff --git a/utils/src/ooinstall/__init__.py b/utils/src/ooinstall/__init__.py new file mode 100644 index 000000000..944dea3b5 --- /dev/null +++ b/utils/src/ooinstall/__init__.py @@ -0,0 +1,5 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=missing-docstring + +from .oo_config import OOConfig diff --git a/utils/src/ooinstall/ansible_plugins/facts_callback.py b/utils/src/ooinstall/ansible_plugins/facts_callback.py new file mode 100644 index 000000000..ea6ed6574 --- /dev/null +++ b/utils/src/ooinstall/ansible_plugins/facts_callback.py @@ -0,0 +1,88 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,no-value-for-parameter + +import os +import yaml + +class CallbackModule(object): + + def __init__(self): + ###################### + # This is ugly stoopid. This should be updated in the following ways: + # 1) it should probably only be used for the + # openshift_facts.yml playbook, so maybe there's some way to check + # a variable that's set when that playbook is run? + try: + self.hosts_yaml_name = os.environ['OO_INSTALL_CALLBACK_FACTS_YAML'] + except KeyError: + raise ValueError('The OO_INSTALL_CALLBACK_FACTS_YAML environment ' + 'variable must be set.') + self.hosts_yaml = os.open(self.hosts_yaml_name, os.O_CREAT | + os.O_WRONLY) + + def on_any(self, *args, **kwargs): + pass + + def runner_on_failed(self, host, res, ignore_errors=False): + pass + + def runner_on_ok(self, host, res): + if res['invocation']['module_args'] == 'var=result': + facts = res['var']['result']['ansible_facts']['openshift'] + hosts_yaml = {} + hosts_yaml[host] = facts + os.write(self.hosts_yaml, yaml.safe_dump(hosts_yaml)) + + def runner_on_skipped(self, host, item=None): + pass + + def runner_on_unreachable(self, host, res): + pass + + def runner_on_no_hosts(self): + pass + + def runner_on_async_poll(self, host, res): + pass + + def runner_on_async_ok(self, host, res): + pass + + def runner_on_async_failed(self, host, res): + pass + + def playbook_on_start(self): + pass + + def playbook_on_notify(self, host, handler): + pass + + def playbook_on_no_hosts_matched(self): + pass + + def playbook_on_no_hosts_remaining(self): + pass + + def playbook_on_task_start(self, name, is_conditional): + pass + + #pylint: disable=too-many-arguments + def playbook_on_vars_prompt(self, varname, private=True, prompt=None, + encrypt=None, confirm=False, salt_size=None, salt=None, default=None): + pass + + def playbook_on_setup(self): + pass + + def playbook_on_import_for_host(self, host, imported_file): + pass + + def playbook_on_not_import_for_host(self, host, missing_file): + pass + + def playbook_on_play_start(self, name): + pass + + def playbook_on_stats(self, stats): + pass diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py new file mode 100644 index 000000000..c2ae00bd1 --- /dev/null +++ b/utils/src/ooinstall/cli_installer.py @@ -0,0 +1,479 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,no-value-for-parameter + +import click +import os +import re +import sys +from ooinstall import install_transactions +from ooinstall import OOConfig +from ooinstall.oo_config import Host +from ooinstall.variants import find_variant, get_variant_version_combos + +DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-util/ansible.cfg' + +def validate_ansible_dir(path): + if not path: + raise click.BadParameter('An ansible path must be provided') + return path + # if not os.path.exists(path)): + # raise click.BadParameter("Path \"{}\" doesn't exist".format(path)) + +def is_valid_hostname(hostname): + if not hostname or len(hostname) > 255: + return False + if hostname[-1] == ".": + hostname = hostname[:-1] # strip exactly one dot from the right, if present + allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE) + return all(allowed.match(x) for x in hostname.split(".")) + +def validate_prompt_hostname(hostname): + if '' == hostname or is_valid_hostname(hostname): + return hostname + raise click.BadParameter('"{}" appears to be an invalid hostname. ' \ + 'Please double-check this value i' \ + 'and re-enter it.'.format(hostname)) + +def get_ansible_ssh_user(): + click.clear() + message = """ +This installation process will involve connecting to remote hosts via ssh. Any +account may be used however if a non-root account is used it must have +passwordless sudo access. +""" + click.echo(message) + return click.prompt('User for ssh access', default='root') + +def list_hosts(hosts): + hosts_idx = range(len(hosts)) + for idx in hosts_idx: + click.echo(' {}: {}'.format(idx, hosts[idx])) + +def delete_hosts(hosts): + while True: + list_hosts(hosts) + del_idx = click.prompt('Select host to delete, y/Y to confirm, ' \ + 'or n/N to add more hosts', default='n') + try: + del_idx = int(del_idx) + hosts.remove(hosts[del_idx]) + except IndexError: + click.echo("\"{}\" doesn't match any hosts listed.".format(del_idx)) + except ValueError: + try: + response = del_idx.lower() + if response in ['y', 'n']: + return hosts, response + click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx)) + except AttributeError: + click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx)) + return hosts, None + +def collect_hosts(): + """ + Collect host information from user. This will later be filled in using + ansible. + + Returns: a list of host information collected from the user + """ + click.clear() + click.echo('***Host Configuration***') + message = """ +The OpenShift Master serves the API and web console. It also coordinates the +jobs that have to run across the environment. It can even run the datastore. +For wizard based installations the database will be embedded. It's possible to +change this later using etcd from Red Hat Enterprise Linux 7. + +Any Masters configured as part of this installation process will also be +configured as Nodes. This is so that the Master will be able to proxy to Pods +from the API. By default this Node will be unscheduleable but this can be changed +after installation with 'oadm manage-node'. + +The OpenShift Node provides the runtime environments for containers. It will +host the required services to be managed by the Master. + +http://docs.openshift.com/enterprise/latest/architecture/infrastructure_components/kubernetes_infrastructure.html#master +http://docs.openshift.com/enterprise/3.0/architecture/infrastructure_components/kubernetes_infrastructure.html#node + """ + click.echo(message) + + hosts = [] + more_hosts = True + ip_regex = re.compile(r'^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$') + + while more_hosts: + host_props = {} + hostname_or_ip = click.prompt('Enter hostname or IP address:', + default='', + value_proc=validate_prompt_hostname) + + if ip_regex.match(hostname_or_ip): + host_props['ip'] = hostname_or_ip + else: + host_props['hostname'] = hostname_or_ip + + host_props['master'] = click.confirm('Will this host be an OpenShift Master?') + host_props['node'] = True + + rpm_or_container = click.prompt('Will this host be RPM or Container based (rpm/container)?', + type=click.Choice(['rpm', 'container']), + default='rpm') + if rpm_or_container == 'container': + host_props['containerized'] = True + else: + host_props['containerized'] = False + + host = Host(**host_props) + + hosts.append(host) + + more_hosts = click.confirm('Do you want to add additional hosts?') + return hosts + +def confirm_hosts_facts(oo_cfg, callback_facts): + hosts = oo_cfg.hosts + click.clear() + message = """ +A list of the facts gathered from the provided hosts follows. Because it is +often the case that the hostname for a system inside the cluster is different +from the hostname that is resolveable from command line or web clients +these settings cannot be validated automatically. + +For some cloud providers the installer is able to gather metadata exposed in +the instance so reasonable defaults will be provided. + +Plese confirm that they are correct before moving forward. + +""" + notes = """ +Format: + +IP,public IP,hostname,public hostname + +Notes: + * The installation host is the hostname from the installer's perspective. + * The IP of the host should be the internal IP of the instance. + * The public IP should be the externally accessible IP associated with the instance + * The hostname should resolve to the internal IP from the instances + themselves. + * The public hostname should resolve to the external ip from hosts outside of + the cloud. +""" + + # For testing purposes we need to click.echo only once, so build up + # the message: + output = message + + default_facts_lines = [] + default_facts = {} + validated_facts = {} + for h in hosts: + default_facts[h] = {} + h.ip = callback_facts[str(h)]["common"]["ip"] + h.public_ip = callback_facts[str(h)]["common"]["public_ip"] + h.hostname = callback_facts[str(h)]["common"]["hostname"] + h.public_hostname = callback_facts[str(h)]["common"]["public_hostname"] + + validated_facts[h] = {} + default_facts_lines.append(",".join([h.ip, + h.public_ip, + h.hostname, + h.public_hostname])) + output = "%s\n%s" % (output, ",".join([h.ip, + h.public_ip, + h.hostname, + h.public_hostname])) + + output = "%s\n%s" % (output, notes) + click.echo(output) + facts_confirmed = click.confirm("Do the above facts look correct?") + if not facts_confirmed: + message = """ +Edit %s with the desired values and rerun oo-install with --unattended . +""" % oo_cfg.config_path + click.echo(message) + # Make sure we actually write out the config file. + oo_cfg.save_to_disk() + sys.exit(0) + return default_facts + +def get_variant_and_version(): + message = "\nWhich variant would you like to install?\n\n" + + i = 1 + combos = get_variant_version_combos() + for (variant, version) in combos: + message = "%s\n(%s) %s %s" % (message, i, variant.description, + version.name) + i = i + 1 + + click.echo(message) + response = click.prompt("Choose a variant from above: ", default=1) + product, version = combos[response - 1] + + return product, version + +def confirm_continue(message): + click.echo(message) + click.confirm("Are you ready to continue?", default=False, abort=True) + return + +def error_if_missing_info(oo_cfg): + missing_info = False + if not oo_cfg.hosts: + missing_info = True + click.echo('For unattended installs, hosts must be specified on the ' + 'command line or in the config file: %s' % oo_cfg.config_path) + sys.exit(1) + + if 'ansible_ssh_user' not in oo_cfg.settings: + click.echo("Must specify ansible_ssh_user in configuration file.") + sys.exit(1) + + # Lookup a variant based on the key we were given: + if not oo_cfg.settings['variant']: + click.echo("No variant specified in configuration file.") + sys.exit(1) + + ver = None + if 'variant_version' in oo_cfg.settings: + ver = oo_cfg.settings['variant_version'] + variant, version = find_variant(oo_cfg.settings['variant'], version=ver) + if variant is None or version is None: + err_variant_name = oo_cfg.settings['variant'] + if ver: + err_variant_name = "%s %s" % (err_variant_name, ver) + click.echo("%s is not an installable variant." % err_variant_name) + sys.exit(1) + oo_cfg.settings['variant_version'] = version.name + + missing_facts = oo_cfg.calc_missing_facts() + if len(missing_facts) > 0: + missing_info = True + click.echo('For unattended installs, facts must be provided for all masters/nodes:') + for host in missing_facts: + click.echo('Host "%s" missing facts: %s' % (host, ", ".join(missing_facts[host]))) + + if missing_info: + sys.exit(1) + + +def get_missing_info_from_user(oo_cfg): + """ Prompts the user for any information missing from the given configuration. """ + click.clear() + + message = """ +Welcome to the OpenShift Enterprise 3 installation. + +Please confirm that following prerequisites have been met: + +* All systems where OpenShift will be installed are running Red Hat Enterprise + Linux 7. +* All systems are properly subscribed to the required OpenShift Enterprise 3 + repositories. +* All systems have run docker-storage-setup (part of the Red Hat docker RPM). +* All systems have working DNS that resolves not only from the perspective of + the installer but also from within the cluster. + +When the process completes you will have a default configuration for Masters +and Nodes. For ongoing environment maintenance it's recommended that the +official Ansible playbooks be used. + +For more information on installation prerequisites please see: +https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.html +""" + confirm_continue(message) + click.clear() + + if oo_cfg.settings.get('ansible_ssh_user', '') == '': + oo_cfg.settings['ansible_ssh_user'] = get_ansible_ssh_user() + click.clear() + + if not oo_cfg.hosts: + oo_cfg.hosts = collect_hosts() + click.clear() + + if oo_cfg.settings.get('variant', '') == '': + variant, version = get_variant_and_version() + oo_cfg.settings['variant'] = variant.name + oo_cfg.settings['variant_version'] = version.name + click.clear() + + return oo_cfg + + +def collect_new_nodes(): + click.clear() + click.echo('***New Node Configuration***') + message = """ +Add new nodes here + """ + click.echo(message) + return collect_hosts() + +def get_installed_hosts(hosts, callback_facts): + installed_hosts = [] + for host in hosts: + if(host.name in callback_facts.keys() + and 'common' in callback_facts[host.name].keys() + and callback_facts[host.name]['common'].get('version', '') + and callback_facts[host.name]['common'].get('version', '') != 'None'): + installed_hosts.append(host) + return installed_hosts + +def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): + + # Copy the list of existing hosts so we can remove any already installed nodes. + hosts_to_run_on = list(oo_cfg.hosts) + + # Check if master or nodes already have something installed + installed_hosts = get_installed_hosts(oo_cfg.hosts, callback_facts) + if len(installed_hosts) > 0: + # present a message listing already installed hosts + for host in installed_hosts: + if host.master: + click.echo("{} is already an OpenShift Master".format(host)) + # Masters stay in the list, we need to run against them when adding + # new nodes. + elif host.node: + click.echo("{} is already an OpenShift Node".format(host)) + hosts_to_run_on.remove(host) + # for unattended either continue if they force install or exit if they didn't + if unattended: + if not force: + click.echo('Installed environment detected and no additional nodes specified: ' \ + 'aborting. If you want a fresh install, use --force') + sys.exit(1) + # for attended ask the user what to do + else: + click.echo('Installed environment detected and no additional nodes specified. ') + response = click.prompt('Do you want to (1) add more nodes or ' \ + '(2) perform a clean install?', type=int) + if response == 1: # add more nodes + new_nodes = collect_new_nodes() + + hosts_to_run_on.extend(new_nodes) + oo_cfg.hosts.extend(new_nodes) + + install_transactions.set_config(oo_cfg) + callback_facts, error = install_transactions.default_facts(oo_cfg.hosts) + if error: + click.echo("There was a problem fetching the required information. " \ + "See {} for details.".format(oo_cfg.settings['ansible_log_path'])) + sys.exit(1) + else: + pass # proceeding as normal should do a clean install + + return hosts_to_run_on, callback_facts + +@click.command() +@click.option('--configuration', '-c', + type=click.Path(file_okay=True, + dir_okay=False, + writable=True, + readable=True), + default=None) +@click.option('--ansible-playbook-directory', + '-a', + type=click.Path(exists=True, + file_okay=False, + dir_okay=True, + writable=True, + readable=True), + # callback=validate_ansible_dir, + envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY') +@click.option('--ansible-config', + type=click.Path(file_okay=True, + dir_okay=False, + writable=True, + readable=True), + default=None) +@click.option('--ansible-log-path', + type=click.Path(file_okay=True, + dir_okay=False, + writable=True, + readable=True), + default="/tmp/ansible.log") +@click.option('--unattended', '-u', is_flag=True, default=False) +@click.option('--force', '-f', is_flag=True, default=False) +#pylint: disable=too-many-arguments +# Main CLI entrypoint, not much we can do about too many arguments. +def main(configuration, ansible_playbook_directory, ansible_config, ansible_log_path, unattended, force): + oo_cfg = OOConfig(configuration) + + if not ansible_playbook_directory: + ansible_playbook_directory = oo_cfg.settings.get('ansible_playbook_directory', '') + + if ansible_config: + oo_cfg.settings['ansible_config'] = ansible_config + elif os.path.exists(DEFAULT_ANSIBLE_CONFIG): + # If we're installed by RPM this file should exist and we can use it as our default: + oo_cfg.settings['ansible_config'] = DEFAULT_ANSIBLE_CONFIG + + validate_ansible_dir(ansible_playbook_directory) + oo_cfg.settings['ansible_playbook_directory'] = ansible_playbook_directory + oo_cfg.ansible_playbook_directory = ansible_playbook_directory + + oo_cfg.settings['ansible_log_path'] = ansible_log_path + install_transactions.set_config(oo_cfg) + + if unattended: + error_if_missing_info(oo_cfg) + else: + oo_cfg = get_missing_info_from_user(oo_cfg) + + click.echo('Gathering information from hosts...') + callback_facts, error = install_transactions.default_facts(oo_cfg.hosts) + if error: + click.echo("There was a problem fetching the required information. " \ + "Please see {} for details.".format(oo_cfg.settings['ansible_log_path'])) + sys.exit(1) + + hosts_to_run_on, callback_facts = get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force) + + + click.echo('Writing config to: %s' % oo_cfg.config_path) + + # We already verified this is not the case for unattended installs, so this can + # only trigger for live CLI users: + # TODO: if there are *new* nodes and this is a live install, we may need the user + # to confirm the settings for new nodes. Look into this once we're distinguishing + # between new and pre-existing nodes. + if len(oo_cfg.calc_missing_facts()) > 0: + confirm_hosts_facts(oo_cfg, callback_facts) + + oo_cfg.save_to_disk() + + click.echo('Ready to run installation process.') + message = """ +If changes are needed to the values recorded by the installer please update {}. +""".format(oo_cfg.config_path) + if not unattended: + confirm_continue(message) + + error = install_transactions.run_main_playbook(oo_cfg.hosts, + hosts_to_run_on) + if error: + # The bootstrap script will print out the log location. + message = """ +An error was detected. After resolving the problem please relaunch the +installation process. +""" + click.echo(message) + sys.exit(1) + else: + message = """ +The installation was successful! + +If this is your first time installing please take a look at the Administrator +Guide for advanced options related to routing, storage, authentication and much +more: + +http://docs.openshift.com/enterprise/latest/admin_guide/overview.html +""" + click.echo(message) + click.pause() + +if __name__ == '__main__': + main() diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py new file mode 100644 index 000000000..cef6662d7 --- /dev/null +++ b/utils/src/ooinstall/install_transactions.py @@ -0,0 +1,133 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,global-statement,global-variable-not-assigned + +import subprocess +import os +import yaml +from ooinstall.variants import find_variant + +CFG = None + +def set_config(cfg): + global CFG + CFG = cfg + +def generate_inventory(hosts): + print hosts + global CFG + base_inventory_path = CFG.settings['ansible_inventory_path'] + base_inventory = open(base_inventory_path, 'w') + base_inventory.write('\n[OSEv3:children]\nmasters\nnodes\n') + base_inventory.write('\n[OSEv3:vars]\n') + base_inventory.write('ansible_ssh_user={}\n'.format(CFG.settings['ansible_ssh_user'])) + if CFG.settings['ansible_ssh_user'] != 'root': + base_inventory.write('ansible_sudo=true\n') + + # Find the correct deployment type for ansible: + ver = find_variant(CFG.settings['variant'], + version=CFG.settings.get('variant_version', None))[1] + base_inventory.write('deployment_type={}\n'.format(ver.ansible_key)) + + if 'OO_INSTALL_DEVEL_REGISTRY' in os.environ: + base_inventory.write('oreg_url=rcm-img-docker01.build.eng.bos.redhat.com:' + '5001/openshift3/ose-${component}:${version}\n') + if 'OO_INSTALL_PUDDLE_REPO_ENABLE' in os.environ: + base_inventory.write("openshift_additional_repos=[{'id': 'ose-devel', " + "'name': 'ose-devel', " + "'baseurl': 'http://buildvm-devops.usersys.redhat.com" + "/puddle/build/AtomicOpenShift/3.1/latest/RH7-RHAOS-3.1/$basearch/os', " + "'enabled': 1, 'gpgcheck': 0}]\n") + if 'OO_INSTALL_STAGE_REGISTRY' in os.environ: + base_inventory.write('oreg_url=registry.access.stage.redhat.com/openshift3/ose-${component}:${version}\n') + + base_inventory.write('\n[masters]\n') + masters = (host for host in hosts if host.master) + for master in masters: + write_host(master, base_inventory) + base_inventory.write('\n[nodes]\n') + nodes = (host for host in hosts if host.node) + for node in nodes: + # TODO: Until the Master can run the SDN itself we have to configure the Masters + # as Nodes too. + scheduleable = True + # If there's only one Node and it's also a Master we want it to be scheduleable: + if node in masters and len(masters) != 1: + scheduleable = False + write_host(node, base_inventory, scheduleable) + base_inventory.close() + return base_inventory_path + + +def write_host(host, inventory, scheduleable=True): + global CFG + facts = '' + if host.ip: + facts += ' openshift_ip={}'.format(host.ip) + if host.public_ip: + facts += ' openshift_public_ip={}'.format(host.public_ip) + if host.hostname: + facts += ' openshift_hostname={}'.format(host.hostname) + if host.public_hostname: + facts += ' openshift_public_hostname={}'.format(host.public_hostname) + # TODO: For not write_host is handles both master and nodes. + # Technically only nodes will ever need this. + if not scheduleable: + facts += ' openshift_scheduleable=False' + inventory.write('{} {}\n'.format(host, facts)) + + +def load_system_facts(inventory_file, os_facts_path, env_vars): + """ + Retrieves system facts from the remote systems. + """ + FNULL = open(os.devnull, 'w') + status = subprocess.call(['ansible-playbook', + '--inventory-file={}'.format(inventory_file), + os_facts_path], + env=env_vars, + stdout=FNULL) + if not status == 0: + return [], 1 + callback_facts_file = open(CFG.settings['ansible_callback_facts_yaml'], 'r') + callback_facts = yaml.load(callback_facts_file) + callback_facts_file.close() + return callback_facts, 0 + + +def default_facts(hosts): + global CFG + inventory_file = generate_inventory(hosts) + os_facts_path = '{}/playbooks/byo/openshift_facts.yml'.format(CFG.ansible_playbook_directory) + + facts_env = os.environ.copy() + facts_env["OO_INSTALL_CALLBACK_FACTS_YAML"] = CFG.settings['ansible_callback_facts_yaml'] + facts_env["ANSIBLE_CALLBACK_PLUGINS"] = CFG.settings['ansible_plugins_directory'] + if 'ansible_log_path' in CFG.settings: + facts_env["ANSIBLE_LOG_PATH"] = CFG.settings['ansible_log_path'] + if 'ansible_config' in CFG.settings: + facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config'] + return load_system_facts(inventory_file, os_facts_path, facts_env) + + +def run_main_playbook(hosts, hosts_to_run_on): + global CFG + inventory_file = generate_inventory(hosts) + if len(hosts_to_run_on) != len(hosts): + main_playbook_path = os.path.join(CFG.ansible_playbook_directory, + 'playbooks/common/openshift-cluster/scaleup.yml') + else: + main_playbook_path = os.path.join(CFG.ansible_playbook_directory, + 'playbooks/byo/config.yml') + facts_env = os.environ.copy() + if 'ansible_log_path' in CFG.settings: + facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path'] + if 'ansible_config' in CFG.settings: + facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config'] + return run_ansible(main_playbook_path, inventory_file, facts_env) + +def run_ansible(playbook, inventory, env_vars): + return subprocess.call(['ansible-playbook', + '--inventory-file={}'.format(inventory), + playbook], + env=env_vars) diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py new file mode 100644 index 000000000..a2f53cf78 --- /dev/null +++ b/utils/src/ooinstall/oo_config.py @@ -0,0 +1,195 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-many-instance-attributes,too-few-public-methods + +import os +import yaml +from pkg_resources import resource_filename + +PERSIST_SETTINGS = [ + 'ansible_ssh_user', + 'ansible_config', + 'ansible_log_path', + 'variant', + 'variant_version', + ] +REQUIRED_FACTS = ['ip', 'public_ip', 'hostname', 'public_hostname'] + + +class OOConfigFileError(Exception): + """The provided config file path can't be read/written + """ + pass + + +class OOConfigInvalidHostError(Exception): + """ Host in config is missing both ip and hostname. """ + pass + + +class Host(object): + """ A system we will or have installed OpenShift on. """ + def __init__(self, **kwargs): + self.ip = kwargs.get('ip', None) + self.hostname = kwargs.get('hostname', None) + self.public_ip = kwargs.get('public_ip', None) + self.public_hostname = kwargs.get('public_hostname', None) + + # Should this host run as an OpenShift master: + self.master = kwargs.get('master', False) + + # Should this host run as an OpenShift node: + self.node = kwargs.get('node', False) + self.containerized = kwargs.get('containerized', False) + + if self.ip is None and self.hostname is None: + raise OOConfigInvalidHostError("You must specify either 'ip' or 'hostname'") + + if self.master is False and self.node is False: + raise OOConfigInvalidHostError( + "You must specify each host as either a master or a node.") + + # Hosts can be specified with an ip, hostname, or both. However we need + # something authoritative we can connect to and refer to the host by. + # Preference given to the IP if specified as this is more specific. + # We know one must be set by this point. + self.name = self.ip if self.ip is not None else self.hostname + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def to_dict(self): + """ Used when exporting to yaml. """ + d = {} + for prop in ['ip', 'hostname', 'public_ip', 'public_hostname', + 'master', 'node', 'containerized']: + # If the property is defined (not None or False), export it: + if getattr(self, prop): + d[prop] = getattr(self, prop) + return d + + +class OOConfig(object): + new_config = True + default_dir = os.path.normpath( + os.environ.get('XDG_CONFIG_HOME', + os.environ['HOME'] + '/.config/') + '/openshift/') + default_file = '/installer.cfg.yml' + + def __init__(self, config_path): + if config_path: + self.config_path = os.path.normpath(config_path) + else: + self.config_path = os.path.normpath(self.default_dir + + self.default_file) + self.settings = {} + self.read_config() + self.set_defaults() + + def read_config(self, is_new=False): + self.hosts = [] + try: + new_settings = None + if os.path.exists(self.config_path): + cfgfile = open(self.config_path, 'r') + new_settings = yaml.safe_load(cfgfile.read()) + cfgfile.close() + if new_settings: + self.settings = new_settings + # Parse the hosts into DTO objects: + if 'hosts' in self.settings: + for host in self.settings['hosts']: + self.hosts.append(Host(**host)) + + # Watchout for the variant_version coming in as a float: + if 'variant_version' in self.settings: + self.settings['variant_version'] = \ + str(self.settings['variant_version']) + + except IOError, ferr: + raise OOConfigFileError('Cannot open config file "{}": {}'.format(ferr.filename, + ferr.strerror)) + except yaml.scanner.ScannerError: + raise OOConfigFileError('Config file "{}" is not a valid YAML document'.format(self.config_path)) + self.new_config = is_new + + def set_defaults(self): + + if 'ansible_inventory_directory' not in self.settings: + self.settings['ansible_inventory_directory'] = \ + self._default_ansible_inv_dir() + if not os.path.exists(self.settings['ansible_inventory_directory']): + os.makedirs(self.settings['ansible_inventory_directory']) + if 'ansible_plugins_directory' not in self.settings: + self.settings['ansible_plugins_directory'] = resource_filename(__name__, 'ansible_plugins') + + if 'ansible_callback_facts_yaml' not in self.settings: + self.settings['ansible_callback_facts_yaml'] = '%s/callback_facts.yaml' % \ + self.settings['ansible_inventory_directory'] + + if 'ansible_ssh_user' not in self.settings: + self.settings['ansible_ssh_user'] = '' + + self.settings['ansible_inventory_path'] = '{}/hosts'.format(self.settings['ansible_inventory_directory']) + + # clean up any empty sets + for setting in self.settings.keys(): + if not self.settings[setting]: + self.settings.pop(setting) + + def _default_ansible_inv_dir(self): + return os.path.normpath( + os.path.dirname(self.config_path) + "/.ansible") + + def calc_missing_facts(self): + """ + Determine which host facts are not defined in the config. + + Returns a hash of host to a list of the missing facts. + """ + result = {} + + for host in self.hosts: + missing_facts = [] + for required_fact in REQUIRED_FACTS: + if not getattr(host, required_fact): + missing_facts.append(required_fact) + if len(missing_facts) > 0: + result[host.name] = missing_facts + return result + + def save_to_disk(self): + out_file = open(self.config_path, 'w') + out_file.write(self.yaml()) + out_file.close() + + def persist_settings(self): + p_settings = {} + for setting in PERSIST_SETTINGS: + if setting in self.settings and self.settings[setting]: + p_settings[setting] = self.settings[setting] + p_settings['hosts'] = [] + for host in self.hosts: + p_settings['hosts'].append(host.to_dict()) + + if self.settings['ansible_inventory_directory'] != \ + self._default_ansible_inv_dir(): + p_settings['ansible_inventory_directory'] = \ + self.settings['ansible_inventory_directory'] + + return p_settings + + def yaml(self): + return yaml.safe_dump(self.persist_settings(), default_flow_style=False) + + def __str__(self): + return self.yaml() + + def get_host(self, name): + for host in self.hosts: + if host.name == name: + return host + return None diff --git a/utils/src/ooinstall/variants.py b/utils/src/ooinstall/variants.py new file mode 100644 index 000000000..ed98429fc --- /dev/null +++ b/utils/src/ooinstall/variants.py @@ -0,0 +1,74 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-few-public-methods + +""" +Defines the supported variants and versions the installer supports, and metadata +required to run Ansible correctly. + +This module needs to be updated for each major release to allow the new version +to be specified by the user, and to point the generic variants to the latest +version. +""" + + +class Version(object): + def __init__(self, name, ansible_key): + self.name = name # i.e. 3.0, 3.1 + + self.ansible_key = ansible_key + + +class Variant(object): + def __init__(self, name, description, versions): + # Supported variant name: + self.name = name + + # Friendly name for the variant: + self.description = description + + self.versions = versions + + +# WARNING: Keep the versions ordered, most recent last: +OSE = Variant('openshift-enterprise', 'OpenShift Enterprise', + [ + Version('3.0', 'enterprise'), + Version('3.1', 'openshift-enterprise') + ] +) + +AEP = Variant('atomic-enterprise', 'Atomic OpenShift Enterprise', + [ + Version('3.1', 'atomic-enterprise') + ] +) + +# Ordered list of variants we can install, first is the default. +SUPPORTED_VARIANTS = (OSE, AEP) + + +def find_variant(name, version=None): + """ + Locate the variant object for the variant given in config file, and + the correct version to use for it. + Return (None, None) if we can't find a match. + """ + prod = None + for prod in SUPPORTED_VARIANTS: + if prod.name == name: + if version is None: + return (prod, prod.versions[-1]) + for v in prod.versions: + if v.name == version: + return (prod, v) + + return (None, None) + +def get_variant_version_combos(): + combos = [] + for variant in SUPPORTED_VARIANTS: + for ver in variant.versions: + combos.append((variant, ver)) + return combos + diff --git a/utils/test/__init__.py b/utils/test/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/__init__.py diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py new file mode 100644 index 000000000..076fe5dc9 --- /dev/null +++ b/utils/test/cli_installer_tests.py @@ -0,0 +1,471 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name + +import copy +import os +import ConfigParser +import yaml + +import ooinstall.cli_installer as cli + +from click.testing import CliRunner +from test.oo_config_tests import OOInstallFixture +from mock import patch + + +MOCK_FACTS = { + '10.0.0.1': { + 'common': { + 'ip': '10.0.0.1', + 'public_ip': '10.0.0.1', + 'hostname': 'master-private.example.com', + 'public_hostname': 'master.example.com' + } + }, + '10.0.0.2': { + 'common': { + 'ip': '10.0.0.2', + 'public_ip': '10.0.0.2', + 'hostname': 'node1-private.example.com', + 'public_hostname': 'node1.example.com' + } + }, + '10.0.0.3': { + 'common': { + 'ip': '10.0.0.3', + 'public_ip': '10.0.0.3', + 'hostname': 'node2-private.example.com', + 'public_hostname': 'node2.example.com' + } + }, +} + +# Substitute in a product name before use: +SAMPLE_CONFIG = """ +variant: %s +ansible_ssh_user: root +hosts: + - ip: 10.0.0.1 + hostname: master-private.example.com + public_ip: 24.222.0.1 + public_hostname: master.example.com + master: true + node: true + - ip: 10.0.0.2 + hostname: node1-private.example.com + public_ip: 24.222.0.2 + public_hostname: node1.example.com + node: true + - ip: 10.0.0.3 + hostname: node2-private.example.com + public_ip: 24.222.0.3 + public_hostname: node2.example.com + node: true +""" + + +class OOCliFixture(OOInstallFixture): + + def setUp(self): + OOInstallFixture.setUp(self) + self.runner = CliRunner() + + # Add any arguments you would like to test here, the defaults ensure + # we only do unattended invocations here, and using temporary files/dirs. + self.cli_args = ["-a", self.work_dir] + + def run_cli(self): + return self.runner.invoke(cli.main, self.cli_args) + + def assert_result(self, result, exit_code): + if result.exception is not None or result.exit_code != exit_code: + print "Unexpected result from CLI execution" + print "Exit code: %s" % result.exit_code + print "Exception: %s" % result.exception + print result.exc_info + import traceback + traceback.print_exception(*result.exc_info) + print "Output:\n%s" % result.output + self.fail("Exception during CLI execution") + + def _read_yaml(self, config_file_path): + f = open(config_file_path, 'r') + config = yaml.safe_load(f.read()) + f.close() + return config + + +class UnattendedCliTests(OOCliFixture): + + def setUp(self): + OOCliFixture.setUp(self) + self.cli_args.append("-u") + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_cfg_full_run(self, load_facts_mock, run_playbook_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise') + + self.cli_args.extend(["-c", config_file]) + result = self.runner.invoke(cli.main, self.cli_args) + self.assert_result(result, 0) + + load_facts_args = load_facts_mock.call_args[0] + self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"), + load_facts_args[0]) + self.assertEquals(os.path.join(self.work_dir, + "playbooks/byo/openshift_facts.yml"), load_facts_args[1]) + env_vars = load_facts_args[2] + self.assertEquals(os.path.join(self.work_dir, + '.ansible/callback_facts.yaml'), + env_vars['OO_INSTALL_CALLBACK_FACTS_YAML']) + self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH']) + self.assertTrue('ANSIBLE_CONFIG' not in env_vars) + + # Make sure we ran on the expected masters and nodes: + hosts = run_playbook_mock.call_args[0][0] + hosts_to_run_on = run_playbook_mock.call_args[0][1] + self.assertEquals(3, len(hosts)) + self.assertEquals(3, len(hosts_to_run_on)) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_inventory_write(self, load_facts_mock, run_playbook_mock): + + # Add an ssh user so we can verify it makes it to the inventory file: + merged_config = "%s\n%s" % (SAMPLE_CONFIG % 'openshift-enterprise', + "ansible_ssh_user: bob") + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), merged_config) + + self.cli_args.extend(["-c", config_file]) + result = self.runner.invoke(cli.main, self.cli_args) + self.assert_result(result, 0) + + # Check the inventory file looks as we would expect: + inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) + self.assertEquals('bob', + inventory.get('OSEv3:vars', 'ansible_ssh_user')) + self.assertEquals('openshift-enterprise', + inventory.get('OSEv3:vars', 'deployment_type')) + + # Check the masters: + self.assertEquals(1, len(inventory.items('masters'))) + self.assertEquals(3, len(inventory.items('nodes'))) + + for item in inventory.items('masters'): + # ansible host lines do NOT parse nicely: + master_line = item[0] + if item[1] is not None: + master_line = "%s=%s" % (master_line, item[1]) + self.assertTrue('openshift_ip' in master_line) + self.assertTrue('openshift_public_ip' in master_line) + self.assertTrue('openshift_hostname' in master_line) + self.assertTrue('openshift_public_hostname' in master_line) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_variant_version_latest_assumed(self, load_facts_mock, + run_playbook_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise') + + self.cli_args.extend(["-c", config_file]) + result = self.runner.invoke(cli.main, self.cli_args) + self.assert_result(result, 0) + + written_config = self._read_yaml(config_file) + + self.assertEquals('openshift-enterprise', written_config['variant']) + # We didn't specify a version so the latest should have been assumed, + # and written to disk: + self.assertEquals('3.1', written_config['variant_version']) + + # Make sure the correct value was passed to ansible: + inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) + self.assertEquals('openshift-enterprise', + inventory.get('OSEv3:vars', 'deployment_type')) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_variant_version_preserved(self, load_facts_mock, + run_playbook_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + config = SAMPLE_CONFIG % 'openshift-enterprise' + config = '%s\n%s' % (config, 'variant_version: 3.0') + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), config) + + self.cli_args.extend(["-c", config_file]) + result = self.runner.invoke(cli.main, self.cli_args) + self.assert_result(result, 0) + + written_config = self._read_yaml(config_file) + + self.assertEquals('openshift-enterprise', written_config['variant']) + # Make sure our older version was preserved: + # and written to disk: + self.assertEquals('3.0', written_config['variant_version']) + + inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) + self.assertEquals('enterprise', + inventory.get('OSEv3:vars', 'deployment_type')) + + @patch('ooinstall.install_transactions.run_ansible') + @patch('ooinstall.install_transactions.load_system_facts') + def test_no_ansible_config_specified(self, load_facts_mock, run_ansible_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_ansible_mock.return_value = 0 + + config = SAMPLE_CONFIG % 'openshift-enterprise' + + self._ansible_config_test(load_facts_mock, run_ansible_mock, + config, None, None) + + @patch('ooinstall.install_transactions.run_ansible') + @patch('ooinstall.install_transactions.load_system_facts') + def test_ansible_config_specified_cli(self, load_facts_mock, run_ansible_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_ansible_mock.return_value = 0 + + config = SAMPLE_CONFIG % 'openshift-enterprise' + ansible_config = os.path.join(self.work_dir, 'ansible.cfg') + + self._ansible_config_test(load_facts_mock, run_ansible_mock, + config, ansible_config, ansible_config) + + @patch('ooinstall.install_transactions.run_ansible') + @patch('ooinstall.install_transactions.load_system_facts') + def test_ansible_config_specified_in_installer_config(self, + load_facts_mock, run_ansible_mock): + + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_ansible_mock.return_value = 0 + + ansible_config = os.path.join(self.work_dir, 'ansible.cfg') + config = SAMPLE_CONFIG % 'openshift-enterprise' + config = "%s\nansible_config: %s" % (config, ansible_config) + self._ansible_config_test(load_facts_mock, run_ansible_mock, + config, None, ansible_config) + + #pylint: disable=too-many-arguments + # This method allows for drastically simpler tests to write, and the args + # are all useful. + def _ansible_config_test(self, load_facts_mock, run_ansible_mock, + installer_config, ansible_config_cli=None, expected_result=None): + """ + Utility method for testing the ways you can specify the ansible config. + """ + + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_ansible_mock.return_value = 0 + + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), installer_config) + + self.cli_args.extend(["-c", config_file]) + if ansible_config_cli: + self.cli_args.extend(["--ansible-config", ansible_config_cli]) + result = self.runner.invoke(cli.main, self.cli_args) + self.assert_result(result, 0) + + # Test the env vars for facts playbook: + facts_env_vars = load_facts_mock.call_args[0][2] + if expected_result: + self.assertEquals(expected_result, facts_env_vars['ANSIBLE_CONFIG']) + else: + self.assertFalse('ANSIBLE_CONFIG' in facts_env_vars) + + # Test the env vars for main playbook: + env_vars = run_ansible_mock.call_args[0][2] + if expected_result: + self.assertEquals(expected_result, env_vars['ANSIBLE_CONFIG']) + else: + self.assertFalse('ANSIBLE_CONFIG' in env_vars) + + +class AttendedCliTests(OOCliFixture): + + def setUp(self): + OOCliFixture.setUp(self) + # Doesn't exist but keeps us from reading the local users config: + self.config_file = os.path.join(self.work_dir, 'config.yml') + self.cli_args.extend(["-c", self.config_file]) + + #pylint: disable=too-many-arguments + def _build_input(self, ssh_user=None, hosts=None, variant_num=None, + add_nodes=None, confirm_facts=None): + """ + Builds a CLI input string with newline characters to simulate + the full run. + This gives us only one place to update when the input prompts change. + """ + + inputs = [ + 'y', # let's proceed + ] + if ssh_user: + inputs.append(ssh_user) + + if hosts: + i = 0 + for (host, is_master) in hosts: + inputs.append(host) + inputs.append('y' if is_master else 'n') + inputs.append('rpm') + if i < len(hosts) - 1: + inputs.append('y') # Add more hosts + else: + inputs.append('n') # Done adding hosts + i += 1 + + if variant_num: + inputs.append(str(variant_num)) # Choose variant + version + + # TODO: support option 2, fresh install + if add_nodes: + inputs.append('1') # Add more nodes + i = 0 + for (host, is_master) in add_nodes: + inputs.append(host) + inputs.append('y' if is_master else 'n') + inputs.append('rpm') + if i < len(add_nodes) - 1: + inputs.append('y') # Add more hosts + else: + inputs.append('n') # Done adding hosts + i += 1 + + inputs.extend([ + confirm_facts, + 'y', # lets do this + ]) + + return '\n'.join(inputs) + + def _verify_load_facts(self, load_facts_mock): + """ Check that we ran load facts with expected inputs. """ + load_facts_args = load_facts_mock.call_args[0] + self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"), + load_facts_args[0]) + self.assertEquals(os.path.join(self.work_dir, + "playbooks/byo/openshift_facts.yml"), load_facts_args[1]) + env_vars = load_facts_args[2] + self.assertEquals(os.path.join(self.work_dir, + '.ansible/callback_facts.yaml'), + env_vars['OO_INSTALL_CALLBACK_FACTS_YAML']) + self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH']) + + def _verify_run_playbook(self, run_playbook_mock, exp_hosts_len, exp_hosts_to_run_on_len): + """ Check that we ran playbook with expected inputs. """ + hosts = run_playbook_mock.call_args[0][0] + hosts_to_run_on = run_playbook_mock.call_args[0][1] + self.assertEquals(exp_hosts_len, len(hosts)) + self.assertEquals(exp_hosts_to_run_on_len, len(hosts_to_run_on)) + + def _verify_config_hosts(self, written_config, host_count): + self.assertEquals(host_count, len(written_config['hosts'])) + for h in written_config['hosts']: + self.assertTrue(h['node']) + self.assertTrue('ip' in h) + self.assertTrue('hostname' in h) + self.assertTrue('public_ip' in h) + self.assertTrue('public_hostname' in h) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_full_run(self, load_facts_mock, run_playbook_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + cli_input = self._build_input(hosts=[ + ('10.0.0.1', True), + ('10.0.0.2', False), + ('10.0.0.3', False)], + ssh_user='root', + variant_num=1, + confirm_facts='y') + result = self.runner.invoke(cli.main, self.cli_args, + input=cli_input) + self.assert_result(result, 0) + + self._verify_load_facts(load_facts_mock) + self._verify_run_playbook(run_playbook_mock, 3, 3) + + written_config = self._read_yaml(self.config_file) + self._verify_config_hosts(written_config, 3) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_add_nodes(self, load_facts_mock, run_playbook_mock): + + # Modify the mock facts to return a version indicating OpenShift + # is already installed on our master, and the first node. + mock_facts = copy.deepcopy(MOCK_FACTS) + mock_facts['10.0.0.1']['common']['version'] = "3.0.0" + mock_facts['10.0.0.2']['common']['version'] = "3.0.0" + + load_facts_mock.return_value = (mock_facts, 0) + run_playbook_mock.return_value = 0 + + cli_input = self._build_input(hosts=[ + ('10.0.0.1', True), + ('10.0.0.2', False), + ], + add_nodes=[('10.0.0.3', False)], + ssh_user='root', + variant_num=1, + confirm_facts='y') + result = self.runner.invoke(cli.main, + self.cli_args, + input=cli_input) + self.assert_result(result, 0) + + self._verify_load_facts(load_facts_mock) + self._verify_run_playbook(run_playbook_mock, 3, 2) + + written_config = self._read_yaml(self.config_file) + self._verify_config_hosts(written_config, 3) + + @patch('ooinstall.install_transactions.run_main_playbook') + @patch('ooinstall.install_transactions.load_system_facts') + def test_fresh_install_with_config(self, load_facts_mock, run_playbook_mock): + load_facts_mock.return_value = (MOCK_FACTS, 0) + run_playbook_mock.return_value = 0 + + config_file = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), + SAMPLE_CONFIG % 'openshift-enterprise') + cli_input = self._build_input(confirm_facts='y') + self.cli_args.extend(["-c", config_file]) + result = self.runner.invoke(cli.main, + self.cli_args, + input=cli_input) + self.assert_result(result, 0) + + self._verify_load_facts(load_facts_mock) + self._verify_run_playbook(run_playbook_mock, 3, 3) + + written_config = self._read_yaml(config_file) + self._verify_config_hosts(written_config, 3) + +# TODO: test with config file, attended add node +# TODO: test with config file, attended new node already in config file +# TODO: test with config file, attended new node already in config file, plus manually added nodes +# TODO: test with config file, attended reject facts diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py new file mode 100644 index 000000000..01af33fd9 --- /dev/null +++ b/utils/test/oo_config_tests.py @@ -0,0 +1,158 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name + +import os +import unittest +import tempfile +import shutil +import yaml + +from ooinstall.oo_config import OOConfig, Host, OOConfigInvalidHostError + +SAMPLE_CONFIG = """ +variant: openshift-enterprise +ansible_ssh_user: root +hosts: + - ip: 10.0.0.1 + hostname: master-private.example.com + public_ip: 24.222.0.1 + public_hostname: master.example.com + master: true + node: true + - ip: 10.0.0.2 + hostname: node1-private.example.com + public_ip: 24.222.0.2 + public_hostname: node1.example.com + node: true + - ip: 10.0.0.3 + hostname: node2-private.example.com + public_ip: 24.222.0.3 + public_hostname: node2.example.com + node: true +""" + +CONFIG_INCOMPLETE_FACTS = """ +hosts: + - ip: 10.0.0.1 + hostname: master-private.example.com + public_ip: 24.222.0.1 + public_hostname: master.example.com + master: true + - ip: 10.0.0.2 + hostname: node1-private.example.com + public_ip: 24.222.0.2 + node: true + - ip: 10.0.0.3 + node: true +""" + + +class OOInstallFixture(unittest.TestCase): + + def setUp(self): + self.tempfiles = [] + self.work_dir = tempfile.mkdtemp(prefix='ooconfigtests') + self.tempfiles.append(self.work_dir) + + def tearDown(self): + for path in self.tempfiles: + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + + def write_config(self, path, config_str): + """ + Write given config to a temporary file which will be cleaned + up in teardown. + Returns full path to the file. + """ + cfg_file = open(path, 'w') + cfg_file.write(config_str) + cfg_file.close() + return path + + +class OOConfigTests(OOInstallFixture): + + def test_load_config(self): + + cfg_path = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), SAMPLE_CONFIG) + ooconfig = OOConfig(cfg_path) + + self.assertEquals(3, len(ooconfig.hosts)) + self.assertEquals("10.0.0.1", ooconfig.hosts[0].name) + self.assertEquals("10.0.0.1", ooconfig.hosts[0].ip) + self.assertEquals("master-private.example.com", ooconfig.hosts[0].hostname) + + self.assertEquals(["10.0.0.1", "10.0.0.2", "10.0.0.3"], + [host['ip'] for host in ooconfig.settings['hosts']]) + + self.assertEquals('openshift-enterprise', ooconfig.settings['variant']) + + def test_load_complete_facts(self): + cfg_path = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), SAMPLE_CONFIG) + ooconfig = OOConfig(cfg_path) + missing_host_facts = ooconfig.calc_missing_facts() + self.assertEquals(0, len(missing_host_facts)) + + # Test missing optional facts the user must confirm: + def test_load_host_incomplete_facts(self): + cfg_path = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), CONFIG_INCOMPLETE_FACTS) + ooconfig = OOConfig(cfg_path) + missing_host_facts = ooconfig.calc_missing_facts() + self.assertEquals(2, len(missing_host_facts)) + self.assertEquals(1, len(missing_host_facts['10.0.0.2'])) + self.assertEquals(3, len(missing_host_facts['10.0.0.3'])) + + def test_write_config(self): + cfg_path = self.write_config(os.path.join(self.work_dir, + 'ooinstall.conf'), SAMPLE_CONFIG) + ooconfig = OOConfig(cfg_path) + ooconfig.save_to_disk() + + f = open(cfg_path, 'r') + written_config = yaml.safe_load(f.read()) + f.close() + + self.assertEquals(3, len(written_config['hosts'])) + for h in written_config['hosts']: + self.assertTrue('ip' in h) + self.assertTrue('public_ip' in h) + self.assertTrue('hostname' in h) + self.assertTrue('public_hostname' in h) + + self.assertTrue('ansible_ssh_user' in written_config) + self.assertTrue('variant' in written_config) + + # Some advanced settings should not get written out if they + # were not specified by the user: + self.assertFalse('ansible_inventory_directory' in written_config) + + +class HostTests(OOInstallFixture): + + def test_load_host_no_ip_or_hostname(self): + yaml_props = { + 'public_ip': '192.168.0.1', + 'public_hostname': 'a.example.com', + 'master': True + } + self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props) + + def test_load_host_no_master_or_node_specified(self): + yaml_props = { + 'ip': '192.168.0.1', + 'hostname': 'a.example.com', + 'public_ip': '192.168.0.1', + 'public_hostname': 'a.example.com', + } + self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props) + + + + diff --git a/utils/workflows/enterprise_deploy/openshift.sh b/utils/workflows/enterprise_deploy/openshift.sh new file mode 100644 index 000000000..040a9a84d --- /dev/null +++ b/utils/workflows/enterprise_deploy/openshift.sh @@ -0,0 +1,2 @@ +# This file is not used for OpenShift 3.0. It's merely an artifact of the the +# installation framework originally used for OpenShift 2.x. |