diff options
Diffstat (limited to 'roles')
142 files changed, 12298 insertions, 1355 deletions
diff --git a/roles/ansible_service_broker/tasks/install.yml b/roles/ansible_service_broker/tasks/install.yml index ba2f7293b..f869b5fae 100644 --- a/roles/ansible_service_broker/tasks/install.yml +++ b/roles/ansible_service_broker/tasks/install.yml @@ -72,6 +72,15 @@        - apiGroups: ["image.openshift.io", ""]          resources: ["images"]          verbs: ["get", "list"] +      - apiGroups: ["network.openshift.io"] +        resources: ["clusternetworks", "netnamespaces"] +        verbs: ["get"] +      - apiGroups: ["network.openshift.io"] +        resources: ["netnamespaces"] +        verbs: ["update"] +      - apiGroups: ["networking.k8s.io"] +        resources: ["networkpolicies"] +        verbs: ["create", "delete"]  - name: Create asb-access cluster role    oc_clusterrole: @@ -366,6 +375,11 @@                    secret:                      secretName: etcd-auth-secret +- name: set auth name and type facts if needed +  set_fact: +    ansible_service_broker_registry_auth_type: "secret" +    ansible_service_broker_registry_auth_name: "asb-registry-auth" +  when: ansible_service_broker_registry_user != "" and ansible_service_broker_registry_password != ""  # TODO: saw a oc_configmap in the library, but didn't understand how to get it to do the following:  - name: Create config map for ansible-service-broker @@ -393,6 +407,8 @@                  org:  {{ ansible_service_broker_registry_organization }}                  tag:  {{ ansible_service_broker_registry_tag }}                  white_list: {{  ansible_service_broker_registry_whitelist | to_yaml }} +                auth_type: "{{ ansible_service_broker_registry_auth_type | default("") }}" +                auth_name: "{{ ansible_service_broker_registry_auth_name | default("") }}"                - type: local_openshift                  name: localregistry                  namespaces: ['openshift'] @@ -438,6 +454,7 @@          data: "{{ ansible_service_broker_registry_user }}"        - path: password          data: "{{ ansible_service_broker_registry_password }}" +  when: ansible_service_broker_registry_user != "" and ansible_service_broker_registry_password != ""  - name: Create the Broker resource in the catalog    oc_obj: diff --git a/roles/calico_master/tasks/main.yml b/roles/calico_master/tasks/main.yml index 05415a4d6..834ebba64 100644 --- a/roles/calico_master/tasks/main.yml +++ b/roles/calico_master/tasks/main.yml @@ -23,7 +23,7 @@      -f {{ mktemp.stdout }}/calico-policy-controller.yml      --config={{ openshift.common.config_base }}/master/admin.kubeconfig    register: calico_create_output -  failed_when: ('already exists' not in calico_create_output.stderr) and ('created' not in calico_create_output.stdout) +  failed_when: "('already exists' not in calico_create_output.stderr) and ('created' not in calico_create_output.stdout) and calico_create_output.rc != 0"    changed_when: ('created' in calico_create_output.stdout)  - name: Calico Master | Delete temp directory diff --git a/roles/container_runtime/defaults/main.yml b/roles/container_runtime/defaults/main.yml index d0e37e2f4..8203d15f5 100644 --- a/roles/container_runtime/defaults/main.yml +++ b/roles/container_runtime/defaults/main.yml @@ -101,45 +101,34 @@ l_crt_crio_image_tag_dict:    openshift-enterprise: "{{ l_openshift_image_tag }}"    origin: "{{ openshift_crio_image_tag | default(openshift_crio_image_tag_default) }}" -l_crt_crio_image_prepend_dict: -  openshift-enterprise: "registry.access.redhat.com/openshift3" -  origin: "docker.io/gscrivano" -  l_crt_crio_image_dict: -  Fedora: -    crio_image_name: "cri-o-fedora" -    crio_image_tag: "latest" -  CentOS: -    crio_image_name: "cri-o-centos" -    crio_image_tag: "latest" -  RedHat: -    crio_image_name: "cri-o" -    crio_image_tag: "{{ openshift_crio_image_tag | default(l_crt_crio_image_tag_dict[openshift_deployment_type]) }}" - -l_crio_image_prepend: "{{ l_crt_crio_image_prepend_dict[openshift_deployment_type] }}" -l_crio_image_name: "{{ l_crt_crio_image_dict[ansible_distribution]['crio_image_name'] }}" -l_crio_image_tag: "{{ l_crt_crio_image_dict[ansible_distribution] }}" - -l_crio_image_default: "{{ l_crio_image_prepend }}/{{ l_crio_image_name }}:{{ l_crio_image_tag }}" +  Fedora: "registry.fedoraproject.org/latest/cri-o" +  CentOS: "registry.centos.org/projectatomic/cri-o" +  RedHat: "registry.access.redhat.com/openshift3/cri-o" + +l_crio_image_name: "{{ l_crt_crio_image_dict[ansible_distribution] }}" +l_crio_image_tag: "{{ l_crt_crio_image_tag_dict[openshift_deployment_type] }}" + +l_crio_image_default: "{{ l_crio_image_name }}:{{ l_crio_image_tag }}"  l_crio_image: "{{ openshift_crio_systemcontainer_image_override | default(l_crio_image_default) }}"  # ----------------------- #  # systemcontainers_docker #  # ----------------------- # -l_crt_docker_image_prepend_dict: -  Fedora: "registry.fedoraproject.org/latest" -  Centos: "docker.io/gscrivano" -  RedHat: "registry.access.redhat.com/openshift3" +l_crt_docker_image_dict: +  Fedora: "registry.fedoraproject.org/latest/docker" +  Centos: "registry.centos.org/projectatomic/docker" +  RedHat: "registry.access.redhat.com/openshift3/container-engine"  openshift_docker_image_tag_default: "latest"  l_crt_docker_image_tag_dict:    openshift-enterprise: "{{ l_openshift_image_tag }}"    origin: "{{ openshift_docker_image_tag | default(openshift_docker_image_tag_default) }}" -l_docker_image_prepend: "{{ l_crt_docker_image_prepend_dict[ansible_distribution] }}" +l_docker_image_prepend: "{{ l_crt_docker_image_dict[ansible_distribution] }}"  l_docker_image_tag: "{{ l_crt_docker_image_tag_dict[openshift_deployment_type] }}" -l_docker_image_default: "{{ l_docker_image_prepend }}/{{ openshift_docker_service_name }}:{{ l_docker_image_tag }}" +l_docker_image_default: "{{ l_docker_image_prepend }}:{{ l_docker_image_tag }}"  l_docker_image: "{{ openshift_docker_systemcontainer_image_override | default(l_docker_image_default) }}"  l_is_node_system_container: "{{ (openshift_use_node_system_container | default(openshift_use_system_containers | default(false)) | bool) }}" diff --git a/roles/container_runtime/tasks/package_docker.yml b/roles/container_runtime/tasks/package_docker.yml index d6e7e7fed..ed9a2709b 100644 --- a/roles/container_runtime/tasks/package_docker.yml +++ b/roles/container_runtime/tasks/package_docker.yml @@ -1,6 +1,17 @@  ---  - include_tasks: common/pre.yml +# In some cases, some services may be run as containers and docker may still +# be installed via rpm. +- include_tasks: common/atomic_proxy.yml +  when: +  - > +    (openshift_use_system_containers | default(False)) | bool +    or (openshift_use_etcd_system_container | default(False)) | bool +    or (openshift_use_openvswitch_system_container | default(False)) | bool +    or (openshift_use_node_system_container | default(False)) | bool +    or (openshift_use_master_system_container | default(False)) | bool +  - name: Get current installed Docker version    command: "{{ repoquery_installed }} --qf '%{version}' docker"    when: not openshift_is_atomic | bool diff --git a/roles/etcd/tasks/auxiliary/drop_etcdctl.yml b/roles/etcd/tasks/auxiliary/drop_etcdctl.yml index 881a8c270..cab835e20 100644 --- a/roles/etcd/tasks/auxiliary/drop_etcdctl.yml +++ b/roles/etcd/tasks/auxiliary/drop_etcdctl.yml @@ -1,7 +1,7 @@  ---  - name: Install etcd for etcdctl    package: name=etcd{{ '-' + etcd_version if etcd_version is defined else '' }} state=present -  when: not openshift_is_atomic | bool +  when: not openshift_is_containerized | bool    register: result    until: result is succeeded diff --git a/roles/flannel/meta/main.yml b/roles/flannel/meta/main.yml index 7634b8192..38d2f748b 100644 --- a/roles/flannel/meta/main.yml +++ b/roles/flannel/meta/main.yml @@ -14,3 +14,4 @@ galaxy_info:    - system  dependencies:  - role: lib_utils +- role: openshift_facts diff --git a/roles/kuryr/tasks/node.yaml b/roles/kuryr/tasks/node.yaml index 08f2d5adc..41d0ead20 100644 --- a/roles/kuryr/tasks/node.yaml +++ b/roles/kuryr/tasks/node.yaml @@ -40,7 +40,7 @@      regexp: '^OPTIONS="?(.*?)"?$'      backrefs: yes      backup: yes -    line: 'OPTIONS="\1 --disable dns,proxy,plugins"' +    line: 'OPTIONS="\1 --disable proxy"'  - name: force node restart to disable the proxy    service: diff --git a/roles/kuryr/templates/cni-daemonset.yaml.j2 b/roles/kuryr/templates/cni-daemonset.yaml.j2 index 39348ae90..09f4c7dfe 100644 --- a/roles/kuryr/templates/cni-daemonset.yaml.j2 +++ b/roles/kuryr/templates/cni-daemonset.yaml.j2 @@ -26,6 +26,13 @@ spec:          image: kuryr/cni:latest          imagePullPolicy: IfNotPresent          command: [ "cni_ds_init" ] +        env: +        - name: CNI_DAEMON +          value: "True" +        - name: KUBERNETES_NODE_NAME +          valueFrom: +            fieldRef: +              fieldPath: spec.nodeName          securityContext:            privileged: true          volumeMounts: @@ -38,6 +45,10 @@ spec:            subPath: kuryr-cni.conf          - name: etc            mountPath: /etc +        - name: proc +          mountPath: /host_proc +        - name: openvswitch +          mountPath: /var/run/openvswitch        volumes:          - name: bin            hostPath: @@ -50,4 +61,10 @@ spec:              name: kuryr-config          - name: etc            hostPath: -            path: /etc
\ No newline at end of file +            path: /etc +        - name: proc +          hostPath: +            path: /proc +        - name: openvswitch +          hostPath: +            path: /var/run/openvswitch diff --git a/roles/kuryr/templates/configmap.yaml.j2 b/roles/kuryr/templates/configmap.yaml.j2 index 96c215f00..4bf1dbddf 100644 --- a/roles/kuryr/templates/configmap.yaml.j2 +++ b/roles/kuryr/templates/configmap.yaml.j2 @@ -16,17 +16,17 @@ data:      # Directory for Kuryr vif binding executables. (string value)      #bindir = /usr/libexec/kuryr +    # Neutron subnetpool name will be prefixed by this. (string value) +    #subnetpool_name_prefix = kuryrPool + +    # baremetal or nested-containers are the supported values. (string value) +    #deployment_type = baremetal +      # If set to true, the logging level will be set to DEBUG instead of the default      # INFO level. (boolean value)      # Note: This option can be changed without restarting.      #debug = false -    # DEPRECATED: If set to false, the logging level will be set to WARNING instead -    # of the default INFO level. (boolean value) -    # This option is deprecated for removal. -    # Its value may be silently ignored in the future. -    #verbose = true -      # The name of a logging configuration file. This file is appended to any      # existing logging configuration files. For details about logging configuration      # files, see the Python logging module documentation. Note that when logging @@ -46,7 +46,7 @@ data:      # logging will go to stderr as defined by use_stderr. This option is ignored if      # log_config_append is set. (string value)      # Deprecated group/name - [DEFAULT]/logfile -    #log_file = /var/log/kuryr/kuryr-controller.log +    #log_file = <None>      # (Optional) The base directory used for relative log_file  paths. This option      # is ignored if log_config_append is set. (string value) @@ -65,13 +65,19 @@ data:      # is set. (boolean value)      #use_syslog = false +    # Enable journald for logging. If running in a systemd environment you may wish +    # to enable journal support. Doing so will use the journal native protocol +    # which includes structured metadata in addition to log messages.This option is +    # ignored if log_config_append is set. (boolean value) +    #use_journal = false +      # Syslog facility to receive log lines. This option is ignored if      # log_config_append is set. (string value)      #syslog_log_facility = LOG_USER      # Log output to standard error. This option is ignored if log_config_append is      # set. (boolean value) -    #use_stderr = true +    #use_stderr = false      # Format string to use for log messages with context. (string value)      #logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s @@ -93,7 +99,7 @@ data:      # List of package logging levels in logger=LEVEL pairs. This option is ignored      # if log_config_append is set. (list value) -    #default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO +    #default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO      # Enables or disables publication of error events. (boolean value)      #publish_errors = false @@ -106,15 +112,86 @@ data:      # value)      #instance_uuid_format = "[instance: %(uuid)s] " +    # Interval, number of seconds, of log rate limiting. (integer value) +    #rate_limit_interval = 0 + +    # Maximum number of logged messages per rate_limit_interval. (integer value) +    #rate_limit_burst = 0 + +    # Log level name used by rate limiting: CRITICAL, ERROR, INFO, WARNING, DEBUG +    # or empty string. Logs with level greater or equal to rate_limit_except_level +    # are not filtered. An empty string means that all levels are filtered. (string +    # value) +    #rate_limit_except_level = CRITICAL +      # Enables or disables fatal status of deprecations. (boolean value)      #fatal_deprecations = false      [binding] +    # Configuration options for container interface binding. -    driver = kuryr.lib.binding.drivers.vlan +    # +    # From kuryr_kubernetes +    # + +    # The name prefix of the veth endpoint put inside the container. (string value) +    #veth_dst_prefix = eth + +    # Driver to use for binding and unbinding ports. (string value) +    # Deprecated group/name - [binding]/driver +    #default_driver = kuryr.lib.binding.drivers.veth + +    # Drivers to use for binding and unbinding ports. (list value) +    #enabled_drivers = kuryr.lib.binding.drivers.veth + +    # Specifies the name of the Nova instance interface to link the virtual devices +    # to (only applicable to some binding drivers. (string value)      link_iface = eth0 +    driver = kuryr.lib.binding.drivers.vlan + + +    [cni_daemon] + +    # +    # From kuryr_kubernetes +    # + +    # Enable CNI Daemon configuration. (boolean value) +    daemon_enabled = true + +    # Bind address for CNI daemon HTTP server. It is recommened to allow only local +    # connections. (string value) +    bind_address = 127.0.0.1:50036 + +    # Maximum number of processes that will be spawned to process requests from CNI +    # driver. (integer value) +    #worker_num = 30 + +    # Time (in seconds) the CNI daemon will wait for VIF annotation to appear in +    # pod metadata before failing the CNI request. (integer value) +    #vif_annotation_timeout = 120 + +    # Kuryr uses pyroute2 library to manipulate networking interfaces. When +    # processing a high number of Kuryr requests in parallel, it may take kernel +    # more time to process all networking stack changes. This option allows to tune +    # internal pyroute2 timeout. (integer value) +    #pyroute2_timeout = 30 + +    # Set to True when you are running kuryr-daemon inside a Docker container on +    # Kubernetes host. E.g. as DaemonSet on Kubernetes cluster Kuryr is supposed to +    # provide networking for. This mainly means thatkuryr-daemon will look for +    # network namespaces in $netns_proc_dir instead of /proc. (boolean value) +    docker_mode = true + +    # When docker_mode is set to True, this config option should be set to where +    # host's /proc directory is mounted. Please note that mounting it is necessary +    # to allow Kuryr-Kubernetes to move host interfaces between host network +    # namespaces, which is essential for Kuryr to work. (string value) +    netns_proc_dir = /host_proc + +      [kubernetes]      # @@ -164,11 +241,6 @@ data:      # The driver that manages VIFs pools for Kubernetes Pods (string value)      vif_pool_driver = {{ kuryr_openstack_enable_pools | default(False) | ternary('nested', 'noop') }} -    [vif_pool] -    ports_pool_max = {{ kuryr_openstack_pool_max | default(0) }} -    ports_pool_min = {{ kuryr_openstack_pool_min | default(1) }} -    ports_pool_batch = {{ kuryr_openstack_pool_batch | default(5) }} -    ports_pool_update_frequency = {{ kuryr_openstack_pool_update_frequency | default(20) }}      [neutron]      # Configuration options for OpenStack Neutron @@ -232,13 +304,55 @@ data:      external_svc_subnet = {{ kuryr_openstack_external_svc_subnet_id }}      [pod_vif_nested] +      worker_nodes_subnet = {{ kuryr_openstack_worker_nodes_subnet_id }} + + +    [pool_manager] + +    # +    # From kuryr_kubernetes +    # + +    # Absolute path to socket file that will be used for communication with the +    # Pool Manager daemon (string value) +    #sock_file = /run/kuryr/kuryr_manage.sock + + +    [vif_pool] + +    # +    # From kuryr_kubernetes +    # + +    # Set a maximun amount of ports per pool. 0 to disable (integer value) +    ports_pool_max = {{ kuryr_openstack_pool_max | default(0) }} + +    # Set a target minimum size of the pool of ports (integer value) +    ports_pool_min = {{ kuryr_openstack_pool_min | default(1) }} + +    # Number of ports to be created in a bulk request (integer value) +    ports_pool_batch = {{ kuryr_openstack_pool_batch | default(5) }} + +    # Minimun interval (in seconds) between pool updates (integer value) +    ports_pool_update_frequency = {{ kuryr_openstack_pool_update_frequency | default(20) }} +    kuryr-cni.conf: |+      [DEFAULT]      #      # From kuryr_kubernetes      # + +    # Directory for Kuryr vif binding executables. (string value) +    #bindir = /usr/libexec/kuryr + +    # Neutron subnetpool name will be prefixed by this. (string value) +    #subnetpool_name_prefix = kuryrPool + +    # baremetal or nested-containers are the supported values. (string value) +    #deployment_type = baremetal +      # If set to true, the logging level will be set to DEBUG instead of the default      # INFO level. (boolean value)      # Note: This option can be changed without restarting. @@ -263,7 +377,7 @@ data:      # logging will go to stderr as defined by use_stderr. This option is ignored if      # log_config_append is set. (string value)      # Deprecated group/name - [DEFAULT]/logfile -    #log_file = /var/log/kuryr/cni.log +    #log_file = <None>      # (Optional) The base directory used for relative log_file  paths. This option      # is ignored if log_config_append is set. (string value) @@ -282,6 +396,12 @@ data:      # is set. (boolean value)      #use_syslog = false +    # Enable journald for logging. If running in a systemd environment you may wish +    # to enable journal support. Doing so will use the journal native protocol +    # which includes structured metadata in addition to log messages.This option is +    # ignored if log_config_append is set. (boolean value) +    #use_journal = false +      # Syslog facility to receive log lines. This option is ignored if      # log_config_append is set. (string value)      #syslog_log_facility = LOG_USER @@ -310,7 +430,7 @@ data:      # List of package logging levels in logger=LEVEL pairs. This option is ignored      # if log_config_append is set. (list value) -    #default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO +    #default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO      # Enables or disables publication of error events. (boolean value)      #publish_errors = false @@ -323,14 +443,85 @@ data:      # value)      #instance_uuid_format = "[instance: %(uuid)s] " +    # Interval, number of seconds, of log rate limiting. (integer value) +    #rate_limit_interval = 0 + +    # Maximum number of logged messages per rate_limit_interval. (integer value) +    #rate_limit_burst = 0 + +    # Log level name used by rate limiting: CRITICAL, ERROR, INFO, WARNING, DEBUG +    # or empty string. Logs with level greater or equal to rate_limit_except_level +    # are not filtered. An empty string means that all levels are filtered. (string +    # value) +    #rate_limit_except_level = CRITICAL +      # Enables or disables fatal status of deprecations. (boolean value)      #fatal_deprecations = false      [binding] +    # Configuration options for container interface binding. + +    # +    # From kuryr_kubernetes +    # + +    # The name prefix of the veth endpoint put inside the container. (string value) +    #veth_dst_prefix = eth + +    # Driver to use for binding and unbinding ports. (string value) +    # Deprecated group/name - [binding]/driver +    #default_driver = kuryr.lib.binding.drivers.veth + +    # Drivers to use for binding and unbinding ports. (list value) +    #enabled_drivers = kuryr.lib.binding.drivers.veth + +    # Specifies the name of the Nova instance interface to link the virtual devices +    # to (only applicable to some binding drivers. (string value) +    link_iface = eth0      driver = kuryr.lib.binding.drivers.vlan -    link_iface = {{ kuryr_cni_link_interface }} + + +    [cni_daemon] + +    # +    # From kuryr_kubernetes +    # + +    # Enable CNI Daemon configuration. (boolean value) +    daemon_enabled = true + +    # Bind address for CNI daemon HTTP server. It is recommened to allow only local +    # connections. (string value) +    bind_address = 127.0.0.1:50036 + +    # Maximum number of processes that will be spawned to process requests from CNI +    # driver. (integer value) +    #worker_num = 30 + +    # Time (in seconds) the CNI daemon will wait for VIF annotation to appear in +    # pod metadata before failing the CNI request. (integer value) +    #vif_annotation_timeout = 120 + +    # Kuryr uses pyroute2 library to manipulate networking interfaces. When +    # processing a high number of Kuryr requests in parallel, it may take kernel +    # more time to process all networking stack changes. This option allows to tune +    # internal pyroute2 timeout. (integer value) +    #pyroute2_timeout = 30 + +    # Set to True when you are running kuryr-daemon inside a Docker container on +    # Kubernetes host. E.g. as DaemonSet on Kubernetes cluster Kuryr is supposed to +    # provide networking for. This mainly means thatkuryr-daemon will look for +    # network namespaces in $netns_proc_dir instead of /proc. (boolean value) +    docker_mode = true + +    # When docker_mode is set to True, this config option should be set to where +    # host's /proc directory is mounted. Please note that mounting it is necessary +    # to allow Kuryr-Kubernetes to move host interfaces between host network +    # namespaces, which is essential for Kuryr to work. (string value) +    netns_proc_dir = /host_proc +      [kubernetes] @@ -341,12 +532,136 @@ data:      # The root URL of the Kubernetes API (string value)      api_root = {{ openshift.master.api_url }} -    # The token to talk to the k8s API -    token_file = /etc/kuryr/token +    # Absolute path to client cert to connect to HTTPS K8S_API (string value) +    # ssl_client_crt_file = /etc/kuryr/controller.crt + +    # Absolute path client key file to connect to HTTPS K8S_API (string value) +    # ssl_client_key_file = /etc/kuryr/controller.key      # Absolute path to ca cert file to connect to HTTPS K8S_API (string value) -    ssl_ca_crt_file = /etc/kuryr/ca.crt +    ssl_ca_crt_file = /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + +    # The token to talk to the k8s API +    token_file = /var/run/secrets/kubernetes.io/serviceaccount/token      # HTTPS K8S_API server identity verification (boolean value)      # TODO (apuimedo): Make configurable      ssl_verify_server_crt = True + +    # The driver to determine OpenStack project for pod ports (string value) +    pod_project_driver = default + +    # The driver to determine OpenStack project for services (string value) +    service_project_driver = default + +    # The driver to determine Neutron subnets for pod ports (string value) +    pod_subnets_driver = default + +    # The driver to determine Neutron subnets for services (string value) +    service_subnets_driver = default + +    # The driver to determine Neutron security groups for pods (string value) +    pod_security_groups_driver = default + +    # The driver to determine Neutron security groups for services (string value) +    service_security_groups_driver = default + +    # The driver that provides VIFs for Kubernetes Pods. (string value) +    pod_vif_driver = nested-vlan + +    # The driver that manages VIFs pools for Kubernetes Pods (string value) +    vif_pool_driver = {{ kuryr_openstack_enable_pools | default(False) | ternary('nested', 'noop') }} + +    [neutron] +    # Configuration options for OpenStack Neutron + +    # +    # From kuryr_kubernetes +    # + +    # Authentication URL (string value) +    auth_url = {{ kuryr_openstack_auth_url }} + +    # Authentication type to load (string value) +    # Deprecated group/name - [neutron]/auth_plugin +    auth_type = password + +    # Domain ID to scope to (string value) +    user_domain_name = {{ kuryr_openstack_user_domain_name }} + +    # User's password (string value) +    password = {{ kuryr_openstack_password }} + +    # Domain name containing project (string value) +    project_domain_name = {{ kuryr_openstack_project_domain_name }} + +    # Project ID to scope to (string value) +    # Deprecated group/name - [neutron]/tenant-id +    project_id = {{ kuryr_openstack_project_id }} + +    # Token (string value) +    #token = <None> + +    # Trust ID (string value) +    #trust_id = <None> + +    # User's domain id (string value) +    #user_domain_id = <None> + +    # User id (string value) +    #user_id = <None> + +    # Username (string value) +    # Deprecated group/name - [neutron]/user-name +    username = {{kuryr_openstack_username }} + +    # Whether a plugging operation is failed if the port to plug does not become +    # active (boolean value) +    #vif_plugging_is_fatal = false + +    # Seconds to wait for port to become active (integer value) +    #vif_plugging_timeout = 0 + +    [neutron_defaults] + +    pod_security_groups = {{ kuryr_openstack_pod_sg_id }} +    pod_subnet = {{ kuryr_openstack_pod_subnet_id }} +    service_subnet = {{ kuryr_openstack_service_subnet_id }} +    project = {{ kuryr_openstack_pod_project_id }} +    # TODO (apuimedo): Remove the duplicated line just after this one once the +    # RDO packaging contains the upstream patch +    worker_nodes_subnet = {{ kuryr_openstack_worker_nodes_subnet_id }} + +    [pod_vif_nested] + +    worker_nodes_subnet = {{ kuryr_openstack_worker_nodes_subnet_id }} + + +    [pool_manager] + +    # +    # From kuryr_kubernetes +    # + +    # Absolute path to socket file that will be used for communication with the +    # Pool Manager daemon (string value) +    #sock_file = /run/kuryr/kuryr_manage.sock + + +    [vif_pool] + +    # +    # From kuryr_kubernetes +    # + +    # Set a maximun amount of ports per pool. 0 to disable (integer value) +    ports_pool_max = {{ kuryr_openstack_pool_max | default(0) }} + +    # Set a target minimum size of the pool of ports (integer value) +    ports_pool_min = {{ kuryr_openstack_pool_min | default(1) }} + +    # Number of ports to be created in a bulk request (integer value) +    ports_pool_batch = {{ kuryr_openstack_pool_batch | default(5) }} + +    # Minimun interval (in seconds) between pool updates (integer value) +    ports_pool_update_frequency = {{ kuryr_openstack_pool_update_frequency | default(20) }} diff --git a/roles/lib_utils/filter_plugins/oo_filters.py b/roles/lib_utils/filter_plugins/oo_filters.py index fc14b5633..ef996fefe 100644 --- a/roles/lib_utils/filter_plugins/oo_filters.py +++ b/roles/lib_utils/filter_plugins/oo_filters.py @@ -4,6 +4,7 @@  """  Custom filters for use in openshift-ansible  """ +import json  import os  import pdb  import random @@ -21,13 +22,10 @@ import yaml  from ansible import errors  from ansible.parsing.yaml.dumper import AnsibleDumper -# ansible.compat.six goes away with Ansible 2.4 -try: -    from ansible.compat.six import string_types, u -    from ansible.compat.six.moves.urllib.parse import urlparse -except ImportError: -    from ansible.module_utils.six import string_types, u -    from ansible.module_utils.six.moves.urllib.parse import urlparse +# pylint: disable=import-error,no-name-in-module +from ansible.module_utils.six import string_types, u +# pylint: disable=import-error,no-name-in-module +from ansible.module_utils.six.moves.urllib.parse import urlparse  HAS_OPENSSL = False  try: @@ -589,6 +587,18 @@ that result to this filter plugin.      return secret_name +def lib_utils_oo_l_of_d_to_csv(input_list): +    """Map a list of dictionaries, input_list, into a csv string +    of json values. + +    Example input: +    [{'var1': 'val1', 'var2': 'val2'}, {'var1': 'val3', 'var2': 'val4'}] +    Example output: +    u'{"var1": "val1", "var2": "val2"},{"var1": "val3", "var2": "val4"}' +    """ +    return ','.join(json.dumps(x) for x in input_list) + +  def map_from_pairs(source, delim="="):      ''' Returns a dict given the source and delim delimited '''      if source == '': @@ -626,5 +636,6 @@ class FilterModule(object):              "lib_utils_oo_contains_rule": lib_utils_oo_contains_rule,              "lib_utils_oo_selector_to_string_list": lib_utils_oo_selector_to_string_list,              "lib_utils_oo_filter_sa_secrets": lib_utils_oo_filter_sa_secrets, +            "lib_utils_oo_l_of_d_to_csv": lib_utils_oo_l_of_d_to_csv,              "map_from_pairs": map_from_pairs          } diff --git a/roles/lib_utils/filter_plugins/openshift_master.py b/roles/lib_utils/filter_plugins/openshift_master.py index ff15f693b..e67b19c28 100644 --- a/roles/lib_utils/filter_plugins/openshift_master.py +++ b/roles/lib_utils/filter_plugins/openshift_master.py @@ -10,11 +10,7 @@ from ansible import errors  from ansible.parsing.yaml.dumper import AnsibleDumper  from ansible.plugins.filter.core import to_bool as ansible_bool -# ansible.compat.six goes away with Ansible 2.4 -try: -    from ansible.compat.six import string_types, u -except ImportError: -    from ansible.module_utils.six import string_types, u +from ansible.module_utils.six import string_types, u  import yaml diff --git a/roles/lib_utils/library/docker_creds.py b/roles/lib_utils/library/docker_creds.py index d4674845e..b94c0b779 100644 --- a/roles/lib_utils/library/docker_creds.py +++ b/roles/lib_utils/library/docker_creds.py @@ -135,7 +135,7 @@ def update_config(docker_config, registry, username, password):          docker_config['auths'][registry] = {}      # base64 encode our username:password string -    encoded_data = base64.b64encode('{}:{}'.format(username, password)) +    encoded_data = base64.b64encode('{}:{}'.format(username, password).encode())      # check if the same value is already present for idempotency.      if 'auth' in docker_config['auths'][registry]: @@ -151,7 +151,7 @@ def write_config(module, docker_config, dest):      conf_file_path = os.path.join(dest, 'config.json')      try:          with open(conf_file_path, 'w') as conf_file: -            json.dump(docker_config, conf_file, indent=8) +            json.dump(docker_config.decode(), conf_file, indent=8)      except IOError as ioerror:          result = {'failed': True,                    'changed': False, diff --git a/roles/openshift_aws/defaults/main.yml b/roles/openshift_aws/defaults/main.yml index 6de603661..e14d57702 100644 --- a/roles/openshift_aws/defaults/main.yml +++ b/roles/openshift_aws/defaults/main.yml @@ -59,7 +59,7 @@ openshift_aws_elb_name_dict:      external: "{{ openshift_aws_elb_basename }}-infra"  openshift_aws_elb_idle_timout: 400 -openshift_aws_elb_scheme: internet-facing +  openshift_aws_elb_cert_arn: ''  openshift_aws_elb_dict: @@ -98,12 +98,20 @@ openshift_aws_elb_dict:        proxy_protocol: True  openshift_aws_node_group_config_master_volumes: +- device_name: /dev/sda1 +  volume_size: 100 +  device_type: gp2 +  delete_on_termination: False  - device_name: /dev/sdb    volume_size: 100    device_type: gp2    delete_on_termination: False  openshift_aws_node_group_config_node_volumes: +- device_name: /dev/sda1 +  volume_size: 100 +  device_type: gp2 +  delete_on_termination: True  - device_name: /dev/sdb    volume_size: 100    device_type: gp2 @@ -294,3 +302,7 @@ openshift_aws_node_user_data: ''  openshift_aws_node_config_namespace: openshift-node  openshift_aws_masters_groups: masters,etcd,nodes + +# By default, don't delete things like the shared IAM instance +# profile and uploaded ssh keys +openshift_aws_enable_uninstall_shared_objects: False diff --git a/roles/openshift_aws/tasks/accept_nodes.yml b/roles/openshift_aws/tasks/accept_nodes.yml index c2a2cea30..db30fe5c9 100644 --- a/roles/openshift_aws/tasks/accept_nodes.yml +++ b/roles/openshift_aws/tasks/accept_nodes.yml @@ -1,4 +1,6 @@  --- +- include_tasks: setup_master_group.yml +  - name: fetch masters    ec2_instance_facts:      region: "{{ openshift_aws_region | default('us-east-1') }}" @@ -36,4 +38,4 @@      nodes: "{{ instancesout.instances|map(attribute='private_dns_name') | list  }}"      timeout: 60    register: nodeout -  delegate_to: "{{ mastersout.instances[0].public_ip_address }}" +  delegate_to: "{{ groups.masters.0 }}" diff --git a/roles/openshift_aws/tasks/elb.yml b/roles/openshift_aws/tasks/elb.yml index 5d371ec7a..6f0028a3d 100644 --- a/roles/openshift_aws/tasks/elb.yml +++ b/roles/openshift_aws/tasks/elb.yml @@ -15,7 +15,7 @@      - "{{ subnetout.subnets[0].id }}"      health_check: "{{ openshift_aws_elb_health_check }}"      listeners: "{{ item.value }}" -    scheme: "{{ openshift_aws_elb_scheme }}" +    scheme: "{{ (item.key == 'internal') | ternary('internal','internet-facing') }}"      tags: "{{ openshift_aws_elb_tags }}"      wait: True    register: new_elb diff --git a/roles/openshift_aws/tasks/provision.yml b/roles/openshift_aws/tasks/provision.yml index 786a2e4cf..2b5f317d8 100644 --- a/roles/openshift_aws/tasks/provision.yml +++ b/roles/openshift_aws/tasks/provision.yml @@ -1,23 +1,6 @@  --- -- when: openshift_aws_create_iam_cert | bool -  name: create the iam_cert for elb certificate -  include_tasks: iam_cert.yml - -- when: openshift_aws_create_s3 | bool -  name: create s3 bucket for registry -  include_tasks: s3.yml -  - include_tasks: vpc_and_subnet_id.yml -- name: create elbs -  include_tasks: elb.yml -  with_dict: "{{ openshift_aws_elb_dict }}" -  vars: -    l_elb_security_groups: "{{ openshift_aws_elb_security_groups }}" -    l_openshift_aws_elb_name_dict: "{{ openshift_aws_elb_name_dict }}" -  loop_control: -    loop_var: l_elb_dict_item -  - name: include scale group creation for master    include_tasks: build_node_group.yml    with_items: "{{ openshift_aws_master_group }}" diff --git a/roles/openshift_aws/tasks/provision_elb.yml b/roles/openshift_aws/tasks/provision_elb.yml new file mode 100644 index 000000000..a52f63bd5 --- /dev/null +++ b/roles/openshift_aws/tasks/provision_elb.yml @@ -0,0 +1,15 @@ +--- +- when: openshift_aws_create_iam_cert | bool +  name: create the iam_cert for elb certificate +  include_tasks: iam_cert.yml + +- include_tasks: vpc_and_subnet_id.yml + +- name: create elbs +  include_tasks: elb.yml +  with_dict: "{{ openshift_aws_elb_dict }}" +  vars: +    l_elb_security_groups: "{{ openshift_aws_elb_security_groups }}" +    l_openshift_aws_elb_name_dict: "{{ openshift_aws_elb_name_dict }}" +  loop_control: +    loop_var: l_elb_dict_item diff --git a/roles/openshift_aws/tasks/provision_nodes.yml b/roles/openshift_aws/tasks/provision_nodes.yml index d82f18574..9105b5b4c 100644 --- a/roles/openshift_aws/tasks/provision_nodes.yml +++ b/roles/openshift_aws/tasks/provision_nodes.yml @@ -2,25 +2,12 @@  # Get bootstrap config token  # bootstrap should be created on first master  # need to fetch it and shove it into cloud data -- name: fetch master instances -  ec2_instance_facts: -    region: "{{ openshift_aws_region }}" -    filters: -      "tag:clusterid": "{{ openshift_aws_clusterid }}" -      "tag:host-type": master -      instance-state-name: running -  register: instancesout -  retries: 20 -  delay: 3 -  until: -  - "'instances' in instancesout" -  - instancesout.instances|length > 0 +- include_tasks: setup_master_group.yml  - name: slurp down the bootstrap.kubeconfig    slurp:      src: /etc/origin/master/bootstrap.kubeconfig -  delegate_to: "{{ instancesout.instances[0].public_ip_address }}" -  remote_user: root +  delegate_to: "{{ groups.masters.0 }}"    register: bootstrap  - name: set_fact for kubeconfig token diff --git a/roles/openshift_aws/tasks/uninstall_security_group.yml b/roles/openshift_aws/tasks/uninstall_security_group.yml new file mode 100644 index 000000000..55d40e8ec --- /dev/null +++ b/roles/openshift_aws/tasks/uninstall_security_group.yml @@ -0,0 +1,14 @@ +--- +- name: delete the node group sgs +  oo_ec2_group: +    state: absent +    name: "{{ item.value.name}}" +    region: "{{ openshift_aws_region }}" +  with_dict: "{{ openshift_aws_node_security_groups }}" + +- name: delete the k8s sgs for the node group +  oo_ec2_group: +    state: absent +    name: "{{ item.value.name }}_k8s" +    region: "{{ openshift_aws_region }}" +  with_dict: "{{ openshift_aws_node_security_groups }}" diff --git a/roles/openshift_aws/tasks/uninstall_ssh_keys.yml b/roles/openshift_aws/tasks/uninstall_ssh_keys.yml new file mode 100644 index 000000000..27e42da53 --- /dev/null +++ b/roles/openshift_aws/tasks/uninstall_ssh_keys.yml @@ -0,0 +1,9 @@ +--- +- name: Remove the public keys for the user(s) +  ec2_key: +    state: absent +    name: "{{ item.key_name }}" +    region: "{{ openshift_aws_region }}" +  with_items: "{{ openshift_aws_users }}" +  no_log: True +  when: openshift_aws_enable_uninstall_shared_objects | bool diff --git a/roles/openshift_aws/tasks/uninstall_vpc.yml b/roles/openshift_aws/tasks/uninstall_vpc.yml new file mode 100644 index 000000000..ecf39f694 --- /dev/null +++ b/roles/openshift_aws/tasks/uninstall_vpc.yml @@ -0,0 +1,36 @@ +--- +- name: Fetch the VPC for the vpc.id +  ec2_vpc_net_facts: +    region: "{{ openshift_aws_region }}" +    filters: +      "tag:Name": "{{ openshift_aws_clusterid }}" +  register: vpcout +- debug: +    var: vpcout +    verbosity: 1 + +- when: vpcout.vpcs | length > 0 +  block: +  - name: delete the vpc igw +    ec2_vpc_igw: +      state: absent +      region: "{{ openshift_aws_region }}" +      vpc_id: "{{ vpcout.vpcs[0].id }}" +    register: igw + +  - name: delete the vpc subnets +    ec2_vpc_subnet: +      state: absent +      region: "{{ openshift_aws_region }}" +      vpc_id: "{{ vpcout.vpcs[0].id }}" +      cidr: "{{ item.cidr }}" +      az: "{{ item.az }}" +    with_items: "{{ openshift_aws_vpc.subnets[openshift_aws_region] }}" + +  - name: Delete AWS VPC +    ec2_vpc_net: +      state: absent +      region: "{{ openshift_aws_region }}" +      name: "{{ openshift_aws_clusterid }}" +      cidr_block: "{{ openshift_aws_vpc.cidr }}" +    register: vpc diff --git a/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-policy.yaml b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-policy.yaml new file mode 100644 index 000000000..90ee40943 --- /dev/null +++ b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-policy.yaml @@ -0,0 +1,10 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: +  name: bootstrap-autoapprover +roleRef: +  kind: ClusterRole +  name: system:node-bootstrap-autoapprover +subjects: +- kind: User +  name: system:serviceaccount:openshift-infra:bootstrap-autoapprover diff --git a/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-role.yaml b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-role.yaml new file mode 100644 index 000000000..d8143d047 --- /dev/null +++ b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-role.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: +  name: system:node-bootstrap-autoapprover +rules: +- apiGroups: +  - certificates.k8s.io +  resources: +  - certificatesigningrequests +  verbs: +  - delete +  - get +  - list +  - watch +- apiGroups: +  - certificates.k8s.io +  resources: +  - certificatesigningrequests/approval +  verbs: +  - create +  - update diff --git a/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-serviceaccount.yaml b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-serviceaccount.yaml new file mode 100644 index 000000000..e22ce6f34 --- /dev/null +++ b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller-serviceaccount.yaml @@ -0,0 +1,5 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: +  name: bootstrap-autoapprover +  namespace: openshift-infra diff --git a/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller.yaml b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller.yaml new file mode 100644 index 000000000..dbcedb407 --- /dev/null +++ b/roles/openshift_bootstrap_autoapprover/files/openshift-bootstrap-controller.yaml @@ -0,0 +1,68 @@ +kind: StatefulSet +apiVersion: apps/v1beta1 +metadata: +  name: bootstrap-autoapprover +  namespace: openshift-infra +spec: +  updateStrategy: +    type: RollingUpdate +  template: +    metadata: +      labels: +        app: bootstrap-autoapprover +    spec: +      serviceAccountName: bootstrap-autoapprover +      terminationGracePeriodSeconds: 1 +      containers: +      - name: signer +        image: openshift/node:v3.7.0-rc.0 +        command: +        - /bin/bash +        - -c +        args: +        - | +          #!/bin/bash +          set -o errexit +          set -o nounset +          set -o pipefail + +          unset KUBECONFIG +          cat <<SCRIPT > /tmp/signer +          #!/bin/bash +          # +          # It will approve any CSR that is not approved yet, and delete any CSR that expired more than 60 seconds +          # ago. +          # + +          set -o errexit +          set -o nounset +          set -o pipefail + +          name=\${1} +          condition=\${2} +          certificate=\${3} +          username=\${4} + +          # auto approve +          if [[ -z "\${condition}" && ("\${username}" == "system:serviceaccount:openshift-infra:node-bootstrapper" || "\${username}" == "system:node:"* ) ]]; then +            oc adm certificate approve "\${name}" +            exit 0 +          fi + +          # check certificate age +          if [[ -n "\${certificate}" ]]; then +            text="\$( echo "\${certificate}" | base64 -d - )" +            if ! echo "\${text}" | openssl x509 -noout; then +              echo "error: Unable to parse certificate" 2>&1 +              exit 1 +            fi  +            if ! echo "\${text}" | openssl x509 -checkend -60 > /dev/null; then +              echo "Certificate is expired, deleting" +              oc delete csr "\${name}" +            fi +            exit 0 +          fi +          SCRIPT +          chmod u+x /tmp/signer + +          exec oc observe csr --maximum-errors=1 --resync-period=10m -a '{.status.conditions[*].type}' -a '{.status.certificate}' -a '{.spec.username}' -- /tmp/signer diff --git a/roles/openshift_bootstrap_autoapprover/tasks/main.yml b/roles/openshift_bootstrap_autoapprover/tasks/main.yml new file mode 100644 index 000000000..88e9d08e7 --- /dev/null +++ b/roles/openshift_bootstrap_autoapprover/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: Copy auto-approver config to host +  run_once: true +  copy: +    src: "{{ item }}" +    dest: /tmp/openshift-approver/ +    owner: root +    mode: 0400 +  with_fileglob: +    - "*.yaml" + +- name: Set auto-approver nodeSelector +  run_once: true +  yedit: +    src: "/tmp/openshift-approver/openshift-bootstrap-controller.yaml" +    key: spec.template.spec.nodeSelector +    value: "{{ openshift_master_bootstrap_auto_approver_node_selector | default({}) }}" +    value_type: list + +- name: Create auto-approver on cluster +  run_once: true +  command: oc apply -f /tmp/openshift-approver/ + +- name: Remove auto-approver config +  run_once: true +  file: +    path: /tmp/openshift-approver/ +    state: absent diff --git a/roles/openshift_ca/tasks/main.yml b/roles/openshift_ca/tasks/main.yml index b94cd9fba..9c8534c74 100644 --- a/roles/openshift_ca/tasks/main.yml +++ b/roles/openshift_ca/tasks/main.yml @@ -19,7 +19,8 @@  - name: Reload generated facts    openshift_facts: -  when: hostvars[openshift_ca_host].install_result is changed +  when: +  - hostvars[openshift_ca_host].install_result | default({'changed':false}) is changed  - name: Create openshift_ca_config_dir if it does not exist    file: diff --git a/roles/openshift_cloud_provider/tasks/gce.yml b/roles/openshift_cloud_provider/tasks/gce.yml index ee4048911..395bd304c 100644 --- a/roles/openshift_cloud_provider/tasks/gce.yml +++ b/roles/openshift_cloud_provider/tasks/gce.yml @@ -13,5 +13,11 @@    ini_file:      dest: "{{ openshift.common.config_base }}/cloudprovider/gce.conf"      section: Global -    option: multizone -    value: "true" +    option: "{{ item.key }}" +    value: "{{ item.value }}" +  with_items: +    - { key: 'project-id', value: '{{ openshift_gcp_project }}' } +    - { key: 'network-name', value: '{{ openshift_gcp_network_name }}' } +    - { key: 'node-tags', value: '{{ openshift_gcp_prefix }}ocp' } +    - { key: 'node-instance-prefix', value: '{{ openshift_gcp_prefix }}' } +    - { key: 'multizone', value: 'false' } diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-job.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-job.yaml new file mode 100644 index 000000000..48d1d4e26 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-job.yaml @@ -0,0 +1,28 @@ +apiVersion: batch/v1 +kind: Job +metadata: +  name: cloudforms-backup +spec: +  template: +    metadata: +      name: cloudforms-backup +    spec: +      containers: +      - name: postgresql +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest +        command: +        - "/opt/rh/cfme-container-scripts/backup_db" +        env: +        - name: DATABASE_URL +          valueFrom: +            secretKeyRef: +              name: cloudforms-secrets +              key: database-url +        volumeMounts: +        - name: cfme-backup-vol +          mountPath: "/backups" +      volumes: +      - name: cfme-backup-vol +        persistentVolumeClaim: +          claimName: cloudforms-backup +      restartPolicy: Never diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-pvc.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-pvc.yaml new file mode 100644 index 000000000..92598ce82 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-backup-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: +  name: cloudforms-backup +spec: +  accessModes: +  - ReadWriteOnce +  resources: +    requests: +      storage: 15Gi diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-backup-example.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-backup-example.yaml new file mode 100644 index 000000000..4fe349897 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-backup-example.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: +  name: cfme-pv03 +spec: +  capacity: +    storage: 15Gi +  accessModes: +  - ReadWriteOnce +  nfs: +    path: "/exports/cfme-pv03" +    server: "<your-nfs-host-here>" +  persistentVolumeReclaimPolicy: Retain diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-db-example.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-db-example.yaml index 250a99b8d..0cdd821b5 100644 --- a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-db-example.yaml +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-db-example.yaml @@ -1,13 +1,38 @@  apiVersion: v1 -kind: PersistentVolume +kind: Template +labels: +  template: cloudforms-db-pv  metadata: -  name: cfme-pv01 -spec: -  capacity: -    storage: 15Gi -  accessModes: +  name: cloudforms-db-pv +  annotations: +    description: PV Template for CFME PostgreSQL DB +    tags: PVS, CFME +objects: +- apiVersion: v1 +  kind: PersistentVolume +  metadata: +    name: cfme-db +  spec: +    capacity: +      storage: "${PV_SIZE}" +    accessModes:      - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv01 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain +    nfs: +      path: "${BASE_PATH}/cfme-db" +      server: "${NFS_HOST}" +    persistentVolumeReclaimPolicy: Retain +parameters: +- name: PV_SIZE +  displayName: PV Size for DB +  required: true +  description: The size of the CFME DB PV given in Gi +  value: 15Gi +- name: BASE_PATH +  displayName: Exports Directory Base Path +  required: true +  description: The parent directory of your NFS exports +  value: "/exports" +- name: NFS_HOST +  displayName: NFS Server Hostname +  required: true +  description: The hostname or IP address of the NFS server diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-region-example.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-region-example.yaml deleted file mode 100644 index cba9bbe35..000000000 --- a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-region-example.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: PersistentVolume -metadata: -  name: cfme-pv02 -spec: -  capacity: -    storage: 5Gi -  accessModes: -    - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv02 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-server-example.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-server-example.yaml index c08c21265..527090ae8 100644 --- a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-server-example.yaml +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-pv-server-example.yaml @@ -1,13 +1,38 @@  apiVersion: v1 -kind: PersistentVolume +kind: Template +labels: +  template: cloudforms-app-pv  metadata: -  name: cfme-pv03 -spec: -  capacity: -    storage: 5Gi -  accessModes: +  name: cloudforms-app-pv +  annotations: +    description: PV Template for CFME Server +    tags: PVS, CFME +objects: +- apiVersion: v1 +  kind: PersistentVolume +  metadata: +    name: cfme-app +  spec: +    capacity: +      storage: "${PV_SIZE}" +    accessModes:      - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv03 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain +    nfs: +      path: "${BASE_PATH}/cfme-app" +      server: "${NFS_HOST}" +    persistentVolumeReclaimPolicy: Retain +parameters: +- name: PV_SIZE +  displayName: PV Size for App +  required: true +  description: The size of the CFME APP PV given in Gi +  value: 5Gi +- name: BASE_PATH +  displayName: Exports Directory Base Path +  required: true +  description: The parent directory of your NFS exports +  value: "/exports" +- name: NFS_HOST +  displayName: NFS Server Hostname +  required: true +  description: The hostname or IP address of the NFS server diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-restore-job.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-restore-job.yaml new file mode 100644 index 000000000..7fd4fc2e1 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-restore-job.yaml @@ -0,0 +1,35 @@ +apiVersion: batch/v1 +kind: Job +metadata: +  name: cloudforms-restore +spec: +  template: +    metadata: +      name: cloudforms-restore +    spec: +      containers: +      - name: postgresql +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest +        command: +        - "/opt/rh/cfme-container-scripts/restore_db" +        env: +        - name: DATABASE_URL +          valueFrom: +            secretKeyRef: +              name: cloudforms-secrets +              key: database-url +        - name: BACKUP_VERSION +          value: latest +        volumeMounts: +        - name: cfme-backup-vol +          mountPath: "/backups" +        - name: cfme-prod-vol +          mountPath: "/restore" +      volumes: +      - name: cfme-backup-vol +        persistentVolumeClaim: +          claimName: cloudforms-backup +      - name: cfme-prod-vol +        persistentVolumeClaim: +          claimName: cloudforms-postgresql +      restartPolicy: Never diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-scc-sysadmin.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-scc-sysadmin.yaml new file mode 100644 index 000000000..d2ece9298 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-scc-sysadmin.yaml @@ -0,0 +1,38 @@ +allowHostDirVolumePlugin: false +allowHostIPC: false +allowHostNetwork: false +allowHostPID: false +allowHostPorts: false +allowPrivilegedContainer: false +allowedCapabilities: +apiVersion: v1 +defaultAddCapabilities: +- SYS_ADMIN +fsGroup: +  type: RunAsAny +groups: +- system:cluster-admins +kind: SecurityContextConstraints +metadata: +  annotations: +    kubernetes.io/description: cfme-sysadmin provides all features of the anyuid SCC but allows users to have SYS_ADMIN capabilities. This is the required scc for Pods requiring to run with systemd and the message bus. +  creationTimestamp: +  name: cfme-sysadmin +priority: 10 +readOnlyRootFilesystem: false +requiredDropCapabilities: +- MKNOD +- SYS_CHROOT +runAsUser: +  type: RunAsAny +seLinuxContext: +  type: MustRunAs +supplementalGroups: +  type: RunAsAny +users: +volumes: +- configMap +- downwardAPI +- emptyDir +- persistentVolumeClaim +- secret diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template-ext-db.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template-ext-db.yaml new file mode 100644 index 000000000..9866c29c3 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template-ext-db.yaml @@ -0,0 +1,956 @@ +apiVersion: v1 +kind: Template +labels: +  template: cloudforms-ext-db +metadata: +  name: cloudforms-ext-db +  annotations: +    description: CloudForms appliance with persistent storage using a external DB host +    tags: instant-app,cloudforms,cfme +    iconClass: icon-rails +objects: +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-orchestrator +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-anyuid +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-privileged +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-httpd +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${NAME}-secrets" +  stringData: +    pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}" +    database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5 +    v2-key: "${V2_KEY}" +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}-secrets" +  stringData: +    rabbit-password: "${ANSIBLE_RABBITMQ_PASSWORD}" +    secret-key: "${ANSIBLE_SECRET_KEY}" +    admin-password: "${ANSIBLE_ADMIN_PASSWORD}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances CloudForms pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"},{"name":"${MEMCACHED_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${NAME}" +  spec: +    clusterIP: None +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    selector: +      name: "${NAME}" +- apiVersion: v1 +  kind: Route +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +  spec: +    host: "${APPLICATION_DOMAIN}" +    port: +      targetPort: http +    tls: +      termination: edge +      insecureEdgeTerminationPolicy: Redirect +    to: +      kind: Service +      name: "${HTTPD_SERVICE_NAME}" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}" +    replicas: "${APPLICATION_REPLICA_COUNT}" +    template: +      metadata: +        labels: +          name: "${NAME}" +        name: "${NAME}" +      spec: +        containers: +        - name: cloudforms +          image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: MY_POD_NAMESPACE +            valueFrom: +              fieldRef: +                fieldPath: metadata.namespace +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_REGION +            value: "${DATABASE_REGION}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          resources: +            requests: +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Headless service for CloudForms backend pods +    name: "${NAME}-backend" +  spec: +    clusterIP: None +    selector: +      name: "${NAME}-backend" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}-backend" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}-backend" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${NAME}-backend" +        name: "${NAME}-backend" +      spec: +        containers: +        - name: cloudforms +          image: "${BACKEND_APPLICATION_IMG_NAME}:${BACKEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: MIQ_SERVER_DEFAULT_ROLES +            value: database_operations,event,reporting,scheduler,smartstate,ems_operations,ems_inventory,automate +          - name: FRONTEND_SERVICE_NAME +            value: "${NAME}" +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          resources: +            requests: +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${MEMCACHED_SERVICE_NAME}" +    annotations: +      description: Exposes the memcached server +  spec: +    ports: +    - name: memcached +      port: 11211 +      targetPort: 11211 +    selector: +      name: "${MEMCACHED_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${MEMCACHED_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy memcached +  spec: +    strategy: +      type: Recreate +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${MEMCACHED_SERVICE_NAME}" +    template: +      metadata: +        name: "${MEMCACHED_SERVICE_NAME}" +        labels: +          name: "${MEMCACHED_SERVICE_NAME}" +      spec: +        volumes: [] +        containers: +        - name: memcached +          image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" +          ports: +          - containerPort: 11211 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 5 +            tcpSocket: +              port: 11211 +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 30 +            tcpSocket: +              port: 11211 +          volumeMounts: [] +          env: +          - name: MEMCACHED_MAX_MEMORY +            value: "${MEMCACHED_MAX_MEMORY}" +          - name: MEMCACHED_MAX_CONNECTIONS +            value: "${MEMCACHED_MAX_CONNECTIONS}" +          - name: MEMCACHED_SLAB_PAGE_SIZE +            value: "${MEMCACHED_SLAB_PAGE_SIZE}" +          resources: +            requests: +              memory: "${MEMCACHED_MEM_REQ}" +              cpu: "${MEMCACHED_CPU_REQ}" +            limits: +              memory: "${MEMCACHED_MEM_LIMIT}" +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${DATABASE_SERVICE_NAME}" +    annotations: +      description: Remote database service +  spec: +    ports: +    - name: postgresql +      port: 5432 +      targetPort: "${{DATABASE_PORT}}" +    selector: {} +- apiVersion: v1 +  kind: Endpoints +  metadata: +    name: "${DATABASE_SERVICE_NAME}" +  subsets: +  - addresses: +    - ip: "${DATABASE_IP}" +    ports: +    - port: "${{DATABASE_PORT}}" +      name: postgresql +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances Ansible pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${ANSIBLE_SERVICE_NAME}" +  spec: +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    - name: https +      port: 443 +      protocol: TCP +      targetPort: 443 +    selector: +      name: "${ANSIBLE_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy the Ansible appliance +  spec: +    strategy: +      type: Recreate +    serviceName: "${ANSIBLE_SERVICE_NAME}" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${ANSIBLE_SERVICE_NAME}" +        name: "${ANSIBLE_SERVICE_NAME}" +      spec: +        containers: +        - name: ansible +          image: "${ANSIBLE_IMG_NAME}:${ANSIBLE_IMG_TAG}" +          livenessProbe: +            tcpSocket: +              port: 443 +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            httpGet: +              path: "/" +              port: 443 +              scheme: HTTPS +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 443 +            protocol: TCP +          securityContext: +            privileged: true +          env: +          - name: ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          - name: RABBITMQ_USER_NAME +            value: "${ANSIBLE_RABBITMQ_USER_NAME}" +          - name: RABBITMQ_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: rabbit-password +          - name: ANSIBLE_SECRET_KEY +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: secret-key +          - name: DATABASE_SERVICE_NAME +            value: "${DATABASE_SERVICE_NAME}" +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${ANSIBLE_DATABASE_NAME}" +          resources: +            requests: +              memory: "${ANSIBLE_MEM_REQ}" +              cpu: "${ANSIBLE_CPU_REQ}" +            limits: +              memory: "${ANSIBLE_MEM_LIMIT}" +        serviceAccount: cfme-privileged +        serviceAccountName: cfme-privileged +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-configs" +  data: +    application.conf: | +      # Timeout: The number of seconds before receives and sends time out. +      Timeout 120 + +      RewriteEngine On +      Options SymLinksIfOwnerMatch + +      <VirtualHost *:80> +        KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} + +        ProxyPreserveHost on + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L] +        ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common +      </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-auth-configs" +  data: +    auth-type: internal +    auth-kerberos-realms: undefined +    auth-configuration.conf: | +      # External Authentication Configuration File +      # +      # For details on usage please see https://github.com/ManageIQ/manageiq-pods/blob/master/README.md#configuring-external-authentication +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http +      port: 80 +      targetPort: 80 +    selector: +      name: httpd +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy httpd +  spec: +    strategy: +      type: Recreate +      recreateParams: +        timeoutSeconds: 1200 +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${HTTPD_SERVICE_NAME}" +    template: +      metadata: +        name: "${HTTPD_SERVICE_NAME}" +        labels: +          name: "${HTTPD_SERVICE_NAME}" +      spec: +        volumes: +        - name: httpd-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-configs" +        - name: httpd-auth-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-auth-configs" +        containers: +        - name: httpd +          image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}" +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP +          livenessProbe: +            exec: +              command: +              - pidof +              - httpd +            initialDelaySeconds: 15 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 10 +            timeoutSeconds: 3 +          volumeMounts: +          - name: httpd-config +            mountPath: "${HTTPD_CONFIG_DIR}" +          - name: httpd-auth-config +            mountPath: "${HTTPD_AUTH_CONFIG_DIR}" +          resources: +            requests: +              memory: "${HTTPD_MEM_REQ}" +              cpu: "${HTTPD_CPU_REQ}" +            limits: +              memory: "${HTTPD_MEM_LIMIT}" +          env: +          - name: HTTPD_AUTH_TYPE +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms +          lifecycle: +            postStart: +              exec: +                command: +                - "/usr/bin/save-container-environment" +        serviceAccount: cfme-httpd +        serviceAccountName: cfme-httpd +parameters: +- name: NAME +  displayName: Name +  required: true +  description: The name assigned to all of the frontend objects defined in this template. +  value: cloudforms +- name: V2_KEY +  displayName: CloudForms Encryption Key +  required: true +  description: Encryption Key for CloudForms Passwords +  from: "[a-zA-Z0-9]{43}" +  generate: expression +- name: DATABASE_SERVICE_NAME +  displayName: PostgreSQL Service Name +  required: true +  description: The name of the OpenShift Service exposed for the PostgreSQL container. +  value: postgresql +- name: DATABASE_USER +  displayName: PostgreSQL User +  required: true +  description: PostgreSQL user that will access the database. +  value: root +- name: DATABASE_PASSWORD +  displayName: PostgreSQL Password +  required: true +  description: Password for the PostgreSQL user. +  from: "[a-zA-Z0-9]{8}" +  generate: expression +- name: DATABASE_IP +  displayName: PostgreSQL Server IP +  required: true +  description: PostgreSQL external server IP used to configure service. +  value: '' +- name: DATABASE_PORT +  displayName: PostgreSQL Server Port +  required: true +  description: PostgreSQL external server port used to configure service. +  value: '5432' +- name: DATABASE_NAME +  required: true +  displayName: PostgreSQL Database Name +  description: Name of the PostgreSQL database accessed. +  value: vmdb_production +- name: DATABASE_REGION +  required: true +  displayName: Application Database Region +  description: Database region that will be used for application. +  value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm +- name: ANSIBLE_DATABASE_NAME +  displayName: Ansible PostgreSQL database name +  required: true +  description: The database to be used by the Ansible continer +  value: awx +- name: MEMCACHED_SERVICE_NAME +  required: true +  displayName: Memcached Service Name +  description: The name of the OpenShift Service exposed for the Memcached container. +  value: memcached +- name: MEMCACHED_MAX_MEMORY +  displayName: Memcached Max Memory +  description: Memcached maximum memory for memcached object storage in MB. +  value: '64' +- name: MEMCACHED_MAX_CONNECTIONS +  displayName: Memcached Max Connections +  description: Memcached maximum number of connections allowed. +  value: '1024' +- name: MEMCACHED_SLAB_PAGE_SIZE +  displayName: Memcached Slab Page Size +  description: Memcached size of each slab page. +  value: 1m +- name: ANSIBLE_SERVICE_NAME +  displayName: Ansible Service Name +  description: The name of the OpenShift Service exposed for the Ansible container. +  value: ansible +- name: ANSIBLE_ADMIN_PASSWORD +  displayName: Ansible admin User password +  required: true +  description: The password for the Ansible container admin user +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: ANSIBLE_SECRET_KEY +  displayName: Ansible Secret Key +  required: true +  description: Encryption key for the Ansible container +  from: "[a-f0-9]{32}" +  generate: expression +- name: ANSIBLE_RABBITMQ_USER_NAME +  displayName: RabbitMQ Username +  required: true +  description: Username for the Ansible RabbitMQ Server +  value: ansible +- name: ANSIBLE_RABBITMQ_PASSWORD +  displayName: RabbitMQ Server Password +  required: true +  description: Password for the Ansible RabbitMQ Server +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: APPLICATION_CPU_REQ +  displayName: Application Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Application container will need (expressed in millicores). +  value: 1000m +- name: MEMCACHED_CPU_REQ +  displayName: Memcached Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Memcached container will need (expressed in millicores). +  value: 200m +- name: ANSIBLE_CPU_REQ +  displayName: Ansible Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Ansible container will need (expressed in millicores). +  value: 1000m +- name: APPLICATION_MEM_REQ +  displayName: Application Min RAM Requested +  required: true +  description: Minimum amount of memory the Application container will need. +  value: 6144Mi +- name: MEMCACHED_MEM_REQ +  displayName: Memcached Min RAM Requested +  required: true +  description: Minimum amount of memory the Memcached container will need. +  value: 64Mi +- name: ANSIBLE_MEM_REQ +  displayName: Ansible Min RAM Requested +  required: true +  description: Minimum amount of memory the Ansible container will need. +  value: 2048Mi +- name: APPLICATION_MEM_LIMIT +  displayName: Application Max RAM Limit +  required: true +  description: Maximum amount of memory the Application container can consume. +  value: 16384Mi +- name: MEMCACHED_MEM_LIMIT +  displayName: Memcached Max RAM Limit +  required: true +  description: Maximum amount of memory the Memcached container can consume. +  value: 256Mi +- name: ANSIBLE_MEM_LIMIT +  displayName: Ansible Max RAM Limit +  required: true +  description: Maximum amount of memory the Ansible container can consume. +  value: 8096Mi +- name: MEMCACHED_IMG_NAME +  displayName: Memcached Image Name +  description: This is the Memcached image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached +- name: MEMCACHED_IMG_TAG +  displayName: Memcached Image Tag +  description: This is the Memcached image tag/version requested to deploy. +  value: latest +- name: FRONTEND_APPLICATION_IMG_NAME +  displayName: Frontend Application Image Name +  description: This is the Frontend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui +- name: BACKEND_APPLICATION_IMG_NAME +  displayName: Backend Application Image Name +  description: This is the Backend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app +- name: FRONTEND_APPLICATION_IMG_TAG +  displayName: Front end Application Image Tag +  description: This is the CloudForms Frontend Application image tag/version requested to deploy. +  value: latest +- name: BACKEND_APPLICATION_IMG_TAG +  displayName: Back end Application Image Tag +  description: This is the CloudForms Backend Application image tag/version requested to deploy. +  value: latest +- name: ANSIBLE_IMG_NAME +  displayName: Ansible Image Name +  description: This is the Ansible image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible +- name: ANSIBLE_IMG_TAG +  displayName: Ansible Image Tag +  description: This is the Ansible image tag/version requested to deploy. +  value: latest +- name: APPLICATION_DOMAIN +  displayName: Application Hostname +  description: The exposed hostname that will route to the application service, if left blank a value will be defaulted. +  value: '' +- name: APPLICATION_REPLICA_COUNT +  displayName: Application Replica Count +  description: This is the number of Application replicas requested to deploy. +  value: '1' +- name: APPLICATION_INIT_DELAY +  displayName: Application Init Delay +  required: true +  description: Delay in seconds before we attempt to initialize the application. +  value: '15' +- name: APPLICATION_VOLUME_CAPACITY +  displayName: Application Volume Capacity +  required: true +  description: Volume space available for application data. +  value: 5Gi +- name: HTTPD_SERVICE_NAME +  required: true +  displayName: Apache httpd Service Name +  description: The name of the OpenShift Service exposed for the httpd container. +  value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api +- name: HTTPD_IMG_NAME +  displayName: Apache httpd Image Name +  description: This is the httpd image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd +- name: HTTPD_IMG_TAG +  displayName: Apache httpd Image Tag +  description: This is the httpd image tag/version requested to deploy. +  value: latest +- name: HTTPD_CONFIG_DIR +  displayName: Apache httpd Configuration Directory +  description: Directory used to store the Apache configuration files. +  value: "/etc/httpd/conf.d" +- name: HTTPD_AUTH_CONFIG_DIR +  displayName: External Authentication Configuration Directory +  description: Directory used to store the external authentication configuration files. +  value: "/etc/httpd/auth-conf.d" +- name: HTTPD_CPU_REQ +  displayName: Apache httpd Min CPU Requested +  required: true +  description: Minimum amount of CPU time the httpd container will need (expressed in millicores). +  value: 500m +- name: HTTPD_MEM_REQ +  displayName: Apache httpd Min RAM Requested +  required: true +  description: Minimum amount of memory the httpd container will need. +  value: 512Mi +- name: HTTPD_MEM_LIMIT +  displayName: Apache httpd Max RAM Limit +  required: true +  description: Maximum amount of memory the httpd container can consume. +  value: 8192Mi diff --git a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template.yaml b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template.yaml index 3bc6c5813..5c757b6c2 100644 --- a/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template.yaml +++ b/roles/openshift_examples/files/examples/v3.7/cfme-templates/cfme-template.yaml @@ -5,17 +5,308 @@ labels:  metadata:    name: cloudforms    annotations: -    description: "CloudForms appliance with persistent storage" -    tags: "instant-app,cloudforms,cfme" -    iconClass: "icon-rails" +    description: CloudForms appliance with persistent storage +    tags: instant-app,cloudforms,cfme +    iconClass: icon-rails  objects:  - apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-orchestrator +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-anyuid +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-privileged +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-httpd +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${NAME}-secrets" +  stringData: +    pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}" +    database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5 +    v2-key: "${V2_KEY}" +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}-secrets" +  stringData: +    rabbit-password: "${ANSIBLE_RABBITMQ_PASSWORD}" +    secret-key: "${ANSIBLE_SECRET_KEY}" +    admin-password: "${ANSIBLE_ADMIN_PASSWORD}" +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${DATABASE_SERVICE_NAME}-configs" +  data: +    01_miq_overrides.conf: | +      #------------------------------------------------------------------------------ +      # CONNECTIONS AND AUTHENTICATION +      #------------------------------------------------------------------------------ + +      tcp_keepalives_count = 9 +      tcp_keepalives_idle = 3 +      tcp_keepalives_interval = 75 + +      #------------------------------------------------------------------------------ +      # RESOURCE USAGE (except WAL) +      #------------------------------------------------------------------------------ + +      shared_preload_libraries = 'pglogical,repmgr_funcs' +      max_worker_processes = 10 + +      #------------------------------------------------------------------------------ +      # WRITE AHEAD LOG +      #------------------------------------------------------------------------------ + +      wal_level = 'logical' +      wal_log_hints = on +      wal_buffers = 16MB +      checkpoint_completion_target = 0.9 + +      #------------------------------------------------------------------------------ +      # REPLICATION +      #------------------------------------------------------------------------------ + +      max_wal_senders = 10 +      wal_sender_timeout = 0 +      max_replication_slots = 10 +      hot_standby = on + +      #------------------------------------------------------------------------------ +      # ERROR REPORTING AND LOGGING +      #------------------------------------------------------------------------------ + +      log_filename = 'postgresql.log' +      log_rotation_age = 0 +      log_min_duration_statement = 5000 +      log_connections = on +      log_disconnections = on +      log_line_prefix = '%t:%r:%c:%u@%d:[%p]:' +      log_lock_waits = on + +      #------------------------------------------------------------------------------ +      # AUTOVACUUM PARAMETERS +      #------------------------------------------------------------------------------ + +      log_autovacuum_min_duration = 0 +      autovacuum_naptime = 5min +      autovacuum_vacuum_threshold = 500 +      autovacuum_analyze_threshold = 500 +      autovacuum_vacuum_scale_factor = 0.05 + +      #------------------------------------------------------------------------------ +      # LOCK MANAGEMENT +      #------------------------------------------------------------------------------ + +      deadlock_timeout = 5s + +      #------------------------------------------------------------------------------ +      # VERSION/PLATFORM COMPATIBILITY +      #------------------------------------------------------------------------------ + +      escape_string_warning = off +      standard_conforming_strings = off +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-configs" +  data: +    application.conf: | +      # Timeout: The number of seconds before receives and sends time out. +      Timeout 120 + +      RewriteEngine On +      Options SymLinksIfOwnerMatch + +      <VirtualHost *:80> +        KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} + +        ProxyPreserveHost on + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L] +        ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common +      </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-auth-configs" +  data: +    auth-type: internal +    auth-kerberos-realms: undefined +    auth-configuration.conf: | +      # External Authentication Configuration File +      # +      # For details on usage please see https://github.com/ManageIQ/manageiq-pods/blob/master/README.md#configuring-external-authentication +- apiVersion: v1    kind: Service    metadata:      annotations: -      description: "Exposes and load balances CloudForms pods" +      description: Exposes and load balances CloudForms pods        service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"},{"name":"${MEMCACHED_SERVICE_NAME}","namespace":"","kind":"Service"}]' -    name: ${NAME} +    name: "${NAME}"    spec:      clusterIP: None      ports: @@ -23,141 +314,97 @@ objects:        port: 80        protocol: TCP        targetPort: 80 -    - name: https -      port: 443 -      protocol: TCP -      targetPort: 443      selector: -      name: ${NAME} +      name: "${NAME}"  - apiVersion: v1    kind: Route    metadata: -    name: ${NAME} +    name: "${HTTPD_SERVICE_NAME}"    spec: -    host: ${APPLICATION_DOMAIN} +    host: "${APPLICATION_DOMAIN}"      port: -      targetPort: https +      targetPort: http      tls: -      termination: passthrough +      termination: edge +      insecureEdgeTerminationPolicy: Redirect      to:        kind: Service -      name: ${NAME} -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-app -    annotations: -      description: "Keeps track of changes in the CloudForms app image" -  spec: -    dockerImageRepository: "${APPLICATION_IMG_NAME}" -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-postgresql -    annotations: -      description: "Keeps track of changes in the CloudForms postgresql image" -  spec: -    dockerImageRepository: "${POSTGRESQL_IMG_NAME}" -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-memcached -    annotations: -      description: "Keeps track of changes in the CloudForms memcached image" -  spec: -    dockerImageRepository: "${MEMCACHED_IMG_NAME}" +      name: "${HTTPD_SERVICE_NAME}"  - apiVersion: v1    kind: PersistentVolumeClaim    metadata:      name: "${NAME}-${DATABASE_SERVICE_NAME}"    spec:      accessModes: -      - ReadWriteOnce +    - ReadWriteOnce      resources:        requests: -        storage: ${DATABASE_VOLUME_CAPACITY} -- apiVersion: v1 -  kind: PersistentVolumeClaim -  metadata: -    name: "${NAME}-region" -  spec: -    accessModes: -      - ReadWriteOnce -    resources: -      requests: -        storage: ${APPLICATION_REGION_VOLUME_CAPACITY} +        storage: "${DATABASE_VOLUME_CAPACITY}"  - apiVersion: apps/v1beta1 -  kind: "StatefulSet" +  kind: StatefulSet    metadata: -    name: ${NAME} +    name: "${NAME}"      annotations: -      description: "Defines how to deploy the CloudForms appliance" +      description: Defines how to deploy the CloudForms appliance    spec:      serviceName: "${NAME}" -    replicas: 1 +    replicas: "${APPLICATION_REPLICA_COUNT}"      template:        metadata:          labels: -          name: ${NAME} -        name: ${NAME} +          name: "${NAME}" +        name: "${NAME}"        spec:          containers:          - name: cloudforms -          image: "${APPLICATION_IMG_NAME}:${APPLICATION_IMG_TAG}" +          image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}"            livenessProbe: -            tcpSocket: -              port: 443 +            exec: +              command: +              - pidof +              - MIQ Server              initialDelaySeconds: 480              timeoutSeconds: 3            readinessProbe: -            httpGet: -              path: / -              port: 443 -              scheme: HTTPS +            tcpSocket: +              port: 80              initialDelaySeconds: 200              timeoutSeconds: 3            ports:            - containerPort: 80              protocol: TCP -          - containerPort: 443 -            protocol: TCP -          securityContext: -            privileged: true            volumeMounts: -              - -                name: "${NAME}-server" -                mountPath: "/persistent" -              - -                name: "${NAME}-region" -                mountPath: "/persistent-region" +          - name: "${NAME}-server" +            mountPath: "/persistent"            env: -            - -              name: "APPLICATION_INIT_DELAY" -              value: "${APPLICATION_INIT_DELAY}" -            - -              name: "DATABASE_SERVICE_NAME" -              value: "${DATABASE_SERVICE_NAME}" -            - -              name: "DATABASE_REGION" -              value: "${DATABASE_REGION}" -            - -              name: "MEMCACHED_SERVICE_NAME" -              value: "${MEMCACHED_SERVICE_NAME}" -            - -              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}" +          - name: MY_POD_NAMESPACE +            valueFrom: +              fieldRef: +                fieldPath: metadata.namespace +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_REGION +            value: "${DATABASE_REGION}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password            resources:              requests:                memory: "${APPLICATION_MEM_REQ}" @@ -168,59 +415,128 @@ objects:              preStop:                exec:                  command: -                  - /opt/rh/cfme-container-scripts/sync-pv-data -        volumes: -         - -           name: "${NAME}-region" -           persistentVolumeClaim: -             claimName: ${NAME}-region +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90      volumeClaimTemplates: -      - metadata: -          name: "${NAME}-server" -          annotations: -            # Uncomment this if using dynamic volume provisioning. -            # https://docs.openshift.org/latest/install_config/persistent_storage/dynamically_provisioning_pvs.html -            # volume.alpha.kubernetes.io/storage-class: anything -        spec: -          accessModes: [ ReadWriteOnce ] +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Headless service for CloudForms backend pods +    name: "${NAME}-backend" +  spec: +    clusterIP: None +    selector: +      name: "${NAME}-backend" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}-backend" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}-backend" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${NAME}-backend" +        name: "${NAME}-backend" +      spec: +        containers: +        - name: cloudforms +          image: "${BACKEND_APPLICATION_IMG_NAME}:${BACKEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: MIQ_SERVER_DEFAULT_ROLES +            value: database_operations,event,reporting,scheduler,smartstate,ems_operations,ems_inventory,automate +          - name: FRONTEND_SERVICE_NAME +            value: "${NAME}" +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password            resources:              requests: -              storage: "${APPLICATION_VOLUME_CAPACITY}" +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}"  - apiVersion: v1 -  kind: "Service" +  kind: Service    metadata:      name: "${MEMCACHED_SERVICE_NAME}"      annotations: -      description: "Exposes the memcached server" +      description: Exposes the memcached server    spec:      ports: -      - -        name: "memcached" -        port: 11211 -        targetPort: 11211 +    - name: memcached +      port: 11211 +      targetPort: 11211      selector:        name: "${MEMCACHED_SERVICE_NAME}"  - apiVersion: v1 -  kind: "DeploymentConfig" +  kind: DeploymentConfig    metadata:      name: "${MEMCACHED_SERVICE_NAME}"      annotations: -      description: "Defines how to deploy memcached" +      description: Defines how to deploy memcached    spec:      strategy: -      type: "Recreate" +      type: Recreate      triggers: -      - -        type: "ImageChange" -        imageChangeParams: -          automatic: true -          containerNames: -            - "memcached" -          from: -            kind: "ImageStreamTag" -            name: "cfme-openshift-memcached:${MEMCACHED_IMG_TAG}" -      - -        type: "ConfigChange" +    - type: ConfigChange      replicas: 1      selector:        name: "${MEMCACHED_SERVICE_NAME}" @@ -232,74 +548,58 @@ objects:        spec:          volumes: []          containers: -          - -            name: "memcached" -            image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" -            ports: -              - -                containerPort: 11211 -            readinessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 5 -              tcpSocket: -                port: 11211 -            livenessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 30 -              tcpSocket: -                port: 11211 -            volumeMounts: [] -            env: -              - -                name: "MEMCACHED_MAX_MEMORY" -                value: "${MEMCACHED_MAX_MEMORY}" -              - -                name: "MEMCACHED_MAX_CONNECTIONS" -                value: "${MEMCACHED_MAX_CONNECTIONS}" -              - -                name: "MEMCACHED_SLAB_PAGE_SIZE" -                value: "${MEMCACHED_SLAB_PAGE_SIZE}" -            resources: -              requests: -                memory: "${MEMCACHED_MEM_REQ}" -                cpu: "${MEMCACHED_CPU_REQ}" -              limits: -                memory: "${MEMCACHED_MEM_LIMIT}" +        - name: memcached +          image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" +          ports: +          - containerPort: 11211 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 5 +            tcpSocket: +              port: 11211 +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 30 +            tcpSocket: +              port: 11211 +          volumeMounts: [] +          env: +          - name: MEMCACHED_MAX_MEMORY +            value: "${MEMCACHED_MAX_MEMORY}" +          - name: MEMCACHED_MAX_CONNECTIONS +            value: "${MEMCACHED_MAX_CONNECTIONS}" +          - name: MEMCACHED_SLAB_PAGE_SIZE +            value: "${MEMCACHED_SLAB_PAGE_SIZE}" +          resources: +            requests: +              memory: "${MEMCACHED_MEM_REQ}" +              cpu: "${MEMCACHED_CPU_REQ}" +            limits: +              memory: "${MEMCACHED_MEM_LIMIT}"  - apiVersion: v1 -  kind: "Service" +  kind: Service    metadata:      name: "${DATABASE_SERVICE_NAME}"      annotations: -      description: "Exposes the database server" +      description: Exposes the database server    spec:      ports: -      - -        name: "postgresql" -        port: 5432 -        targetPort: 5432 +    - name: postgresql +      port: 5432 +      targetPort: 5432      selector:        name: "${DATABASE_SERVICE_NAME}"  - apiVersion: v1 -  kind: "DeploymentConfig" +  kind: DeploymentConfig    metadata:      name: "${DATABASE_SERVICE_NAME}"      annotations: -      description: "Defines how to deploy the database" +      description: Defines how to deploy the database    spec:      strategy: -      type: "Recreate" +      type: Recreate      triggers: -      - -        type: "ImageChange" -        imageChangeParams: -          automatic: true -          containerNames: -            - "postgresql" -          from: -            kind: "ImageStreamTag" -            name: "cfme-openshift-postgresql:${POSTGRESQL_IMG_TAG}" -      - -        type: "ConfigChange" +    - type: ConfigChange      replicas: 1      selector:        name: "${DATABASE_SERVICE_NAME}" @@ -310,236 +610,524 @@ objects:            name: "${DATABASE_SERVICE_NAME}"        spec:          volumes: -          - -            name: "cfme-pgdb-volume" -            persistentVolumeClaim: -              claimName: "${NAME}-${DATABASE_SERVICE_NAME}" +        - name: cfme-pgdb-volume +          persistentVolumeClaim: +            claimName: "${NAME}-${DATABASE_SERVICE_NAME}" +        - name: cfme-pg-configs +          configMap: +            name: "${DATABASE_SERVICE_NAME}-configs"          containers: -          - -            name: "postgresql" -            image: "${POSTGRESQL_IMG_NAME}:${POSTGRESQL_IMG_TAG}" -            ports: -              - -                containerPort: 5432 -            readinessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 15 +        - name: postgresql +          image: "${POSTGRESQL_IMG_NAME}:${POSTGRESQL_IMG_TAG}" +          ports: +          - containerPort: 5432 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 15 +            exec: +              command: +              - "/bin/sh" +              - "-i" +              - "-c" +              - psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1' +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 60 +            tcpSocket: +              port: 5432 +          volumeMounts: +          - name: cfme-pgdb-volume +            mountPath: "/var/lib/pgsql/data" +          - name: cfme-pg-configs +            mountPath: "${POSTGRESQL_CONFIG_DIR}" +          env: +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${DATABASE_NAME}" +          - name: POSTGRESQL_MAX_CONNECTIONS +            value: "${POSTGRESQL_MAX_CONNECTIONS}" +          - name: POSTGRESQL_SHARED_BUFFERS +            value: "${POSTGRESQL_SHARED_BUFFERS}" +          - name: POSTGRESQL_CONFIG_DIR +            value: "${POSTGRESQL_CONFIG_DIR}" +          resources: +            requests: +              memory: "${POSTGRESQL_MEM_REQ}" +              cpu: "${POSTGRESQL_CPU_REQ}" +            limits: +              memory: "${POSTGRESQL_MEM_LIMIT}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances Ansible pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${ANSIBLE_SERVICE_NAME}" +  spec: +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    - name: https +      port: 443 +      protocol: TCP +      targetPort: 443 +    selector: +      name: "${ANSIBLE_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy the Ansible appliance +  spec: +    strategy: +      type: Recreate +    serviceName: "${ANSIBLE_SERVICE_NAME}" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${ANSIBLE_SERVICE_NAME}" +        name: "${ANSIBLE_SERVICE_NAME}" +      spec: +        containers: +        - name: ansible +          image: "${ANSIBLE_IMG_NAME}:${ANSIBLE_IMG_TAG}" +          livenessProbe: +            tcpSocket: +              port: 443 +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            httpGet: +              path: "/" +              port: 443 +              scheme: HTTPS +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 443 +            protocol: TCP +          securityContext: +            privileged: true +          env: +          - name: ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          - name: RABBITMQ_USER_NAME +            value: "${ANSIBLE_RABBITMQ_USER_NAME}" +          - name: RABBITMQ_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: rabbit-password +          - name: ANSIBLE_SECRET_KEY +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: secret-key +          - name: DATABASE_SERVICE_NAME +            value: "${DATABASE_SERVICE_NAME}" +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${ANSIBLE_DATABASE_NAME}" +          resources: +            requests: +              memory: "${ANSIBLE_MEM_REQ}" +              cpu: "${ANSIBLE_CPU_REQ}" +            limits: +              memory: "${ANSIBLE_MEM_LIMIT}" +        serviceAccount: cfme-privileged +        serviceAccountName: cfme-privileged +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http +      port: 80 +      targetPort: 80 +    selector: +      name: httpd +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy httpd +  spec: +    strategy: +      type: Recreate +      recreateParams: +        timeoutSeconds: 1200 +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${HTTPD_SERVICE_NAME}" +    template: +      metadata: +        name: "${HTTPD_SERVICE_NAME}" +        labels: +          name: "${HTTPD_SERVICE_NAME}" +      spec: +        volumes: +        - name: httpd-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-configs" +        - name: httpd-auth-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-auth-configs" +        containers: +        - name: httpd +          image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}" +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP +          livenessProbe: +            exec: +              command: +              - pidof +              - httpd +            initialDelaySeconds: 15 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 10 +            timeoutSeconds: 3 +          volumeMounts: +          - name: httpd-config +            mountPath: "${HTTPD_CONFIG_DIR}" +          - name: httpd-auth-config +            mountPath: "${HTTPD_AUTH_CONFIG_DIR}" +          resources: +            requests: +              memory: "${HTTPD_MEM_REQ}" +              cpu: "${HTTPD_CPU_REQ}" +            limits: +              memory: "${HTTPD_MEM_LIMIT}" +          env: +          - name: HTTPD_AUTH_TYPE +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms +          lifecycle: +            postStart:                exec:                  command: -                  - "/bin/sh" -                  - "-i" -                  - "-c" -                  - "psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1'" -            livenessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 60 -              tcpSocket: -                port: 5432 -            volumeMounts: -              - -                name: "cfme-pgdb-volume" -                mountPath: "/var/lib/pgsql/data" -            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}" -            resources: -              requests: -                memory: "${POSTGRESQL_MEM_REQ}" -                cpu: "${POSTGRESQL_CPU_REQ}" -              limits: -                memory: "${POSTGRESQL_MEM_LIMIT}" - +                - "/usr/bin/save-container-environment" +        serviceAccount: cfme-httpd +        serviceAccountName: cfme-httpd  parameters: -  - -    name: "NAME" -    displayName: Name -    required: true -    description: "The name assigned to all of the frontend objects defined in this template." -    value: cloudforms -  - -    name: "DATABASE_SERVICE_NAME" -    displayName: "PostgreSQL Service Name" -    required: true -    description: "The name of the OpenShift Service exposed for the PostgreSQL container." -    value: "postgresql" -  - -    name: "DATABASE_USER" -    displayName: "PostgreSQL User" -    required: true -    description: "PostgreSQL user that will access the database." -    value: "root" -  - -    name: "DATABASE_PASSWORD" -    displayName: "PostgreSQL Password" -    required: true -    description: "Password for the PostgreSQL user." -    value: "smartvm" -  - -    name: "DATABASE_NAME" -    required: true -    displayName: "PostgreSQL Database Name" -    description: "Name of the PostgreSQL database accessed." -    value: "vmdb_production" -  - -    name: "DATABASE_REGION" -    required: true -    displayName: "Application Database Region" -    description: "Database region that will be used for application." -    value: "0" -  - -    name: "MEMCACHED_SERVICE_NAME" -    required: true -    displayName: "Memcached Service Name" -    description: "The name of the OpenShift Service exposed for the Memcached container." -    value: "memcached" -  - -    name: "MEMCACHED_MAX_MEMORY" -    displayName: "Memcached Max Memory" -    description: "Memcached maximum memory for memcached object storage in MB." -    value: "64" -  - -    name: "MEMCACHED_MAX_CONNECTIONS" -    displayName: "Memcached Max Connections" -    description: "Memcached maximum number of connections allowed." -    value: "1024" -  - -    name: "MEMCACHED_SLAB_PAGE_SIZE" -    displayName: "Memcached Slab Page Size" -    description: "Memcached size of each slab page." -    value: "1m" -  - -    name: "POSTGRESQL_MAX_CONNECTIONS" -    displayName: "PostgreSQL Max Connections" -    description: "PostgreSQL maximum number of database connections allowed." -    value: "100" -  - -    name: "POSTGRESQL_SHARED_BUFFERS" -    displayName: "PostgreSQL Shared Buffer Amount" -    description: "Amount of memory dedicated for PostgreSQL shared memory buffers." -    value: "256MB" -  - -    name: "APPLICATION_CPU_REQ" -    displayName: "Application Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the Application container will need (expressed in millicores)." -    value: "1000m" -  - -    name: "POSTGRESQL_CPU_REQ" -    displayName: "PostgreSQL Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the PostgreSQL container will need (expressed in millicores)." -    value: "500m" -  - -    name: "MEMCACHED_CPU_REQ" -    displayName: "Memcached Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the Memcached container will need (expressed in millicores)." -    value: "200m" -  - -    name: "APPLICATION_MEM_REQ" -    displayName: "Application Min RAM Requested" -    required: true -    description: "Minimum amount of memory the Application container will need." -    value: "6144Mi" -  - -    name: "POSTGRESQL_MEM_REQ" -    displayName: "PostgreSQL Min RAM Requested" -    required: true -    description: "Minimum amount of memory the PostgreSQL container will need." -    value: "1024Mi" -  - -    name: "MEMCACHED_MEM_REQ" -    displayName: "Memcached Min RAM Requested" -    required: true -    description: "Minimum amount of memory the Memcached container will need." -    value: "64Mi" -  - -    name: "APPLICATION_MEM_LIMIT" -    displayName: "Application Max RAM Limit" -    required: true -    description: "Maximum amount of memory the Application container can consume." -    value: "16384Mi" -  - -    name: "POSTGRESQL_MEM_LIMIT" -    displayName: "PostgreSQL Max RAM Limit" -    required: true -    description: "Maximum amount of memory the PostgreSQL container can consume." -    value: "8192Mi" -  - -    name: "MEMCACHED_MEM_LIMIT" -    displayName: "Memcached Max RAM Limit" -    required: true -    description: "Maximum amount of memory the Memcached container can consume." -    value: "256Mi" -  - -    name: "POSTGRESQL_IMG_NAME" -    displayName: "PostgreSQL Image Name" -    description: "This is the PostgreSQL image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-postgresql" -  - -    name: "POSTGRESQL_IMG_TAG" -    displayName: "PostgreSQL Image Tag" -    description: "This is the PostgreSQL image tag/version requested to deploy." -    value: "latest" -  - -    name: "MEMCACHED_IMG_NAME" -    displayName: "Memcached Image Name" -    description: "This is the Memcached image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-memcached" -  - -    name: "MEMCACHED_IMG_TAG" -    displayName: "Memcached Image Tag" -    description: "This is the Memcached image tag/version requested to deploy." -    value: "latest" -  - -    name: "APPLICATION_IMG_NAME" -    displayName: "Application Image Name" -    description: "This is the Application image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-app" -  - -    name: "APPLICATION_IMG_TAG" -    displayName: "Application Image Tag" -    description: "This is the Application image tag/version requested to deploy." -    value: "latest" -  - -    name: "APPLICATION_DOMAIN" -    displayName: "Application Hostname" -    description: "The exposed hostname that will route to the application service, if left blank a value will be defaulted." -    value: "" -  - -    name: "APPLICATION_INIT_DELAY" -    displayName: "Application Init Delay" -    required: true -    description: "Delay in seconds before we attempt to initialize the application." -    value: "15" -  - -    name: "APPLICATION_VOLUME_CAPACITY" -    displayName: "Application Volume Capacity" -    required: true -    description: "Volume space available for application data." -    value: "5Gi" -  - -    name: "APPLICATION_REGION_VOLUME_CAPACITY" -    displayName: "Application Region Volume Capacity" -    required: true -    description: "Volume space available for region application data." -    value: "5Gi" -  - -    name: "DATABASE_VOLUME_CAPACITY" -    displayName: "Database Volume Capacity" -    required: true -    description: "Volume space available for database." -    value: "15Gi" +- name: NAME +  displayName: Name +  required: true +  description: The name assigned to all of the frontend objects defined in this template. +  value: cloudforms +- name: V2_KEY +  displayName: CloudForms Encryption Key +  required: true +  description: Encryption Key for CloudForms Passwords +  from: "[a-zA-Z0-9]{43}" +  generate: expression +- name: DATABASE_SERVICE_NAME +  displayName: PostgreSQL Service Name +  required: true +  description: The name of the OpenShift Service exposed for the PostgreSQL container. +  value: postgresql +- name: DATABASE_USER +  displayName: PostgreSQL User +  required: true +  description: PostgreSQL user that will access the database. +  value: root +- name: DATABASE_PASSWORD +  displayName: PostgreSQL Password +  required: true +  description: Password for the PostgreSQL user. +  from: "[a-zA-Z0-9]{8}" +  generate: expression +- name: DATABASE_NAME +  required: true +  displayName: PostgreSQL Database Name +  description: Name of the PostgreSQL database accessed. +  value: vmdb_production +- name: DATABASE_REGION +  required: true +  displayName: Application Database Region +  description: Database region that will be used for application. +  value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm +- name: ANSIBLE_DATABASE_NAME +  displayName: Ansible PostgreSQL database name +  required: true +  description: The database to be used by the Ansible continer +  value: awx +- name: MEMCACHED_SERVICE_NAME +  required: true +  displayName: Memcached Service Name +  description: The name of the OpenShift Service exposed for the Memcached container. +  value: memcached +- name: MEMCACHED_MAX_MEMORY +  displayName: Memcached Max Memory +  description: Memcached maximum memory for memcached object storage in MB. +  value: '64' +- name: MEMCACHED_MAX_CONNECTIONS +  displayName: Memcached Max Connections +  description: Memcached maximum number of connections allowed. +  value: '1024' +- name: MEMCACHED_SLAB_PAGE_SIZE +  displayName: Memcached Slab Page Size +  description: Memcached size of each slab page. +  value: 1m +- name: POSTGRESQL_CONFIG_DIR +  displayName: PostgreSQL Configuration Overrides +  description: Directory used to store PostgreSQL configuration overrides. +  value: "/var/lib/pgsql/conf.d" +- name: POSTGRESQL_MAX_CONNECTIONS +  displayName: PostgreSQL Max Connections +  description: PostgreSQL maximum number of database connections allowed. +  value: '1000' +- name: POSTGRESQL_SHARED_BUFFERS +  displayName: PostgreSQL Shared Buffer Amount +  description: Amount of memory dedicated for PostgreSQL shared memory buffers. +  value: 1GB +- name: ANSIBLE_SERVICE_NAME +  displayName: Ansible Service Name +  description: The name of the OpenShift Service exposed for the Ansible container. +  value: ansible +- name: ANSIBLE_ADMIN_PASSWORD +  displayName: Ansible admin User password +  required: true +  description: The password for the Ansible container admin user +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: ANSIBLE_SECRET_KEY +  displayName: Ansible Secret Key +  required: true +  description: Encryption key for the Ansible container +  from: "[a-f0-9]{32}" +  generate: expression +- name: ANSIBLE_RABBITMQ_USER_NAME +  displayName: RabbitMQ Username +  required: true +  description: Username for the Ansible RabbitMQ Server +  value: ansible +- name: ANSIBLE_RABBITMQ_PASSWORD +  displayName: RabbitMQ Server Password +  required: true +  description: Password for the Ansible RabbitMQ Server +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: APPLICATION_CPU_REQ +  displayName: Application Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Application container will need (expressed in millicores). +  value: 1000m +- name: POSTGRESQL_CPU_REQ +  displayName: PostgreSQL Min CPU Requested +  required: true +  description: Minimum amount of CPU time the PostgreSQL container will need (expressed in millicores). +  value: 500m +- name: MEMCACHED_CPU_REQ +  displayName: Memcached Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Memcached container will need (expressed in millicores). +  value: 200m +- name: ANSIBLE_CPU_REQ +  displayName: Ansible Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Ansible container will need (expressed in millicores). +  value: 1000m +- name: APPLICATION_MEM_REQ +  displayName: Application Min RAM Requested +  required: true +  description: Minimum amount of memory the Application container will need. +  value: 6144Mi +- name: POSTGRESQL_MEM_REQ +  displayName: PostgreSQL Min RAM Requested +  required: true +  description: Minimum amount of memory the PostgreSQL container will need. +  value: 4Gi +- name: MEMCACHED_MEM_REQ +  displayName: Memcached Min RAM Requested +  required: true +  description: Minimum amount of memory the Memcached container will need. +  value: 64Mi +- name: ANSIBLE_MEM_REQ +  displayName: Ansible Min RAM Requested +  required: true +  description: Minimum amount of memory the Ansible container will need. +  value: 2048Mi +- name: APPLICATION_MEM_LIMIT +  displayName: Application Max RAM Limit +  required: true +  description: Maximum amount of memory the Application container can consume. +  value: 16384Mi +- name: POSTGRESQL_MEM_LIMIT +  displayName: PostgreSQL Max RAM Limit +  required: true +  description: Maximum amount of memory the PostgreSQL container can consume. +  value: 8Gi +- name: MEMCACHED_MEM_LIMIT +  displayName: Memcached Max RAM Limit +  required: true +  description: Maximum amount of memory the Memcached container can consume. +  value: 256Mi +- name: ANSIBLE_MEM_LIMIT +  displayName: Ansible Max RAM Limit +  required: true +  description: Maximum amount of memory the Ansible container can consume. +  value: 8096Mi +- name: POSTGRESQL_IMG_NAME +  displayName: PostgreSQL Image Name +  description: This is the PostgreSQL image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql +- name: POSTGRESQL_IMG_TAG +  displayName: PostgreSQL Image Tag +  description: This is the PostgreSQL image tag/version requested to deploy. +  value: latest +- name: MEMCACHED_IMG_NAME +  displayName: Memcached Image Name +  description: This is the Memcached image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached +- name: MEMCACHED_IMG_TAG +  displayName: Memcached Image Tag +  description: This is the Memcached image tag/version requested to deploy. +  value: latest +- name: FRONTEND_APPLICATION_IMG_NAME +  displayName: Frontend Application Image Name +  description: This is the Frontend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui +- name: BACKEND_APPLICATION_IMG_NAME +  displayName: Backend Application Image Name +  description: This is the Backend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app +- name: FRONTEND_APPLICATION_IMG_TAG +  displayName: Front end Application Image Tag +  description: This is the CloudForms Frontend Application image tag/version requested to deploy. +  value: latest +- name: BACKEND_APPLICATION_IMG_TAG +  displayName: Back end Application Image Tag +  description: This is the CloudForms Backend Application image tag/version requested to deploy. +  value: latest +- name: ANSIBLE_IMG_NAME +  displayName: Ansible Image Name +  description: This is the Ansible image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible +- name: ANSIBLE_IMG_TAG +  displayName: Ansible Image Tag +  description: This is the Ansible image tag/version requested to deploy. +  value: latest +- name: APPLICATION_DOMAIN +  displayName: Application Hostname +  description: The exposed hostname that will route to the application service, if left blank a value will be defaulted. +  value: '' +- name: APPLICATION_REPLICA_COUNT +  displayName: Application Replica Count +  description: This is the number of Application replicas requested to deploy. +  value: '1' +- name: APPLICATION_INIT_DELAY +  displayName: Application Init Delay +  required: true +  description: Delay in seconds before we attempt to initialize the application. +  value: '15' +- name: APPLICATION_VOLUME_CAPACITY +  displayName: Application Volume Capacity +  required: true +  description: Volume space available for application data. +  value: 5Gi +- name: DATABASE_VOLUME_CAPACITY +  displayName: Database Volume Capacity +  required: true +  description: Volume space available for database. +  value: 15Gi +- name: HTTPD_SERVICE_NAME +  required: true +  displayName: Apache httpd Service Name +  description: The name of the OpenShift Service exposed for the httpd container. +  value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api +- name: HTTPD_IMG_NAME +  displayName: Apache httpd Image Name +  description: This is the httpd image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd +- name: HTTPD_IMG_TAG +  displayName: Apache httpd Image Tag +  description: This is the httpd image tag/version requested to deploy. +  value: latest +- name: HTTPD_CONFIG_DIR +  displayName: Apache Configuration Directory +  description: Directory used to store the Apache configuration files. +  value: "/etc/httpd/conf.d" +- name: HTTPD_AUTH_CONFIG_DIR +  displayName: External Authentication Configuration Directory +  description: Directory used to store the external authentication configuration files. +  value: "/etc/httpd/auth-conf.d" +- name: HTTPD_CPU_REQ +  displayName: Apache httpd Min CPU Requested +  required: true +  description: Minimum amount of CPU time the httpd container will need (expressed in millicores). +  value: 500m +- name: HTTPD_MEM_REQ +  displayName: Apache httpd Min RAM Requested +  required: true +  description: Minimum amount of memory the httpd container will need. +  value: 512Mi +- name: HTTPD_MEM_LIMIT +  displayName: Apache httpd Max RAM Limit +  required: true +  description: Maximum amount of memory the httpd container can consume. +  value: 8192Mi diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-job.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-job.yaml new file mode 100644 index 000000000..48d1d4e26 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-job.yaml @@ -0,0 +1,28 @@ +apiVersion: batch/v1 +kind: Job +metadata: +  name: cloudforms-backup +spec: +  template: +    metadata: +      name: cloudforms-backup +    spec: +      containers: +      - name: postgresql +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest +        command: +        - "/opt/rh/cfme-container-scripts/backup_db" +        env: +        - name: DATABASE_URL +          valueFrom: +            secretKeyRef: +              name: cloudforms-secrets +              key: database-url +        volumeMounts: +        - name: cfme-backup-vol +          mountPath: "/backups" +      volumes: +      - name: cfme-backup-vol +        persistentVolumeClaim: +          claimName: cloudforms-backup +      restartPolicy: Never diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-pvc.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-pvc.yaml new file mode 100644 index 000000000..92598ce82 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-backup-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: +  name: cloudforms-backup +spec: +  accessModes: +  - ReadWriteOnce +  resources: +    requests: +      storage: 15Gi diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-backup-example.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-backup-example.yaml new file mode 100644 index 000000000..4fe349897 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-backup-example.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: +  name: cfme-pv03 +spec: +  capacity: +    storage: 15Gi +  accessModes: +  - ReadWriteOnce +  nfs: +    path: "/exports/cfme-pv03" +    server: "<your-nfs-host-here>" +  persistentVolumeReclaimPolicy: Retain diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-db-example.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-db-example.yaml index 250a99b8d..0cdd821b5 100644 --- a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-db-example.yaml +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-db-example.yaml @@ -1,13 +1,38 @@  apiVersion: v1 -kind: PersistentVolume +kind: Template +labels: +  template: cloudforms-db-pv  metadata: -  name: cfme-pv01 -spec: -  capacity: -    storage: 15Gi -  accessModes: +  name: cloudforms-db-pv +  annotations: +    description: PV Template for CFME PostgreSQL DB +    tags: PVS, CFME +objects: +- apiVersion: v1 +  kind: PersistentVolume +  metadata: +    name: cfme-db +  spec: +    capacity: +      storage: "${PV_SIZE}" +    accessModes:      - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv01 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain +    nfs: +      path: "${BASE_PATH}/cfme-db" +      server: "${NFS_HOST}" +    persistentVolumeReclaimPolicy: Retain +parameters: +- name: PV_SIZE +  displayName: PV Size for DB +  required: true +  description: The size of the CFME DB PV given in Gi +  value: 15Gi +- name: BASE_PATH +  displayName: Exports Directory Base Path +  required: true +  description: The parent directory of your NFS exports +  value: "/exports" +- name: NFS_HOST +  displayName: NFS Server Hostname +  required: true +  description: The hostname or IP address of the NFS server diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-region-example.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-region-example.yaml deleted file mode 100644 index cba9bbe35..000000000 --- a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-region-example.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: PersistentVolume -metadata: -  name: cfme-pv02 -spec: -  capacity: -    storage: 5Gi -  accessModes: -    - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv02 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-server-example.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-server-example.yaml index c08c21265..527090ae8 100644 --- a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-server-example.yaml +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-pv-server-example.yaml @@ -1,13 +1,38 @@  apiVersion: v1 -kind: PersistentVolume +kind: Template +labels: +  template: cloudforms-app-pv  metadata: -  name: cfme-pv03 -spec: -  capacity: -    storage: 5Gi -  accessModes: +  name: cloudforms-app-pv +  annotations: +    description: PV Template for CFME Server +    tags: PVS, CFME +objects: +- apiVersion: v1 +  kind: PersistentVolume +  metadata: +    name: cfme-app +  spec: +    capacity: +      storage: "${PV_SIZE}" +    accessModes:      - ReadWriteOnce -  nfs:  -    path: /exports/cfme-pv03 -    server: <your-nfs-host-here> -  persistentVolumeReclaimPolicy: Retain +    nfs: +      path: "${BASE_PATH}/cfme-app" +      server: "${NFS_HOST}" +    persistentVolumeReclaimPolicy: Retain +parameters: +- name: PV_SIZE +  displayName: PV Size for App +  required: true +  description: The size of the CFME APP PV given in Gi +  value: 5Gi +- name: BASE_PATH +  displayName: Exports Directory Base Path +  required: true +  description: The parent directory of your NFS exports +  value: "/exports" +- name: NFS_HOST +  displayName: NFS Server Hostname +  required: true +  description: The hostname or IP address of the NFS server diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-restore-job.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-restore-job.yaml new file mode 100644 index 000000000..7fd4fc2e1 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-restore-job.yaml @@ -0,0 +1,35 @@ +apiVersion: batch/v1 +kind: Job +metadata: +  name: cloudforms-restore +spec: +  template: +    metadata: +      name: cloudforms-restore +    spec: +      containers: +      - name: postgresql +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest +        command: +        - "/opt/rh/cfme-container-scripts/restore_db" +        env: +        - name: DATABASE_URL +          valueFrom: +            secretKeyRef: +              name: cloudforms-secrets +              key: database-url +        - name: BACKUP_VERSION +          value: latest +        volumeMounts: +        - name: cfme-backup-vol +          mountPath: "/backups" +        - name: cfme-prod-vol +          mountPath: "/restore" +      volumes: +      - name: cfme-backup-vol +        persistentVolumeClaim: +          claimName: cloudforms-backup +      - name: cfme-prod-vol +        persistentVolumeClaim: +          claimName: cloudforms-postgresql +      restartPolicy: Never diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-scc-sysadmin.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-scc-sysadmin.yaml new file mode 100644 index 000000000..d2ece9298 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-scc-sysadmin.yaml @@ -0,0 +1,38 @@ +allowHostDirVolumePlugin: false +allowHostIPC: false +allowHostNetwork: false +allowHostPID: false +allowHostPorts: false +allowPrivilegedContainer: false +allowedCapabilities: +apiVersion: v1 +defaultAddCapabilities: +- SYS_ADMIN +fsGroup: +  type: RunAsAny +groups: +- system:cluster-admins +kind: SecurityContextConstraints +metadata: +  annotations: +    kubernetes.io/description: cfme-sysadmin provides all features of the anyuid SCC but allows users to have SYS_ADMIN capabilities. This is the required scc for Pods requiring to run with systemd and the message bus. +  creationTimestamp: +  name: cfme-sysadmin +priority: 10 +readOnlyRootFilesystem: false +requiredDropCapabilities: +- MKNOD +- SYS_CHROOT +runAsUser: +  type: RunAsAny +seLinuxContext: +  type: MustRunAs +supplementalGroups: +  type: RunAsAny +users: +volumes: +- configMap +- downwardAPI +- emptyDir +- persistentVolumeClaim +- secret diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template-ext-db.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template-ext-db.yaml new file mode 100644 index 000000000..9866c29c3 --- /dev/null +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template-ext-db.yaml @@ -0,0 +1,956 @@ +apiVersion: v1 +kind: Template +labels: +  template: cloudforms-ext-db +metadata: +  name: cloudforms-ext-db +  annotations: +    description: CloudForms appliance with persistent storage using a external DB host +    tags: instant-app,cloudforms,cfme +    iconClass: icon-rails +objects: +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-orchestrator +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-anyuid +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-privileged +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-httpd +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${NAME}-secrets" +  stringData: +    pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}" +    database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5 +    v2-key: "${V2_KEY}" +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}-secrets" +  stringData: +    rabbit-password: "${ANSIBLE_RABBITMQ_PASSWORD}" +    secret-key: "${ANSIBLE_SECRET_KEY}" +    admin-password: "${ANSIBLE_ADMIN_PASSWORD}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances CloudForms pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"},{"name":"${MEMCACHED_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${NAME}" +  spec: +    clusterIP: None +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    selector: +      name: "${NAME}" +- apiVersion: v1 +  kind: Route +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +  spec: +    host: "${APPLICATION_DOMAIN}" +    port: +      targetPort: http +    tls: +      termination: edge +      insecureEdgeTerminationPolicy: Redirect +    to: +      kind: Service +      name: "${HTTPD_SERVICE_NAME}" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}" +    replicas: "${APPLICATION_REPLICA_COUNT}" +    template: +      metadata: +        labels: +          name: "${NAME}" +        name: "${NAME}" +      spec: +        containers: +        - name: cloudforms +          image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: MY_POD_NAMESPACE +            valueFrom: +              fieldRef: +                fieldPath: metadata.namespace +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_REGION +            value: "${DATABASE_REGION}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          resources: +            requests: +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Headless service for CloudForms backend pods +    name: "${NAME}-backend" +  spec: +    clusterIP: None +    selector: +      name: "${NAME}-backend" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}-backend" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}-backend" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${NAME}-backend" +        name: "${NAME}-backend" +      spec: +        containers: +        - name: cloudforms +          image: "${BACKEND_APPLICATION_IMG_NAME}:${BACKEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: MIQ_SERVER_DEFAULT_ROLES +            value: database_operations,event,reporting,scheduler,smartstate,ems_operations,ems_inventory,automate +          - name: FRONTEND_SERVICE_NAME +            value: "${NAME}" +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          resources: +            requests: +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${MEMCACHED_SERVICE_NAME}" +    annotations: +      description: Exposes the memcached server +  spec: +    ports: +    - name: memcached +      port: 11211 +      targetPort: 11211 +    selector: +      name: "${MEMCACHED_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${MEMCACHED_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy memcached +  spec: +    strategy: +      type: Recreate +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${MEMCACHED_SERVICE_NAME}" +    template: +      metadata: +        name: "${MEMCACHED_SERVICE_NAME}" +        labels: +          name: "${MEMCACHED_SERVICE_NAME}" +      spec: +        volumes: [] +        containers: +        - name: memcached +          image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" +          ports: +          - containerPort: 11211 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 5 +            tcpSocket: +              port: 11211 +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 30 +            tcpSocket: +              port: 11211 +          volumeMounts: [] +          env: +          - name: MEMCACHED_MAX_MEMORY +            value: "${MEMCACHED_MAX_MEMORY}" +          - name: MEMCACHED_MAX_CONNECTIONS +            value: "${MEMCACHED_MAX_CONNECTIONS}" +          - name: MEMCACHED_SLAB_PAGE_SIZE +            value: "${MEMCACHED_SLAB_PAGE_SIZE}" +          resources: +            requests: +              memory: "${MEMCACHED_MEM_REQ}" +              cpu: "${MEMCACHED_CPU_REQ}" +            limits: +              memory: "${MEMCACHED_MEM_LIMIT}" +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${DATABASE_SERVICE_NAME}" +    annotations: +      description: Remote database service +  spec: +    ports: +    - name: postgresql +      port: 5432 +      targetPort: "${{DATABASE_PORT}}" +    selector: {} +- apiVersion: v1 +  kind: Endpoints +  metadata: +    name: "${DATABASE_SERVICE_NAME}" +  subsets: +  - addresses: +    - ip: "${DATABASE_IP}" +    ports: +    - port: "${{DATABASE_PORT}}" +      name: postgresql +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances Ansible pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${ANSIBLE_SERVICE_NAME}" +  spec: +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    - name: https +      port: 443 +      protocol: TCP +      targetPort: 443 +    selector: +      name: "${ANSIBLE_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy the Ansible appliance +  spec: +    strategy: +      type: Recreate +    serviceName: "${ANSIBLE_SERVICE_NAME}" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${ANSIBLE_SERVICE_NAME}" +        name: "${ANSIBLE_SERVICE_NAME}" +      spec: +        containers: +        - name: ansible +          image: "${ANSIBLE_IMG_NAME}:${ANSIBLE_IMG_TAG}" +          livenessProbe: +            tcpSocket: +              port: 443 +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            httpGet: +              path: "/" +              port: 443 +              scheme: HTTPS +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 443 +            protocol: TCP +          securityContext: +            privileged: true +          env: +          - name: ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          - name: RABBITMQ_USER_NAME +            value: "${ANSIBLE_RABBITMQ_USER_NAME}" +          - name: RABBITMQ_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: rabbit-password +          - name: ANSIBLE_SECRET_KEY +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: secret-key +          - name: DATABASE_SERVICE_NAME +            value: "${DATABASE_SERVICE_NAME}" +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${ANSIBLE_DATABASE_NAME}" +          resources: +            requests: +              memory: "${ANSIBLE_MEM_REQ}" +              cpu: "${ANSIBLE_CPU_REQ}" +            limits: +              memory: "${ANSIBLE_MEM_LIMIT}" +        serviceAccount: cfme-privileged +        serviceAccountName: cfme-privileged +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-configs" +  data: +    application.conf: | +      # Timeout: The number of seconds before receives and sends time out. +      Timeout 120 + +      RewriteEngine On +      Options SymLinksIfOwnerMatch + +      <VirtualHost *:80> +        KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} + +        ProxyPreserveHost on + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L] +        ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common +      </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-auth-configs" +  data: +    auth-type: internal +    auth-kerberos-realms: undefined +    auth-configuration.conf: | +      # External Authentication Configuration File +      # +      # For details on usage please see https://github.com/ManageIQ/manageiq-pods/blob/master/README.md#configuring-external-authentication +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http +      port: 80 +      targetPort: 80 +    selector: +      name: httpd +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy httpd +  spec: +    strategy: +      type: Recreate +      recreateParams: +        timeoutSeconds: 1200 +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${HTTPD_SERVICE_NAME}" +    template: +      metadata: +        name: "${HTTPD_SERVICE_NAME}" +        labels: +          name: "${HTTPD_SERVICE_NAME}" +      spec: +        volumes: +        - name: httpd-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-configs" +        - name: httpd-auth-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-auth-configs" +        containers: +        - name: httpd +          image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}" +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP +          livenessProbe: +            exec: +              command: +              - pidof +              - httpd +            initialDelaySeconds: 15 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 10 +            timeoutSeconds: 3 +          volumeMounts: +          - name: httpd-config +            mountPath: "${HTTPD_CONFIG_DIR}" +          - name: httpd-auth-config +            mountPath: "${HTTPD_AUTH_CONFIG_DIR}" +          resources: +            requests: +              memory: "${HTTPD_MEM_REQ}" +              cpu: "${HTTPD_CPU_REQ}" +            limits: +              memory: "${HTTPD_MEM_LIMIT}" +          env: +          - name: HTTPD_AUTH_TYPE +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms +          lifecycle: +            postStart: +              exec: +                command: +                - "/usr/bin/save-container-environment" +        serviceAccount: cfme-httpd +        serviceAccountName: cfme-httpd +parameters: +- name: NAME +  displayName: Name +  required: true +  description: The name assigned to all of the frontend objects defined in this template. +  value: cloudforms +- name: V2_KEY +  displayName: CloudForms Encryption Key +  required: true +  description: Encryption Key for CloudForms Passwords +  from: "[a-zA-Z0-9]{43}" +  generate: expression +- name: DATABASE_SERVICE_NAME +  displayName: PostgreSQL Service Name +  required: true +  description: The name of the OpenShift Service exposed for the PostgreSQL container. +  value: postgresql +- name: DATABASE_USER +  displayName: PostgreSQL User +  required: true +  description: PostgreSQL user that will access the database. +  value: root +- name: DATABASE_PASSWORD +  displayName: PostgreSQL Password +  required: true +  description: Password for the PostgreSQL user. +  from: "[a-zA-Z0-9]{8}" +  generate: expression +- name: DATABASE_IP +  displayName: PostgreSQL Server IP +  required: true +  description: PostgreSQL external server IP used to configure service. +  value: '' +- name: DATABASE_PORT +  displayName: PostgreSQL Server Port +  required: true +  description: PostgreSQL external server port used to configure service. +  value: '5432' +- name: DATABASE_NAME +  required: true +  displayName: PostgreSQL Database Name +  description: Name of the PostgreSQL database accessed. +  value: vmdb_production +- name: DATABASE_REGION +  required: true +  displayName: Application Database Region +  description: Database region that will be used for application. +  value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm +- name: ANSIBLE_DATABASE_NAME +  displayName: Ansible PostgreSQL database name +  required: true +  description: The database to be used by the Ansible continer +  value: awx +- name: MEMCACHED_SERVICE_NAME +  required: true +  displayName: Memcached Service Name +  description: The name of the OpenShift Service exposed for the Memcached container. +  value: memcached +- name: MEMCACHED_MAX_MEMORY +  displayName: Memcached Max Memory +  description: Memcached maximum memory for memcached object storage in MB. +  value: '64' +- name: MEMCACHED_MAX_CONNECTIONS +  displayName: Memcached Max Connections +  description: Memcached maximum number of connections allowed. +  value: '1024' +- name: MEMCACHED_SLAB_PAGE_SIZE +  displayName: Memcached Slab Page Size +  description: Memcached size of each slab page. +  value: 1m +- name: ANSIBLE_SERVICE_NAME +  displayName: Ansible Service Name +  description: The name of the OpenShift Service exposed for the Ansible container. +  value: ansible +- name: ANSIBLE_ADMIN_PASSWORD +  displayName: Ansible admin User password +  required: true +  description: The password for the Ansible container admin user +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: ANSIBLE_SECRET_KEY +  displayName: Ansible Secret Key +  required: true +  description: Encryption key for the Ansible container +  from: "[a-f0-9]{32}" +  generate: expression +- name: ANSIBLE_RABBITMQ_USER_NAME +  displayName: RabbitMQ Username +  required: true +  description: Username for the Ansible RabbitMQ Server +  value: ansible +- name: ANSIBLE_RABBITMQ_PASSWORD +  displayName: RabbitMQ Server Password +  required: true +  description: Password for the Ansible RabbitMQ Server +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: APPLICATION_CPU_REQ +  displayName: Application Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Application container will need (expressed in millicores). +  value: 1000m +- name: MEMCACHED_CPU_REQ +  displayName: Memcached Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Memcached container will need (expressed in millicores). +  value: 200m +- name: ANSIBLE_CPU_REQ +  displayName: Ansible Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Ansible container will need (expressed in millicores). +  value: 1000m +- name: APPLICATION_MEM_REQ +  displayName: Application Min RAM Requested +  required: true +  description: Minimum amount of memory the Application container will need. +  value: 6144Mi +- name: MEMCACHED_MEM_REQ +  displayName: Memcached Min RAM Requested +  required: true +  description: Minimum amount of memory the Memcached container will need. +  value: 64Mi +- name: ANSIBLE_MEM_REQ +  displayName: Ansible Min RAM Requested +  required: true +  description: Minimum amount of memory the Ansible container will need. +  value: 2048Mi +- name: APPLICATION_MEM_LIMIT +  displayName: Application Max RAM Limit +  required: true +  description: Maximum amount of memory the Application container can consume. +  value: 16384Mi +- name: MEMCACHED_MEM_LIMIT +  displayName: Memcached Max RAM Limit +  required: true +  description: Maximum amount of memory the Memcached container can consume. +  value: 256Mi +- name: ANSIBLE_MEM_LIMIT +  displayName: Ansible Max RAM Limit +  required: true +  description: Maximum amount of memory the Ansible container can consume. +  value: 8096Mi +- name: MEMCACHED_IMG_NAME +  displayName: Memcached Image Name +  description: This is the Memcached image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached +- name: MEMCACHED_IMG_TAG +  displayName: Memcached Image Tag +  description: This is the Memcached image tag/version requested to deploy. +  value: latest +- name: FRONTEND_APPLICATION_IMG_NAME +  displayName: Frontend Application Image Name +  description: This is the Frontend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui +- name: BACKEND_APPLICATION_IMG_NAME +  displayName: Backend Application Image Name +  description: This is the Backend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app +- name: FRONTEND_APPLICATION_IMG_TAG +  displayName: Front end Application Image Tag +  description: This is the CloudForms Frontend Application image tag/version requested to deploy. +  value: latest +- name: BACKEND_APPLICATION_IMG_TAG +  displayName: Back end Application Image Tag +  description: This is the CloudForms Backend Application image tag/version requested to deploy. +  value: latest +- name: ANSIBLE_IMG_NAME +  displayName: Ansible Image Name +  description: This is the Ansible image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible +- name: ANSIBLE_IMG_TAG +  displayName: Ansible Image Tag +  description: This is the Ansible image tag/version requested to deploy. +  value: latest +- name: APPLICATION_DOMAIN +  displayName: Application Hostname +  description: The exposed hostname that will route to the application service, if left blank a value will be defaulted. +  value: '' +- name: APPLICATION_REPLICA_COUNT +  displayName: Application Replica Count +  description: This is the number of Application replicas requested to deploy. +  value: '1' +- name: APPLICATION_INIT_DELAY +  displayName: Application Init Delay +  required: true +  description: Delay in seconds before we attempt to initialize the application. +  value: '15' +- name: APPLICATION_VOLUME_CAPACITY +  displayName: Application Volume Capacity +  required: true +  description: Volume space available for application data. +  value: 5Gi +- name: HTTPD_SERVICE_NAME +  required: true +  displayName: Apache httpd Service Name +  description: The name of the OpenShift Service exposed for the httpd container. +  value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api +- name: HTTPD_IMG_NAME +  displayName: Apache httpd Image Name +  description: This is the httpd image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd +- name: HTTPD_IMG_TAG +  displayName: Apache httpd Image Tag +  description: This is the httpd image tag/version requested to deploy. +  value: latest +- name: HTTPD_CONFIG_DIR +  displayName: Apache httpd Configuration Directory +  description: Directory used to store the Apache configuration files. +  value: "/etc/httpd/conf.d" +- name: HTTPD_AUTH_CONFIG_DIR +  displayName: External Authentication Configuration Directory +  description: Directory used to store the external authentication configuration files. +  value: "/etc/httpd/auth-conf.d" +- name: HTTPD_CPU_REQ +  displayName: Apache httpd Min CPU Requested +  required: true +  description: Minimum amount of CPU time the httpd container will need (expressed in millicores). +  value: 500m +- name: HTTPD_MEM_REQ +  displayName: Apache httpd Min RAM Requested +  required: true +  description: Minimum amount of memory the httpd container will need. +  value: 512Mi +- name: HTTPD_MEM_LIMIT +  displayName: Apache httpd Max RAM Limit +  required: true +  description: Maximum amount of memory the httpd container can consume. +  value: 8192Mi diff --git a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template.yaml b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template.yaml index 3bc6c5813..5c757b6c2 100644 --- a/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template.yaml +++ b/roles/openshift_examples/files/examples/v3.9/cfme-templates/cfme-template.yaml @@ -5,17 +5,308 @@ labels:  metadata:    name: cloudforms    annotations: -    description: "CloudForms appliance with persistent storage" -    tags: "instant-app,cloudforms,cfme" -    iconClass: "icon-rails" +    description: CloudForms appliance with persistent storage +    tags: instant-app,cloudforms,cfme +    iconClass: icon-rails  objects:  - apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-orchestrator +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-anyuid +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-privileged +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: cfme-httpd +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${NAME}-secrets" +  stringData: +    pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}" +    database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5 +    v2-key: "${V2_KEY}" +- apiVersion: v1 +  kind: Secret +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}-secrets" +  stringData: +    rabbit-password: "${ANSIBLE_RABBITMQ_PASSWORD}" +    secret-key: "${ANSIBLE_SECRET_KEY}" +    admin-password: "${ANSIBLE_ADMIN_PASSWORD}" +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${DATABASE_SERVICE_NAME}-configs" +  data: +    01_miq_overrides.conf: | +      #------------------------------------------------------------------------------ +      # CONNECTIONS AND AUTHENTICATION +      #------------------------------------------------------------------------------ + +      tcp_keepalives_count = 9 +      tcp_keepalives_idle = 3 +      tcp_keepalives_interval = 75 + +      #------------------------------------------------------------------------------ +      # RESOURCE USAGE (except WAL) +      #------------------------------------------------------------------------------ + +      shared_preload_libraries = 'pglogical,repmgr_funcs' +      max_worker_processes = 10 + +      #------------------------------------------------------------------------------ +      # WRITE AHEAD LOG +      #------------------------------------------------------------------------------ + +      wal_level = 'logical' +      wal_log_hints = on +      wal_buffers = 16MB +      checkpoint_completion_target = 0.9 + +      #------------------------------------------------------------------------------ +      # REPLICATION +      #------------------------------------------------------------------------------ + +      max_wal_senders = 10 +      wal_sender_timeout = 0 +      max_replication_slots = 10 +      hot_standby = on + +      #------------------------------------------------------------------------------ +      # ERROR REPORTING AND LOGGING +      #------------------------------------------------------------------------------ + +      log_filename = 'postgresql.log' +      log_rotation_age = 0 +      log_min_duration_statement = 5000 +      log_connections = on +      log_disconnections = on +      log_line_prefix = '%t:%r:%c:%u@%d:[%p]:' +      log_lock_waits = on + +      #------------------------------------------------------------------------------ +      # AUTOVACUUM PARAMETERS +      #------------------------------------------------------------------------------ + +      log_autovacuum_min_duration = 0 +      autovacuum_naptime = 5min +      autovacuum_vacuum_threshold = 500 +      autovacuum_analyze_threshold = 500 +      autovacuum_vacuum_scale_factor = 0.05 + +      #------------------------------------------------------------------------------ +      # LOCK MANAGEMENT +      #------------------------------------------------------------------------------ + +      deadlock_timeout = 5s + +      #------------------------------------------------------------------------------ +      # VERSION/PLATFORM COMPATIBILITY +      #------------------------------------------------------------------------------ + +      escape_string_warning = off +      standard_conforming_strings = off +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-configs" +  data: +    application.conf: | +      # Timeout: The number of seconds before receives and sends time out. +      Timeout 120 + +      RewriteEngine On +      Options SymLinksIfOwnerMatch + +      <VirtualHost *:80> +        KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} + +        ProxyPreserveHost on + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L] +        ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common +      </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: "${HTTPD_SERVICE_NAME}-auth-configs" +  data: +    auth-type: internal +    auth-kerberos-realms: undefined +    auth-configuration.conf: | +      # External Authentication Configuration File +      # +      # For details on usage please see https://github.com/ManageIQ/manageiq-pods/blob/master/README.md#configuring-external-authentication +- apiVersion: v1    kind: Service    metadata:      annotations: -      description: "Exposes and load balances CloudForms pods" +      description: Exposes and load balances CloudForms pods        service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"},{"name":"${MEMCACHED_SERVICE_NAME}","namespace":"","kind":"Service"}]' -    name: ${NAME} +    name: "${NAME}"    spec:      clusterIP: None      ports: @@ -23,141 +314,97 @@ objects:        port: 80        protocol: TCP        targetPort: 80 -    - name: https -      port: 443 -      protocol: TCP -      targetPort: 443      selector: -      name: ${NAME} +      name: "${NAME}"  - apiVersion: v1    kind: Route    metadata: -    name: ${NAME} +    name: "${HTTPD_SERVICE_NAME}"    spec: -    host: ${APPLICATION_DOMAIN} +    host: "${APPLICATION_DOMAIN}"      port: -      targetPort: https +      targetPort: http      tls: -      termination: passthrough +      termination: edge +      insecureEdgeTerminationPolicy: Redirect      to:        kind: Service -      name: ${NAME} -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-app -    annotations: -      description: "Keeps track of changes in the CloudForms app image" -  spec: -    dockerImageRepository: "${APPLICATION_IMG_NAME}" -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-postgresql -    annotations: -      description: "Keeps track of changes in the CloudForms postgresql image" -  spec: -    dockerImageRepository: "${POSTGRESQL_IMG_NAME}" -- apiVersion: v1 -  kind: ImageStream -  metadata: -    name: cfme-openshift-memcached -    annotations: -      description: "Keeps track of changes in the CloudForms memcached image" -  spec: -    dockerImageRepository: "${MEMCACHED_IMG_NAME}" +      name: "${HTTPD_SERVICE_NAME}"  - apiVersion: v1    kind: PersistentVolumeClaim    metadata:      name: "${NAME}-${DATABASE_SERVICE_NAME}"    spec:      accessModes: -      - ReadWriteOnce +    - ReadWriteOnce      resources:        requests: -        storage: ${DATABASE_VOLUME_CAPACITY} -- apiVersion: v1 -  kind: PersistentVolumeClaim -  metadata: -    name: "${NAME}-region" -  spec: -    accessModes: -      - ReadWriteOnce -    resources: -      requests: -        storage: ${APPLICATION_REGION_VOLUME_CAPACITY} +        storage: "${DATABASE_VOLUME_CAPACITY}"  - apiVersion: apps/v1beta1 -  kind: "StatefulSet" +  kind: StatefulSet    metadata: -    name: ${NAME} +    name: "${NAME}"      annotations: -      description: "Defines how to deploy the CloudForms appliance" +      description: Defines how to deploy the CloudForms appliance    spec:      serviceName: "${NAME}" -    replicas: 1 +    replicas: "${APPLICATION_REPLICA_COUNT}"      template:        metadata:          labels: -          name: ${NAME} -        name: ${NAME} +          name: "${NAME}" +        name: "${NAME}"        spec:          containers:          - name: cloudforms -          image: "${APPLICATION_IMG_NAME}:${APPLICATION_IMG_TAG}" +          image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}"            livenessProbe: -            tcpSocket: -              port: 443 +            exec: +              command: +              - pidof +              - MIQ Server              initialDelaySeconds: 480              timeoutSeconds: 3            readinessProbe: -            httpGet: -              path: / -              port: 443 -              scheme: HTTPS +            tcpSocket: +              port: 80              initialDelaySeconds: 200              timeoutSeconds: 3            ports:            - containerPort: 80              protocol: TCP -          - containerPort: 443 -            protocol: TCP -          securityContext: -            privileged: true            volumeMounts: -              - -                name: "${NAME}-server" -                mountPath: "/persistent" -              - -                name: "${NAME}-region" -                mountPath: "/persistent-region" +          - name: "${NAME}-server" +            mountPath: "/persistent"            env: -            - -              name: "APPLICATION_INIT_DELAY" -              value: "${APPLICATION_INIT_DELAY}" -            - -              name: "DATABASE_SERVICE_NAME" -              value: "${DATABASE_SERVICE_NAME}" -            - -              name: "DATABASE_REGION" -              value: "${DATABASE_REGION}" -            - -              name: "MEMCACHED_SERVICE_NAME" -              value: "${MEMCACHED_SERVICE_NAME}" -            - -              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}" +          - name: MY_POD_NAMESPACE +            valueFrom: +              fieldRef: +                fieldPath: metadata.namespace +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_REGION +            value: "${DATABASE_REGION}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password            resources:              requests:                memory: "${APPLICATION_MEM_REQ}" @@ -168,59 +415,128 @@ objects:              preStop:                exec:                  command: -                  - /opt/rh/cfme-container-scripts/sync-pv-data -        volumes: -         - -           name: "${NAME}-region" -           persistentVolumeClaim: -             claimName: ${NAME}-region +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90      volumeClaimTemplates: -      - metadata: -          name: "${NAME}-server" -          annotations: -            # Uncomment this if using dynamic volume provisioning. -            # https://docs.openshift.org/latest/install_config/persistent_storage/dynamically_provisioning_pvs.html -            # volume.alpha.kubernetes.io/storage-class: anything -        spec: -          accessModes: [ ReadWriteOnce ] +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Headless service for CloudForms backend pods +    name: "${NAME}-backend" +  spec: +    clusterIP: None +    selector: +      name: "${NAME}-backend" +- apiVersion: apps/v1beta1 +  kind: StatefulSet +  metadata: +    name: "${NAME}-backend" +    annotations: +      description: Defines how to deploy the CloudForms appliance +  spec: +    serviceName: "${NAME}-backend" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${NAME}-backend" +        name: "${NAME}-backend" +      spec: +        containers: +        - name: cloudforms +          image: "${BACKEND_APPLICATION_IMG_NAME}:${BACKEND_APPLICATION_IMG_TAG}" +          livenessProbe: +            exec: +              command: +              - pidof +              - MIQ Server +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          volumeMounts: +          - name: "${NAME}-server" +            mountPath: "/persistent" +          env: +          - name: APPLICATION_INIT_DELAY +            value: "${APPLICATION_INIT_DELAY}" +          - name: DATABASE_URL +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: database-url +          - name: MIQ_SERVER_DEFAULT_ROLES +            value: database_operations,event,reporting,scheduler,smartstate,ems_operations,ems_inventory,automate +          - name: FRONTEND_SERVICE_NAME +            value: "${NAME}" +          - name: V2_KEY +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: v2-key +          - name: ANSIBLE_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password            resources:              requests: -              storage: "${APPLICATION_VOLUME_CAPACITY}" +              memory: "${APPLICATION_MEM_REQ}" +              cpu: "${APPLICATION_CPU_REQ}" +            limits: +              memory: "${APPLICATION_MEM_LIMIT}" +          lifecycle: +            preStop: +              exec: +                command: +                - "/opt/rh/cfme-container-scripts/sync-pv-data" +        serviceAccount: cfme-orchestrator +        serviceAccountName: cfme-orchestrator +        terminationGracePeriodSeconds: 90 +    volumeClaimTemplates: +    - metadata: +        name: "${NAME}-server" +        annotations: +      spec: +        accessModes: +        - ReadWriteOnce +        resources: +          requests: +            storage: "${APPLICATION_VOLUME_CAPACITY}"  - apiVersion: v1 -  kind: "Service" +  kind: Service    metadata:      name: "${MEMCACHED_SERVICE_NAME}"      annotations: -      description: "Exposes the memcached server" +      description: Exposes the memcached server    spec:      ports: -      - -        name: "memcached" -        port: 11211 -        targetPort: 11211 +    - name: memcached +      port: 11211 +      targetPort: 11211      selector:        name: "${MEMCACHED_SERVICE_NAME}"  - apiVersion: v1 -  kind: "DeploymentConfig" +  kind: DeploymentConfig    metadata:      name: "${MEMCACHED_SERVICE_NAME}"      annotations: -      description: "Defines how to deploy memcached" +      description: Defines how to deploy memcached    spec:      strategy: -      type: "Recreate" +      type: Recreate      triggers: -      - -        type: "ImageChange" -        imageChangeParams: -          automatic: true -          containerNames: -            - "memcached" -          from: -            kind: "ImageStreamTag" -            name: "cfme-openshift-memcached:${MEMCACHED_IMG_TAG}" -      - -        type: "ConfigChange" +    - type: ConfigChange      replicas: 1      selector:        name: "${MEMCACHED_SERVICE_NAME}" @@ -232,74 +548,58 @@ objects:        spec:          volumes: []          containers: -          - -            name: "memcached" -            image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" -            ports: -              - -                containerPort: 11211 -            readinessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 5 -              tcpSocket: -                port: 11211 -            livenessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 30 -              tcpSocket: -                port: 11211 -            volumeMounts: [] -            env: -              - -                name: "MEMCACHED_MAX_MEMORY" -                value: "${MEMCACHED_MAX_MEMORY}" -              - -                name: "MEMCACHED_MAX_CONNECTIONS" -                value: "${MEMCACHED_MAX_CONNECTIONS}" -              - -                name: "MEMCACHED_SLAB_PAGE_SIZE" -                value: "${MEMCACHED_SLAB_PAGE_SIZE}" -            resources: -              requests: -                memory: "${MEMCACHED_MEM_REQ}" -                cpu: "${MEMCACHED_CPU_REQ}" -              limits: -                memory: "${MEMCACHED_MEM_LIMIT}" +        - name: memcached +          image: "${MEMCACHED_IMG_NAME}:${MEMCACHED_IMG_TAG}" +          ports: +          - containerPort: 11211 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 5 +            tcpSocket: +              port: 11211 +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 30 +            tcpSocket: +              port: 11211 +          volumeMounts: [] +          env: +          - name: MEMCACHED_MAX_MEMORY +            value: "${MEMCACHED_MAX_MEMORY}" +          - name: MEMCACHED_MAX_CONNECTIONS +            value: "${MEMCACHED_MAX_CONNECTIONS}" +          - name: MEMCACHED_SLAB_PAGE_SIZE +            value: "${MEMCACHED_SLAB_PAGE_SIZE}" +          resources: +            requests: +              memory: "${MEMCACHED_MEM_REQ}" +              cpu: "${MEMCACHED_CPU_REQ}" +            limits: +              memory: "${MEMCACHED_MEM_LIMIT}"  - apiVersion: v1 -  kind: "Service" +  kind: Service    metadata:      name: "${DATABASE_SERVICE_NAME}"      annotations: -      description: "Exposes the database server" +      description: Exposes the database server    spec:      ports: -      - -        name: "postgresql" -        port: 5432 -        targetPort: 5432 +    - name: postgresql +      port: 5432 +      targetPort: 5432      selector:        name: "${DATABASE_SERVICE_NAME}"  - apiVersion: v1 -  kind: "DeploymentConfig" +  kind: DeploymentConfig    metadata:      name: "${DATABASE_SERVICE_NAME}"      annotations: -      description: "Defines how to deploy the database" +      description: Defines how to deploy the database    spec:      strategy: -      type: "Recreate" +      type: Recreate      triggers: -      - -        type: "ImageChange" -        imageChangeParams: -          automatic: true -          containerNames: -            - "postgresql" -          from: -            kind: "ImageStreamTag" -            name: "cfme-openshift-postgresql:${POSTGRESQL_IMG_TAG}" -      - -        type: "ConfigChange" +    - type: ConfigChange      replicas: 1      selector:        name: "${DATABASE_SERVICE_NAME}" @@ -310,236 +610,524 @@ objects:            name: "${DATABASE_SERVICE_NAME}"        spec:          volumes: -          - -            name: "cfme-pgdb-volume" -            persistentVolumeClaim: -              claimName: "${NAME}-${DATABASE_SERVICE_NAME}" +        - name: cfme-pgdb-volume +          persistentVolumeClaim: +            claimName: "${NAME}-${DATABASE_SERVICE_NAME}" +        - name: cfme-pg-configs +          configMap: +            name: "${DATABASE_SERVICE_NAME}-configs"          containers: -          - -            name: "postgresql" -            image: "${POSTGRESQL_IMG_NAME}:${POSTGRESQL_IMG_TAG}" -            ports: -              - -                containerPort: 5432 -            readinessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 15 +        - name: postgresql +          image: "${POSTGRESQL_IMG_NAME}:${POSTGRESQL_IMG_TAG}" +          ports: +          - containerPort: 5432 +          readinessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 15 +            exec: +              command: +              - "/bin/sh" +              - "-i" +              - "-c" +              - psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1' +          livenessProbe: +            timeoutSeconds: 1 +            initialDelaySeconds: 60 +            tcpSocket: +              port: 5432 +          volumeMounts: +          - name: cfme-pgdb-volume +            mountPath: "/var/lib/pgsql/data" +          - name: cfme-pg-configs +            mountPath: "${POSTGRESQL_CONFIG_DIR}" +          env: +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${DATABASE_NAME}" +          - name: POSTGRESQL_MAX_CONNECTIONS +            value: "${POSTGRESQL_MAX_CONNECTIONS}" +          - name: POSTGRESQL_SHARED_BUFFERS +            value: "${POSTGRESQL_SHARED_BUFFERS}" +          - name: POSTGRESQL_CONFIG_DIR +            value: "${POSTGRESQL_CONFIG_DIR}" +          resources: +            requests: +              memory: "${POSTGRESQL_MEM_REQ}" +              cpu: "${POSTGRESQL_CPU_REQ}" +            limits: +              memory: "${POSTGRESQL_MEM_LIMIT}" +- apiVersion: v1 +  kind: Service +  metadata: +    annotations: +      description: Exposes and load balances Ansible pods +      service.alpha.openshift.io/dependencies: '[{"name":"${DATABASE_SERVICE_NAME}","namespace":"","kind":"Service"}]' +    name: "${ANSIBLE_SERVICE_NAME}" +  spec: +    ports: +    - name: http +      port: 80 +      protocol: TCP +      targetPort: 80 +    - name: https +      port: 443 +      protocol: TCP +      targetPort: 443 +    selector: +      name: "${ANSIBLE_SERVICE_NAME}" +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${ANSIBLE_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy the Ansible appliance +  spec: +    strategy: +      type: Recreate +    serviceName: "${ANSIBLE_SERVICE_NAME}" +    replicas: 0 +    template: +      metadata: +        labels: +          name: "${ANSIBLE_SERVICE_NAME}" +        name: "${ANSIBLE_SERVICE_NAME}" +      spec: +        containers: +        - name: ansible +          image: "${ANSIBLE_IMG_NAME}:${ANSIBLE_IMG_TAG}" +          livenessProbe: +            tcpSocket: +              port: 443 +            initialDelaySeconds: 480 +            timeoutSeconds: 3 +          readinessProbe: +            httpGet: +              path: "/" +              port: 443 +              scheme: HTTPS +            initialDelaySeconds: 200 +            timeoutSeconds: 3 +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 443 +            protocol: TCP +          securityContext: +            privileged: true +          env: +          - name: ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: admin-password +          - name: RABBITMQ_USER_NAME +            value: "${ANSIBLE_RABBITMQ_USER_NAME}" +          - name: RABBITMQ_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: rabbit-password +          - name: ANSIBLE_SECRET_KEY +            valueFrom: +              secretKeyRef: +                name: "${ANSIBLE_SERVICE_NAME}-secrets" +                key: secret-key +          - name: DATABASE_SERVICE_NAME +            value: "${DATABASE_SERVICE_NAME}" +          - name: POSTGRESQL_USER +            value: "${DATABASE_USER}" +          - name: POSTGRESQL_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: pg-password +          - name: POSTGRESQL_DATABASE +            value: "${ANSIBLE_DATABASE_NAME}" +          resources: +            requests: +              memory: "${ANSIBLE_MEM_REQ}" +              cpu: "${ANSIBLE_CPU_REQ}" +            limits: +              memory: "${ANSIBLE_MEM_LIMIT}" +        serviceAccount: cfme-privileged +        serviceAccountName: cfme-privileged +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http +      port: 80 +      targetPort: 80 +    selector: +      name: httpd +- apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1 +  kind: DeploymentConfig +  metadata: +    name: "${HTTPD_SERVICE_NAME}" +    annotations: +      description: Defines how to deploy httpd +  spec: +    strategy: +      type: Recreate +      recreateParams: +        timeoutSeconds: 1200 +    triggers: +    - type: ConfigChange +    replicas: 1 +    selector: +      name: "${HTTPD_SERVICE_NAME}" +    template: +      metadata: +        name: "${HTTPD_SERVICE_NAME}" +        labels: +          name: "${HTTPD_SERVICE_NAME}" +      spec: +        volumes: +        - name: httpd-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-configs" +        - name: httpd-auth-config +          configMap: +            name: "${HTTPD_SERVICE_NAME}-auth-configs" +        containers: +        - name: httpd +          image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}" +          ports: +          - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP +          livenessProbe: +            exec: +              command: +              - pidof +              - httpd +            initialDelaySeconds: 15 +            timeoutSeconds: 3 +          readinessProbe: +            tcpSocket: +              port: 80 +            initialDelaySeconds: 10 +            timeoutSeconds: 3 +          volumeMounts: +          - name: httpd-config +            mountPath: "${HTTPD_CONFIG_DIR}" +          - name: httpd-auth-config +            mountPath: "${HTTPD_AUTH_CONFIG_DIR}" +          resources: +            requests: +              memory: "${HTTPD_MEM_REQ}" +              cpu: "${HTTPD_CPU_REQ}" +            limits: +              memory: "${HTTPD_MEM_LIMIT}" +          env: +          - name: HTTPD_AUTH_TYPE +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms +          lifecycle: +            postStart:                exec:                  command: -                  - "/bin/sh" -                  - "-i" -                  - "-c" -                  - "psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1'" -            livenessProbe: -              timeoutSeconds: 1 -              initialDelaySeconds: 60 -              tcpSocket: -                port: 5432 -            volumeMounts: -              - -                name: "cfme-pgdb-volume" -                mountPath: "/var/lib/pgsql/data" -            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}" -            resources: -              requests: -                memory: "${POSTGRESQL_MEM_REQ}" -                cpu: "${POSTGRESQL_CPU_REQ}" -              limits: -                memory: "${POSTGRESQL_MEM_LIMIT}" - +                - "/usr/bin/save-container-environment" +        serviceAccount: cfme-httpd +        serviceAccountName: cfme-httpd  parameters: -  - -    name: "NAME" -    displayName: Name -    required: true -    description: "The name assigned to all of the frontend objects defined in this template." -    value: cloudforms -  - -    name: "DATABASE_SERVICE_NAME" -    displayName: "PostgreSQL Service Name" -    required: true -    description: "The name of the OpenShift Service exposed for the PostgreSQL container." -    value: "postgresql" -  - -    name: "DATABASE_USER" -    displayName: "PostgreSQL User" -    required: true -    description: "PostgreSQL user that will access the database." -    value: "root" -  - -    name: "DATABASE_PASSWORD" -    displayName: "PostgreSQL Password" -    required: true -    description: "Password for the PostgreSQL user." -    value: "smartvm" -  - -    name: "DATABASE_NAME" -    required: true -    displayName: "PostgreSQL Database Name" -    description: "Name of the PostgreSQL database accessed." -    value: "vmdb_production" -  - -    name: "DATABASE_REGION" -    required: true -    displayName: "Application Database Region" -    description: "Database region that will be used for application." -    value: "0" -  - -    name: "MEMCACHED_SERVICE_NAME" -    required: true -    displayName: "Memcached Service Name" -    description: "The name of the OpenShift Service exposed for the Memcached container." -    value: "memcached" -  - -    name: "MEMCACHED_MAX_MEMORY" -    displayName: "Memcached Max Memory" -    description: "Memcached maximum memory for memcached object storage in MB." -    value: "64" -  - -    name: "MEMCACHED_MAX_CONNECTIONS" -    displayName: "Memcached Max Connections" -    description: "Memcached maximum number of connections allowed." -    value: "1024" -  - -    name: "MEMCACHED_SLAB_PAGE_SIZE" -    displayName: "Memcached Slab Page Size" -    description: "Memcached size of each slab page." -    value: "1m" -  - -    name: "POSTGRESQL_MAX_CONNECTIONS" -    displayName: "PostgreSQL Max Connections" -    description: "PostgreSQL maximum number of database connections allowed." -    value: "100" -  - -    name: "POSTGRESQL_SHARED_BUFFERS" -    displayName: "PostgreSQL Shared Buffer Amount" -    description: "Amount of memory dedicated for PostgreSQL shared memory buffers." -    value: "256MB" -  - -    name: "APPLICATION_CPU_REQ" -    displayName: "Application Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the Application container will need (expressed in millicores)." -    value: "1000m" -  - -    name: "POSTGRESQL_CPU_REQ" -    displayName: "PostgreSQL Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the PostgreSQL container will need (expressed in millicores)." -    value: "500m" -  - -    name: "MEMCACHED_CPU_REQ" -    displayName: "Memcached Min CPU Requested" -    required: true -    description: "Minimum amount of CPU time the Memcached container will need (expressed in millicores)." -    value: "200m" -  - -    name: "APPLICATION_MEM_REQ" -    displayName: "Application Min RAM Requested" -    required: true -    description: "Minimum amount of memory the Application container will need." -    value: "6144Mi" -  - -    name: "POSTGRESQL_MEM_REQ" -    displayName: "PostgreSQL Min RAM Requested" -    required: true -    description: "Minimum amount of memory the PostgreSQL container will need." -    value: "1024Mi" -  - -    name: "MEMCACHED_MEM_REQ" -    displayName: "Memcached Min RAM Requested" -    required: true -    description: "Minimum amount of memory the Memcached container will need." -    value: "64Mi" -  - -    name: "APPLICATION_MEM_LIMIT" -    displayName: "Application Max RAM Limit" -    required: true -    description: "Maximum amount of memory the Application container can consume." -    value: "16384Mi" -  - -    name: "POSTGRESQL_MEM_LIMIT" -    displayName: "PostgreSQL Max RAM Limit" -    required: true -    description: "Maximum amount of memory the PostgreSQL container can consume." -    value: "8192Mi" -  - -    name: "MEMCACHED_MEM_LIMIT" -    displayName: "Memcached Max RAM Limit" -    required: true -    description: "Maximum amount of memory the Memcached container can consume." -    value: "256Mi" -  - -    name: "POSTGRESQL_IMG_NAME" -    displayName: "PostgreSQL Image Name" -    description: "This is the PostgreSQL image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-postgresql" -  - -    name: "POSTGRESQL_IMG_TAG" -    displayName: "PostgreSQL Image Tag" -    description: "This is the PostgreSQL image tag/version requested to deploy." -    value: "latest" -  - -    name: "MEMCACHED_IMG_NAME" -    displayName: "Memcached Image Name" -    description: "This is the Memcached image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-memcached" -  - -    name: "MEMCACHED_IMG_TAG" -    displayName: "Memcached Image Tag" -    description: "This is the Memcached image tag/version requested to deploy." -    value: "latest" -  - -    name: "APPLICATION_IMG_NAME" -    displayName: "Application Image Name" -    description: "This is the Application image name requested to deploy." -    value: "registry.access.redhat.com/cloudforms45/cfme-openshift-app" -  - -    name: "APPLICATION_IMG_TAG" -    displayName: "Application Image Tag" -    description: "This is the Application image tag/version requested to deploy." -    value: "latest" -  - -    name: "APPLICATION_DOMAIN" -    displayName: "Application Hostname" -    description: "The exposed hostname that will route to the application service, if left blank a value will be defaulted." -    value: "" -  - -    name: "APPLICATION_INIT_DELAY" -    displayName: "Application Init Delay" -    required: true -    description: "Delay in seconds before we attempt to initialize the application." -    value: "15" -  - -    name: "APPLICATION_VOLUME_CAPACITY" -    displayName: "Application Volume Capacity" -    required: true -    description: "Volume space available for application data." -    value: "5Gi" -  - -    name: "APPLICATION_REGION_VOLUME_CAPACITY" -    displayName: "Application Region Volume Capacity" -    required: true -    description: "Volume space available for region application data." -    value: "5Gi" -  - -    name: "DATABASE_VOLUME_CAPACITY" -    displayName: "Database Volume Capacity" -    required: true -    description: "Volume space available for database." -    value: "15Gi" +- name: NAME +  displayName: Name +  required: true +  description: The name assigned to all of the frontend objects defined in this template. +  value: cloudforms +- name: V2_KEY +  displayName: CloudForms Encryption Key +  required: true +  description: Encryption Key for CloudForms Passwords +  from: "[a-zA-Z0-9]{43}" +  generate: expression +- name: DATABASE_SERVICE_NAME +  displayName: PostgreSQL Service Name +  required: true +  description: The name of the OpenShift Service exposed for the PostgreSQL container. +  value: postgresql +- name: DATABASE_USER +  displayName: PostgreSQL User +  required: true +  description: PostgreSQL user that will access the database. +  value: root +- name: DATABASE_PASSWORD +  displayName: PostgreSQL Password +  required: true +  description: Password for the PostgreSQL user. +  from: "[a-zA-Z0-9]{8}" +  generate: expression +- name: DATABASE_NAME +  required: true +  displayName: PostgreSQL Database Name +  description: Name of the PostgreSQL database accessed. +  value: vmdb_production +- name: DATABASE_REGION +  required: true +  displayName: Application Database Region +  description: Database region that will be used for application. +  value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm +- name: ANSIBLE_DATABASE_NAME +  displayName: Ansible PostgreSQL database name +  required: true +  description: The database to be used by the Ansible continer +  value: awx +- name: MEMCACHED_SERVICE_NAME +  required: true +  displayName: Memcached Service Name +  description: The name of the OpenShift Service exposed for the Memcached container. +  value: memcached +- name: MEMCACHED_MAX_MEMORY +  displayName: Memcached Max Memory +  description: Memcached maximum memory for memcached object storage in MB. +  value: '64' +- name: MEMCACHED_MAX_CONNECTIONS +  displayName: Memcached Max Connections +  description: Memcached maximum number of connections allowed. +  value: '1024' +- name: MEMCACHED_SLAB_PAGE_SIZE +  displayName: Memcached Slab Page Size +  description: Memcached size of each slab page. +  value: 1m +- name: POSTGRESQL_CONFIG_DIR +  displayName: PostgreSQL Configuration Overrides +  description: Directory used to store PostgreSQL configuration overrides. +  value: "/var/lib/pgsql/conf.d" +- name: POSTGRESQL_MAX_CONNECTIONS +  displayName: PostgreSQL Max Connections +  description: PostgreSQL maximum number of database connections allowed. +  value: '1000' +- name: POSTGRESQL_SHARED_BUFFERS +  displayName: PostgreSQL Shared Buffer Amount +  description: Amount of memory dedicated for PostgreSQL shared memory buffers. +  value: 1GB +- name: ANSIBLE_SERVICE_NAME +  displayName: Ansible Service Name +  description: The name of the OpenShift Service exposed for the Ansible container. +  value: ansible +- name: ANSIBLE_ADMIN_PASSWORD +  displayName: Ansible admin User password +  required: true +  description: The password for the Ansible container admin user +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: ANSIBLE_SECRET_KEY +  displayName: Ansible Secret Key +  required: true +  description: Encryption key for the Ansible container +  from: "[a-f0-9]{32}" +  generate: expression +- name: ANSIBLE_RABBITMQ_USER_NAME +  displayName: RabbitMQ Username +  required: true +  description: Username for the Ansible RabbitMQ Server +  value: ansible +- name: ANSIBLE_RABBITMQ_PASSWORD +  displayName: RabbitMQ Server Password +  required: true +  description: Password for the Ansible RabbitMQ Server +  from: "[a-zA-Z0-9]{32}" +  generate: expression +- name: APPLICATION_CPU_REQ +  displayName: Application Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Application container will need (expressed in millicores). +  value: 1000m +- name: POSTGRESQL_CPU_REQ +  displayName: PostgreSQL Min CPU Requested +  required: true +  description: Minimum amount of CPU time the PostgreSQL container will need (expressed in millicores). +  value: 500m +- name: MEMCACHED_CPU_REQ +  displayName: Memcached Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Memcached container will need (expressed in millicores). +  value: 200m +- name: ANSIBLE_CPU_REQ +  displayName: Ansible Min CPU Requested +  required: true +  description: Minimum amount of CPU time the Ansible container will need (expressed in millicores). +  value: 1000m +- name: APPLICATION_MEM_REQ +  displayName: Application Min RAM Requested +  required: true +  description: Minimum amount of memory the Application container will need. +  value: 6144Mi +- name: POSTGRESQL_MEM_REQ +  displayName: PostgreSQL Min RAM Requested +  required: true +  description: Minimum amount of memory the PostgreSQL container will need. +  value: 4Gi +- name: MEMCACHED_MEM_REQ +  displayName: Memcached Min RAM Requested +  required: true +  description: Minimum amount of memory the Memcached container will need. +  value: 64Mi +- name: ANSIBLE_MEM_REQ +  displayName: Ansible Min RAM Requested +  required: true +  description: Minimum amount of memory the Ansible container will need. +  value: 2048Mi +- name: APPLICATION_MEM_LIMIT +  displayName: Application Max RAM Limit +  required: true +  description: Maximum amount of memory the Application container can consume. +  value: 16384Mi +- name: POSTGRESQL_MEM_LIMIT +  displayName: PostgreSQL Max RAM Limit +  required: true +  description: Maximum amount of memory the PostgreSQL container can consume. +  value: 8Gi +- name: MEMCACHED_MEM_LIMIT +  displayName: Memcached Max RAM Limit +  required: true +  description: Maximum amount of memory the Memcached container can consume. +  value: 256Mi +- name: ANSIBLE_MEM_LIMIT +  displayName: Ansible Max RAM Limit +  required: true +  description: Maximum amount of memory the Ansible container can consume. +  value: 8096Mi +- name: POSTGRESQL_IMG_NAME +  displayName: PostgreSQL Image Name +  description: This is the PostgreSQL image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql +- name: POSTGRESQL_IMG_TAG +  displayName: PostgreSQL Image Tag +  description: This is the PostgreSQL image tag/version requested to deploy. +  value: latest +- name: MEMCACHED_IMG_NAME +  displayName: Memcached Image Name +  description: This is the Memcached image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached +- name: MEMCACHED_IMG_TAG +  displayName: Memcached Image Tag +  description: This is the Memcached image tag/version requested to deploy. +  value: latest +- name: FRONTEND_APPLICATION_IMG_NAME +  displayName: Frontend Application Image Name +  description: This is the Frontend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui +- name: BACKEND_APPLICATION_IMG_NAME +  displayName: Backend Application Image Name +  description: This is the Backend Application image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app +- name: FRONTEND_APPLICATION_IMG_TAG +  displayName: Front end Application Image Tag +  description: This is the CloudForms Frontend Application image tag/version requested to deploy. +  value: latest +- name: BACKEND_APPLICATION_IMG_TAG +  displayName: Back end Application Image Tag +  description: This is the CloudForms Backend Application image tag/version requested to deploy. +  value: latest +- name: ANSIBLE_IMG_NAME +  displayName: Ansible Image Name +  description: This is the Ansible image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible +- name: ANSIBLE_IMG_TAG +  displayName: Ansible Image Tag +  description: This is the Ansible image tag/version requested to deploy. +  value: latest +- name: APPLICATION_DOMAIN +  displayName: Application Hostname +  description: The exposed hostname that will route to the application service, if left blank a value will be defaulted. +  value: '' +- name: APPLICATION_REPLICA_COUNT +  displayName: Application Replica Count +  description: This is the number of Application replicas requested to deploy. +  value: '1' +- name: APPLICATION_INIT_DELAY +  displayName: Application Init Delay +  required: true +  description: Delay in seconds before we attempt to initialize the application. +  value: '15' +- name: APPLICATION_VOLUME_CAPACITY +  displayName: Application Volume Capacity +  required: true +  description: Volume space available for application data. +  value: 5Gi +- name: DATABASE_VOLUME_CAPACITY +  displayName: Database Volume Capacity +  required: true +  description: Volume space available for database. +  value: 15Gi +- name: HTTPD_SERVICE_NAME +  required: true +  displayName: Apache httpd Service Name +  description: The name of the OpenShift Service exposed for the httpd container. +  value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api +- name: HTTPD_IMG_NAME +  displayName: Apache httpd Image Name +  description: This is the httpd image name requested to deploy. +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd +- name: HTTPD_IMG_TAG +  displayName: Apache httpd Image Tag +  description: This is the httpd image tag/version requested to deploy. +  value: latest +- name: HTTPD_CONFIG_DIR +  displayName: Apache Configuration Directory +  description: Directory used to store the Apache configuration files. +  value: "/etc/httpd/conf.d" +- name: HTTPD_AUTH_CONFIG_DIR +  displayName: External Authentication Configuration Directory +  description: Directory used to store the external authentication configuration files. +  value: "/etc/httpd/auth-conf.d" +- name: HTTPD_CPU_REQ +  displayName: Apache httpd Min CPU Requested +  required: true +  description: Minimum amount of CPU time the httpd container will need (expressed in millicores). +  value: 500m +- name: HTTPD_MEM_REQ +  displayName: Apache httpd Min RAM Requested +  required: true +  description: Minimum amount of memory the httpd container will need. +  value: 512Mi +- name: HTTPD_MEM_LIMIT +  displayName: Apache httpd Max RAM Limit +  required: true +  description: Maximum amount of memory the httpd container can consume. +  value: 8192Mi diff --git a/roles/openshift_examples/meta/main.yml b/roles/openshift_examples/meta/main.yml index 1a34c85fc..9f46a4683 100644 --- a/roles/openshift_examples/meta/main.yml +++ b/roles/openshift_examples/meta/main.yml @@ -13,3 +13,4 @@ galaxy_info:    - cloud  dependencies:  - role: lib_utils +- role: openshift_facts diff --git a/roles/openshift_excluder/tasks/verify_excluder.yml b/roles/openshift_excluder/tasks/verify_excluder.yml index 4f5277fa2..22a3fcd3b 100644 --- a/roles/openshift_excluder/tasks/verify_excluder.yml +++ b/roles/openshift_excluder/tasks/verify_excluder.yml @@ -3,7 +3,7 @@  # - excluder  - name: Get available excluder version    repoquery: -    name: "{{ excluder }}" +    name: "{{ excluder }}{{ '-' ~ r_openshift_excluder_upgrade_target.split('.')[0:2] | join('.') ~ '*' if r_openshift_excluder_upgrade_target is defined else '' }}"      ignore_excluders: true    register: repoquery_out diff --git a/roles/openshift_expand_partition/tasks/main.yml b/roles/openshift_expand_partition/tasks/main.yml index 5ae863871..b38ebdfb4 100644 --- a/roles/openshift_expand_partition/tasks/main.yml +++ b/roles/openshift_expand_partition/tasks/main.yml @@ -8,7 +8,7 @@  - name: Determine if growpart is installed    command: "rpm -q cloud-utils-growpart"    register: has_growpart -  failed_when: has_growpart.cr != 0 and 'package cloud-utils-growpart is not installed' not in has_growpart.stdout +  failed_when: has_growpart.rc != 0 and 'package cloud-utils-growpart is not installed' not in has_growpart.stdout    changed_when: false    when: openshift_is_containerized | bool diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index d7c358a2f..26f0525e9 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -1465,6 +1465,11 @@ class OpenShiftFacts(object):              if metadata:                  metadata['project']['attributes'].pop('sshKeys', None)                  metadata['instance'].pop('serviceAccounts', None) +        elif bios_vendor == 'Amazon EC2': +            # Adds support for Amazon EC2 C5 instance types +            provider = 'aws' +            metadata_url = 'http://169.254.169.254/latest/meta-data/' +            metadata = get_provider_metadata(metadata_url)          elif virt_type == 'xen' and virt_role == 'guest' and re.match(r'.*\.amazon$', product_version):              provider = 'aws'              metadata_url = 'http://169.254.169.254/latest/meta-data/' diff --git a/roles/openshift_gcp/files/bootstrap-script.sh b/roles/openshift_gcp/files/bootstrap-script.sh new file mode 100644 index 000000000..0c3f1999b --- /dev/null +++ b/roles/openshift_gcp/files/bootstrap-script.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# This script is a startup script for bootstrapping a GCP node +# from a config stored in the project metadata. It loops until +# it finds the script and then starts the origin-node service. +# TODO: generalize + +set -o errexit +set -o nounset +set -o pipefail + +if [[ "$( curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/bootstrap" -H "Metadata-Flavor: Google" )" != "true" ]]; then +  echo "info: Bootstrap is not enabled for this instance, skipping" 1>&2 +  exit 0 +fi + +if ! id=$( curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-id" -H "Metadata-Flavor: Google" ); then +  echo "error: Unable to get cluster-id for instance from cluster metadata" 1>&2 +  exit 1 +fi + +if ! node_group=$( curl "http://metadata.google.internal/computeMetadata/v1/instance/attributes/node-group" -H "Metadata-Flavor: Google" ); then +  echo "error: Unable to get node-group for instance from cluster metadata" 1>&2 +  exit 1 +fi + +if ! config=$( curl -f "http://metadata.google.internal/computeMetadata/v1/instance/attributes/bootstrap-config" -H "Metadata-Flavor: Google" 2>/dev/null ); then +  while true; do +    if config=$( curl -f "http://metadata.google.internal/computeMetadata/v1/project/attributes/${id}-bootstrap-config" -H "Metadata-Flavor: Google" 2>/dev/null ); then +      break +    fi +    echo "info: waiting for ${id}-bootstrap-config to become available in cluster metadata ..." 1>&2 +    sleep 5 +  done +fi + +echo "Got bootstrap config from metadata" +mkdir -p /etc/origin/node +echo -n "${config}" > /etc/origin/node/bootstrap.kubeconfig +echo "BOOTSTRAP_CONFIG_NAME=node-config-${node_group}" >> /etc/sysconfig/origin-node +systemctl enable origin-node +systemctl start origin-node diff --git a/roles/openshift_gcp/files/openshift-bootstrap-update.service b/roles/openshift_gcp/files/openshift-bootstrap-update.service new file mode 100644 index 000000000..c65b1b34e --- /dev/null +++ b/roles/openshift_gcp/files/openshift-bootstrap-update.service @@ -0,0 +1,7 @@ +[Unit] +Description=Update the OpenShift node bootstrap configuration + +[Service] +Type=oneshot +ExecStart=/usr/bin/openshift-bootstrap-update +User=root diff --git a/roles/openshift_gcp/files/openshift-bootstrap-update.timer b/roles/openshift_gcp/files/openshift-bootstrap-update.timer new file mode 100644 index 000000000..1a517b33e --- /dev/null +++ b/roles/openshift_gcp/files/openshift-bootstrap-update.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Update the OpenShift node bootstrap credentials hourly + +[Timer] +OnBootSec=30s +OnCalendar=hourly +Persistent=true      +  +[Install] +WantedBy=timers.target
\ No newline at end of file diff --git a/roles/openshift_gcp_image_prep/files/partition.conf b/roles/openshift_gcp/files/partition.conf index b87e5e0b6..76e65ab9c 100644 --- a/roles/openshift_gcp_image_prep/files/partition.conf +++ b/roles/openshift_gcp/files/partition.conf @@ -1,3 +1,3 @@  [Service]  ExecStartPost=-/usr/bin/growpart /dev/sda 1 -ExecStartPost=-/sbin/xfs_growfs / +ExecStartPost=-/sbin/xfs_growfs /
\ No newline at end of file diff --git a/roles/openshift_gcp/meta/main.yml b/roles/openshift_gcp/meta/main.yml new file mode 100644 index 000000000..5e428f8de --- /dev/null +++ b/roles/openshift_gcp/meta/main.yml @@ -0,0 +1,17 @@ +--- +galaxy_info: +  author: Clayton Coleman +  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: lib_utils +- role: lib_openshift diff --git a/roles/openshift_gcp/tasks/add_custom_repositories.yml b/roles/openshift_gcp/tasks/add_custom_repositories.yml new file mode 100644 index 000000000..04718f78e --- /dev/null +++ b/roles/openshift_gcp/tasks/add_custom_repositories.yml @@ -0,0 +1,20 @@ +--- +- name: Copy custom repository secrets +  copy: +    src: "{{ files_dir }}/{{ item.1.sslclientcert }}" +    dest: /var/lib/yum/custom_secret_{{ item.0 }}_cert +  when: item.1.sslclientcert | default(false) +  with_indexed_items: "{{ provision_custom_repositories }}" +- name: Copy custom repository secrets +  copy: +    src: "{{ files_dir }}/{{ item.1.sslclientkey }}" +    dest: /var/lib/yum/custom_secret_{{ item.0 }}_key +  when: item.1.sslclientkey | default(false) +  with_indexed_items: "{{ provision_custom_repositories }}" + +- name: Create any custom repos that are defined +  template: +    src: yum_repo.j2 +    dest: /etc/yum.repos.d/provision_custom_repositories.repo +  when: provision_custom_repositories | length > 0 +  notify: refresh cache diff --git a/roles/openshift_gcp_image_prep/tasks/main.yaml b/roles/openshift_gcp/tasks/configure_gcp_base_image.yml index fee5ab618..2c6e2790a 100644 --- a/roles/openshift_gcp_image_prep/tasks/main.yaml +++ b/roles/openshift_gcp/tasks/configure_gcp_base_image.yml @@ -1,18 +1,10 @@ ----  # GCE instances are starting with xfs AND barrier=1, which is only for extfs. +---  - name: Remove barrier=1 from XFS fstab entries -  lineinfile: -    path: /etc/fstab -    regexp: '^(.+)xfs(.+?),?barrier=1,?(.*?)$' -    line: '\1xfs\2 \4' -    backrefs: yes +  command: sed -i -e 's/xfs\(.*\)barrier=1/xfs\1/g; s/, / /g' /etc/fstab  - name: Ensure the root filesystem has XFS group quota turned on -  lineinfile: -    path: /boot/grub2/grub.cfg -    regexp: '^(.*)linux16 (.*)$' -    line: '\1linux16 \2 rootflags=gquota' -    backrefs: yes +  command: sed -i -e 's/linux16 \(.*\)$/linux16 \1 rootflags=gquota/g' /boot/grub2/grub.cfg  - name: Ensure the root partition grows on startup    copy: src=partition.conf dest=/etc/systemd/system/google-instance-setup.service.d/ diff --git a/roles/openshift_gcp/tasks/configure_master_bootstrap.yml b/roles/openshift_gcp/tasks/configure_master_bootstrap.yml new file mode 100644 index 000000000..591cb593c --- /dev/null +++ b/roles/openshift_gcp/tasks/configure_master_bootstrap.yml @@ -0,0 +1,36 @@ +# +# These tasks configure the instance to periodically update the project metadata with the +# latest bootstrap kubeconfig from the project metadata. This keeps the project metadata +# in sync with the cluster's configuration. We then invoke a CSR approve on any nodes that +# are waiting to join the cluster. +# +--- +- name: Copy unit service +  copy: +    src: openshift-bootstrap-update.timer +    dest: /etc/systemd/system/openshift-bootstrap-update.timer +    owner: root +    group: root +    mode: 0664 + +- name: Copy unit timer +  copy: +    src: openshift-bootstrap-update.service +    dest: /etc/systemd/system/openshift-bootstrap-update.service +    owner: root +    group: root +    mode: 0664 + +- name: Create bootstrap update script +  template: src=openshift-bootstrap-update.j2 dest=/usr/bin/openshift-bootstrap-update mode=u+rx + +- name: Start bootstrap update timer +  systemd: +    name: "openshift-bootstrap-update.timer" +    state: started + +- name: Bootstrap all nodes that were identified with bootstrap metadata +  run_once: true +  oc_adm_csr: +    nodes: "{{ groups['all'] | map('extract', hostvars) | selectattr('gce_metadata.bootstrap', 'match', 'true') | map(attribute='gce_name') | list }}" +    timeout: 60 diff --git a/roles/openshift_gcp/tasks/configure_master_healthcheck.yml b/roles/openshift_gcp/tasks/configure_master_healthcheck.yml new file mode 100644 index 000000000..aa9655977 --- /dev/null +++ b/roles/openshift_gcp/tasks/configure_master_healthcheck.yml @@ -0,0 +1,19 @@ +--- +- name: refresh yum cache +  command: yum clean all +  args: +    warn: no +  when: ansible_os_family == "RedHat" + +- name: install haproxy +  package: name=haproxy state=present +  register: result +  until: '"failed" not in result' +  retries: 10 +  delay: 10 + +- name: configure haproxy +  template: src=master_healthcheck.j2 dest=/etc/haproxy/haproxy.cfg + +- name: start and enable haproxy service +  service: name=haproxy state=started enabled=yes diff --git a/roles/openshift_gcp/tasks/dynamic_inventory.yml b/roles/openshift_gcp/tasks/dynamic_inventory.yml new file mode 100644 index 000000000..1637da945 --- /dev/null +++ b/roles/openshift_gcp/tasks/dynamic_inventory.yml @@ -0,0 +1,5 @@ +--- +- name: Extract PEM from service account file +  copy: content="{{ (lookup('file', openshift_gcp_iam_service_account_keyfile ) | from_json ).private_key }}" dest=/tmp/gce.pem mode=0600 +- name: Templatize environment script +  template: src=inventory.j2.sh dest=/tmp/inventory.sh mode=u+rx diff --git a/roles/openshift_gcp/tasks/frequent_log_rotation.yml b/roles/openshift_gcp/tasks/frequent_log_rotation.yml new file mode 100644 index 000000000..0b4b27f84 --- /dev/null +++ b/roles/openshift_gcp/tasks/frequent_log_rotation.yml @@ -0,0 +1,18 @@ +--- +- name: Rotate logs daily +  replace: +    dest: /etc/logrotate.conf +    regexp: '^weekly|monthly|yearly$' +    replace: daily +- name: Rotate at a smaller size of log +  lineinfile: +    dest: /etc/logrotate.conf +    state: present +    regexp: '^size' +    line: size 10M +- name: Limit total size of log files +  lineinfile: +    dest: /etc/logrotate.conf +    state: present +    regexp: '^maxsize' +    line: maxsize 20M diff --git a/roles/openshift_gcp/tasks/main.yaml b/roles/openshift_gcp/tasks/main.yml index ad205ba33..fb147bc78 100644 --- a/roles/openshift_gcp/tasks/main.yaml +++ b/roles/openshift_gcp/tasks/main.yml @@ -17,7 +17,7 @@  - name: Provision GCP DNS domain    command: /tmp/openshift_gcp_provision_dns.sh    args: -    chdir: "{{ playbook_dir }}/files" +    chdir: "{{ files_dir }}"    register: dns_provision    when:    - state | default('present') == 'present' @@ -33,7 +33,7 @@  - name: Provision GCP resources    command: /tmp/openshift_gcp_provision.sh    args: -    chdir: "{{ playbook_dir }}/files" +    chdir: "{{ files_dir }}"    when:    - state | default('present') == 'present' diff --git a/roles/openshift_gcp/tasks/node_cloud_config.yml b/roles/openshift_gcp/tasks/node_cloud_config.yml new file mode 100644 index 000000000..4e982f497 --- /dev/null +++ b/roles/openshift_gcp/tasks/node_cloud_config.yml @@ -0,0 +1,12 @@ +--- +- name: ensure the /etc/origin folder exists +  file: name=/etc/origin state=directory + +- name: configure gce cloud config options +  ini_file: dest=/etc/origin/cloudprovider/gce.conf section=Global option={{ item.key }} value={{ item.value }} state=present create=yes +  with_items: +    - { key: 'project-id', value: '{{ openshift_gcp_project }}' } +    - { key: 'network-name', value: '{{ openshift_gcp_network_name }}' } +    - { key: 'node-tags', value: '{{ openshift_gcp_prefix }}ocp' } +    - { key: 'node-instance-prefix', value: '{{ openshift_gcp_prefix }}' } +    - { key: 'multizone', value: 'false' } diff --git a/roles/openshift_gcp/tasks/publish_image.yml b/roles/openshift_gcp/tasks/publish_image.yml new file mode 100644 index 000000000..db8a7ca69 --- /dev/null +++ b/roles/openshift_gcp/tasks/publish_image.yml @@ -0,0 +1,32 @@ +--- +- name: Require openshift_gcp_image +  fail: +    msg: "A source image name or family is required for image publishing.  Please ensure `openshift_gcp_image` is defined." +  when: openshift_gcp_image is undefined + +- name: Require openshift_gcp_target_image +  fail: +    msg: "A target image name or family is required for image publishing.  Please ensure `openshift_gcp_target_image` is defined." +  when: openshift_gcp_target_image is undefined + +- block: +  - name: Retrieve images in the {{ openshift_gcp_target_image }} family +    command: > +      gcloud --project "{{ openshift_gcp_project }}" compute images list +        "--filter=family={{ openshift_gcp_target_image }}" +        --format=json --sort-by ~creationTimestamp +    register: images +  - name: Prune oldest images +    command: > +      gcloud --project "{{ openshift_gcp_project }}" compute images delete "{{ item['name'] }}" +    with_items: "{{ (images.stdout | default('[]') | from_json )[( openshift_gcp_keep_images | int ):] }}" +  when: openshift_gcp_keep_images is defined + +- name: Copy the latest image in the family {{ openshift_gcp_image }} to {{ openshift_gcp_target_image }} +  command: > +    gcloud --project "{{ openshift_gcp_target_project | default(openshift_gcp_project) }}" +      beta compute images create +      "{{ openshift_gcp_target_image_name | default(openshift_gcp_target_image + '-' + lookup('pipe','date +%Y%m%d-%H%M%S')) }}" +      --family "{{ openshift_gcp_target_image }}" +      --source-image-family "{{ openshift_gcp_image }}" +      --source-image-project "{{ openshift_gcp_project }}" diff --git a/roles/openshift_gcp/tasks/setup_scale_group_facts.yml b/roles/openshift_gcp/tasks/setup_scale_group_facts.yml new file mode 100644 index 000000000..0fda43123 --- /dev/null +++ b/roles/openshift_gcp/tasks/setup_scale_group_facts.yml @@ -0,0 +1,44 @@ +--- +- name: Add masters to requisite groups +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: masters, etcd +  with_items: "{{ groups['tag_ocp-master'] }}" + +- name: Add a master to the primary masters group +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: primary_master +  with_items: "{{ groups['tag_ocp-master'].0 }}" + +- name: Add non-bootstrapping master node instances to node group +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: nodes +    openshift_node_labels: +      role: infra +  with_items: "{{ groups['tag_ocp-master'] | default([]) | difference(groups['tag_ocp-bootstrap'] | default([])) }}" + +- name: Add infra node instances to node group +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: nodes +    openshift_node_labels: +      role: infra +  with_items: "{{ groups['tag_ocp-infra-node'] | default([]) | difference(groups['tag_ocp-bootstrap'] | default([])) }}" + +- name: Add node instances to node group +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: nodes +    openshift_node_labels: +      role: app +  with_items: "{{ groups['tag_ocp-node'] | default([]) | difference(groups['tag_ocp-bootstrap'] | default([])) }}" + +- name: Add bootstrap node instances +  add_host: +    name: "{{ hostvars[item].gce_name }}" +    groups: bootstrap_nodes +    openshift_node_bootstrap: True +  with_items: "{{ groups['tag_ocp-node'] | default([]) | intersect(groups['tag_ocp-bootstrap'] | default([])) }}" +  when: not (openshift_node_bootstrap | default(False)) diff --git a/roles/openshift_gcp/templates/inventory.j2.sh b/roles/openshift_gcp/templates/inventory.j2.sh new file mode 100644 index 000000000..dcaffb578 --- /dev/null +++ b/roles/openshift_gcp/templates/inventory.j2.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +export GCE_PROJECT="{{ openshift_gcp_project }}" +export GCE_ZONE="{{ openshift_gcp_zone }}" +export GCE_EMAIL="{{ (lookup('file', openshift_gcp_iam_service_account_keyfile ) | from_json ).client_email }}" +export GCE_PEM_FILE_PATH="/tmp/gce.pem" +export INVENTORY_IP_TYPE="{{ inventory_ip_type }}" +export GCE_TAGGED_INSTANCES="{{ openshift_gcp_prefix }}ocp"
\ No newline at end of file diff --git a/roles/openshift_gcp/templates/master_healthcheck.j2 b/roles/openshift_gcp/templates/master_healthcheck.j2 new file mode 100644 index 000000000..189e578c5 --- /dev/null +++ b/roles/openshift_gcp/templates/master_healthcheck.j2 @@ -0,0 +1,68 @@ +#--------------------------------------------------------------------- +# Example configuration for a possible web application.  See the +# full configuration options online. +# +#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt +# +#--------------------------------------------------------------------- + +#--------------------------------------------------------------------- +# Global settings +#--------------------------------------------------------------------- +global +    # to have these messages end up in /var/log/haproxy.log you will +    # need to: +    # +    # 1) configure syslog to accept network log events.  This is done +    #    by adding the '-r' option to the SYSLOGD_OPTIONS in +    #    /etc/sysconfig/syslog +    # +    # 2) configure local2 events to go to the /var/log/haproxy.log +    #   file. A line like the following can be added to +    #   /etc/sysconfig/syslog +    # +    #    local2.*                       /var/log/haproxy.log +    # +    log         127.0.0.1 local2 + +    chroot      /var/lib/haproxy +    pidfile     /var/run/haproxy.pid +    maxconn     4000 +    user        haproxy +    group       haproxy +    daemon + +    # turn on stats unix socket +    stats socket /var/lib/haproxy/stats + +#--------------------------------------------------------------------- +# common defaults that all the 'listen' and 'backend' sections will +# use if not designated in their block +#--------------------------------------------------------------------- +defaults +    mode                    http +    log                     global +    option                  httplog +    option                  dontlognull +    option http-server-close +    option forwardfor       except 127.0.0.0/8 +    option                  redispatch +    retries                 3 +    timeout http-request    10s +    timeout queue           1m +    timeout connect         10s +    timeout client          1m +    timeout server          1m +    timeout http-keep-alive 10s +    timeout check           10s +    maxconn                 3000 + +#--------------------------------------------------------------------- +# main frontend which proxys to the backends +#--------------------------------------------------------------------- +frontend  http-proxy *:8080 +    acl          url_healthz  path_beg  -i /healthz +    use_backend  ocp          if url_healthz + +backend ocp +    server       ocp localhost:{{ internal_console_port }} ssl verify none diff --git a/roles/openshift_gcp/templates/openshift-bootstrap-update.j2 b/roles/openshift_gcp/templates/openshift-bootstrap-update.j2 new file mode 100644 index 000000000..5b0563724 --- /dev/null +++ b/roles/openshift_gcp/templates/openshift-bootstrap-update.j2 @@ -0,0 +1,7 @@ +#!/bin/bash + +set -euo pipefail + +oc serviceaccounts create-kubeconfig -n openshift-infra node-bootstrapper > /root/bootstrap.kubeconfig +gcloud compute project-info --project '{{ openshift_gcp_project }}' add-metadata --metadata-from-file '{{ openshift_gcp_prefix + openshift_gcp_clusterid | default("default") }}-bootstrap-config=/root/bootstrap.kubeconfig' +rm -f /root/bootstrap.kubeconfig diff --git a/roles/openshift_gcp/templates/provision.j2.sh b/roles/openshift_gcp/templates/provision.j2.sh index 4d150bc74..794985322 100644 --- a/roles/openshift_gcp/templates/provision.j2.sh +++ b/roles/openshift_gcp/templates/provision.j2.sh @@ -9,15 +9,26 @@ if [[ -n "{{ openshift_gcp_ssh_private_key }}" ]]; then          ssh-add "{{ openshift_gcp_ssh_private_key }}" || true      fi -    # Check if the ~/.ssh/google_compute_engine.pub key is in the project metadata, and if not, add it there -    pub_key=$(cut -d ' ' -f 2 < "{{ openshift_gcp_ssh_private_key }}.pub") +    # Check if the public key is in the project metadata, and if not, add it there +    if [ -f "{{ openshift_gcp_ssh_private_key }}.pub" ]; then +        pub_file="{{ openshift_gcp_ssh_private_key }}.pub" +        pub_key=$(cut -d ' ' -f 2 < "{{ openshift_gcp_ssh_private_key }}.pub") +    else +        keyfile="${HOME}/.ssh/google_compute_engine" +        pub_file="${keyfile}.pub" +        mkdir -p "${HOME}/.ssh" +        cp "{{ openshift_gcp_ssh_private_key }}" "${keyfile}" +        chmod 0600 "${keyfile}" +        ssh-keygen -y -f "${keyfile}" >  "${pub_file}" +        pub_key=$(cut -d ' ' -f 2 <  "${pub_file}") +    fi      key_tmp_file='/tmp/ocp-gce-keys'      if ! gcloud --project "{{ openshift_gcp_project }}" compute project-info describe | grep -q "$pub_key"; then          if gcloud --project "{{ openshift_gcp_project }}" compute project-info describe | grep -q ssh-rsa; then              gcloud --project "{{ openshift_gcp_project }}" compute project-info describe | grep ssh-rsa | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/value: //' > "$key_tmp_file"          fi          echo -n 'cloud-user:' >> "$key_tmp_file" -        cat "{{ openshift_gcp_ssh_private_key }}.pub" >> "$key_tmp_file" +        cat "${pub_file}" >> "$key_tmp_file"          gcloud --project "{{ openshift_gcp_project }}" compute project-info add-metadata --metadata-from-file "sshKeys=${key_tmp_file}"          rm -f "$key_tmp_file"      fi diff --git a/roles/openshift_gcp/templates/yum_repo.j2 b/roles/openshift_gcp/templates/yum_repo.j2 new file mode 100644 index 000000000..77919ea75 --- /dev/null +++ b/roles/openshift_gcp/templates/yum_repo.j2 @@ -0,0 +1,20 @@ +{% for repo in provision_custom_repositories %} +[{{ repo.id | default(repo.name) }}] +name={{ repo.name | default(repo.id) }} +baseurl={{ repo.baseurl }} +{% set enable_repo = repo.enabled | default(1) %} +enabled={{ 1 if ( enable_repo == 1 or enable_repo == True ) else 0 }} +{% set enable_gpg_check = repo.gpgcheck | default(1) %} +gpgcheck={{ 1 if ( enable_gpg_check == 1 or enable_gpg_check == True ) else 0 }} +{% if 'sslclientcert' in repo %} +sslclientcert={{ "/var/lib/yum/custom_secret_" + (loop.index-1)|string + "_cert" if repo.sslclientcert }} +{% endif %} +{% if 'sslclientkey' in repo %} +sslclientkey={{ "/var/lib/yum/custom_secret_" + (loop.index-1)|string + "_key" if repo.sslclientkey }} +{% endif %} +{% for key, value in repo.iteritems() %} +{% if key not in ['id', 'name', 'baseurl', 'enabled', 'gpgcheck', 'sslclientkey', 'sslclientcert'] and value is defined %} +{{ key }}={{ value }} +{% endif %} +{% endfor %} +{% endfor %} diff --git a/roles/openshift_grafana/defaults/main.yml b/roles/openshift_grafana/defaults/main.yml new file mode 100644 index 000000000..7fd7a085d --- /dev/null +++ b/roles/openshift_grafana/defaults/main.yml @@ -0,0 +1,12 @@ +--- +gf_body_tmp: +  name: grafana_name +  type: prometheus +  typeLogoUrl: '' +  access: proxy +  url: prometheus_url +  basicAuth: false +  withCredentials: false +  jsonData: +    tlsSkipVerify: true +    token: satoken diff --git a/roles/openshift_grafana/files/grafana-ocp-oauth.yml b/roles/openshift_grafana/files/grafana-ocp-oauth.yml new file mode 100644 index 000000000..82fa89004 --- /dev/null +++ b/roles/openshift_grafana/files/grafana-ocp-oauth.yml @@ -0,0 +1,661 @@ +--- +kind: Template +apiVersion: v1 +metadata: +  name: grafana-ocp +  annotations: +    "openshift.io/display-name": Grafana ocp +    description: | +      Grafana server with patched Prometheus datasource. +    iconClass: icon-cogs +    tags: "metrics,monitoring,grafana,prometheus" +parameters: +- description: The location of the proxy image +  name: IMAGE_GF +  value: mrsiano/grafana-ocp:latest +- description: The location of the proxy image +  name: IMAGE_PROXY +  value: openshift/oauth-proxy:v1.0.0 +- description: External URL for the grafana route +  name: ROUTE_URL +  value: "" +- description: The namespace to instantiate heapster under. Defaults to 'grafana'. +  name: NAMESPACE +  value: grafana +- description: The session secret for the proxy +  name: SESSION_SECRET +  generate: expression +  from: "[a-zA-Z0-9]{43}" +objects: +- apiVersion: v1 +  kind: ServiceAccount +  metadata: +    name: grafana-ocp +    namespace: "${NAMESPACE}" +    annotations: +      serviceaccounts.openshift.io/oauth-redirectreference.primary: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"grafana-ocp"}}' +- apiVersion: authorization.openshift.io/v1 +  kind: ClusterRoleBinding +  metadata: +    name: gf-cluster-reader +  roleRef: +    name: cluster-reader +  subjects: +  - kind: ServiceAccount +    name: grafana-ocp +    namespace: "${NAMESPACE}" +- apiVersion: route.openshift.io/v1 +  kind: Route +  metadata: +    name: grafana-ocp +    namespace: "${NAMESPACE}" +  spec: +    host: "${ROUTE_URL}" +    to: +      name: grafana-ocp +    tls: +      termination: Reencrypt +- apiVersion: v1 +  kind: Service +  metadata: +    name: grafana-ocp +    annotations: +      prometheus.io/scrape: "true" +      prometheus.io/scheme: https +      service.alpha.openshift.io/serving-cert-secret-name: gf-tls +    namespace: "${NAMESPACE}" +    labels: +      metrics-infra: grafana-ocp +      name: grafana-ocp +  spec: +    ports: +    - name: grafana-ocp +      port: 443 +      protocol: TCP +      targetPort: 8443 +    selector: +      app: grafana-ocp +- apiVersion: v1 +  kind: Secret +  metadata: +    name: gf-proxy +    namespace: "${NAMESPACE}" +  stringData: +    session_secret: "${SESSION_SECRET}=" +# Deploy Prometheus behind an oauth proxy +- apiVersion: extensions/v1beta1 +  kind: Deployment +  metadata: +    labels: +      app: grafana-ocp +    name: grafana-ocp +    namespace: "${NAMESPACE}" +  spec: +    replicas: 1 +    selector: +      matchLabels: +        app: grafana-ocp +    template: +      metadata: +        labels: +          app: grafana-ocp +        name: grafana-ocp-app +      spec: +        serviceAccountName: grafana-ocp +        containers: +        - name: oauth-proxy +          image: ${IMAGE_PROXY} +          imagePullPolicy: IfNotPresent +          ports: +          - containerPort: 8443 +            name: web +          args: +          - -https-address=:8443 +          - -http-address= +          - -email-domain=* +          - -client-id=system:serviceaccount:${NAMESPACE}:grafana-ocp +          - -upstream=http://localhost:3000 +          - -provider=openshift +#          - '-openshift-delegate-urls={"/api/datasources": {"resource": "namespace", "verb": "get", "resourceName": "grafana-ocp", "namespace": "${NAMESPACE}"}}' +          - '-openshift-sar={"namespace": "${NAMESPACE}", "verb": "list", "resource": "services"}' +          - -tls-cert=/etc/tls/private/tls.crt +          - -tls-key=/etc/tls/private/tls.key +          - -client-secret-file=/var/run/secrets/kubernetes.io/serviceaccount/token +          - -cookie-secret-file=/etc/proxy/secrets/session_secret +          - -skip-auth-regex=^/metrics,/api/datasources,/api/dashboards +          volumeMounts: +          - mountPath: /etc/tls/private +            name: gf-tls +          - mountPath: /etc/proxy/secrets +            name: secrets + +        - name: grafana-ocp +          image: ${IMAGE_GF} +          ports: +          - name: grafana-http +            containerPort: 3000 +          volumeMounts: +          - mountPath: "/root/go/src/github.com/grafana/grafana/data" +            name: gf-data +          - mountPath: "/root/go/src/github.com/grafana/grafana/conf" +            name: gfconfig +          - mountPath: /etc/tls/private +            name: gf-tls +          - mountPath: /etc/proxy/secrets +            name: secrets +          command: +           - "./bin/grafana-server" + +        volumes: +        - name: gfconfig +          configMap: +            name: gf-config +        - name: secrets +          secret: +            secretName: gf-proxy +        - name: gf-tls +          secret: +            secretName: gf-tls +        - emptyDir: {} +          name: gf-data +- apiVersion: v1 +  kind: ConfigMap +  metadata: +    name: gf-config +    namespace: "${NAMESPACE}" +  data: +    defaults.ini: |- +      ##################### Grafana Configuration Defaults ##################### +      # +      # Do not modify this file in grafana installs +      # + +      # possible values : production, development +      app_mode = production + +      # instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty +      instance_name = ${HOSTNAME} + +      #################################### Paths ############################### +      [paths] +      # Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) +      # +      data = data +      # +      # Directory where grafana can store logs +      # +      logs = data/log +      # +      # Directory where grafana will automatically scan and look for plugins +      # +      plugins = data/plugins + +      #################################### Server ############################## +      [server] +      # Protocol (http, https, socket) +      protocol = http + +      # The ip address to bind to, empty will bind to all interfaces +      http_addr = + +      # The http port  to use +      http_port = 3000 + +      # The public facing domain name used to access grafana from a browser +      domain = localhost + +      # Redirect to correct domain if host header does not match domain +      # Prevents DNS rebinding attacks +      enforce_domain = false + +      # The full public facing url +      root_url = %(protocol)s://%(domain)s:%(http_port)s/ + +      # Log web requests +      router_logging = false + +      # the path relative working path +      static_root_path = public + +      # enable gzip +      enable_gzip = false + +      # https certs & key file +      cert_file = /etc/tls/private/tls.crt +      cert_key = /etc/tls/private/tls.key + +      # Unix socket path +      socket = /tmp/grafana.sock + +      #################################### Database ############################ +      [database] +      # You can configure the database connection by specifying type, host, name, user and password +      # as separate properties or as on string using the url property. + +      # Either "mysql", "postgres" or "sqlite3", it's your choice +      type = sqlite3 +      host = 127.0.0.1:3306 +      name = grafana +      user = root +      # If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" +      password = +      # Use either URL or the previous fields to configure the database +      # Example: mysql://user:secret@host:port/database +      url = + +      # Max idle conn setting default is 2 +      max_idle_conn = 2 + +      # Max conn setting default is 0 (mean not set) +      max_open_conn = + +      # For "postgres", use either "disable", "require" or "verify-full" +      # For "mysql", use either "true", "false", or "skip-verify". +      ssl_mode = disable + +      ca_cert_path = +      client_key_path = +      client_cert_path = +      server_cert_name = + +      # For "sqlite3" only, path relative to data_path setting +      path = grafana.db + +      #################################### Session ############################# +      [session] +      # Either "memory", "file", "redis", "mysql", "postgres", "memcache", default is "file" +      provider = file + +      # Provider config options +      # memory: not have any config yet +      # file: session dir path, is relative to grafana data_path +      # redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana` +      # postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable +      # mysql: go-sql-driver/mysql dsn config string, examples: +      #         `user:password@tcp(127.0.0.1:3306)/database_name` +      #         `user:password@unix(/var/run/mysqld/mysqld.sock)/database_name` +      # memcache: 127.0.0.1:11211 + + +      provider_config = sessions + +      # Session cookie name +      cookie_name = grafana_sess + +      # If you use session in https only, default is false +      cookie_secure = false + +      # Session life time, default is 86400 +      session_life_time = 86400 +      gc_interval_time = 86400 + +      #################################### Data proxy ########################### +      [dataproxy] + +      # This enables data proxy logging, default is false +      logging = false + +      #################################### Analytics ########################### +      [analytics] +      # Server reporting, sends usage counters to stats.grafana.org every 24 hours. +      # No ip addresses are being tracked, only simple counters to track +      # running instances, dashboard and error counts. It is very helpful to us. +      # Change this option to false to disable reporting. +      reporting_enabled = true + +      # Set to false to disable all checks to https://grafana.com +      # for new versions (grafana itself and plugins), check is used +      # in some UI views to notify that grafana or plugin update exists +      # This option does not cause any auto updates, nor send any information +      # only a GET request to https://grafana.com to get latest versions +      check_for_updates = true + +      # Google Analytics universal tracking code, only enabled if you specify an id here +      google_analytics_ua_id = + +      # Google Tag Manager ID, only enabled if you specify an id here +      google_tag_manager_id = + +      #################################### Security ############################ +      [security] +      # default admin user, created on startup +      admin_user = admin + +      # default admin password, can be changed before first start of grafana,  or in profile settings +      admin_password = admin + +      # used for signing +      secret_key = SW2YcwTIb9zpOOhoPsMm + +      # Auto-login remember days +      login_remember_days = 7 +      cookie_username = grafana_user +      cookie_remember_name = grafana_remember + +      # disable gravatar profile images +      disable_gravatar = false + +      # data source proxy whitelist (ip_or_domain:port separated by spaces) +      data_source_proxy_whitelist = + +      [snapshots] +      # snapshot sharing options +      external_enabled = true +      external_snapshot_url = https://snapshots-origin.raintank.io +      external_snapshot_name = Publish to snapshot.raintank.io + +      # remove expired snapshot +      snapshot_remove_expired = true + +      # remove snapshots after 90 days +      snapshot_TTL_days = 90 + +      #################################### Users #################################### +      [users] +      # disable user signup / registration +      allow_sign_up = true + +      # Allow non admin users to create organizations +      allow_org_create = true + +      # Set to true to automatically assign new users to the default organization (id 1) +      auto_assign_org = true + +      # Default role new users will be automatically assigned (if auto_assign_org above is set to true) +      auto_assign_org_role = Admin + +      # Require email validation before sign up completes +      verify_email_enabled = false + +      # Background text for the user field on the login page +      login_hint = email or username + +      # Default UI theme ("dark" or "light") +      default_theme = dark + +      # External user management +      external_manage_link_url = +      external_manage_link_name = +      external_manage_info = + +      [auth] +      # Set to true to disable (hide) the login form, useful if you use OAuth +      disable_login_form = true + +      # Set to true to disable the signout link in the side menu. useful if you use auth.proxy +      disable_signout_menu = true + +      #################################### Anonymous Auth ###################### +      [auth.anonymous] +      # enable anonymous access +      enabled = true + +      # specify organization name that should be used for unauthenticated users +      org_name = Main Org. + +      # specify role for unauthenticated users +      org_role = Admin + +      #################################### Github Auth ######################### +      [auth.github] +      enabled = false +      allow_sign_up = true +      client_id = some_id +      client_secret = some_secret +      scopes = user:email +      auth_url = https://github.com/login/oauth/authorize +      token_url = https://github.com/login/oauth/access_token +      api_url = https://api.github.com/user +      team_ids = +      allowed_organizations = + +      #################################### Google Auth ######################### +      [auth.google] +      enabled = false +      allow_sign_up = true +      client_id = some_client_id +      client_secret = some_client_secret +      scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email +      auth_url = https://accounts.google.com/o/oauth2/auth +      token_url = https://accounts.google.com/o/oauth2/token +      api_url = https://www.googleapis.com/oauth2/v1/userinfo +      allowed_domains = +      hosted_domain = + +      #################################### Grafana.com Auth #################### +      # legacy key names (so they work in env variables) +      [auth.grafananet] +      enabled = false +      allow_sign_up = true +      client_id = some_id +      client_secret = some_secret +      scopes = user:email +      allowed_organizations = + +      [auth.grafana_com] +      enabled = false +      allow_sign_up = true +      client_id = some_id +      client_secret = some_secret +      scopes = user:email +      allowed_organizations = + +      #################################### Generic OAuth ####################### +      [auth.generic_oauth] +      name = OAuth +      enabled = false +      allow_sign_up = true +      client_id = some_id +      client_secret = some_secret +      scopes = user:email +      auth_url = +      token_url = +      api_url = +      team_ids = +      allowed_organizations = + +      #################################### Basic Auth ########################## +      [auth.basic] +      enabled = false + +      #################################### Auth Proxy ########################## +      [auth.proxy] +      enabled = true +      header_name = X-WEBAUTH-USER +      header_property = username +      auto_sign_up = true +      ldap_sync_ttl = 60 +      whitelist = + +      #################################### Auth LDAP ########################### +      [auth.ldap] +      enabled = false +      config_file = /etc/grafana/ldap.toml +      allow_sign_up = true + +      #################################### SMTP / Emailing ##################### +      [smtp] +      enabled = false +      host = localhost:25 +      user = +      # If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +      password = +      cert_file = +      key_file = +      skip_verify = false +      from_address = admin@grafana.localhost +      from_name = Grafana +      ehlo_identity = + +      [emails] +      welcome_email_on_sign_up = false +      templates_pattern = emails/*.html + +      #################################### Logging ########################## +      [log] +      # Either "console", "file", "syslog". Default is console and  file +      # Use space to separate multiple modes, e.g. "console file" +      mode = console file + +      # Either "debug", "info", "warn", "error", "critical", default is "info" +      level = error + +      # optional settings to set different levels for specific loggers. Ex filters = sqlstore:debug +      filters = + +      # For "console" mode only +      [log.console] +      level = + +      # log line format, valid options are text, console and json +      format = console + +      # For "file" mode only +      [log.file] +      level = + +      # log line format, valid options are text, console and json +      format = text + +      # This enables automated log rotate(switch of following options), default is true +      log_rotate = true + +      # Max line number of single file, default is 1000000 +      max_lines = 1000000 + +      # Max size shift of single file, default is 28 means 1 << 28, 256MB +      max_size_shift = 28 + +      # Segment log daily, default is true +      daily_rotate = true + +      # Expired days of log file(delete after max days), default is 7 +      max_days = 7 + +      [log.syslog] +      level = + +      # log line format, valid options are text, console and json +      format = text + +      # Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used. +      network = +      address = + +      # Syslog facility. user, daemon and local0 through local7 are valid. +      facility = + +      # Syslog tag. By default, the process' argv[0] is used. +      tag = + + +      #################################### AMQP Event Publisher ################ +      [event_publisher] +      enabled = false +      rabbitmq_url = amqp://localhost/ +      exchange = grafana_events + +      #################################### Dashboard JSON files ################ +      [dashboards.json] +      enabled = false +      path = /var/lib/grafana/dashboards + +      #################################### Usage Quotas ######################## +      [quota] +      enabled = false + +      #### set quotas to -1 to make unlimited. #### +      # limit number of users per Org. +      org_user = 10 + +      # limit number of dashboards per Org. +      org_dashboard = 100 + +      # limit number of data_sources per Org. +      org_data_source = 10 + +      # limit number of api_keys per Org. +      org_api_key = 10 + +      # limit number of orgs a user can create. +      user_org = 10 + +      # Global limit of users. +      global_user = -1 + +      # global limit of orgs. +      global_org = -1 + +      # global limit of dashboards +      global_dashboard = -1 + +      # global limit of api_keys +      global_api_key = -1 + +      # global limit on number of logged in users. +      global_session = -1 + +      #################################### Alerting ############################ +      [alerting] +      # Disable alerting engine & UI features +      enabled = true +      # Makes it possible to turn off alert rule execution but alerting UI is visible +      execute_alerts = true + +      #################################### Internal Grafana Metrics ############ +      # Metrics available at HTTP API Url /api/metrics +      [metrics] +      enabled           = true +      interval_seconds  = 10 + +      # Send internal Grafana metrics to graphite +      [metrics.graphite] +      # Enable by setting the address setting (ex localhost:2003) +      address = +      prefix = prod.grafana.%(instance_name)s. + +      [grafana_net] +      url = https://grafana.com + +      [grafana_com] +      url = https://grafana.com + +      #################################### Distributed tracing ############ +      [tracing.jaeger] +      # jaeger destination (ex localhost:6831) +      address = +      # tag that will always be included in when creating new spans. ex (tag1:value1,tag2:value2) +      always_included_tag = +      # Type specifies the type of the sampler: const, probabilistic, rateLimiting, or remote +      sampler_type = const +      # jaeger samplerconfig param +      # for "const" sampler, 0 or 1 for always false/true respectively +      # for "probabilistic" sampler, a probability between 0 and 1 +      # for "rateLimiting" sampler, the number of spans per second +      # for "remote" sampler, param is the same as for "probabilistic" +      # and indicates the initial sampling rate before the actual one +      # is received from the mothership +      sampler_param = 1 + +      #################################### External Image Storage ############## +      [external_image_storage] +      # You can choose between (s3, webdav, gcs) +      provider = + +      [external_image_storage.s3] +      bucket_url = +      bucket = +      region = +      path = +      access_key = +      secret_key = + +      [external_image_storage.webdav] +      url = +      username = +      password = +      public_url = + +      [external_image_storage.gcs] +      key_file = +      bucket = diff --git a/roles/openshift_grafana/files/grafana-ocp.yml b/roles/openshift_grafana/files/grafana-ocp.yml new file mode 100644 index 000000000..bc7b4b286 --- /dev/null +++ b/roles/openshift_grafana/files/grafana-ocp.yml @@ -0,0 +1,76 @@ +--- +kind: Template +apiVersion: v1 +metadata: +  name: grafana-ocp +  annotations: +    "openshift.io/display-name": Grafana ocp +    description: | +      Grafana server with patched Prometheus datasource. +    iconClass: icon-cogs +    tags: "metrics,monitoring,grafana,prometheus" +parameters: +- description: External URL for the grafana route +  name: ROUTE_URL +  value: "" +- description: The namespace to instantiate heapster under. Defaults to 'grafana'. +  name: NAMESPACE +  value: grafana +objects: +- apiVersion: route.openshift.io/v1 +  kind: Route +  metadata: +    name: grafana-ocp +    namespace: "${NAMESPACE}" +  spec: +    host: "${ROUTE_URL}" +    to: +      name: grafana-ocp +- apiVersion: v1 +  kind: Service +  metadata: +    name: grafana-ocp +    namespace: "${NAMESPACE}" +    labels: +      metrics-infra: grafana-ocp +      name: grafana-ocp +  spec: +    selector: +      name: grafana-ocp +    ports: +    - port: 8082 +      protocol: TCP +      targetPort: grafana-http +- apiVersion: v1 +  kind: ReplicationController +  metadata: +    name: grafana-ocp +    namespace: "${NAMESPACE}" +    labels: +      metrics-infra: grafana-ocp +      name: grafana-ocp +  spec: +    selector: +      name: grafana-ocp +    replicas: 1 +    template: +      version: v1 +      metadata: +        labels: +          metrics-infra: grafana-ocp +          name: grafana-ocp +      spec: +        volumes: +        - name: data +          emptyDir: {} +        containers: +        - image: "mrsiano/grafana-ocp:latest" +          name: grafana-ocp +          ports: +          - name: grafana-http +            containerPort: 3000 +          volumeMounts: +          - name: data +            mountPath: "/root/go/src/github.com/grafana/grafana/data" +          command: +          - "./bin/grafana-server" diff --git a/roles/openshift_grafana/files/openshift-cluster-monitoring.json b/roles/openshift_grafana/files/openshift-cluster-monitoring.json new file mode 100644 index 000000000..f59ca997f --- /dev/null +++ b/roles/openshift_grafana/files/openshift-cluster-monitoring.json @@ -0,0 +1,5138 @@ +{ +  "dashboard": { +    "description": "Monitors Openshift cluster using Prometheus. Shows overall cluster CPU / Memory / Filesystem usage as well as individual pod, containers, systemd services statistics. Uses cAdvisor metrics only.", +    "editable": true, +    "gnetId": 315, +    "graphTooltip": 0, +    "hideControls": false, +    "id": null, +    "links": [], +    "rows": [ +      { +        "collapse": false, +        "height": "200px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 1, +            "grid": {}, +            "height": "200px", +            "id": 32, +            "legend": { +              "alignAsTable": false, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": false, +              "show": false, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate (container_network_receive_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[2m]))", +                "format": "time_series", +                "instant": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "Received", +                "metric": "network", +                "refId": "A", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{kubernetes_io_hostname=~\"^$Node$\"}[2m]))", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "Sent", +                "metric": "network", +                "refId": "B", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Network I/O pressure", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 0, +              "value_type": "cumulative" +            }, +            "transparent": false, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "Bps", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "Bps", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Network I/O pressure", +        "titleSize": "h6" +      }, +      { +        "collapse": false, +        "height": "250px", +        "panels": [ +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": true, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "editable": true, +            "error": false, +            "format": "percent", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": true, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "180px", +            "id": 4, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 4, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) / sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"}) * 100", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Cluster memory usage", +            "transparent": false, +            "type": "singlestat", +            "valueFontSize": "80%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": true, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "percent", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": true, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "180px", +            "id": 6, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 4, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) / sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"}) * 100", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Cluster CPU usage ", +            "type": "singlestat", +            "valueFontSize": "80%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": true, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "percent", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": true, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "180px", +            "id": 7, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 4, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (container_fs_usage_bytes{device=~\"^/dev/mapper/docker_.*\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) / sum (container_fs_limit_bytes{device=~\"^/dev/mapper/docker_.*\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) * 100", +                "format": "time_series", +                "hide": false, +                "interval": "", +                "intervalFactor": 1, +                "legendFormat": "", +                "metric": "", +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Cluster filesystem usage", +            "type": "singlestat", +            "valueFontSize": "80%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "bytes", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 9, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "20%", +            "prefix": "", +            "prefixFontSize": "20%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (container_memory_working_set_bytes{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Used", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "bytes", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 10, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (machine_memory_bytes{kubernetes_io_hostname=~\"^$Node$\"})", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Total", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "none", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 11, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": " cores", +            "postfixFontSize": "30%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m]))", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Used", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "none", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 12, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": " cores", +            "postfixFontSize": "30%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"})", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Total", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "bytes", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 13, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (container_fs_usage_bytes{device=~\"^/dev/mapper/docker_.*$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Used", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          }, +          { +            "cacheTimeout": null, +            "colorBackground": false, +            "colorValue": false, +            "colors": [ +              "rgba(50, 172, 45, 0.97)", +              "rgba(237, 129, 40, 0.89)", +              "rgba(245, 54, 54, 0.9)" +            ], +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "format": "bytes", +            "gauge": { +              "maxValue": 100, +              "minValue": 0, +              "show": false, +              "thresholdLabels": false, +              "thresholdMarkers": true +            }, +            "height": "1px", +            "id": 14, +            "interval": null, +            "links": [], +            "mappingType": 1, +            "mappingTypes": [ +              { +                "name": "value to text", +                "value": 1 +              }, +              { +                "name": "range to text", +                "value": 2 +              } +            ], +            "maxDataPoints": 100, +            "nullPointMode": "connected", +            "nullText": null, +            "postfix": "", +            "postfixFontSize": "50%", +            "prefix": "", +            "prefixFontSize": "50%", +            "rangeMaps": [ +              { +                "from": "null", +                "text": "N/A", +                "to": "null" +              } +            ], +            "span": 2, +            "sparkline": { +              "fillColor": "rgba(31, 118, 189, 0.18)", +              "full": false, +              "lineColor": "rgb(31, 120, 193)", +              "show": false +            }, +            "tableColumn": "", +            "targets": [ +              { +                "expr": "sum (container_fs_limit_bytes{device=~\"^/dev/mapper/docker_.*$\",id=\"/\",kubernetes_io_hostname=~\"^$Node$\"})", +                "format": "time_series", +                "hide": false, +                "interval": "", +                "intervalFactor": 1, +                "refId": "A", +                "step": 20 +              } +            ], +            "thresholds": "", +            "title": "Total", +            "type": "singlestat", +            "valueFontSize": "50%", +            "valueMaps": [ +              { +                "op": "=", +                "text": "N/A", +                "value": "null" +              } +            ], +            "valueName": "current" +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Total usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 33, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": true, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{id=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) / sum (machine_cpu_cores{kubernetes_io_hostname=~\"^$Node$\"}) ", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "overall cpu usage", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Cluster CPU Usage", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "percent", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Dashboard Row", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 3, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "height": "", +            "id": 17, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (pod_name) * 100", +                "format": "time_series", +                "hide": false, +                "interval": "", +                "intervalFactor": 1, +                "legendFormat": "{{ pod_name }}", +                "metric": "container_cpu", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Pods CPU usage ", +            "tooltip": { +              "msResolution": true, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "transparent": false, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "percent", +                "label": "% Usage", +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Pods CPU usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 3, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "height": "", +            "id": 24, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "hideEmpty": false, +              "hideZero": false, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": null, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{image!=\"\",name=~\"^k8s_.*\",container_name!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (container_name, pod_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "pod: {{ pod_name }} | {{ container_name }}", +                "metric": "container_cpu", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Containers Cores Usage", +            "tooltip": { +              "msResolution": true, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": "cores", +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Containers CPU usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 3, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "height": "", +            "id": 23, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (irate (container_cpu_usage_seconds_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (id)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ id }}", +                "metric": "container_cpu", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "System services CPU usage ", +            "tooltip": { +              "msResolution": true, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": "cores", +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "System services CPU usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 411, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 3, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "id": 34, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": false, +              "show": true, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (irate (container_memory_usage_bytes{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (id)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ id }}", +                "metric": "container_cpu", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "All processes Memory usage ", +            "tooltip": { +              "msResolution": true, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "bytes", +                "label": "cores", +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "All processes CPU usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "id": 25, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (container_memory_working_set_bytes{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}) by (pod_name)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ pod_name }}", +                "metric": "container_memory_usage:sort_desc", +                "refId": "A", +                "step": 10 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Pods memory usage", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "bytes", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Pods memory usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "id": 26, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (container_memory_rss{systemd_service_name=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (systemd_service_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ systemd_service_name }}", +                "metric": "container_memory_usage:sort_desc", +                "refId": "B", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "System services memory usage", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "bytes", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "System services memory usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "id": 27, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (container_memory_working_set_bytes{image!=\"\",name=~\"^k8s_.*\",container_name!=\"POD\",kubernetes_io_hostname=~\"^$Node$\"}) by (container_name, pod_name)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "pod: {{ pod_name }} | {{ container_name }}", +                "metric": "container_memory_usage:sort_desc", +                "refId": "A", +                "step": 10 +              }, +              { +                "expr": "sum (container_memory_working_set_bytes{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, name, image)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", +                "metric": "container_memory_usage:sort_desc", +                "refId": "B", +                "step": 10 +              }, +              { +                "expr": "sum (container_memory_working_set_bytes{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}) by (kubernetes_io_hostname, rkt_container_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", +                "metric": "container_memory_usage:sort_desc", +                "refId": "C", +                "step": 10 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Containers memory usage", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "bytes", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Containers memory usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "500px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 0, +            "grid": {}, +            "id": 28, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": false, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": true, +            "targets": [ +              { +                "expr": "sum (container_memory_working_set_bytes{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}) by (id)", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ id }}", +                "metric": "container_memory_usage:sort_desc", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "All processes memory usage", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "bytes", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "All processes memory usage", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "250px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 1, +            "grid": {}, +            "id": 30, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate (container_network_receive_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (container_name, pod_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "-> pod: {{ pod_name }} | {{ container_name }}", +                "metric": "network", +                "refId": "B", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (container_name, pod_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "<- pod: {{ pod_name }} | {{ container_name }}", +                "metric": "network", +                "refId": "D", +                "step": 1 +              }, +              { +                "expr": "sum (irate (container_network_receive_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (kubernetes_io_hostname, name, image)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "-> docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", +                "metric": "network", +                "refId": "A", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{image!=\"\",name!~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (kubernetes_io_hostname, name, image)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "<- docker: {{ kubernetes_io_hostname }} | {{ image }} ({{ name }})", +                "metric": "network", +                "refId": "C", +                "step": 1 +              }, +              { +                "expr": "sum (irate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (kubernetes_io_hostname, rkt_container_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "-> rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", +                "metric": "network", +                "refId": "E", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{rkt_container_name!=\"\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (kubernetes_io_hostname, rkt_container_name)", +                "format": "time_series", +                "hide": false, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "<- rkt: {{ kubernetes_io_hostname }} | {{ rkt_container_name }}", +                "metric": "network", +                "refId": "F", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Containers network I/O ", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "Bps", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Containers network I/O", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 277, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 1, +            "grid": {}, +            "id": 16, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate (container_network_receive_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (pod_name)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "-> {{ pod_name }}", +                "metric": "network", +                "refId": "A", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{image!=\"\",name=~\"^k8s_.*\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (pod_name)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "<- {{ pod_name }}", +                "metric": "network", +                "refId": "B", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Pods network I/O ", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "Bps", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "Pods network I/O", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": "500px", +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "decimals": 2, +            "editable": true, +            "error": false, +            "fill": 1, +            "grid": {}, +            "id": 29, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": false, +              "show": true, +              "sideWidth": 200, +              "sort": "current", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 2, +            "links": [], +            "nullPointMode": "connected", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate (container_network_receive_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (id)", +                "format": "time_series", +                "instant": true, +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "-> {{ id }}", +                "metric": "network", +                "refId": "A", +                "step": 1 +              }, +              { +                "expr": "- sum (irate (container_network_transmit_bytes_total{id!=\"/\",kubernetes_io_hostname=~\"^$Node$\"}[2m])) by (id)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "<- {{ id }}", +                "metric": "network", +                "refId": "B", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "All processes network I/O ", +            "tooltip": { +              "msResolution": false, +              "shared": true, +              "sort": 2, +              "value_type": "cumulative" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "Bps", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": false +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": false, +        "title": "All processes network I/O", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 35, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(openshift_build_total) by (phase,reason)", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ phase }} | {{ reason }}", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_build_total", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 54, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "count(openshift_build_active_time_seconds{phase=\"running\"} offset 10m)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the number of builds that have been running for more than 10 minutes (600 seconds).", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 55, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "count(openshift_build_active_time_seconds{phase=\"pending\"} offset 10m)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the number of build that have been waiting at least 10 minutes (600 seconds) to start.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 56, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(openshift_build_total{phase=\"Failed\"})", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the number of failed builds, regardless of the failure reason.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 57, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "openshift_build_total{phase=\"Failed\",reason=\"FetchSourceFailed\"}", +                "format": "time_series", +                "intervalFactor": 1, +                "legendFormat": "{{ instance }}", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the number of failed builds because of problems retrieving source from the associated Git repository.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": true, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 58, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": false, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null as zero", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(openshift_build_total{phase=\"Complete\"})", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the number of successfully completed builds.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 0, +            "id": 59, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 1, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "openshift_build_total{phase=\"Failed\"} offset 5m", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ reason }}", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns the failed builds totals, per failure reason, from 5 minutes ago.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "OpenShift Builds", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 36, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(openshift_sdn_pod_setup_latency_sum)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_sdn_pod_setup_latency_sum", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 41, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(openshift_sdn_pod_teardown_latency{quantile=\"0.9\"}) by (instance)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_sdn_pod_teardown_latency", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 50, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "topk(10, (sum by (pod_name) (irate(container_network_receive_bytes_total{pod_name!=\"\"}[5m]))))", +                "format": "time_series", +                "interval": "", +                "intervalFactor": 1, +                "legendFormat": "{{ pod_name }}", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Top 10 pods doing the most receive network traffic", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "decbytes", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 37, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "openshift_sdn_pod_ips", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ instance }} | {{ role }}", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_sdn_pod_ips", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 39, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "garbage_collector_monitoring_route:openshift:io_v1_rate_limiter_use", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "garbage_collector_monitoring_route:openshift:io_v1_rate_limiter_use", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 42, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "openshift_sdn_arp_cache_entries", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ role }} | {{ instance }}", +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_sdn_arp_cache_entries", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 40, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "openshift_sdn_arp_cache_entries", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 1 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "openshift_sdn_arp_cache_entries", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "OpenShift SDN", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 44, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "irate(kubelet_pleg_relist_latency_microseconds{kubernetes_io_hostname=~\"$Node\",quantile=\"0.9\"}[2m])", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ role }} | {{ instance }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "kubelet_pleg_relist", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "µs", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 51, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "irate(kubelet_docker_operations_latency_microseconds{quantile=\"0.9\"}[2m])", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ operation_type }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "kubelet_docker_operations_latency_microseconds{quantile=\"0.9\"}", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "µs", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 52, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "kubelet_docker_operations_timeout", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ operation_type }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns a running count (not a rate) of docker operations that have timed out since the kubelet was started.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 53, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "kubelet_docker_operations_errors", +                "format": "time_series", +                "intervalFactor": 1, +                "legendFormat": "{{ operation_type }}", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Returns a running count (not a rate) of docker operations that have failed since the kubelet was started.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "Kubelet", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 46, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "irate(scrape_samples_scraped[2m])", +                "format": "time_series", +                "hide": false, +                "intervalFactor": 2, +                "legendFormat": "{{ kubernetes_name }} | {{ instance }} ", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "scrape_samples_scraped", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 68, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum without (cpu) (irate(container_cpu_usage_seconds_total{container_name=\"prometheus\"}[5m])))", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "CPU per instance of Prometheus container.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "Prometheus", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 48, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum without (instance,type,client,contentType) (irate(apiserver_request_count{verb!~\"GET|LIST|WATCH\"}[2m]))) > 0", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ resource }} || {{ verb }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Number of mutating API requests being made to the control plane.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 49, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum without (instance,type,client,contentType) (irate(apiserver_request_count{verb=~\"GET|LIST|WATCH\"}[2m]))) > 0", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ resource }} || {{ pod }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Number of non-mutating API requests being made to the control plane.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 74, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "endpoint_queue_latency", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": " quantile   {{ quantile }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "endpoint_queue_latency", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "ms", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "API Server", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 61, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "etcd_disk_wal_fsync_duration_seconds_count", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 10 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "etcd_disk_wal_fsync_duration_seconds_count", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "etcd", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 62, +            "legend": { +              "alignAsTable": false, +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "rightSide": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 12, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(changes(container_start_time_seconds[10m]))", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "The number of containers that start or restart over the last ten minutes.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "Changes in your cluster", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 63, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(machine_cpu_cores)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Total number of cores in the cluster.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 64, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(sort_desc(irate(container_cpu_usage_seconds_total{id=\"/\"}[5m])))", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Total number of consumed cores.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 65, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum by (kubernetes_io_hostname,type) (irate(container_cpu_usage_seconds_total{id=\"/\"}[5m])))", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "CPU consumed per node in the cluster.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 66, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum by (cpu,id,pod_name,container_name) (irate(container_cpu_usage_seconds_total{role=\"infra\"}[5m])))", +                "format": "time_series", +                "hide": false, +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "CPU consumption per system service or container on the infrastructure nodes.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 67, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sort_desc(sum by (namespace) (irate(container_cpu_usage_seconds_total[5m])))", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "CPU consumed per namespace on the cluster.", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 47, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(irate(container_cpu_usage_seconds_total{id=\"/\"}[3m])) / sum(machine_cpu_cores)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Percentage of total cluster CPU in use", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "percent", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 69, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum(container_memory_rss) / sum(machine_memory_bytes)", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Percentage of total cluster memory in use", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "percent", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 70, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum by (kubernetes_io_hostname) (irate(container_cpu_usage_seconds_total{id=~\"/system.slice/(docker|etcd).service\"}[5m]))", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "Aggregate CPU usage (seconds total) of etcd+docker", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "System and container CPU", +        "titleSize": "h6" +      }, +      { +        "collapse": true, +        "height": 250, +        "panels": [ +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 71, +            "legend": { +              "avg": false, +              "current": false, +              "max": false, +              "min": false, +              "show": false, +              "total": false, +              "values": false +            }, +            "lines": true, +            "linewidth": 1, +            "links": [ +              { +                "title": "Kubernetes Storage Metrics via Prometheus", +                "type": "absolute", +                "url": "https://docs.google.com/document/d/1Fh0T60T_y888LsRwC51CQHO75b2IZ3A34ZQS71s_F0g" +              } +            ], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "volumes_queue_latency", +                "format": "time_series", +                "intervalFactor": 2, +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "volumes_queue_latency", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 72, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [ +              { +                "title": "Kubernetes Storage Metrics via Prometheus", +                "type": "absolute", +                "url": "https://docs.google.com/document/d/1Fh0T60T_y888LsRwC51CQHO75b2IZ3A34ZQS71s_F0g" +              } +            ], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "irate(cloudprovider_gce_api_request_duration_seconds_count[2m])", +                "format": "time_series", +                "intervalFactor": 2, +                "legendFormat": "{{ request }}", +                "refId": "A", +                "step": 4 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "cloudprovider_aws_api_request_duration_seconds_count", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "none", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          }, +          { +            "aliasColors": {}, +            "bars": false, +            "dashLength": 10, +            "dashes": false, +            "datasource": "${DS_PR}", +            "fill": 1, +            "id": 73, +            "legend": { +              "alignAsTable": true, +              "avg": true, +              "current": true, +              "max": false, +              "min": false, +              "rightSide": true, +              "show": true, +              "sort": "avg", +              "sortDesc": true, +              "total": false, +              "values": true +            }, +            "lines": true, +            "linewidth": 1, +            "links": [ +              { +                "title": "Kubernetes Storage Metrics via Prometheus", +                "type": "absolute", +                "url": "https://docs.google.com/document/d/1Fh0T60T_y888LsRwC51CQHO75b2IZ3A34ZQS71s_F0g" +              } +            ], +            "nullPointMode": "null", +            "percentage": false, +            "pointradius": 5, +            "points": false, +            "renderer": "flot", +            "seriesOverrides": [], +            "spaceLength": 10, +            "span": 6, +            "stack": false, +            "steppedLine": false, +            "targets": [ +              { +                "expr": "sum (irate(storage_operation_duration_seconds_sum{kubernetes_io_hostname=~\"$Node\"}[2m])) by (operation_name,kubernetes_io_hostname)", +                "format": "time_series", +                "interval": "1s", +                "intervalFactor": 1, +                "legendFormat": "{{ operation_name }} || {{ kubernetes_io_hostname }}", +                "refId": "A", +                "step": 2 +              } +            ], +            "thresholds": [], +            "timeFrom": null, +            "timeShift": null, +            "title": "storage_operation_duration_seconds_sum", +            "tooltip": { +              "shared": true, +              "sort": 0, +              "value_type": "individual" +            }, +            "type": "graph", +            "xaxis": { +              "buckets": null, +              "mode": "time", +              "name": null, +              "show": true, +              "values": [] +            }, +            "yaxes": [ +              { +                "format": "s", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              }, +              { +                "format": "short", +                "label": null, +                "logBase": 1, +                "max": null, +                "min": null, +                "show": true +              } +            ] +          } +        ], +        "repeat": null, +        "repeatIteration": null, +        "repeatRowId": null, +        "showTitle": true, +        "title": "OpenShift Volumes", +        "titleSize": "h6" +      } +    ], +    "schemaVersion": 14, +    "style": "dark", +    "tags": [ +      "kubernetes", +      "openshift" +    ], +    "templating": { +      "list": [ +        { +          "allValue": ".*", +          "current": {}, +          "datasource": "${DS_PR}", +          "hide": 0, +          "includeAll": true, +          "label": null, +          "multi": false, +          "name": "Node", +          "options": [], +          "query": "label_values(kubernetes_io_hostname)", +          "refresh": 1, +          "regex": "", +          "sort": 0, +          "tagValuesQuery": "", +          "tags": [], +          "tagsQuery": "", +          "type": "query", +          "useTags": false +        } +      ] +    }, +    "time": { +      "from": "now-30m", +      "to": "now" +    }, +    "timepicker": { +      "refresh_intervals": [ +        "5s", +        "1s", +        "2m", +        "20s", +        "5m", +        "15m", +        "30m", +        "1h", +        "2h", +        "1d" +      ], +      "time_options": [ +        "5m", +        "15m", +        "1h", +        "6h", +        "12h", +        "24h", +        "2d", +        "7d", +        "30d" +      ] +    }, +    "timezone": "browser", +    "title": "openshift cluster monitoring", +    "version": 6 +  } +} diff --git a/roles/openshift_grafana/meta/main.yml b/roles/openshift_grafana/meta/main.yml new file mode 100644 index 000000000..8dea6f197 --- /dev/null +++ b/roles/openshift_grafana/meta/main.yml @@ -0,0 +1,13 @@ +--- +galaxy_info: +  author: Eldad Marciano +  description: Setup grafana pod +  company: Red Hat, Inc. +  license: Apache License, Version 2.0 +  min_ansible_version: 2.3 +  platforms: +  - name: EL +    versions: +    - 7 +  categories: +  - metrics diff --git a/roles/openshift_grafana/tasks/gf-permissions.yml b/roles/openshift_grafana/tasks/gf-permissions.yml new file mode 100644 index 000000000..9d3c741ee --- /dev/null +++ b/roles/openshift_grafana/tasks/gf-permissions.yml @@ -0,0 +1,12 @@ +--- +- name: Create gf user on htpasswd +  command: htpasswd -c /etc/origin/master/htpasswd gfadmin + +- name: Make sure master config use HTPasswdPasswordIdentityProvider +  command: "sed -ie 's|AllowAllPasswordIdentityProvider|HTPasswdPasswordIdentityProvider\n      file: /etc/origin/master/htpasswd|' /etc/origin/master/master-config.yaml" + +- name: Grant permission for gfuser +  command: oc adm policy add-cluster-role-to-user cluster-reader gfadmin + +- name: Restart mater api +  command: systemctl restart atomic-openshift-master-api.service diff --git a/roles/openshift_grafana/tasks/main.yml b/roles/openshift_grafana/tasks/main.yml new file mode 100644 index 000000000..6a06d40a9 --- /dev/null +++ b/roles/openshift_grafana/tasks/main.yml @@ -0,0 +1,122 @@ +--- +- name: Create grafana namespace +  oc_project: +    state: present +    name: grafana + +- name: Configure Grafana Permissions +  include_tasks: tasks/gf-permissions.yml +  when: gf_oauth | default(false) | bool == true + +# TODO: we should grab this yaml file from openshift/origin +- name: Templatize grafana yaml +  template: src=grafana-ocp.yaml dest=/tmp/grafana-ocp.yaml +  register: +    cl_file: /tmp/grafana-ocp.yaml +  when: gf_oauth | default(false) | bool == false + +# TODO: we should grab this yaml file from openshift/origin +- name: Templatize grafana yaml +  template: src=grafana-ocp-oauth.yaml dest=/tmp/grafana-ocp-oauth.yaml +  register: +    cl_file: /tmp/grafana-ocp-oauth.yaml +  when: gf_oauth | default(false) | bool == true + +- name: Process the grafana file +  oc_process: +    namespace: grafana +    template_name: "{{ cl_file }}" +    create: True +    when: gf_oauth | default(false) | bool == true + +- name: Wait to grafana be running +  command: oc rollout status deployment/grafana-ocp + +- name: oc adm policy add-role-to-user view -z grafana-ocp -n {{ gf_prometheus_namespace }} +  oc_adm_policy_user: +    user: grafana-ocp +    resource_kind: cluster-role +    resource_name: view +    state: present +    role_namespace: "{{ gf_prometheus_namespace }}" + +- name: Get grafana route +  oc_obj: +    kind: route +    name: grafana +    namespace: grafana +  register: route + +- name: Get prometheus route +  oc_obj: +    kind: route +    name: prometheus +    namespace: "{{ gf_prometheus_namespace }}" +  register: route + +- name: Get the prometheus SA +  oc_serviceaccount_secret: +    state: list +    service_account: prometheus +    namespace: "{{ gf_prometheus_namespace }}" +  register: sa + +- name: Get the management SA bearer token +  set_fact: +    management_token: "{{ sa.results | oo_filter_sa_secrets }}" + +- name: Ensure the SA bearer token value is read +  oc_secret: +    state: list +    name: "{{ management_token }}" +    namespace: "{{ gf_prometheus_namespace }}" +  no_log: True +  register: sa_secret + +- name: Get the SA bearer token for prometheus +  set_fact: +    token: "{{ sa_secret.results.encoded.token }}" + +- name: Convert to json +  var: +    ds_json: "{{ gf_body_tmp }} | to_json }}" + +- name: Set protocol type +  var: +    protocol: "{{ 'https' if {{ gf_oauth }} == true else 'http' }}" + +- name: Add gf datasrouce +  uri: +    url: "{{ protocol }}://{{ route }}/api/datasources" +    user: admin +    password: admin +    method: POST +    body: "{{ ds_json | regex_replace('grafana_name', {{ gf_datasource_name }}) | regex_replace('prometheus_url', 'https://'{{ prometheus }} ) | regex_replace('satoken', {{ token }}) }}" +    headers: +      Content-Type: "Content-Type: application/json" +  register: add_ds + +- name: Regex setup ds name +  replace: +    path: "{{ lookup('file', 'openshift-cluster-monitoring.json') }}" +    regexp: '${DS_PR}' +    replace: '{{ gf_datasource_name }}' +    backup: yes + +- name: Add new dashboard +  uri: +    url: "{{ protocol }}://{{ route }}/api/dashboards/db" +    user: admin +    password: admin +    method: POST +    body: "{{ lookup('file', 'openshift-cluster-monitoring.json') }}" +    headers: +      Content-Type: "Content-Type: application/json" +  register: add_ds + +- name: Regex json tear down +  replace: +    path: "{{ lookup('file', 'openshift-cluster-monitoring.json') }}" +    regexp: '${DS_PR}' +    replace: '{{ gf_datasource_name }}' +    backup: yes diff --git a/roles/openshift_health_checker/openshift_checks/__init__.py b/roles/openshift_health_checker/openshift_checks/__init__.py index 83e551b5d..b9c41d1b4 100644 --- a/roles/openshift_health_checker/openshift_checks/__init__.py +++ b/roles/openshift_health_checker/openshift_checks/__init__.py @@ -5,6 +5,7 @@ Health checks for OpenShift clusters.  import json  import operator  import os +import re  import time  import collections @@ -309,28 +310,38 @@ class OpenShiftCheck(object):              name_list = name_list.split(',')          return [name.strip() for name in name_list if name.strip()] -    @staticmethod -    def get_major_minor_version(openshift_image_tag): +    def get_major_minor_version(self, openshift_image_tag=None):          """Parse and return the deployed version of OpenShift as a tuple.""" -        if openshift_image_tag and openshift_image_tag[0] == 'v': -            openshift_image_tag = openshift_image_tag[1:] -        # map major release versions across releases -        # to a common major version -        openshift_major_release_version = { -            "1": "3", -        } +        version = openshift_image_tag or self.get_var("openshift_image_tag") +        components = [int(component) for component in re.findall(r'\d+', version)] -        components = openshift_image_tag.split(".") -        if not components or len(components) < 2: +        if len(components) < 2:              msg = "An invalid version of OpenShift was found for this host: {}" -            raise OpenShiftCheckException(msg.format(openshift_image_tag)) +            raise OpenShiftCheckException(msg.format(version)) + +        # map major release version across releases to OCP major version +        components[0] = {1: 3}.get(components[0], components[0]) + +        return tuple(int(x) for x in components[:2]) + +    def get_required_version(self, name, version_map): +        """Return the correct required version(s) for the current (or nearest) OpenShift version.""" +        openshift_version = self.get_major_minor_version() + +        earliest = min(version_map) +        latest = max(version_map) +        if openshift_version < earliest: +            return version_map[earliest] +        if openshift_version > latest: +            return version_map[latest] -        if components[0] in openshift_major_release_version: -            components[0] = openshift_major_release_version[components[0]] +        required_version = version_map.get(openshift_version) +        if not required_version: +            msg = "There is no recommended version of {} for the current version of OpenShift ({})" +            raise OpenShiftCheckException(msg.format(name, ".".join(str(comp) for comp in openshift_version))) -        components = tuple(int(x) for x in components[:2]) -        return components +        return required_version      def find_ansible_mount(self, path):          """Return the mount point for path from ansible_mounts.""" diff --git a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py index 7afb8f730..d298fbab2 100644 --- a/roles/openshift_health_checker/openshift_checks/docker_image_availability.py +++ b/roles/openshift_health_checker/openshift_checks/docker_image_availability.py @@ -40,7 +40,7 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck):      # to look for images available remotely without waiting to pull them.      dependencies = ["python-docker-py", "skopeo"]      # command for checking if remote registries have an image, without docker pull -    skopeo_command = "timeout 10 skopeo inspect --tls-verify={tls} {creds} docker://{registry}/{image}" +    skopeo_command = "{proxyvars} timeout 10 skopeo inspect --tls-verify={tls} {creds} docker://{registry}/{image}"      skopeo_example_command = "skopeo inspect [--tls-verify=false] [--creds=<user>:<pass>] docker://<registry>/<image>"      def __init__(self, *args, **kwargs): @@ -56,7 +56,7 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck):          # ordered list of registries (according to inventory vars) that docker will try for unscoped images          regs = self.ensure_list("openshift_docker_additional_registries")          # currently one of these registries is added whether the user wants it or not. -        deployment_type = self.get_var("openshift_deployment_type") +        deployment_type = self.get_var("openshift_deployment_type", default="")          if deployment_type == "origin" and "docker.io" not in regs:              regs.append("docker.io")          elif deployment_type == 'openshift-enterprise' and "registry.access.redhat.com" not in regs: @@ -76,11 +76,20 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck):          if oreg_auth_user != '' and oreg_auth_password != '':              oreg_auth_user = self.template_var(oreg_auth_user)              oreg_auth_password = self.template_var(oreg_auth_password) -            self.skopeo_command_creds = "--creds={}:{}".format(quote(oreg_auth_user), quote(oreg_auth_password)) +            self.skopeo_command_creds = quote("--creds={}:{}".format(oreg_auth_user, oreg_auth_password))          # record whether we could reach a registry or not (and remember results)          self.reachable_registries = {} +        # take note of any proxy settings needed +        proxies = [] +        for var in ['http_proxy', 'https_proxy', 'no_proxy']: +            # ansible vars are openshift_http_proxy, openshift_https_proxy, openshift_no_proxy +            value = self.get_var("openshift_" + var, default=None) +            if value: +                proxies.append(var.upper() + "=" + quote(self.template_var(value))) +        self.skopeo_proxy_vars = " ".join(proxies) +      def is_active(self):          """Skip hosts with unsupported deployment types."""          deployment_type = self.get_var("openshift_deployment_type") @@ -249,11 +258,18 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck):              if not self.reachable_registries[registry]:                  continue  # do not keep trying unreachable registries -            args = dict(registry=registry, image=image) -            args["tls"] = "false" if registry in self.registries["insecure"] else "true" -            args["creds"] = self.skopeo_command_creds if registry == self.registries["oreg"] else "" +            args = dict( +                proxyvars=self.skopeo_proxy_vars, +                tls="false" if registry in self.registries["insecure"] else "true", +                creds=self.skopeo_command_creds if registry == self.registries["oreg"] else "", +                registry=quote(registry), +                image=quote(image), +            ) -            result = self.execute_module_with_retries("command", {"_raw_params": self.skopeo_command.format(**args)}) +            result = self.execute_module_with_retries("command", { +                "_uses_shell": True, +                "_raw_params": self.skopeo_command.format(**args), +            })              if result.get("rc", 0) == 0 and not result.get("failed"):                  return True              if result.get("rc") == 124:  # RC 124 == timed out; mark unreachable @@ -263,6 +279,10 @@ class DockerImageAvailability(DockerHostMixin, OpenShiftCheck):      def connect_to_registry(self, registry):          """Use ansible wait_for module to test connectivity from host to registry. Returns bool.""" +        if self.skopeo_proxy_vars != "": +            # assume we can't connect directly; just waive the test +            return True +          # test a simple TCP connection          host, _, port = registry.partition(":")          port = port or 443 diff --git a/roles/openshift_health_checker/openshift_checks/logging/elasticsearch.py b/roles/openshift_health_checker/openshift_checks/logging/elasticsearch.py index 986a01f38..7f8c6ebdc 100644 --- a/roles/openshift_health_checker/openshift_checks/logging/elasticsearch.py +++ b/roles/openshift_health_checker/openshift_checks/logging/elasticsearch.py @@ -170,7 +170,7 @@ class Elasticsearch(LoggingCheck):          """          errors = []          for pod_name in pods_by_name.keys(): -            df_cmd = 'exec {} -- df --output=ipcent,pcent /elasticsearch/persistent'.format(pod_name) +            df_cmd = '-c elasticsearch exec {} -- df --output=ipcent,pcent /elasticsearch/persistent'.format(pod_name)              disk_output = self.exec_oc(df_cmd, [], save_as_name='get_pv_diskspace.json')              lines = disk_output.splitlines()              # expecting one header looking like 'IUse% Use%' and one body line diff --git a/roles/openshift_health_checker/openshift_checks/logging/kibana.py b/roles/openshift_health_checker/openshift_checks/logging/kibana.py index 3b1cf8baa..16ec3a7f6 100644 --- a/roles/openshift_health_checker/openshift_checks/logging/kibana.py +++ b/roles/openshift_health_checker/openshift_checks/logging/kibana.py @@ -5,12 +5,11 @@ Module for performing checks on a Kibana logging deployment  import json  import ssl -try: -    from urllib2 import HTTPError, URLError -    import urllib2 -except ImportError: -    from urllib.error import HTTPError, URLError -    import urllib.request as urllib2 +# pylint can't find the package when its installed in virtualenv +# pylint: disable=import-error,no-name-in-module +from ansible.module_utils.six.moves.urllib import request +# pylint: disable=import-error,no-name-in-module +from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError  from openshift_checks.logging.logging import LoggingCheck, OpenShiftCheckException @@ -65,7 +64,7 @@ class Kibana(LoggingCheck):          # Verify that the url is returning a valid response          try:              # We only care if the url connects and responds -            return_code = urllib2.urlopen(url, context=ctx).getcode() +            return_code = request.urlopen(url, context=ctx).getcode()          except HTTPError as httperr:              return httperr.reason          except URLError as urlerr: diff --git a/roles/openshift_health_checker/openshift_checks/ovs_version.py b/roles/openshift_health_checker/openshift_checks/ovs_version.py index 0cad19842..58a2692bd 100644 --- a/roles/openshift_health_checker/openshift_checks/ovs_version.py +++ b/roles/openshift_health_checker/openshift_checks/ovs_version.py @@ -3,7 +3,7 @@ Ansible module for determining if an installed version of Open vSwitch is incomp  currently installed version of OpenShift.  """ -from openshift_checks import OpenShiftCheck, OpenShiftCheckException +from openshift_checks import OpenShiftCheck  from openshift_checks.mixins import NotContainerizedMixin @@ -16,10 +16,12 @@ class OvsVersion(NotContainerizedMixin, OpenShiftCheck):      tags = ["health"]      openshift_to_ovs_version = { -        "3.7": ["2.6", "2.7", "2.8"], -        "3.6": ["2.6", "2.7", "2.8"], -        "3.5": ["2.6", "2.7"], -        "3.4": "2.4", +        (3, 4): "2.4", +        (3, 5): ["2.6", "2.7"], +        (3, 6): ["2.6", "2.7", "2.8"], +        (3, 7): ["2.6", "2.7", "2.8"], +        (3, 8): ["2.6", "2.7", "2.8"], +        (3, 9): ["2.6", "2.7", "2.8"],      }      def is_active(self): @@ -40,16 +42,5 @@ class OvsVersion(NotContainerizedMixin, OpenShiftCheck):          return self.execute_module("rpm_version", args)      def get_required_ovs_version(self): -        """Return the correct Open vSwitch version for the current OpenShift version""" -        openshift_version_tuple = self.get_major_minor_version(self.get_var("openshift_image_tag")) - -        if openshift_version_tuple < (3, 5): -            return self.openshift_to_ovs_version["3.4"] - -        openshift_version = ".".join(str(x) for x in openshift_version_tuple) -        ovs_version = self.openshift_to_ovs_version.get(openshift_version) -        if ovs_version: -            return self.openshift_to_ovs_version[openshift_version] - -        msg = "There is no recommended version of Open vSwitch for the current version of OpenShift: {}" -        raise OpenShiftCheckException(msg.format(openshift_version)) +        """Return the correct Open vSwitch version(s) for the current OpenShift version.""" +        return self.get_required_version("Open vSwitch", self.openshift_to_ovs_version) diff --git a/roles/openshift_health_checker/openshift_checks/package_version.py b/roles/openshift_health_checker/openshift_checks/package_version.py index f3a628e28..28aee8b35 100644 --- a/roles/openshift_health_checker/openshift_checks/package_version.py +++ b/roles/openshift_health_checker/openshift_checks/package_version.py @@ -1,8 +1,6 @@  """Check that available RPM packages match the required versions.""" -import re - -from openshift_checks import OpenShiftCheck, OpenShiftCheckException +from openshift_checks import OpenShiftCheck  from openshift_checks.mixins import NotContainerizedMixin @@ -18,6 +16,8 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck):          (3, 5): ["2.6", "2.7"],          (3, 6): ["2.6", "2.7", "2.8"],          (3, 7): ["2.6", "2.7", "2.8"], +        (3, 8): ["2.6", "2.7", "2.8"], +        (3, 9): ["2.6", "2.7", "2.8"],      }      openshift_to_docker_version = { @@ -27,11 +27,9 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck):          (3, 4): "1.12",          (3, 5): "1.12",          (3, 6): "1.12", -    } - -    # map major OpenShift release versions across releases to a common major version -    map_major_release_version = { -        1: 3, +        (3, 7): "1.12", +        (3, 8): "1.12", +        (3, 9): ["1.12", "1.13"],      }      def is_active(self): @@ -83,48 +81,8 @@ class PackageVersion(NotContainerizedMixin, OpenShiftCheck):      def get_required_ovs_version(self):          """Return the correct Open vSwitch version(s) for the current OpenShift version.""" -        openshift_version = self.get_openshift_version_tuple() - -        earliest = min(self.openshift_to_ovs_version) -        latest = max(self.openshift_to_ovs_version) -        if openshift_version < earliest: -            return self.openshift_to_ovs_version[earliest] -        if openshift_version > latest: -            return self.openshift_to_ovs_version[latest] - -        ovs_version = self.openshift_to_ovs_version.get(openshift_version) -        if not ovs_version: -            msg = "There is no recommended version of Open vSwitch for the current version of OpenShift: {}" -            raise OpenShiftCheckException(msg.format(".".join(str(comp) for comp in openshift_version))) - -        return ovs_version +        return self.get_required_version("Open vSwitch", self.openshift_to_ovs_version)      def get_required_docker_version(self):          """Return the correct Docker version(s) for the current OpenShift version.""" -        openshift_version = self.get_openshift_version_tuple() - -        earliest = min(self.openshift_to_docker_version) -        latest = max(self.openshift_to_docker_version) -        if openshift_version < earliest: -            return self.openshift_to_docker_version[earliest] -        if openshift_version > latest: -            return self.openshift_to_docker_version[latest] - -        docker_version = self.openshift_to_docker_version.get(openshift_version) -        if not docker_version: -            msg = "There is no recommended version of Docker for the current version of OpenShift: {}" -            raise OpenShiftCheckException(msg.format(".".join(str(comp) for comp in openshift_version))) - -        return docker_version - -    def get_openshift_version_tuple(self): -        """Return received image tag as a normalized (X, Y) minor version tuple.""" -        version = self.get_var("openshift_image_tag") -        comps = [int(component) for component in re.findall(r'\d+', version)] - -        if len(comps) < 2: -            msg = "An invalid version of OpenShift was found for this host: {}" -            raise OpenShiftCheckException(msg.format(version)) - -        comps[0] = self.map_major_release_version.get(comps[0], comps[0]) -        return tuple(comps[0:2]) +        return self.get_required_version("Docker", self.openshift_to_docker_version) diff --git a/roles/openshift_health_checker/test/kibana_test.py b/roles/openshift_health_checker/test/kibana_test.py index 04a5e89c4..750d4b9e9 100644 --- a/roles/openshift_health_checker/test/kibana_test.py +++ b/roles/openshift_health_checker/test/kibana_test.py @@ -1,12 +1,10 @@  import pytest  import json -try: -    import urllib2 -    from urllib2 import HTTPError, URLError -except ImportError: -    from urllib.error import HTTPError, URLError -    import urllib.request as urllib2 +# pylint can't find the package when its installed in virtualenv +from ansible.module_utils.six.moves.urllib import request  # pylint: disable=import-error +# pylint: disable=import-error +from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError  from openshift_checks.logging.kibana import Kibana, OpenShiftCheckException @@ -202,7 +200,7 @@ def test_verify_url_external_failure(lib_result, expect, monkeypatch):          if type(lib_result) is int:              return _http_return(lib_result)          raise lib_result -    monkeypatch.setattr(urllib2, 'urlopen', urlopen) +    monkeypatch.setattr(request, 'urlopen', urlopen)      check = Kibana()      check._get_kibana_url = lambda: 'url' diff --git a/roles/openshift_health_checker/test/ovs_version_test.py b/roles/openshift_health_checker/test/ovs_version_test.py index 0238f49d5..80c7a0541 100644 --- a/roles/openshift_health_checker/test/ovs_version_test.py +++ b/roles/openshift_health_checker/test/ovs_version_test.py @@ -1,26 +1,7 @@  import pytest -from openshift_checks.ovs_version import OvsVersion, OpenShiftCheckException - - -def test_openshift_version_not_supported(): -    def execute_module(*_): -        return {} - -    openshift_release = '111.7.0' - -    task_vars = dict( -        openshift=dict(common=dict()), -        openshift_release=openshift_release, -        openshift_image_tag='v' + openshift_release, -        openshift_deployment_type='origin', -        openshift_service_type='origin' -    ) - -    with pytest.raises(OpenShiftCheckException) as excinfo: -        OvsVersion(execute_module, task_vars).run() - -    assert "no recommended version of Open vSwitch" in str(excinfo.value) +from openshift_checks.ovs_version import OvsVersion +from openshift_checks import OpenShiftCheckException  def test_invalid_openshift_release_format(): diff --git a/roles/openshift_health_checker/test/package_version_test.py b/roles/openshift_health_checker/test/package_version_test.py index d2916f617..868b4bd12 100644 --- a/roles/openshift_health_checker/test/package_version_test.py +++ b/roles/openshift_health_checker/test/package_version_test.py @@ -1,6 +1,7 @@  import pytest -from openshift_checks.package_version import PackageVersion, OpenShiftCheckException +from openshift_checks.package_version import PackageVersion +from openshift_checks import OpenShiftCheckException  def task_vars_for(openshift_release, deployment_type): @@ -18,7 +19,7 @@ def task_vars_for(openshift_release, deployment_type):  def test_openshift_version_not_supported():      check = PackageVersion(None, task_vars_for("1.2.3", 'origin')) -    check.get_openshift_version_tuple = lambda: (3, 4, 1)  # won't be in the dict +    check.get_major_minor_version = lambda: (3, 4, 1)  # won't be in the dict      with pytest.raises(OpenShiftCheckException) as excinfo:          check.get_required_ovs_version() diff --git a/roles/openshift_hosted/tasks/storage/glusterfs_endpoints.yml b/roles/openshift_hosted/tasks/storage/glusterfs_endpoints.yml index 77f020357..fef945d51 100644 --- a/roles/openshift_hosted/tasks/storage/glusterfs_endpoints.yml +++ b/roles/openshift_hosted/tasks/storage/glusterfs_endpoints.yml @@ -1,4 +1,10 @@  --- +- name: Create temp directory for doing work in +  command: mktemp -d /tmp/openshift-hosted-ansible-XXXXXX +  register: mktempHosted +  changed_when: False +  check_mode: no +  - name: Generate GlusterFS registry endpoints    template:      src: "{{ openshift.common.examples_content_version }}/glusterfs-registry-endpoints.yml.j2" @@ -14,3 +20,10 @@    with_items:    - "{{ mktempHosted.stdout }}/glusterfs-registry-service.yml"    - "{{ mktempHosted.stdout }}/glusterfs-registry-endpoints.yml" + +- name: Delete temp directory +  file: +    name: "{{ mktempHosted.stdout }}" +    state: absent +  changed_when: False +  check_mode: no diff --git a/roles/openshift_hosted/tasks/storage/registry_config.j2 b/roles/openshift_hosted/tasks/storage/registry_config.j2 deleted file mode 120000 index f3e82ad4f..000000000 --- a/roles/openshift_hosted/tasks/storage/registry_config.j2 +++ /dev/null @@ -1 +0,0 @@ -../../../templates/registry_config.j2
\ No newline at end of file diff --git a/roles/openshift_hosted_templates/files/v3.6/enterprise/registry-console.yaml b/roles/openshift_hosted_templates/files/v3.6/enterprise/registry-console.yaml index cc3159a32..0786e2d2f 100644 --- a/roles/openshift_hosted_templates/files/v3.6/enterprise/registry-console.yaml +++ b/roles/openshift_hosted_templates/files/v3.6/enterprise/registry-console.yaml @@ -102,7 +102,7 @@ objects:  parameters:    - description: 'Specify "registry/repository" prefix for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", set prefix "registry.access.redhat.com/openshift3/"'      name: IMAGE_PREFIX -    value: "openshift3/" +    value: "registry.access.redhat.com/openshift3/"    - description: 'Specify component name for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", use base name "registry-console"'      name: IMAGE_BASENAME      value: "registry-console" diff --git a/roles/openshift_hosted_templates/files/v3.7/enterprise/registry-console.yaml b/roles/openshift_hosted_templates/files/v3.7/enterprise/registry-console.yaml index 9f2e6125d..ccea54aaf 100644 --- a/roles/openshift_hosted_templates/files/v3.7/enterprise/registry-console.yaml +++ b/roles/openshift_hosted_templates/files/v3.7/enterprise/registry-console.yaml @@ -102,7 +102,7 @@ objects:  parameters:    - description: 'Specify "registry/repository" prefix for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", set prefix "registry.access.redhat.com/openshift3/"'      name: IMAGE_PREFIX -    value: "openshift3/" +    value: "registry.access.redhat.com/openshift3/"    - description: 'Specify component name for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", use base name "registry-console"'      name: IMAGE_BASENAME      value: "registry-console" diff --git a/roles/openshift_hosted_templates/files/v3.8/enterprise/registry-console.yaml b/roles/openshift_hosted_templates/files/v3.8/enterprise/registry-console.yaml index f04ce06d3..15ad4e9af 100644 --- a/roles/openshift_hosted_templates/files/v3.8/enterprise/registry-console.yaml +++ b/roles/openshift_hosted_templates/files/v3.8/enterprise/registry-console.yaml @@ -102,7 +102,7 @@ objects:  parameters:    - description: 'Specify "registry/repository" prefix for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", set prefix "registry.access.redhat.com/openshift3/"'      name: IMAGE_PREFIX -    value: "openshift3/" +    value: "registry.access.redhat.com/openshift3/"    - description: 'Specify component name for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", use base name "registry-console"'      name: IMAGE_BASENAME      value: "registry-console" diff --git a/roles/openshift_hosted_templates/files/v3.9/enterprise/registry-console.yaml b/roles/openshift_hosted_templates/files/v3.9/enterprise/registry-console.yaml index c178cf432..7acefa0f0 100644 --- a/roles/openshift_hosted_templates/files/v3.9/enterprise/registry-console.yaml +++ b/roles/openshift_hosted_templates/files/v3.9/enterprise/registry-console.yaml @@ -102,7 +102,7 @@ objects:  parameters:    - description: 'Specify "registry/repository" prefix for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", set prefix "registry.access.redhat.com/openshift3/"'      name: IMAGE_PREFIX -    value: "openshift3/" +    value: "registry.access.redhat.com/openshift3/"    - description: 'Specify component name for container image; e.g. for "registry.access.redhat.com/openshift3/registry-console:latest", use base name "registry-console"'      name: IMAGE_BASENAME      value: "registry-console" diff --git a/roles/openshift_loadbalancer/templates/haproxy.cfg.j2 b/roles/openshift_loadbalancer/templates/haproxy.cfg.j2 index de5a8d7c2..823f012af 100644 --- a/roles/openshift_loadbalancer/templates/haproxy.cfg.j2 +++ b/roles/openshift_loadbalancer/templates/haproxy.cfg.j2 @@ -38,7 +38,8 @@ defaults      timeout check           10s      maxconn                 {{ openshift_loadbalancer_default_maxconn | default(20000) }} -listen stats :9000 +listen stats +    bind :9000      mode http      stats enable      stats uri / diff --git a/roles/openshift_logging/tasks/annotate_ops_projects.yaml b/roles/openshift_logging/tasks/annotate_ops_projects.yaml index 4a2ee64f0..6fdba6580 100644 --- a/roles/openshift_logging/tasks/annotate_ops_projects.yaml +++ b/roles/openshift_logging/tasks/annotate_ops_projects.yaml @@ -12,6 +12,7 @@      separator: '#'      content:        metadata#annotations#openshift.io/logging.ui.hostname: "{{ openshift_logging_kibana_ops_hostname }}" +      metadata#annotations#openshift.io/logging.data.prefix: ".operations"    with_items: "{{ __logging_ops_projects.stdout.split(' ') }}"    loop_control:      loop_var: project diff --git a/roles/openshift_logging/tasks/delete_logging.yaml b/roles/openshift_logging/tasks/delete_logging.yaml index fbc3e3fd1..ced7397b5 100644 --- a/roles/openshift_logging/tasks/delete_logging.yaml +++ b/roles/openshift_logging/tasks/delete_logging.yaml @@ -131,13 +131,13 @@    when:      not openshift_logging_install_eventrouter | default(false) | bool -# Update asset config in openshift-web-console namespace -- name: Remove Kibana route information from web console asset config +# Update console config in openshift-web-console namespace +- name: Remove Kibana route information from the web console config    include_role:      name: openshift_web_console -    tasks_from: update_asset_config.yml +    tasks_from: update_console_config.yml    vars: -    asset_config_edits: -      - key: loggingPublicURL +    console_config_edits: +      - key: clusterInfo#loggingPublicURL          value: ""    when: openshift_web_console_install | default(true) | bool diff --git a/roles/openshift_logging/tasks/generate_certs.yaml b/roles/openshift_logging/tasks/generate_certs.yaml index 0d7f8c056..a40449bf6 100644 --- a/roles/openshift_logging/tasks/generate_certs.yaml +++ b/roles/openshift_logging/tasks/generate_certs.yaml @@ -19,7 +19,7 @@    command: >      {{ openshift_client_binary }} adm --config={{ mktemp.stdout }}/admin.kubeconfig ca create-signer-cert      --key={{generated_certs_dir}}/ca.key --cert={{generated_certs_dir}}/ca.crt -    --serial={{generated_certs_dir}}/ca.serial.txt --name=logging-signer-test +    --serial={{generated_certs_dir}}/ca.serial.txt --name=logging-signer-test --overwrite=false    check_mode: no    when:      - not ca_key_file.stat.exists diff --git a/roles/openshift_logging/tasks/install_logging.yaml b/roles/openshift_logging/tasks/install_logging.yaml index ebd2d747b..3afd8680f 100644 --- a/roles/openshift_logging/tasks/install_logging.yaml +++ b/roles/openshift_logging/tasks/install_logging.yaml @@ -87,7 +87,7 @@      openshift_logging_elasticsearch_storage_type: "{{ elasticsearch_storage_type }}"      openshift_logging_elasticsearch_pvc_pv_selector: "{{ openshift_logging_es_pv_selector }}" -    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_pvc_storage_class_name }}" +    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_pvc_storage_class_name | default() }}"      openshift_logging_elasticsearch_nodeselector: "{{ openshift_logging_es_nodeselector if outer_item.0.nodeSelector | default(None) is none else outer_item.0.nodeSelector }}"      openshift_logging_elasticsearch_storage_group: "{{ [openshift_logging_es_storage_group] if outer_item.0.storageGroups | default([]) | length == 0 else outer_item.0.storageGroups }}"      _es_containers: "{{ outer_item.0.containers}}" @@ -114,7 +114,7 @@      openshift_logging_elasticsearch_storage_type: "{{ elasticsearch_storage_type }}"      openshift_logging_elasticsearch_pvc_pv_selector: "{{ openshift_logging_es_pv_selector }}" -    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_pvc_storage_class_name }}" +    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_pvc_storage_class_name | default() }}"    with_sequence: count={{ openshift_logging_es_cluster_size | int - openshift_logging_facts.elasticsearch.deploymentconfigs.keys() | count }}    loop_control: @@ -151,7 +151,7 @@      openshift_logging_elasticsearch_pvc_size: "{{ openshift_logging_es_ops_pvc_size }}"      openshift_logging_elasticsearch_pvc_dynamic: "{{ openshift_logging_es_ops_pvc_dynamic }}"      openshift_logging_elasticsearch_pvc_pv_selector: "{{ openshift_logging_es_ops_pv_selector }}" -    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_ops_pvc_storage_class_name }}" +    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_ops_pvc_storage_class_name | default() }}"      openshift_logging_elasticsearch_memory_limit: "{{ openshift_logging_es_ops_memory_limit }}"      openshift_logging_elasticsearch_cpu_limit: "{{ openshift_logging_es_ops_cpu_limit }}"      openshift_logging_elasticsearch_cpu_request: "{{ openshift_logging_es_ops_cpu_request }}" @@ -193,7 +193,7 @@      openshift_logging_elasticsearch_pvc_size: "{{ openshift_logging_es_ops_pvc_size }}"      openshift_logging_elasticsearch_pvc_dynamic: "{{ openshift_logging_es_ops_pvc_dynamic }}"      openshift_logging_elasticsearch_pvc_pv_selector: "{{ openshift_logging_es_ops_pv_selector }}" -    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_ops_pvc_storage_class_name }}" +    openshift_logging_elasticsearch_pvc_storage_class_name: "{{ openshift_logging_es_ops_pvc_storage_class_name | default() }}"      openshift_logging_elasticsearch_memory_limit: "{{ openshift_logging_es_ops_memory_limit }}"      openshift_logging_elasticsearch_cpu_limit: "{{ openshift_logging_es_ops_cpu_limit }}"      openshift_logging_elasticsearch_cpu_request: "{{ openshift_logging_es_ops_cpu_request }}" @@ -321,9 +321,9 @@  - name: Add Kibana route information to web console asset config    include_role:      name: openshift_web_console -    tasks_from: update_asset_config.yml +    tasks_from: update_console_config.yml    vars: -    asset_config_edits: -    - key: loggingPublicURL +    console_config_edits: +    - key: clusterInfo#loggingPublicURL        value: "https://{{ openshift_logging_kibana_hostname }}"    when: openshift_web_console_install | default(true) | bool diff --git a/roles/openshift_logging/tasks/procure_server_certs.yaml b/roles/openshift_logging/tasks/procure_server_certs.yaml index bc817075d..d28d1d160 100644 --- a/roles/openshift_logging/tasks/procure_server_certs.yaml +++ b/roles/openshift_logging/tasks/procure_server_certs.yaml @@ -30,7 +30,7 @@       {{ openshift_client_binary }} adm --config={{ mktemp.stdout }}/admin.kubeconfig ca create-server-cert       --key={{generated_certs_dir}}/{{cert_info.procure_component}}.key --cert={{generated_certs_dir}}/{{cert_info.procure_component}}.crt       --hostnames={{cert_info.hostnames|quote}} --signer-cert={{generated_certs_dir}}/ca.crt --signer-key={{generated_certs_dir}}/ca.key -     --signer-serial={{generated_certs_dir}}/ca.serial.txt +     --signer-serial={{generated_certs_dir}}/ca.serial.txt --overwrite=false    check_mode: no    when:    - cert_info.hostnames is defined diff --git a/roles/openshift_logging_elasticsearch/tasks/get_es_version.yml b/roles/openshift_logging_elasticsearch/tasks/get_es_version.yml index 9182bddb2..16de6f252 100644 --- a/roles/openshift_logging_elasticsearch/tasks/get_es_version.yml +++ b/roles/openshift_logging_elasticsearch/tasks/get_es_version.yml @@ -1,6 +1,6 @@  ---  - command: > -    oc get pod -l component=es,provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[*].metadata.name} +    oc get pod -l component=es,provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[?(@.status.phase==\"Running\")].metadata.name}    register: _cluster_pods  - name: "Getting ES version for logging-es cluster" @@ -10,7 +10,7 @@    when: _cluster_pods.stdout_lines | count > 0  - command: > -    oc get pod -l component=es-ops,provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[*].metadata.name} +    oc get pod -l component=es-ops,provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[?(@.status.phase==\"Running\")].metadata.name}    register: _ops_cluster_pods  - name: "Getting ES version for logging-es-ops cluster" diff --git a/roles/openshift_logging_elasticsearch/tasks/restart_cluster.yml b/roles/openshift_logging_elasticsearch/tasks/restart_cluster.yml index d55beec86..6bce13d1d 100644 --- a/roles/openshift_logging_elasticsearch/tasks/restart_cluster.yml +++ b/roles/openshift_logging_elasticsearch/tasks/restart_cluster.yml @@ -19,7 +19,7 @@  ## get all pods for the cluster  - command: > -    oc get pod -l component={{ _cluster_component }},provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[*].metadata.name} +    oc get pod -l component={{ _cluster_component }},provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[?(@.status.phase==\"Running\")].metadata.name}    register: _cluster_pods  - name: "Disable shard balancing for logging-{{ _cluster_component }} cluster" @@ -64,7 +64,7 @@  ## we may need a new first pod to run against -- fetch them all again  - command: > -    oc get pod -l component={{ _cluster_component }},provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[*].metadata.name} +    oc get pod -l component={{ _cluster_component }},provider=openshift -n {{ openshift_logging_elasticsearch_namespace }} -o jsonpath={.items[?(@.status.phase==\"Running\")].metadata.name}    register: _cluster_pods  - name: "Enable shard balancing for logging-{{ _cluster_component }} cluster" diff --git a/roles/openshift_management/files/templates/cloudforms/cfme-backup-job.yaml b/roles/openshift_management/files/templates/cloudforms/cfme-backup-job.yaml index c3bc1d20c..48d1d4e26 100644 --- a/roles/openshift_management/files/templates/cloudforms/cfme-backup-job.yaml +++ b/roles/openshift_management/files/templates/cloudforms/cfme-backup-job.yaml @@ -9,7 +9,7 @@ spec:      spec:        containers:        - name: postgresql -        image: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-postgresql:latest +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest          command:          - "/opt/rh/cfme-container-scripts/backup_db"          env: diff --git a/roles/openshift_management/files/templates/cloudforms/cfme-restore-job.yaml b/roles/openshift_management/files/templates/cloudforms/cfme-restore-job.yaml index 8b23f8a33..7fd4fc2e1 100644 --- a/roles/openshift_management/files/templates/cloudforms/cfme-restore-job.yaml +++ b/roles/openshift_management/files/templates/cloudforms/cfme-restore-job.yaml @@ -9,7 +9,7 @@ spec:      spec:        containers:        - name: postgresql -        image: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-postgresql:latest +        image: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql:latest          command:          - "/opt/rh/cfme-container-scripts/restore_db"          env: diff --git a/roles/openshift_management/files/templates/cloudforms/cfme-template-ext-db.yaml b/roles/openshift_management/files/templates/cloudforms/cfme-template-ext-db.yaml index 4a04f3372..9866c29c3 100644 --- a/roles/openshift_management/files/templates/cloudforms/cfme-template-ext-db.yaml +++ b/roles/openshift_management/files/templates/cloudforms/cfme-template-ext-db.yaml @@ -31,6 +31,7 @@ objects:      name: "${NAME}-secrets"    stringData:      pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}"      database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5      v2-key: "${V2_KEY}"  - apiVersion: v1 @@ -90,15 +91,15 @@ objects:          - name: cloudforms            image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}"            livenessProbe: -            tcpSocket: -              port: 80 +            exec: +              command: +              - pidof +              - MIQ Server              initialDelaySeconds: 480              timeoutSeconds: 3            readinessProbe: -            httpGet: -              path: "/" +            tcpSocket:                port: 80 -              scheme: HTTP              initialDelaySeconds: 200              timeoutSeconds: 3            ports: @@ -126,6 +127,11 @@ objects:                secretKeyRef:                  name: "${NAME}-secrets"                  key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password            - name: ANSIBLE_ADMIN_PASSWORD              valueFrom:                secretKeyRef: @@ -433,18 +439,173 @@ objects:        <VirtualHost *:80>          KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} +          ProxyPreserveHost on -        ProxyPass        /ws/ ws://${NAME}/ws/ -        ProxyPassReverse /ws/ ws://${NAME}/ws/ -        ProxyPass        / http://${NAME}/ + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L]          ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common        </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN  - apiVersion: v1    kind: ConfigMap    metadata:      name: "${HTTPD_SERVICE_NAME}-auth-configs"    data:      auth-type: internal +    auth-kerberos-realms: undefined      auth-configuration.conf: |        # External Authentication Configuration File        # @@ -464,6 +625,20 @@ objects:      selector:        name: httpd  - apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1    kind: DeploymentConfig    metadata:      name: "${HTTPD_SERVICE_NAME}" @@ -497,6 +672,9 @@ objects:            image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}"            ports:            - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP            livenessProbe:              exec:                command: @@ -526,6 +704,11 @@ objects:                configMapKeyRef:                  name: "${HTTPD_SERVICE_NAME}-auth-configs"                  key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms            lifecycle:              postStart:                exec: @@ -581,6 +764,11 @@ parameters:    displayName: Application Database Region    description: Database region that will be used for application.    value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm  - name: ANSIBLE_DATABASE_NAME    displayName: Ansible PostgreSQL database name    required: true @@ -678,7 +866,7 @@ parameters:  - name: MEMCACHED_IMG_NAME    displayName: Memcached Image Name    description: This is the Memcached image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-memcached +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached  - name: MEMCACHED_IMG_TAG    displayName: Memcached Image Tag    description: This is the Memcached image tag/version requested to deploy. @@ -686,11 +874,11 @@ parameters:  - name: FRONTEND_APPLICATION_IMG_NAME    displayName: Frontend Application Image Name    description: This is the Frontend Application image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-app-ui +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui  - name: BACKEND_APPLICATION_IMG_NAME    displayName: Backend Application Image Name    description: This is the Backend Application image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-app +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app  - name: FRONTEND_APPLICATION_IMG_TAG    displayName: Front end Application Image Tag    description: This is the CloudForms Frontend Application image tag/version requested to deploy. @@ -702,7 +890,7 @@ parameters:  - name: ANSIBLE_IMG_NAME    displayName: Ansible Image Name    description: This is the Ansible image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-embedded-ansible +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible  - name: ANSIBLE_IMG_TAG    displayName: Ansible Image Tag    description: This is the Ansible image tag/version requested to deploy. @@ -730,10 +918,15 @@ parameters:    displayName: Apache httpd Service Name    description: The name of the OpenShift Service exposed for the httpd container.    value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api  - name: HTTPD_IMG_NAME    displayName: Apache httpd Image Name    description: This is the httpd image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-httpd +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd  - name: HTTPD_IMG_TAG    displayName: Apache httpd Image Tag    description: This is the httpd image tag/version requested to deploy. diff --git a/roles/openshift_management/files/templates/cloudforms/cfme-template.yaml b/roles/openshift_management/files/templates/cloudforms/cfme-template.yaml index d7c9f5af7..5c757b6c2 100644 --- a/roles/openshift_management/files/templates/cloudforms/cfme-template.yaml +++ b/roles/openshift_management/files/templates/cloudforms/cfme-template.yaml @@ -31,6 +31,7 @@ objects:      name: "${NAME}-secrets"    stringData:      pg-password: "${DATABASE_PASSWORD}" +    admin-password: "${APPLICATION_ADMIN_PASSWORD}"      database-url: postgresql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_SERVICE_NAME}/${DATABASE_NAME}?encoding=utf8&pool=5&wait_timeout=5      v2-key: "${V2_KEY}"  - apiVersion: v1 @@ -128,18 +129,173 @@ objects:        <VirtualHost *:80>          KeepAlive on +        # Without ServerName mod_auth_mellon compares against http:// and not https:// from the IdP +        ServerName https://%{REQUEST_HOST} +          ProxyPreserveHost on -        ProxyPass        /ws/ ws://${NAME}/ws/ -        ProxyPassReverse /ws/ ws://${NAME}/ws/ -        ProxyPass        / http://${NAME}/ + +        RewriteCond %{REQUEST_URI}     ^/ws        [NC] +        RewriteCond %{HTTP:UPGRADE}    ^websocket$ [NC] +        RewriteCond %{HTTP:CONNECTION} ^Upgrade$   [NC] +        RewriteRule .* ws://${NAME}%{REQUEST_URI}  [P,QSA,L] + +        # For httpd, some ErrorDocuments must by served by the httpd pod +        RewriteCond %{REQUEST_URI} !^/proxy_pages + +        # For SAML /saml2 is only served by mod_auth_mellon in the httpd pod +        RewriteCond %{REQUEST_URI} !^/saml2 +        RewriteRule ^/ http://${NAME}%{REQUEST_URI} [P,QSA,L]          ProxyPassReverse / http://${NAME}/ + +        # Ensures httpd stdout/stderr are seen by docker logs. +        ErrorLog  "| /usr/bin/tee /proc/1/fd/2 /var/log/httpd/error_log" +        CustomLog "| /usr/bin/tee /proc/1/fd/1 /var/log/httpd/access_log" common        </VirtualHost> +    authentication.conf: | +      # Load appropriate authentication configuration files +      # +      Include "conf.d/configuration-${HTTPD_AUTH_TYPE}-auth" +    configuration-internal-auth: | +      # Internal authentication +      # +    configuration-external-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/http.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-active-directory-auth: | +      Include "conf.d/external-auth-load-modules-conf" + +      <Location /dashboard/kerberos_authenticate> +        AuthType                   Kerberos +        AuthName                   "Kerberos Login" +        KrbMethodNegotiate         On +        KrbMethodK5Passwd          Off +        KrbAuthRealms              ${HTTPD_AUTH_KERBEROS_REALMS} +        Krb5KeyTab                 /etc/krb5.keytab +        KrbServiceName             Any +        Require                    pam-account httpd-auth + +        ErrorDocument 401 /proxy_pages/invalid_sso_credentials.js +      </Location> + +      Include "conf.d/external-auth-login-form-conf" +      Include "conf.d/external-auth-application-api-conf" +      Include "conf.d/external-auth-lookup-user-details-conf" +      Include "conf.d/external-auth-remote-user-conf" +    configuration-saml-auth: | +      LoadModule auth_mellon_module modules/mod_auth_mellon.so + +      <Location /> +        MellonEnable               "info" + +        MellonIdPMetadataFile      "/etc/httpd/saml2/idp-metadata.xml" + +        MellonSPPrivateKeyFile     "/etc/httpd/saml2/sp-key.key" +        MellonSPCertFile           "/etc/httpd/saml2/sp-cert.cert" +        MellonSPMetadataFile       "/etc/httpd/saml2/sp-metadata.xml" + +        MellonVariable             "sp-cookie" +        MellonSecureCookie         On +        MellonCookiePath           "/" + +        MellonIdP                  "IDP" + +        MellonEndpointPath         "/saml2" + +        MellonUser                 username +        MellonMergeEnvVars         On + +        MellonSetEnvNoPrefix       "REMOTE_USER"            username +        MellonSetEnvNoPrefix       "REMOTE_USER_EMAIL"      email +        MellonSetEnvNoPrefix       "REMOTE_USER_FIRSTNAME"  firstname +        MellonSetEnvNoPrefix       "REMOTE_USER_LASTNAME"   lastname +        MellonSetEnvNoPrefix       "REMOTE_USER_FULLNAME"   fullname +        MellonSetEnvNoPrefix       "REMOTE_USER_GROUPS"     groups +      </Location> + +      <Location /saml_login> +        AuthType                   "Mellon" +        MellonEnable               "auth" +        Require                    valid-user +      </Location> + +      Include "conf.d/external-auth-remote-user-conf" +    external-auth-load-modules-conf: | +      LoadModule authnz_pam_module            modules/mod_authnz_pam.so +      LoadModule intercept_form_submit_module modules/mod_intercept_form_submit.so +      LoadModule lookup_identity_module       modules/mod_lookup_identity.so +      LoadModule auth_kerb_module             modules/mod_auth_kerb.so +    external-auth-login-form-conf: | +      <Location /dashboard/external_authenticate> +        InterceptFormPAMService    httpd-auth +        InterceptFormLogin         user_name +        InterceptFormPassword      user_password +        InterceptFormLoginSkip     admin +        InterceptFormClearRemoteUserForSkipped on +      </Location> +    external-auth-application-api-conf: | +      <LocationMatch ^/api> +        SetEnvIf Authorization     '^Basic +YWRtaW46' let_admin_in +        SetEnvIf X-Auth-Token      '^.+$'             let_api_token_in +        SetEnvIf X-MIQ-Token       '^.+$'             let_sys_token_in + +        AuthType                   Basic +        AuthName                   "External Authentication (httpd) for API" +        AuthBasicProvider          PAM + +        AuthPAMService             httpd-auth +        Require                    valid-user +        Order                      Allow,Deny +        Allow from                 env=let_admin_in +        Allow from                 env=let_api_token_in +        Allow from                 env=let_sys_token_in +        Satisfy                    Any +      </LocationMatch> +    external-auth-lookup-user-details-conf: | +      <LocationMatch ^/dashboard/external_authenticate$|^/dashboard/kerberos_authenticate$|^/api> +        LookupUserAttr mail        REMOTE_USER_EMAIL +        LookupUserAttr givenname   REMOTE_USER_FIRSTNAME +        LookupUserAttr sn          REMOTE_USER_LASTNAME +        LookupUserAttr displayname REMOTE_USER_FULLNAME +        LookupUserAttr domainname  REMOTE_USER_DOMAIN + +        LookupUserGroups           REMOTE_USER_GROUPS ":" +        LookupDbusTimeout          5000 +      </LocationMatch> +    external-auth-remote-user-conf: | +      RequestHeader unset X_REMOTE_USER + +      RequestHeader set X_REMOTE_USER           %{REMOTE_USER}e           env=REMOTE_USER +      RequestHeader set X_EXTERNAL_AUTH_ERROR   %{EXTERNAL_AUTH_ERROR}e   env=EXTERNAL_AUTH_ERROR +      RequestHeader set X_REMOTE_USER_EMAIL     %{REMOTE_USER_EMAIL}e     env=REMOTE_USER_EMAIL +      RequestHeader set X_REMOTE_USER_FIRSTNAME %{REMOTE_USER_FIRSTNAME}e env=REMOTE_USER_FIRSTNAME +      RequestHeader set X_REMOTE_USER_LASTNAME  %{REMOTE_USER_LASTNAME}e  env=REMOTE_USER_LASTNAME +      RequestHeader set X_REMOTE_USER_FULLNAME  %{REMOTE_USER_FULLNAME}e  env=REMOTE_USER_FULLNAME +      RequestHeader set X_REMOTE_USER_GROUPS    %{REMOTE_USER_GROUPS}e    env=REMOTE_USER_GROUPS +      RequestHeader set X_REMOTE_USER_DOMAIN    %{REMOTE_USER_DOMAIN}e    env=REMOTE_USER_DOMAIN  - apiVersion: v1    kind: ConfigMap    metadata:      name: "${HTTPD_SERVICE_NAME}-auth-configs"    data:      auth-type: internal +    auth-kerberos-realms: undefined      auth-configuration.conf: |        # External Authentication Configuration File        # @@ -203,15 +359,15 @@ objects:          - name: cloudforms            image: "${FRONTEND_APPLICATION_IMG_NAME}:${FRONTEND_APPLICATION_IMG_TAG}"            livenessProbe: -            tcpSocket: -              port: 80 +            exec: +              command: +              - pidof +              - MIQ Server              initialDelaySeconds: 480              timeoutSeconds: 3            readinessProbe: -            httpGet: -              path: "/" +            tcpSocket:                port: 80 -              scheme: HTTP              initialDelaySeconds: 200              timeoutSeconds: 3            ports: @@ -239,6 +395,11 @@ objects:                secretKeyRef:                  name: "${NAME}-secrets"                  key: v2-key +          - name: APPLICATION_ADMIN_PASSWORD +            valueFrom: +              secretKeyRef: +                name: "${NAME}-secrets" +                key: admin-password            - name: ANSIBLE_ADMIN_PASSWORD              valueFrom:                secretKeyRef: @@ -611,6 +772,20 @@ objects:      selector:        name: httpd  - apiVersion: v1 +  kind: Service +  metadata: +    name: "${HTTPD_DBUS_API_SERVICE_NAME}" +    annotations: +      description: Exposes the httpd server dbus api +      service.alpha.openshift.io/dependencies: '[{"name":"${NAME}","namespace":"","kind":"Service"}]' +  spec: +    ports: +    - name: http-dbus-api +      port: 8080 +      targetPort: 8080 +    selector: +      name: httpd +- apiVersion: v1    kind: DeploymentConfig    metadata:      name: "${HTTPD_SERVICE_NAME}" @@ -644,6 +819,9 @@ objects:            image: "${HTTPD_IMG_NAME}:${HTTPD_IMG_TAG}"            ports:            - containerPort: 80 +            protocol: TCP +          - containerPort: 8080 +            protocol: TCP            livenessProbe:              exec:                command: @@ -673,6 +851,11 @@ objects:                configMapKeyRef:                  name: "${HTTPD_SERVICE_NAME}-auth-configs"                  key: auth-type +          - name: HTTPD_AUTH_KERBEROS_REALMS +            valueFrom: +              configMapKeyRef: +                name: "${HTTPD_SERVICE_NAME}-auth-configs" +                key: auth-kerberos-realms            lifecycle:              postStart:                exec: @@ -718,6 +901,11 @@ parameters:    displayName: Application Database Region    description: Database region that will be used for application.    value: '0' +- name: APPLICATION_ADMIN_PASSWORD +  displayName: Application Admin Password +  required: true +  description: Admin password that will be set on the application. +  value: smartvm  - name: ANSIBLE_DATABASE_NAME    displayName: Ansible PostgreSQL database name    required: true @@ -842,7 +1030,7 @@ parameters:  - name: POSTGRESQL_IMG_NAME    displayName: PostgreSQL Image Name    description: This is the PostgreSQL image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-postgresql +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-postgresql  - name: POSTGRESQL_IMG_TAG    displayName: PostgreSQL Image Tag    description: This is the PostgreSQL image tag/version requested to deploy. @@ -850,7 +1038,7 @@ parameters:  - name: MEMCACHED_IMG_NAME    displayName: Memcached Image Name    description: This is the Memcached image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-memcached +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-memcached  - name: MEMCACHED_IMG_TAG    displayName: Memcached Image Tag    description: This is the Memcached image tag/version requested to deploy. @@ -858,11 +1046,11 @@ parameters:  - name: FRONTEND_APPLICATION_IMG_NAME    displayName: Frontend Application Image Name    description: This is the Frontend Application image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-app-ui +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app-ui  - name: BACKEND_APPLICATION_IMG_NAME    displayName: Backend Application Image Name    description: This is the Backend Application image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-app +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-app  - name: FRONTEND_APPLICATION_IMG_TAG    displayName: Front end Application Image Tag    description: This is the CloudForms Frontend Application image tag/version requested to deploy. @@ -874,7 +1062,7 @@ parameters:  - name: ANSIBLE_IMG_NAME    displayName: Ansible Image Name    description: This is the Ansible image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-embedded-ansible +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-embedded-ansible  - name: ANSIBLE_IMG_TAG    displayName: Ansible Image Tag    description: This is the Ansible image tag/version requested to deploy. @@ -907,10 +1095,15 @@ parameters:    displayName: Apache httpd Service Name    description: The name of the OpenShift Service exposed for the httpd container.    value: httpd +- name: HTTPD_DBUS_API_SERVICE_NAME +  required: true +  displayName: Apache httpd DBus API Service Name +  description: The name of httpd dbus api service. +  value: httpd-dbus-api  - name: HTTPD_IMG_NAME    displayName: Apache httpd Image Name    description: This is the httpd image name requested to deploy. -  value: brew-pulp-docker01.web.prod.ext.phx2.redhat.com:8888/cloudforms46/cfme-openshift-httpd +  value: registry.access.redhat.com/cloudforms46-beta/cfme-openshift-httpd  - name: HTTPD_IMG_TAG    displayName: Apache httpd Image Tag    description: This is the httpd image tag/version requested to deploy. diff --git a/roles/openshift_master/tasks/upgrade/rpm_upgrade.yml b/roles/openshift_master/tasks/upgrade/rpm_upgrade.yml index 7870f43e2..4564f33dd 100644 --- a/roles/openshift_master/tasks/upgrade/rpm_upgrade.yml +++ b/roles/openshift_master/tasks/upgrade/rpm_upgrade.yml @@ -8,8 +8,10 @@  # TODO: If the sdn package isn't already installed this will install it, we  # should fix that -- name: Upgrade master packages -  package: name={{ master_pkgs | join(',') }} state=present +- name: Upgrade master packages - yum +  command: +    yum install -y {{ master_pkgs | join(' ') }} \ +    {{ ' --exclude *' ~ openshift_service_type ~ '*3.9*' if openshift_release | version_compare('3.9','<') else '' }}    vars:      master_pkgs:        - "{{ openshift_service_type }}{{ openshift_pkg_version | default('') }}" @@ -17,6 +19,21 @@        - "{{ openshift_service_type }}-node{{ openshift_pkg_version | default('') }}"        - "{{ openshift_service_type }}-sdn-ovs{{ openshift_pkg_version | default('') }}"        - "{{ openshift_service_type }}-clients{{ openshift_pkg_version | default('') }}" -      - "tuned-profiles-{{ openshift_service_type }}-node{{ openshift_pkg_version | default('') }}"    register: result    until: result is succeeded +  when: ansible_pkg_mgr == 'yum' + +- name: Upgrade master packages - dnf +  dnf: +    name: "{{ master_pkgs | join(',') }}" +    state: present +  vars: +    master_pkgs: +      - "{{ openshift_service_type }}{{ openshift_pkg_version }}" +      - "{{ openshift_service_type }}-master{{ openshift_pkg_version }}" +      - "{{ openshift_service_type }}-node{{ openshift_pkg_version }}" +      - "{{ openshift_service_type }}-sdn-ovs{{ openshift_pkg_version }}" +      - "{{ openshift_service_type }}-clients{{ openshift_pkg_version }}" +  register: result +  until: result is succeeded +  when: ansible_pkg_mgr == 'dnf' diff --git a/roles/openshift_metrics/tasks/install_metrics.yaml b/roles/openshift_metrics/tasks/install_metrics.yaml index 0866fe0d2..0dd5d1621 100644 --- a/roles/openshift_metrics/tasks/install_metrics.yaml +++ b/roles/openshift_metrics/tasks/install_metrics.yaml @@ -74,10 +74,10 @@  - name: Add metrics route information to web console asset config    include_role:      name: openshift_web_console -    tasks_from: update_asset_config.yml +    tasks_from: update_console_config.yml    vars: -    asset_config_edits: -      - key: metricsPublicURL +    console_config_edits: +      - key: clusterInfo#metricsPublicURL          value: "https://{{ openshift_metrics_hawkular_hostname}}/hawkular/metrics"    when: openshift_web_console_install | default(true) | bool diff --git a/roles/openshift_metrics/tasks/oc_apply.yaml b/roles/openshift_metrics/tasks/oc_apply.yaml index 8ccfb7192..30fdde94c 100644 --- a/roles/openshift_metrics/tasks/oc_apply.yaml +++ b/roles/openshift_metrics/tasks/oc_apply.yaml @@ -16,7 +16,7 @@      apply -f {{ file_name }}      -n {{namespace}}    register: generation_apply -  failed_when: "'error' in generation_apply.stderr" +  failed_when: "'error' in generation_apply.stderr or (generation_apply.rc | int != 0)"    changed_when: no  - name: Determine change status of {{file_content.kind}} {{file_content.metadata.name}} @@ -28,5 +28,5 @@    register: version_changed    vars:      init_version: "{{ (generation_init is defined) | ternary(generation_init.stdout, '0') }}" -  failed_when: "'error' in version_changed.stderr" +  failed_when: "'error' in version_changed.stderr or version_changed.rc | int != 0"    changed_when: version_changed.stdout | int  > init_version | int diff --git a/roles/openshift_metrics/tasks/uninstall_metrics.yaml b/roles/openshift_metrics/tasks/uninstall_metrics.yaml index 610c7b4e5..1664e9975 100644 --- a/roles/openshift_metrics/tasks/uninstall_metrics.yaml +++ b/roles/openshift_metrics/tasks/uninstall_metrics.yaml @@ -19,13 +19,13 @@      clusterrolebinding/hawkular-metrics    changed_when: delete_metrics.stdout != 'No resources found' -# Update asset config in openshift-web-console namespace -- name: Remove metrics route information from web console asset config +# Update the web config in openshift-web-console namespace +- name: Remove metrics route information from the web console config    include_role:      name: openshift_web_console -    tasks_from: update_asset_config.yml +    tasks_from: update_console_config.yml    vars: -    asset_config_edits: -      - key: metricsPublicURL +    console_config_edits: +      - key: clusterInfo#metricsPublicURL          value: ""    when: openshift_web_console_install | default(true) | bool diff --git a/roles/openshift_node/defaults/main.yml b/roles/openshift_node/defaults/main.yml index c1fab4382..5864d3c03 100644 --- a/roles/openshift_node/defaults/main.yml +++ b/roles/openshift_node/defaults/main.yml @@ -48,6 +48,12 @@ openshift_node_kubelet_args_dict:      cloud-config:      - "{{ openshift_config_base ~ '/cloudprovider/gce.conf' }}"      node-labels: "{{ l_node_kubelet_node_labels }}" +  azure: +    cloud-provider: +    - azure +    cloud-config: +    - "{{ openshift_config_base ~ '/cloudprovider/azure.conf' }}" +    node-labels: "{{ l_node_kubelet_node_labels }}"    undefined:      node-labels: "{{ l_node_kubelet_node_labels }}" @@ -71,6 +77,18 @@ r_openshift_node_use_firewalld: "{{ os_firewall_use_firewalld | default(False) }  l_is_node_system_container: "{{ (openshift_use_node_system_container | default(openshift_use_system_containers | default(false)) | bool) }}" +openshift_node_syscon_auth_mounts_l: +- type: bind +  source: "{{ oreg_auth_credentials_path }}" +  destination: "/root/.docker" +  options: +  - ro + +# If we need to add new mounts in the future, or the user wants to mount data. +# This should be in the same format as auth_mounts_l above. +openshift_node_syscon_add_mounts_l: [] + +  openshift_deployment_type: "{{ openshift_deployment_type | default('origin') }}"  openshift_node_image_dict: diff --git a/roles/openshift_node/tasks/node_system_container.yml b/roles/openshift_node/tasks/node_system_container.yml index 06b879050..008f209d7 100644 --- a/roles/openshift_node/tasks/node_system_container.yml +++ b/roles/openshift_node/tasks/node_system_container.yml @@ -14,4 +14,23 @@      - "DNS_DOMAIN={{ openshift.common.dns_domain }}"      - "DOCKER_SERVICE={{ openshift_docker_service_name }}.service"      - "MASTER_SERVICE={{ openshift_service_type }}.service" +    - 'ADDTL_MOUNTS={{ l_node_syscon_add_mounts2 }}'      state: latest +  vars: +    # We need to evaluate some variables here to ensure +    # l_bind_docker_reg_auth is evaluated after registry_auth.yml has been +    # processed. + +    # Determine if we want to include auth credentials mount. +    l_node_syscon_auth_mounts_l: "{{ l_bind_docker_reg_auth | ternary(openshift_node_syscon_auth_mounts_l,[]) }}" + +    # Join any user-provided mounts and auth_mounts into a combined list. +    l_node_syscon_add_mounts_l: "{{ openshift_node_syscon_add_mounts_l | union(l_node_syscon_auth_mounts_l) }}" + +    # We must prepend a ',' here to ensure the value is inserted properly into an +    # existing json list in the container's config.json +    # lib_utils_oo_l_of_d_to_csv is a custom filter plugin in roles/lib_utils/oo_filters.py +    l_node_syscon_add_mounts: ",{{ l_node_syscon_add_mounts_l | lib_utils_oo_l_of_d_to_csv }}" +    # if we have just a ',' then both mount lists were empty, we don't want to add +    # anything to config.json +    l_node_syscon_add_mounts2: "{{ (l_node_syscon_add_mounts != ',') | bool | ternary(l_node_syscon_add_mounts,'') }}" diff --git a/roles/openshift_node/tasks/upgrade/config_changes.yml b/roles/openshift_node/tasks/upgrade/config_changes.yml index 721656117..dd9183382 100644 --- a/roles/openshift_node/tasks/upgrade/config_changes.yml +++ b/roles/openshift_node/tasks/upgrade/config_changes.yml @@ -21,6 +21,12 @@      path: "/var/lib/dockershim/sandbox/"      state: absent +# https://bugzilla.redhat.com/show_bug.cgi?id=1518912 +- name: Clean up IPAM data +  file: +    path: "/var/lib/cni/networks/openshift-sdn/" +    state: absent +  # Disable Swap Block (pre)  - block:    - name: Remove swap entries from /etc/fstab diff --git a/roles/openshift_node/templates/node.yaml.v1.j2 b/roles/openshift_node/templates/node.yaml.v1.j2 index 5f2a94ea2..7d817463c 100644 --- a/roles/openshift_node/templates/node.yaml.v1.j2 +++ b/roles/openshift_node/templates/node.yaml.v1.j2 @@ -32,7 +32,7 @@ masterClientConnectionOverrides:    contentType: application/vnd.kubernetes.protobuf    burst: 200    qps: 100 -masterKubeConfig: system:node:{{ openshift.common.hostname }}.kubeconfig +masterKubeConfig: system:node:{{ openshift.common.hostname | lower }}.kubeconfig  {% if openshift_node_use_openshift_sdn | bool %}  networkPluginName: {{ openshift_node_sdn_network_plugin_name }}  {% endif %} diff --git a/roles/openshift_node_certificates/tasks/main.yml b/roles/openshift_node_certificates/tasks/main.yml index 5f73f3bdc..13d9fd718 100644 --- a/roles/openshift_node_certificates/tasks/main.yml +++ b/roles/openshift_node_certificates/tasks/main.yml @@ -18,9 +18,9 @@    stat:      path: "{{ openshift.common.config_base }}/node/{{ item }}"    with_items: -  - "system:node:{{ openshift.common.hostname }}.crt" -  - "system:node:{{ openshift.common.hostname }}.key" -  - "system:node:{{ openshift.common.hostname }}.kubeconfig" +  - "system:node:{{ openshift.common.hostname | lower }}.crt" +  - "system:node:{{ openshift.common.hostname | lower }}.key" +  - "system:node:{{ openshift.common.hostname | lower }}.kubeconfig"    - ca.crt    - server.key    - server.crt @@ -59,16 +59,16 @@      --certificate-authority {{ legacy_ca_certificate }}      {% endfor %}      --certificate-authority={{ openshift_ca_cert }} -    --client-dir={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname }} +    --client-dir={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname | lower }}      --groups=system:nodes      --master={{ hostvars[openshift_ca_host].openshift.master.api_url }}      --signer-cert={{ openshift_ca_cert }}      --signer-key={{ openshift_ca_key }}      --signer-serial={{ openshift_ca_serial }} -    --user=system:node:{{ hostvars[item].openshift.common.hostname }} +    --user=system:node:{{ hostvars[item].openshift.common.hostname | lower }}      --expire-days={{ openshift_node_cert_expire_days }}    args: -    creates: "{{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname }}" +    creates: "{{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname | lower }}"    with_items: "{{ hostvars                    | lib_utils_oo_select_keys(groups['oo_nodes_to_config'])                    | lib_utils_oo_collect(attribute='inventory_hostname', filters={'node_certs_missing':True}) }}" @@ -78,16 +78,16 @@  - name: Generate the node server certificate    command: >      {{ hostvars[openshift_ca_host]['first_master_client_binary'] }} adm ca create-server-cert -    --cert={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname }}/server.crt -    --key={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname }}/server.key +    --cert={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname | lower }}/server.crt +    --key={{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname | lower }}/server.key      --expire-days={{ openshift_node_cert_expire_days }}      --overwrite=true -    --hostnames={{ hostvars[item].openshift.common.hostname }},{{ hostvars[item].openshift.common.public_hostname }},{{ hostvars[item].openshift.common.ip }},{{ hostvars[item].openshift.common.public_ip }} +    --hostnames={{ hostvars[item].openshift.common.hostname }},{{ hostvars[item].openshift.common.hostname | lower }},{{ hostvars[item].openshift.common.public_hostname }},{{ hostvars[item].openshift.common.public_hostname | lower }},{{ hostvars[item].openshift.common.ip }},{{ hostvars[item].openshift.common.public_ip }}      --signer-cert={{ openshift_ca_cert }}      --signer-key={{ openshift_ca_key }}      --signer-serial={{ openshift_ca_serial }}    args: -    creates: "{{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname }}/server.crt" +    creates: "{{ openshift_generated_configs_dir }}/node-{{ hostvars[item].openshift.common.hostname | lower }}/server.crt"    with_items: "{{ hostvars                    | lib_utils_oo_select_keys(groups['oo_nodes_to_config'])                    | lib_utils_oo_collect(attribute='inventory_hostname', filters={'node_certs_missing':True}) }}" diff --git a/roles/openshift_node_certificates/vars/main.yml b/roles/openshift_node_certificates/vars/main.yml index 17ad8106d..12a6d3f94 100644 --- a/roles/openshift_node_certificates/vars/main.yml +++ b/roles/openshift_node_certificates/vars/main.yml @@ -1,7 +1,7 @@  ---  openshift_generated_configs_dir: "{{ openshift.common.config_base }}/generated-configs"  openshift_node_cert_dir: "{{ openshift.common.config_base }}/node" -openshift_node_cert_subdir: "node-{{ openshift.common.hostname }}" +openshift_node_cert_subdir: "node-{{ openshift.common.hostname | lower }}"  openshift_node_config_dir: "{{ openshift.common.config_base }}/node"  openshift_node_generated_config_dir: "{{ openshift_generated_configs_dir }}/{{ openshift_node_cert_subdir }}" diff --git a/roles/openshift_openstack/templates/heat_stack.yaml.j2 b/roles/openshift_openstack/templates/heat_stack.yaml.j2 index 1be5d3a62..8e7c6288a 100644 --- a/roles/openshift_openstack/templates/heat_stack.yaml.j2 +++ b/roles/openshift_openstack/templates/heat_stack.yaml.j2 @@ -523,7 +523,7 @@ resources:            floating_network:              if:                - no_floating -              - null +              - ''                - {{ openshift_openstack_external_network_name }}  {% if openshift_openstack_provider_network_name %}            attach_float_net: false @@ -589,8 +589,13 @@ resources:            secgrp:              - { get_resource: lb-secgrp }              - { get_resource: common-secgrp } -{% if not openshift_openstack_provider_network_name %} -          floating_network: {{ openshift_openstack_external_network_name }} +          floating_network: +            if: +              - no_floating +              - '' +              - {{ openshift_openstack_external_network_name }} +{% if openshift_openstack_provider_network_name %} +          attach_float_net: false  {% endif %}            volume_size: {{ openshift_openstack_lb_volume_size }}  {% if not openshift_openstack_provider_network_name %} @@ -655,7 +660,7 @@ resources:            floating_network:              if:                - no_floating -              - null +              - ''                - {{ openshift_openstack_external_network_name }}  {% if openshift_openstack_provider_network_name %}            attach_float_net: false @@ -725,7 +730,7 @@ resources:            floating_network:              if:                - no_floating -              - null +              - ''                - {{ openshift_openstack_external_network_name }}  {% if openshift_openstack_provider_network_name %}            attach_float_net: false @@ -792,8 +797,13 @@ resources:  {% endif %}              - { get_resource: infra-secgrp }              - { get_resource: common-secgrp } -{% if not openshift_openstack_provider_network_name %} -          floating_network: {{ openshift_openstack_external_network_name }} +          floating_network: +            if: +              - no_floating +              - '' +              - {{ openshift_openstack_external_network_name }} +{% if openshift_openstack_provider_network_name %} +          attach_float_net: false  {% endif %}            volume_size: {{ openshift_openstack_infra_volume_size }}  {% if openshift_openstack_infra_server_group_policies|length > 0 %} diff --git a/roles/openshift_openstack/templates/heat_stack_server.yaml.j2 b/roles/openshift_openstack/templates/heat_stack_server.yaml.j2 index 1e73c9e1c..29b09f3c9 100644 --- a/roles/openshift_openstack/templates/heat_stack_server.yaml.j2 +++ b/roles/openshift_openstack/templates/heat_stack_server.yaml.j2 @@ -102,13 +102,11 @@ parameters:      label: Attach-float-net      description: A switch for floating network port connection -{% if not openshift_openstack_provider_network_name %}    floating_network:      type: string      default: ''      label: Floating network      description: Network to allocate floating IP from -{% endif %}    availability_zone:      type: string diff --git a/roles/openshift_persistent_volumes/tasks/pv.yml b/roles/openshift_persistent_volumes/tasks/pv.yml index ef9ab7f5f..865269b7a 100644 --- a/roles/openshift_persistent_volumes/tasks/pv.yml +++ b/roles/openshift_persistent_volumes/tasks/pv.yml @@ -13,5 +13,5 @@      --config={{ mktemp.stdout }}/admin.kubeconfig    register: pv_create_output    when: persistent_volumes | length > 0 -  failed_when: ('already exists' not in pv_create_output.stderr) and ('created' not in pv_create_output.stdout) +  failed_when: "('already exists' not in pv_create_output.stderr) and ('created' not in pv_create_output.stdout) and pv_create_output.rc != 0"    changed_when: ('created' in pv_create_output.stdout) diff --git a/roles/openshift_persistent_volumes/tasks/pvc.yml b/roles/openshift_persistent_volumes/tasks/pvc.yml index 2c5519192..6c12d128c 100644 --- a/roles/openshift_persistent_volumes/tasks/pvc.yml +++ b/roles/openshift_persistent_volumes/tasks/pvc.yml @@ -13,5 +13,5 @@      --config={{ mktemp.stdout }}/admin.kubeconfig    register: pvc_create_output    when: persistent_volume_claims | length > 0 -  failed_when: ('already exists' not in pvc_create_output.stderr) and ('created' not in pvc_create_output.stdout) +  failed_when: "('already exists' not in pvc_create_output.stderr) and ('created' not in pvc_create_output.stdout) and pvc_create_output.rc != 0"    changed_when: ('created' in pvc_create_output.stdout) diff --git a/roles/openshift_provisioners/tasks/oc_apply.yaml b/roles/openshift_provisioners/tasks/oc_apply.yaml index a4ce53eae..27c8a4b81 100644 --- a/roles/openshift_provisioners/tasks/oc_apply.yaml +++ b/roles/openshift_provisioners/tasks/oc_apply.yaml @@ -15,7 +15,7 @@      apply -f {{ file_name }}      -n {{ namespace }}    register: generation_apply -  failed_when: "'error' in generation_apply.stderr" +  failed_when: "'error' in generation_apply.stderr or generation_apply.rc != 0"    changed_when: no  - name: Determine change status of {{file_content.kind}} {{file_content.metadata.name}} @@ -36,7 +36,7 @@      delete -f {{ file_name }}      -n {{ namespace }}    register: generation_delete -  failed_when: "'error' in generation_delete.stderr" +  failed_when: "'error' in generation_delete.stderr or generation_delete.rc != 0"    changed_when: generation_delete.rc == 0    when: generation_apply.rc != 0 @@ -46,6 +46,6 @@      apply -f {{ file_name }}      -n {{ namespace }}    register: generation_apply -  failed_when: "'error' in generation_apply.stderr" +  failed_when: "'error' in generation_apply.stderr or generation_apply.rc | int != 0"    changed_when: generation_apply.rc == 0    when: generation_apply.rc != 0 diff --git a/roles/openshift_service_catalog/defaults/main.yml b/roles/openshift_service_catalog/defaults/main.yml index 7c848cb12..15ca9838c 100644 --- a/roles/openshift_service_catalog/defaults/main.yml +++ b/roles/openshift_service_catalog/defaults/main.yml @@ -1,6 +1,7 @@  ---  openshift_service_catalog_remove: false  openshift_service_catalog_nodeselector: {"openshift-infra": "apiserver"} +openshift_service_catalog_async_bindings_enabled: false  openshift_use_openshift_sdn: True  # os_sdn_network_plugin_name: "{% if openshift_use_openshift_sdn %}redhat/openshift-ovs-subnet{% else %}{% endif %}" diff --git a/roles/openshift_service_catalog/templates/controller_manager.j2 b/roles/openshift_service_catalog/templates/controller_manager.j2 index 137222f04..c61e05f73 100644 --- a/roles/openshift_service_catalog/templates/controller_manager.j2 +++ b/roles/openshift_service_catalog/templates/controller_manager.j2 @@ -8,7 +8,7 @@ spec:    selector:      matchLabels:        app: controller-manager -  strategy: +  updateStrategy:      rollingUpdate:        maxUnavailable: 1      type: RollingUpdate @@ -38,6 +38,10 @@ spec:          - "5m"          - --feature-gates          - OriginatingIdentity=true +{% if openshift_service_catalog_async_bindings_enabled | bool %} +        - --feature-gates +        - AsyncBindingOperations=true +{% endif %}          image: {{ openshift_service_catalog_image_prefix }}service-catalog:{{ openshift_service_catalog_image_version }}          command: ["/usr/bin/service-catalog"]          imagePullPolicy: Always diff --git a/roles/openshift_version/tasks/check_available_rpms.yml b/roles/openshift_version/tasks/check_available_rpms.yml index bdbc63d27..fea0daf77 100644 --- a/roles/openshift_version/tasks/check_available_rpms.yml +++ b/roles/openshift_version/tasks/check_available_rpms.yml @@ -1,7 +1,7 @@  ---  - name: Get available {{ openshift_service_type}} version    repoquery: -    name: "{{ openshift_service_type}}" +    name: "{{ openshift_service_type}}{{ '-' ~ openshift_release ~ '*' if openshift_release is defined else '' }}"      ignore_excluders: true    register: rpm_results diff --git a/roles/openshift_version/tasks/first_master_containerized_version.yml b/roles/openshift_version/tasks/first_master_containerized_version.yml index e02a75eab..3ed1d2cfe 100644 --- a/roles/openshift_version/tasks/first_master_containerized_version.yml +++ b/roles/openshift_version/tasks/first_master_containerized_version.yml @@ -7,6 +7,7 @@    when:    - openshift_image_tag is defined    - openshift_version is not defined +  - not (openshift_version_reinit | default(false))  - name: Set containerized version to configure if openshift_release specified    set_fact: @@ -20,7 +21,7 @@      docker run --rm {{ openshift_cli_image }}:latest version    register: cli_image_version    when: -  - openshift_version is not defined +  - openshift_version is not defined or openshift_version_reinit | default(false)    - not openshift_use_crio_only  # Origin latest = pre-release version (i.e. v1.3.0-alpha.1-321-gb095e3a) @@ -34,7 +35,7 @@  - set_fact:      openshift_version: "{{ cli_image_version.stdout_lines[0].split(' ')[1].split('-')[0][1:] }}" -  when: openshift_version is not defined +  when: openshift_version is not defined or openshift_version_reinit | default(false)  # If we got an openshift_version like "3.2", lookup the latest 3.2 container version  # and use that value instead. diff --git a/roles/openshift_version/tasks/first_master_rpm_version.yml b/roles/openshift_version/tasks/first_master_rpm_version.yml index 264baca65..5d92f90c6 100644 --- a/roles/openshift_version/tasks/first_master_rpm_version.yml +++ b/roles/openshift_version/tasks/first_master_rpm_version.yml @@ -6,6 +6,7 @@    when:    - openshift_pkg_version is defined    - openshift_version is not defined +  - not (openshift_version_reinit | default(false))  # These tasks should only be run against masters and nodes  - name: Set openshift_version for rpm installation @@ -13,4 +14,7 @@  - set_fact:      openshift_version: "{{ rpm_results.results.versions.available_versions.0 }}" -  when: openshift_version is not defined +  when: openshift_version is not defined or ( openshift_version_reinit | default(false) ) +- set_fact: +    openshift_pkg_version: "-{{ rpm_results.results.versions.available_versions.0 }}" +  when: openshift_version_reinit | default(false) diff --git a/roles/openshift_version/tasks/masters_and_nodes.yml b/roles/openshift_version/tasks/masters_and_nodes.yml index fbeb22d8b..eddd5ff42 100644 --- a/roles/openshift_version/tasks/masters_and_nodes.yml +++ b/roles/openshift_version/tasks/masters_and_nodes.yml @@ -6,9 +6,12 @@      include_tasks: check_available_rpms.yml    - name: Fail if rpm version and docker image version are different      fail: -      msg: "OCP rpm version {{ openshift_rpm_version }} is different from OCP image version {{ openshift_version }}" +      msg: "OCP rpm version {{ rpm_results.results.versions.available_versions.0 }} is different from OCP image version {{ openshift_version }}"      # Both versions have the same string representation -    when: rpm_results.results.versions.available_versions.0 != openshift_version +    when: +    - openshift_version not in rpm_results.results.versions.available_versions.0 +    - openshift_version_reinit | default(false) +    # block when    when: not openshift_is_atomic | bool diff --git a/roles/openshift_web_console/defaults/main.yml b/roles/openshift_web_console/defaults/main.yml index 4f395398c..c747f73a8 100644 --- a/roles/openshift_web_console/defaults/main.yml +++ b/roles/openshift_web_console/defaults/main.yml @@ -1,3 +1,2 @@  --- -# TODO: This is temporary and will be updated to use taints and tolerations so that the console runs on the masters -openshift_web_console_nodeselector: {"region":"infra"} +openshift_web_console_nodeselector: "{{ openshift_hosted_infra_selector | default('region=infra') | map_from_pairs }}" diff --git a/roles/openshift_web_console/tasks/install.yml b/roles/openshift_web_console/tasks/install.yml index 12916961b..cc5eef47d 100644 --- a/roles/openshift_web_console/tasks/install.yml +++ b/roles/openshift_web_console/tasks/install.yml @@ -21,43 +21,123 @@      node_selector:        - "" -- name: Make temp directory for asset config files +- name: Make temp directory for web console templates    command: mktemp -d /tmp/console-ansible-XXXXXX    register: mktemp    changed_when: False -- name: Copy asset config template to temp directory +- name: Copy admin client config +  command: > +    cp {{ openshift.common.config_base }}/master//admin.kubeconfig {{ mktemp.stdout }}/admin.kubeconfig +  changed_when: false + +- name: Copy web console templates to temp directory    copy:      src: "{{ __console_files_location }}/{{ item }}"      dest: "{{ mktemp.stdout }}/{{ item }}"    with_items:      - "{{ __console_template_file }}" +    - "{{ __console_rbac_file }}"      - "{{ __console_config_file }}" -- name: Update asset config properties -  yedit: -    src: "{{ mktemp.stdout }}/{{ __console_config_file }}" -    edits: -      - key: logoutURL -        value: "{{ openshift.master.logout_url | default('') }}" -      - key: publicURL -        # Must have a trailing slash -        value: "{{ openshift.master.public_console_url }}/" -      - key: masterPublicURL -        value: "{{ openshift.master.public_api_url }}" +# Check if an existing webconsole-config config map exists. If so, use those +# contents so we don't overwrite changes. +- name: Read the existing web console config map +  oc_configmap: +    namespace: openshift-web-console +    name: webconsole-config +    state: list +  register: webconsole_config_map + +- set_fact: +    existing_config_map_data: "{{ webconsole_config_map.results.results[0].data | default({}) }}" + +- name: Copy the existing web console config to temp directory +  copy: +    content: "{{ existing_config_map_data['webconsole-config.yaml'] }}" +    dest: "{{ mktemp.stdout }}/{{ __console_config_file }}" +  when: existing_config_map_data['webconsole-config.yaml'] is defined + +# Generate a new config when a config map is not defined. +- when: existing_config_map_data['webconsole-config.yaml'] is not defined +  block: +    # Migrate the previous master-config.yaml asset config if it exists into the new +    # web console config config map. +    - name: Read existing assetConfig in master-config.yaml +      slurp: +        src: "{{ openshift.common.config_base }}/master/master-config.yaml" +      register: master_config_output + +    - set_fact: +        config_to_migrate: "{{ master_config_output.content | b64decode | from_yaml }}" + +    # Update properties in the config template based on inventory vars when the +    # asset config does not exist. +    - name: Set web console config properties from inventory variables +      yedit: +        src: "{{ mktemp.stdout }}/{{ __console_config_file }}" +        edits: +          - key: clusterInfo#consolePublicURL +            # Must have a trailing slash +            value: "{{ openshift.master.public_console_url }}/" +          - key: clusterInfo#masterPublicURL +            value: "{{ openshift.master.public_api_url }}" +          - key: clusterInfo#logoutPublicURL +            value: "{{ openshift.master.logout_url | default('') }}" +          - key: features#inactivityTimeoutMinutes +            value: "{{ openshift_web_console_inactivity_timeout_minutes | default(0) }}" +          - key: features#clusterResourceOverridesEnabled +            value: "{{ openshift_web_console_cluster_resource_overrides_enabled | default(false) }}" +          - key: extensions#scriptURLs +            value: "{{ openshift_web_console_extension_script_urls | default([]) }}" +          - key: extensions#stylesheetURLs +            value: "{{ openshift_web_console_extension_stylesheet_urls | default([]) }}" +          - key: extensions#properties +            value: "{{ openshift_web_console_extension_properties | default({}) }}" +        separator: '#' +        state: present +      when: config_to_migrate.assetConfig is not defined + +    - name: Migrate assetConfig from master-config.yaml +      yedit: +        src: "{{ mktemp.stdout }}/{{ __console_config_file }}" +        edits: +          - key: clusterInfo#consolePublicURL +            value: "{{ config_to_migrate.assetConfig.publicURL }}" +          - key: clusterInfo#masterPublicURL +            value: "{{ config_to_migrate.assetConfig.masterPublicURL }}" +          - key: clusterInfo#logoutPublicURL +            value: "{{ config_to_migrate.assetConfig.logoutURL | default('') }}" +          - key: clusterInfo#metricsPublicURL +            value: "{{ config_to_migrate.assetConfig.metricsPublicURL | default('') }}" +          - key: clusterInfo#loggingPublicURL +            value: "{{ config_to_migrate.assetConfig.loggingPublicURL | default('') }}" +          - key: servingInfo#maxRequestsInFlight +            value: "{{ config_to_migrate.assetConfig.servingInfo.maxRequestsInFlight | default(0) }}" +          - key: servingInfo#requestTimeoutSeconds +            value: "{{ config_to_migrate.assetConfig.servingInfo.requestTimeoutSeconds | default(0) }}" +        separator: '#' +        state: present +      when: config_to_migrate.assetConfig is defined  - slurp:      src: "{{ mktemp.stdout }}/{{ __console_config_file }}" -  register: config +  register: updated_console_config + +- name: Reconcile with the web console RBAC file +  shell: > +    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __console_rbac_file }}" --config={{ mktemp.stdout }}/admin.kubeconfig +    | {{ openshift_client_binary }} auth reconcile --config={{ mktemp.stdout }}/admin.kubeconfig -f - -- name: Apply template file +- name: Apply the web console template file    shell: >      {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __console_template_file }}" -    --param API_SERVER_CONFIG="{{ config['content'] | b64decode }}" +    --param API_SERVER_CONFIG="{{ updated_console_config['content'] | b64decode }}"      --param IMAGE="{{ openshift_web_console_prefix }}{{ openshift_web_console_image_name }}:{{ openshift_web_console_version }}"      --param NODE_SELECTOR={{ openshift_web_console_nodeselector | to_json | quote }}      --param REPLICA_COUNT="{{ openshift_web_console_replica_count }}" -    | {{ openshift_client_binary }} apply -f - +    --config={{ mktemp.stdout }}/admin.kubeconfig +    | {{ openshift_client_binary }} apply --config={{ mktemp.stdout }}/admin.kubeconfig -f -  - name: Verify that the web console is running    command: > diff --git a/roles/openshift_web_console/tasks/rollout_console.yml b/roles/openshift_web_console/tasks/rollout_console.yml new file mode 100644 index 000000000..75682ba1d --- /dev/null +++ b/roles/openshift_web_console/tasks/rollout_console.yml @@ -0,0 +1,20 @@ +--- +- name: Check if console deployment exists +  oc_obj: +    kind: deployments +    name: webconsole +    namespace: openshift-web-console +    state: list +  register: console_deployment + +# There's currently no command to trigger a rollout for a k8s deployment +# without changing the pod spec. Add an annotation to force a rollout. +- name: Rollout updated web console deployment +  oc_edit: +    kind: deployments +    name: webconsole +    namespace: openshift-web-console +    separator: '#' +    content: +      spec#template#metadata#annotations#installer-triggered-rollout: "{{ ansible_date_time.iso8601_micro }}" +  when: console_deployment.results.results.0 | length > 0 diff --git a/roles/openshift_web_console/tasks/update_asset_config.yml b/roles/openshift_web_console/tasks/update_asset_config.yml deleted file mode 100644 index 0992b32e1..000000000 --- a/roles/openshift_web_console/tasks/update_asset_config.yml +++ /dev/null @@ -1,68 +0,0 @@ ---- -# This task updates asset config values in the webconsole-config config map in -# the openshift-web-console namespace. The values to set are pased in the -# variable `asset_config_edits`, which is an array of objects with `key` and -# `value` properties in the same format as `yedit` module `edits`. Only -# properties passed are updated. -# -# Note that this triggers a redeployment on the console and a brief downtime -# since it uses a `Recreate` strategy. -# -# Example usage: -# -# - include_role: -#     name: openshift_web_console -#     tasks_from: update_asset_config.yml -#   vars: -#     asset_config_edits: -#       - key: loggingPublicURL -#         value: "https://{{ openshift_logging_kibana_hostname }}" -#   when: openshift_web_console_install | default(true) | bool - -- name: Read web console config map -  oc_configmap: -    namespace: openshift-web-console -    name: webconsole-config -    state: list -  register: webconsole_config - -- name: Make temp directory -  command: mktemp -d /tmp/console-ansible-XXXXXX -  register: mktemp -  changed_when: False - -- name: Copy asset config to temp file -  copy: -    content: "{{webconsole_config.results.results[0].data['webconsole-config.yaml']}}" -    dest: "{{ mktemp.stdout }}/webconsole-config.yaml" - -- name: Change asset config properties -  yedit: -    src: "{{ mktemp.stdout }}/webconsole-config.yaml" -    edits: "{{asset_config_edits}}" - -- name: Update web console config map -  oc_configmap: -    namespace: openshift-web-console -    name: webconsole-config -    state: present -    from_file: -      webconsole-config.yaml: "{{ mktemp.stdout }}/webconsole-config.yaml" - -- name: Remove temp directory -  file: -    state: absent -    name: "{{ mktemp.stdout }}" -  changed_when: False - -# There's currently no command to trigger a rollout for a k8s deployment -# without changing the pod spec. Add an annotation to force a rollout after -# the config map has been edited. -- name: Rollout updated web console deployment -  oc_edit: -    kind: deployments -    name: webconsole -    namespace: openshift-web-console -    separator: '#' -    content: -      spec#template#metadata#annotations#installer-triggered-rollout: "{{ ansible_date_time.iso8601_micro }}" diff --git a/roles/openshift_web_console/tasks/update_console_config.yml b/roles/openshift_web_console/tasks/update_console_config.yml new file mode 100644 index 000000000..967222ea4 --- /dev/null +++ b/roles/openshift_web_console/tasks/update_console_config.yml @@ -0,0 +1,67 @@ +--- +# This task updates asset config values in the webconsole-config config map in +# the openshift-web-console namespace. The values to set are pased in the +# variable `console_config_edits`, which is an array of objects with `key` and +# `value` properties in the same format as `yedit` module `edits`. Only +# properties passed are updated. The separator for nested properties is `#`. +# +# Note that this triggers a redeployment on the console and a brief downtime +# since it uses a `Recreate` strategy. +# +# Example usage: +# +# - include_role: +#     name: openshift_web_console +#     tasks_from: update_console_config.yml +#   vars: +#     console_config_edits: +#       - key: clusterInfo#loggingPublicURL +#         value: "https://{{ openshift_logging_kibana_hostname }}" +#   when: openshift_web_console_install | default(true) | bool + +- name: Read the existing web console config map +  oc_configmap: +    namespace: openshift-web-console +    name: webconsole-config +    state: list +  register: webconsole_config_map + +- set_fact: +    existing_config_map_data: "{{ webconsole_config_map.results.results[0].data | default({}) }}" + +- when: existing_config_map_data['webconsole-config.yaml'] is defined +  block: +  - name: Make temp directory +    command: mktemp -d /tmp/console-ansible-XXXXXX +    register: mktemp_console +    changed_when: False + +  - name: Copy the existing web console config to temp directory +    copy: +      content: "{{ existing_config_map_data['webconsole-config.yaml'] }}" +      dest: "{{ mktemp_console.stdout }}/webconsole-config.yaml" + +  - name: Change web console config properties +    yedit: +      src: "{{ mktemp_console.stdout }}/webconsole-config.yaml" +      edits: "{{console_config_edits}}" +      separator: '#' +      state: present + +  - name: Update web console config map +    oc_configmap: +      namespace: openshift-web-console +      name: webconsole-config +      state: present +      from_file: +        webconsole-config.yaml: "{{ mktemp_console.stdout }}/webconsole-config.yaml" +    register: update_console_config_map + +  - name: Remove temp directory +    file: +      state: absent +      name: "{{ mktemp_console.stdout }}" +    changed_when: False + +  - include_tasks: rollout_console.yml +    when: update_console_config_map.changed | bool diff --git a/roles/openshift_web_console/vars/default_images.yml b/roles/openshift_web_console/vars/default_images.yml index 7adb8a0d0..42d331ac5 100644 --- a/roles/openshift_web_console/vars/default_images.yml +++ b/roles/openshift_web_console/vars/default_images.yml @@ -1,4 +1,4 @@  --- -__openshift_web_console_prefix: "docker.io/openshift/" +__openshift_web_console_prefix: "docker.io/openshift/origin-"  __openshift_web_console_version: "latest" -__openshift_web_console_image_name: "origin-web-console" +__openshift_web_console_image_name: "web-console" diff --git a/roles/openshift_web_console/vars/main.yml b/roles/openshift_web_console/vars/main.yml index 80bc56a17..e91048e38 100644 --- a/roles/openshift_web_console/vars/main.yml +++ b/roles/openshift_web_console/vars/main.yml @@ -2,4 +2,5 @@  __console_files_location: "../../../files/origin-components/"  __console_template_file: "console-template.yaml" +__console_rbac_file: "console-rbac-template.yaml"  __console_config_file: "console-config.yaml" diff --git a/roles/openshift_web_console/vars/openshift-enterprise.yml b/roles/openshift_web_console/vars/openshift-enterprise.yml index 721ac1d27..375c22067 100644 --- a/roles/openshift_web_console/vars/openshift-enterprise.yml +++ b/roles/openshift_web_console/vars/openshift-enterprise.yml @@ -1,4 +1,4 @@  --- -__openshift_web_console_prefix: "registry.access.redhat.com/openshift3/" +__openshift_web_console_prefix: "registry.access.redhat.com/openshift3/ose-"  __openshift_web_console_version: "v3.9" -__openshift_web_console_image_name: "ose-web-console" +__openshift_web_console_image_name: "web-console" diff --git a/roles/os_firewall/tasks/firewalld.yml b/roles/os_firewall/tasks/firewalld.yml index 4eae31596..fa933da51 100644 --- a/roles/os_firewall/tasks/firewalld.yml +++ b/roles/os_firewall/tasks/firewalld.yml @@ -2,7 +2,9 @@  - name: Fail - Firewalld is not supported on Atomic Host    fail:      msg: "Firewalld is not supported on Atomic Host" -  when: r_os_firewall_is_atomic | bool +  when: +    - r_os_firewall_is_atomic | bool +    - not openshift_enable_unsupported_configurations | default(false)  - name: Install firewalld packages    package: @@ -10,6 +12,7 @@      state: present    register: result    until: result is succeeded +  when: not r_os_firewall_is_atomic | bool  - name: Ensure iptables services are not enabled    systemd: diff --git a/roles/template_service_broker/defaults/main.yml b/roles/template_service_broker/defaults/main.yml index c32872d24..3465832cc 100644 --- a/roles/template_service_broker/defaults/main.yml +++ b/roles/template_service_broker/defaults/main.yml @@ -3,4 +3,4 @@  template_service_broker_remove: False  template_service_broker_install: True  openshift_template_service_broker_namespaces: ['openshift'] -template_service_broker_selector: { "region": "infra" } +template_service_broker_selector: "{{ openshift_hosted_infra_selector | default('region=infra') | map_from_pairs }}" diff --git a/roles/template_service_broker/tasks/install.yml b/roles/template_service_broker/tasks/install.yml index 604e94602..4e6ad2ae5 100644 --- a/roles/template_service_broker/tasks/install.yml +++ b/roles/template_service_broker/tasks/install.yml @@ -22,6 +22,11 @@    register: mktemp    changed_when: False +- name: Copy admin client config +  command: > +    cp {{ openshift.common.config_base }}/master//admin.kubeconfig {{ mktemp.stdout }}/admin.kubeconfig +  changed_when: false +  - copy:      src: "{{ __tsb_files_location }}/{{ item }}"      dest: "{{ mktemp.stdout }}/{{ item }}" @@ -43,16 +48,18 @@  - name: Apply template file    shell: > -    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __tsb_template_file }}" +    {{ openshift_client_binary }} process --config={{ mktemp.stdout }}/admin.kubeconfig +    -f "{{ mktemp.stdout }}/{{ __tsb_template_file }}"      --param API_SERVER_CONFIG="{{ config['content'] | b64decode }}"      --param IMAGE="{{ template_service_broker_prefix }}{{ template_service_broker_image_name }}:{{ template_service_broker_version }}"      --param NODE_SELECTOR={{ template_service_broker_selector | to_json | quote }} -    | {{ openshift_client_binary }} apply -f - +    | {{ openshift_client_binary }} apply --config={{ mktemp.stdout }}/admin.kubeconfig -f -  # reconcile with rbac  - name: Reconcile with RBAC file    shell: > -    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __tsb_rbac_file }}" | {{ openshift_client_binary }} auth reconcile -f - +    {{ openshift_client_binary }} process --config={{ mktemp.stdout }}/admin.kubeconfig -f "{{ mktemp.stdout }}/{{ __tsb_rbac_file }}" +    | {{ openshift_client_binary }} auth reconcile --config={{ mktemp.stdout }}/admin.kubeconfig -f -  # Check that the TSB is running  - name: Verify that TSB is running @@ -79,9 +86,15 @@  # Register with broker  - name: Register TSB with broker    shell: > -    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __tsb_broker_file }}" --param CA_BUNDLE="{{ __ca_bundle.content }}" | {{ openshift_client_binary }} apply -f - +    {{ openshift_client_binary }} process --config={{ mktemp.stdout }}/admin.kubeconfig -f "{{ mktemp.stdout }}/{{ __tsb_broker_file }}" --param CA_BUNDLE="{{ __ca_bundle.content }}" | {{ openshift_client_binary }} apply --config={{ mktemp.stdout }}/admin.kubeconfig -f -  - file:      state: absent      name: "{{ mktemp.stdout }}"    changed_when: False + +- name: Rollout console so it discovers the template service broker is installed +  include_role: +    name: openshift_web_console +    tasks_from: rollout_console.yml +  when: openshift_web_console_install | default(true) | bool diff --git a/roles/template_service_broker/tasks/remove.yml b/roles/template_service_broker/tasks/remove.yml index db1b558e4..48dc1327e 100644 --- a/roles/template_service_broker/tasks/remove.yml +++ b/roles/template_service_broker/tasks/remove.yml @@ -3,6 +3,11 @@    register: mktemp    changed_when: False +- name: Copy admin client config +  command: > +    cp {{ openshift.common.config_base }}/master//admin.kubeconfig {{ mktemp.stdout }}/admin.kubeconfig +  changed_when: false +  - copy:      src: "{{ __tsb_files_location }}/{{ item }}"      dest: "{{ mktemp.stdout }}/{{ item }}" @@ -12,11 +17,11 @@  - name: Delete TSB broker    shell: > -    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __tsb_broker_file }}" | {{ openshift_client_binary }} delete --ignore-not-found -f - +    {{ openshift_client_binary }} process --config={{ mktemp.stdout }}/admin.kubeconfig -f "{{ mktemp.stdout }}/{{ __tsb_broker_file }}" | {{ openshift_client_binary }} delete --config={{ mktemp.stdout }}/admin.kubeconfig --ignore-not-found -f -  - name: Delete TSB objects    shell: > -    {{ openshift_client_binary }} process -f "{{ mktemp.stdout }}/{{ __tsb_template_file }}" | {{ openshift_client_binary }} delete --ignore-not-found -f - +    {{ openshift_client_binary }} process --config={{ mktemp.stdout }}/admin.kubeconfig -f "{{ mktemp.stdout }}/{{ __tsb_template_file }}" | {{ openshift_client_binary }} delete --config={{ mktemp.stdout }}/admin.kubeconfig --ignore-not-found -f -  - name: empty out tech preview extension file for service console UI    copy: @@ -31,3 +36,9 @@      state: absent      name: "{{ mktemp.stdout }}"    changed_when: False + +- name: Rollout console so it discovers the template service broker is removed +  include_role: +    name: openshift_web_console +    tasks_from: rollout_console.yml +  when: openshift_web_console_install | default(true) | bool diff --git a/roles/template_service_broker/vars/default_images.yml b/roles/template_service_broker/vars/default_images.yml index 662d65d9f..dc164a4db 100644 --- a/roles/template_service_broker/vars/default_images.yml +++ b/roles/template_service_broker/vars/default_images.yml @@ -1,4 +1,4 @@  --- -__template_service_broker_prefix: "docker.io/openshift/" +__template_service_broker_prefix: "docker.io/openshift/origin-"  __template_service_broker_version: "latest" -__template_service_broker_image_name: "origin-template-service-broker" +__template_service_broker_image_name: "template-service-broker" diff --git a/roles/template_service_broker/vars/openshift-enterprise.yml b/roles/template_service_broker/vars/openshift-enterprise.yml index 16a08e72f..b65b97691 100644 --- a/roles/template_service_broker/vars/openshift-enterprise.yml +++ b/roles/template_service_broker/vars/openshift-enterprise.yml @@ -1,4 +1,4 @@  --- -__template_service_broker_prefix: "registry.access.redhat.com/openshift3/" +__template_service_broker_prefix: "registry.access.redhat.com/openshift3/ose-"  __template_service_broker_version: "v3.7" -__template_service_broker_image_name: "ose-template-service-broker" +__template_service_broker_image_name: "template-service-broker" diff --git a/roles/tuned/tasks/main.yml b/roles/tuned/tasks/main.yml index 4a28d47b2..5129f4471 100644 --- a/roles/tuned/tasks/main.yml +++ b/roles/tuned/tasks/main.yml @@ -28,7 +28,12 @@      when: item.state == 'file'    - name: Make tuned use the recommended tuned profile on restart -    file: path=/etc/tuned/active_profile state=absent +    file: +      path: '{{ item }}' +      state: absent +    with_items: +    - /etc/tuned/active_profile +    - /etc/tuned/profile_mode    - name: Restart tuned service      systemd:  | 
