├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ansible ├── config.j2.template ├── creds.j2.template ├── ocp-deployment-ansible-tower.yml ├── ocp-deployment.yml ├── roles │ ├── build-images │ │ └── tasks │ │ │ └── main.yml │ ├── copy-hdb-nfs │ │ └── tasks │ │ │ └── main.yml │ ├── create-overlay-share │ │ └── tasks │ │ │ └── main.yml │ ├── deploy-images │ │ └── tasks │ │ │ └── main.yml │ ├── ocp-prerequisites │ │ └── tasks │ │ │ ├── generate_ocp_secret.yml │ │ │ └── main.yml │ ├── os-prerequisites │ │ └── tasks │ │ │ ├── check_connection_to_ocp4_cluster.yml │ │ │ ├── check_oc_tool.yml │ │ │ ├── gen-config-creds.yml │ │ │ ├── main.yml │ │ │ ├── verify_nfs_hdb_directories.yml │ │ │ └── verify_nfs_server.yml │ └── push-images │ │ └── tasks │ │ └── main.yml ├── tasks │ ├── copy-git-repo.yml │ ├── oc-admin-login.yml │ ├── oc-user-login.yml │ ├── rhel8.x-prerequisites.yml │ ├── stop-deployment.yml │ ├── wait_for_n_min.yml │ ├── wait_for_pod_running.yml │ └── wait_for_system_running.yml └── vars │ └── ocp-extra-vars.yml ├── config.yaml.template ├── creds.yaml.template ├── docs ├── ANSIBLE-TOWER.md ├── ANSIBLE.md ├── ARCHITECTURE.md ├── BUILDING-CLI.md ├── CLEANUP.md ├── HOWTO.md ├── PORTFORWARD.md ├── POWERVS.md ├── PREREQUISITES.md ├── QUICKSTART.md ├── SCENARIOS.md ├── TOOLS.md ├── VERIFYING-MANAGING.md └── images │ ├── ArchitecturalOverview.png │ ├── BuildingImages.png │ ├── PowerSystemsVirtualServers_1.png │ ├── PowerSystemsVirtualServers_2.png │ ├── PowerSystemsVirtualServers_3.png │ ├── PowerSystemsVirtualServers_4.png │ ├── PowerSystemsVirtualServers_5.png │ ├── ansible_tower_add_new_job_template.png │ ├── ansible_tower_projects_view.png │ ├── howto │ ├── hana_studio_1.png │ ├── hana_studio_10.png │ ├── hana_studio_11.png │ ├── hana_studio_2.png │ ├── hana_studio_3.png │ ├── hana_studio_4.png │ ├── hana_studio_5.png │ ├── hana_studio_6.png │ ├── hana_studio_7.png │ ├── hana_studio_8.png │ └── hana_studio_9.png │ ├── ocp-haproxy-cleanup.png │ ├── ocp-haproxy-forwarding.png │ ├── ocp-port-forwarding.png │ └── sshkeyscopy.png ├── openshift ├── deployment.yaml.template ├── images │ ├── hdb │ │ ├── containerfile.template │ │ └── image-content │ │ │ ├── hdblcm-config.template │ │ │ ├── soos-start.sh │ │ │ ├── soos-stop.sh │ │ │ └── soos.service │ ├── init │ │ ├── containerfile │ │ └── image-content │ │ │ └── soos-create-envdir.sh │ └── nws4 │ │ ├── containerfile.template │ │ └── image-content │ │ ├── soos-start.sh │ │ ├── soos-stop.sh │ │ └── soos.service ├── secret.yaml.template └── service-nodeport.yaml.template └── tools ├── codingstyle ├── config ├── containerize ├── creds ├── gpg-key-gen ├── image-build ├── image-push ├── modules ├── __init__.py ├── args.py ├── argsdoc.py ├── command.py ├── config.py ├── configbase.py ├── constants.py ├── containerize.py ├── context.py ├── creds.py ├── deployment.py ├── exceptions.py ├── fail.py ├── imagebuilder.py ├── logger.py ├── messages.py ├── nestedns.py ├── nfs-ping-test ├── nfstools.py ├── ocp.py ├── quantity.py ├── remotecopy.py ├── ssh.py ├── startup.py ├── table.py ├── times.py ├── tools.py └── verify.py ├── nfs-hdb-copy ├── nfs-overlay-list ├── nfs-overlay-setup ├── nfs-overlay-teardown ├── ocp-container-login ├── ocp-container-run ├── ocp-deployment ├── ocp-etc-hosts ├── ocp-haproxy-forwarding ├── ocp-hdb-secret-gen ├── ocp-login ├── ocp-pod-meminfo ├── ocp-pod-status ├── ocp-port-forwarding ├── ocp-service-account-gen ├── sap-system-status ├── ssh-key-gen ├── ssh-keys ├── tool-shortcuts ├── venv-setup ├── verify-config └── verify-ocp-settings /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # Contributing 20 | 21 | This document contains information on how to contribute code or 22 | documentation to our project. 23 | 24 | 25 | 26 | ## Contents 27 | 28 |
29 | Table of Contents 30 | 31 | - [Contributing in General](#contributing-in-general) 32 | - [Proposing new Features](#proposing-new-features) 33 | - [Fixing Bugs](#fixing-bugs) 34 | - [Merge Approval](#merge-approval) 35 | - [Legal](#legal) 36 | - [Communication](#communication) 37 | - [Setup](#setup) 38 | - [Coding Style Guidelines](#coding-style-guidelines) 39 | 40 |
41 | 42 | 43 | 44 | ## Contributing in General 45 | 46 | Our project welcomes external contributions. 47 | 48 | To contribute code or documentation, please submit a [pull 49 | request](https://github.com/IBM/containerization-for-sap-s4hana/pulls). 50 | 51 | A good way to familiarize yourself with the code base and contribution 52 | process is to look for and tackle low-hanging fruit in the [issue 53 | tracker](https://github.com/IBM/containerization-for-sap-s4hana/issues). 54 | 55 | 56 | **Note: We appreciate your effort, and want to avoid a situation where 57 | a contribution requires extensive rework (by you or by us), sits in 58 | backlog for a long time, or cannot be accepted at all!** 59 | 60 | ### Proposing new Features 61 | 62 | If you would like to implement a new feature, please [raise an 63 | issue](https://github.com/IBM/containerization-for-sap-s4hana/issues) 64 | before sending a pull request so the feature can be discussed. This is 65 | to avoid you wasting your valuable time working on a feature that the 66 | project developers are not interested in accepting into the code base. 67 | 68 | ### Fixing Bugs 69 | 70 | If you would like to fix a bug, please [raise an 71 | issue](https://github.com/IBM/containerization-for-sap-s4hana/issues) 72 | before sending a pull request so it can be tracked. 73 | 74 | ### Merge Approval 75 | 76 | The project maintainers use LGTM (Looks Good To Me) in comments on the 77 | code review to indicate acceptance. A change requires LGTMs from two 78 | of the maintainers of each component affected. 79 | 80 | 83 | 84 | ## Legal 85 | 86 | Each source file must include a license header for the Apache Software 87 | License 2.0. Using the SPDX format is the simplest approach. e.g. 88 | 89 | ``` 90 | /* 91 | Copyright All Rights Reserved. 92 | 93 | SPDX-License-Identifier: Apache-2.0 94 | */ 95 | ``` 96 | 97 | We have tried to make it as easy as possible to make 98 | contributions. This applies to how we handle the legal aspects of 99 | contribution. We use [CLA assistant](https://cla-assistant.io/) which 100 | automatically asks you to sign the [Developer's Certificate of Origin 101 | 1.1 102 | (DCO)](https://gist.github.com/jridfe/cb9ed03deb37baa644e64eea3a327065) 103 | when you open a pull request. For more information see the description 104 | of a pull request workflow in [this 105 | gist](https://gist.github.com/reicolina/f30d7475157f3bf21ec6807a6caff85a). 106 | 107 | ## Communication 108 | 109 | Please feel free to connect with us by using our [issue 110 | tracker](https://github.com/IBM/containerization-for-sap-s4hana/issues). 111 | 112 | ## Setup 113 | 114 | Please refer to our [README.md](README.md) for setup instructions. 115 | 116 | 120 | 121 | ## Coding Style Guidelines 122 | 123 | Please use the [tools/codingstyle](tools/codingstyle) script to check 124 | whether your Python code adheres to our coding style guidelines. 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # Containerization by IBM for SAP S/4HANA with Red Hat OpenShift 20 | 21 | [![License](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) 22 | [![CLA assistant](https://cla-assistant.io/readme/badge/IBM/containerization-for-sap-s4hana)](https://cla-assistant.io/IBM/containerization-for-sap-s4hana) 23 | 24 | Build container images from existing SAP® NetWeaver® and SAP® S/4HANA® 25 | systems deployed on Linux®, and run them on a Red Hat® OpenShift® 26 | cluster. Options for the build process allow to invoke it either from 27 | command line, or automated using Red Hat Ansible® or Red Hat Ansible 28 | Tower®. 29 | 30 | 31 | 32 | ## Contents 33 | 34 |
35 | Table of Contents 36 | 37 | - [Introduction](#introduction) 38 | - [Important Note](#important-note) 39 | - [Documentation](#documentation) 40 | - [Contributors](#contributors) 41 | - [License](#license) 42 | - [Acknowledgments](#acknowledgments) 43 | 44 |
45 | 46 | 47 | 48 | ## Introduction 49 | 50 | This project provides assets for building container images of existing 51 | SAP® systems and for deploying containers based on the created images 52 | in Red Hat® OpenShift® Container Platform running on IBM® Power 53 | Systems™. 54 | 55 | ## Important Note 56 | 57 | **This release targets test and other non-production landscapes. The 58 | created deliverables are not supported by SAP nor 59 | agreed to a roadmap for official support in current state (see also 60 | SAP Note 1122387 - *Linux: SAP Support in virtualized environments*)** 61 | 62 | ## Documentation 63 | 64 | The various aspects of this project are described in the following 65 | documents: 66 | 67 | - [*Architecture*](docs/ARCHITECTURE.md) 68 | 69 | - [*Customer Scenarios*](docs/SCENARIOS.md) 70 | 71 | - [*Quickstart*](docs/QUICKSTART.md) 72 | 73 | - [*Prerequisites*](docs/PREREQUISITES.md) 74 | 75 | - Setup Red Hat OpenShift on IBM PowerVM servers managed using HMC 76 | 77 | - Complete automated setup, see external project [*Red Hat OpenShift on IBM PowerVM servers managed using HMC*](https://github.com/ocp-power-automation/ocp4-upi-powervm-hmc) or 78 | 79 | - Complete setup with some manual steps, see external project [*Helper Node Quickstart Install*](https://github.com/redhat-cop/ocp4-helpernode/blob/main/docs/quickstart-powervm.md) 80 | 81 | - [*Containerization for SAP S/4HANA with Red Hat OpenShift on IBM Power Systems Virtual Servers*](docs/POWERVS.md#containerization-for-sap-s4hana-with-red-hat-openshift-on-ibm-power-systems-virtual-server) 82 | 83 | - Build and deployment options 84 | 85 | - [*Building Images and Starting Deployments from the Command 86 | Line*](docs/BUILDING-CLI.md) 87 | 88 | In addition, see [*Tools*](docs/TOOLS.md) about the 89 | available tools and their options. 90 | 91 | - [*Building Images and Starting Deployments with Red Hat® 92 | Ansible®*](docs/ANSIBLE.md) 93 | 94 | - [*Building Images and Starting Deployments with Red Hat® Ansible 95 | Tower®*](docs/ANSIBLE-TOWER.md) 96 | 97 | - [*Verifying and Managing the Deployment*](docs/VERIFYING-MANAGING.md) 98 | 99 | - How To 100 | 101 | - [*Introducing Options for End-User GUI Access to the Containerized Systems*](docs/PORTFORWARD.md#introducing-options-for-end-user-gui-access-to-the-containerized-systems). 102 | 103 | - [*Connecting to the SAP® S/4HANA® Database using SAP HANA 104 | Studio®*](docs/HOWTO.md#connecting-to-the-sap-s4hana-database-using-sap-hana-studio) 105 | 106 | - [*Cleaning up the Environment*](docs/CLEANUP.md#cleaning-up-the-environment) 107 | 108 | - Please refer also to this [IBM® 109 | Redpaper™](http://www.redbooks.ibm.com/Redbooks.nsf/RedpieceAbstracts/redp5619.html?Open) 110 | for more information on how to setup the required environment. 111 | 112 | ## Contributors 113 | 114 | See the list of 115 | [contributors](https://github.com/IBM/containerization-for-sap-s4hana/graphs/contributors) 116 | who participated in this project. 117 | 118 | ## License 119 | 120 | This project is licensed under the Apache 2 License - see the 121 | [LICENSE](LICENSE) file for details. 122 | 123 | ## Acknowledgments 124 | 125 | Thanks to all the people who contributed to all the amazing open 126 | source tools that made this project possible. 127 | -------------------------------------------------------------------------------- /ansible/config.j2.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | build: 18 | description: Build machine 19 | repo: 20 | description: Github repository 'https://github.com/IBM/containerization-for-sap-s4hana' 21 | root: 22 | description: Path to the root directory of the repository clone 23 | on the build machine 24 | required: true 25 | value: '{{ path_to_ocp_tool }}' 26 | 27 | refsys: 28 | description: Reference SAP NetWeaver or SAP S/4HANA system 29 | nws4: 30 | description: ASCS and Dialog instance 31 | sid: 32 | description: SAP system ID 33 | required: true 34 | value: '{{ nws4_sid | upper }}' 35 | 36 | host: 37 | description: Host on which the system is installed 38 | name: 39 | description: Name of the host 40 | required: true 41 | value: '{{ nws4_host_name }}' 42 | 43 | ocp: 44 | description: OpenShift Container Platform (OCP) cluster 45 | project: 46 | description: Project under which the generated images 47 | are stored and the containers are started 48 | required: true 49 | value: '{{ ocp_project_name }}' 50 | 51 | domain: 52 | description: Cluster domain name (used for 'oc' operations) 53 | required: true 54 | value: '{{ ocp_cluster_domain }}' 55 | 56 | helper: 57 | description: Cluster helper node 58 | host: 59 | description: Host on which the helper node is installed 60 | name: 61 | description: Name of the host as seen in the intranet 62 | (*not* in the cluster network) 63 | required: true 64 | value: '{{ ocp_helper_node }}' 65 | 66 | containers: 67 | description: Container instances 68 | di: 69 | description: SAP dialog instance 70 | secret: 71 | description: Name of the OCP secret in which credentials 72 | of the SAP HANA database user (see creds.yaml) 73 | are stored for use within the Pod; 74 | *required* if the reference system is not a standard system 75 | required: false 76 | value: '{{ containers_di_secret }}' 77 | 78 | resources: 79 | requests: 80 | memory: 81 | description: Requested memory 82 | required: false 83 | value: '{{ containers_di_requests_memory }}' 84 | limits: 85 | memory: 86 | description: Memory limit; must be >= requested memory 87 | required: false 88 | value: '{{ containers_di_limits_memory }}' 89 | 90 | ascs: 91 | description: SAP ASCS instance 92 | resources: 93 | requests: 94 | memory: 95 | description: Requested memory 96 | required: true 97 | value: '{{ containers_ascs_requests_memory }}' 98 | limits: 99 | memory: 100 | description: Memory limit; must be >= requested memory 101 | required: true 102 | value: '{{ containers_ascs_limits_memory }}' 103 | 104 | hdb: 105 | description: SAP HANA instance 106 | resources: 107 | requests: 108 | memory: 109 | description: Requested memory; will be derived from the 110 | original database size if not supplied 111 | required: false 112 | value: '{{ containers_hdb_requests_memory }}' 113 | limits: 114 | memory: 115 | description: Memory limit; must be >= requested memory; 116 | will be derived from the original database 117 | size if not supplied 118 | required: false 119 | value: '{{ containers_hdb_limits_memory }}' 120 | 121 | nfs: 122 | description: NFS server 123 | host: 124 | description: Host on which the NFS server is running 125 | name: 126 | description: Name of host; if not specified 127 | ocp.helper.host.name is used 128 | required: false 129 | value: '{{ nfs_host_name }}' 130 | 131 | bases: 132 | description: Base directories 133 | copy: 134 | description: Path where directories {data,log} of the original 135 | SAP HANA system are copied to 136 | required: true 137 | value: '{{ nfs_path_to_hdb_copy }}' 138 | 139 | overlay: 140 | description: Path under which overlay file systems for container 141 | instances are created 142 | required: true 143 | value: '{{ nfs_path_to_overlay }}' 144 | -------------------------------------------------------------------------------- /ansible/creds.j2.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | build: 18 | description: Build machine 19 | user: 20 | description: User on the build machine which is used for 21 | executing build, deploy and maintenance operations 22 | sshid: 23 | description: Absolute path to the private SSH ID file which is 24 | used for SSH connect operations from the build machine 25 | to remote systems 26 | required: false 27 | value: '{{ build_user_sshid }}' 28 | 29 | refsys: 30 | description: Reference SAP NetWeaver or SAP S/4HANA system 31 | nws4: 32 | description: ASCS and Dialog instance 33 | sidadm: 34 | description: adm-user 35 | name: 36 | description: Name 37 | required: true 38 | value: '{{ nws4_sidadm_name }}' 39 | 40 | password: 41 | description: Password 42 | required: false 43 | value: '{{ nws4_sidadm_password }}' 44 | 45 | hdbconnect: 46 | description: SAP HANA database user which is used by the 47 | Dialog instance to connect to the database; 48 | *required* if the reference system is not a 49 | standard system 50 | name: 51 | description: Name 52 | required: false 53 | value: '{{ nws4_hdbconnect_name }}' 54 | 55 | password: 56 | description: Password 57 | required: false 58 | value: '{{ nws4_hdbconnect_password }}' 59 | 60 | hdb: 61 | description: SAP HANA database instance 62 | sidadm: 63 | description: adm-user 64 | name: 65 | description: Name 66 | required: true 67 | value: '{{ hdb_sidadm_name }}' 68 | 69 | password: 70 | description: Password 71 | required: false 72 | value: '{{ hdb_sidadm_password }}' 73 | 74 | nfs: 75 | description: NFS server 76 | user: 77 | description: User on the NFS server which is used for accessing 78 | the NFS host via SSH (needs root permissions) 79 | name: 80 | description: Name 81 | required: true 82 | value: '{{ nfs_user_name }}' 83 | 84 | password: 85 | description: Password 86 | required: false 87 | value: '{{ nfs_user_password }}' 88 | 89 | ocp: 90 | description: OpenShift Container Platform (OCP) cluster 91 | user: 92 | description: OCP cluster user which is used for non-admin 93 | 'oc' operations 94 | name: 95 | description: Name 96 | required: true 97 | value: '{{ ocp_user_name }}' 98 | 99 | password: 100 | description: Password 101 | required: true 102 | value: '{{ ocp_user_password }}' 103 | 104 | admin: 105 | description: OCP cluster user which is used for admin 106 | 'oc' operations 107 | name: 108 | description: Name 109 | required: true 110 | value: '{{ ocp_admin_name }}' 111 | 112 | password: 113 | description: Password 114 | required: true 115 | value: '{{ ocp_admin_password }}' 116 | 117 | helper: 118 | description: Cluster helper node 119 | user: 120 | description: User on the OCP helper host which is used for accessing 121 | the helper host via SSH (needs root permissions) 122 | 123 | name: 124 | description: Name 125 | required: true 126 | value: '{{ ocp_helper_node_user_name }}' 127 | 128 | password: 129 | description: Password 130 | required: false 131 | value: '{{ ocp_helper_node_user_password }}' 132 | 133 | sshid: 134 | description: Absolute path to the private SSH ID file which is 135 | used for SSH connect operations from the OCP helper 136 | node to the OCP worker nodes 137 | required: false 138 | value: '{{ ocp_helper_node_user_sshid }}' 139 | -------------------------------------------------------------------------------- /ansible/ocp-deployment-ansible-tower.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - hosts: all 18 | pre_tasks: 19 | - import_tasks: tasks/copy-git-repo.yml 20 | roles: 21 | - os-prerequisites 22 | - ocp-prerequisites 23 | - copy-hdb-nfs 24 | - build-images 25 | - push-images 26 | - create-overlay-share 27 | - deploy-images 28 | 29 | -------------------------------------------------------------------------------- /ansible/ocp-deployment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - hosts: all 18 | roles: 19 | - os-prerequisites 20 | - ocp-prerequisites 21 | - copy-hdb-nfs 22 | - build-images 23 | - push-images 24 | - create-overlay-share 25 | - deploy-images 26 | -------------------------------------------------------------------------------- /ansible/roles/build-images/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: building INIT container image 18 | shell: "source {{path_to_ocp_tool}}/venv/bin/activate && cd {{path_to_ocp_tool}}/ansible && {{path_to_ocp_tool}}/tools/image-build -c {{path_to_ocp_tool}}/config.yaml -q {{path_to_ocp_tool}}/creds.yaml -f init -v {{ debug_level_ocp_tool }}" 19 | register: outmsg 20 | ignore_errors: true 21 | - name: cat result after building INIT container image 22 | shell: "cat {{path_to_ocp_tool}}/ansible/log/*" 23 | register: outmsg_init 24 | ignore_errors: true 25 | - name: show result after building INIT container image 26 | debug: 27 | var: outmsg_init.stdout_lines 28 | ignore_errors: true 29 | - name: show stderr when rc!=0 after building INIT container image 30 | fail: 31 | msg: "Building INIT container image failed" 32 | when: outmsg.rc != 0 33 | - name: delete old logs 34 | file: 35 | path: "{{ path_to_ocp_tool }}/ansible/log" 36 | state: absent 37 | 38 | - name: building NWS4 container image 39 | shell: "source {{path_to_ocp_tool}}/venv/bin/activate && cd {{path_to_ocp_tool}}/ansible && {{path_to_ocp_tool}}/tools/image-build -c {{path_to_ocp_tool}}/config.yaml -q {{path_to_ocp_tool}}/creds.yaml -f nws4 -v {{ debug_level_ocp_tool }}" 40 | register: outmsg 41 | ignore_errors: true 42 | - name: cat result after building NWS4 container image 43 | shell: "cat {{path_to_ocp_tool}}/ansible/log/*" 44 | register: outmsg_nws4 45 | ignore_errors: true 46 | - name: show result after building NWS4 container image 47 | debug: 48 | var: outmsg_nws4.stdout_lines 49 | ignore_errors: true 50 | - name: show stderr when rc!=0 after building NWS4 container image 51 | fail: 52 | msg: "Building NWS4 container image failed" 53 | when: outmsg.rc != 0 54 | - name: delete old logs 55 | file: 56 | path: "{{ path_to_ocp_tool }}/ansible/log" 57 | state: absent 58 | 59 | - name: building SAP HANA container image 60 | shell: "source {{path_to_ocp_tool}}/venv/bin/activate && cd {{path_to_ocp_tool}}/ansible && {{path_to_ocp_tool}}/tools/image-build -c {{path_to_ocp_tool}}/config.yaml -q {{path_to_ocp_tool}}/creds.yaml -f hdb -v {{ debug_level_ocp_tool }}" 61 | register: outmsg 62 | - name: cat result after building SAP HANA container image 63 | shell: "cat {{path_to_ocp_tool}}/ansible/log/*" 64 | register: outmsg_hdb 65 | ignore_errors: true 66 | - name: show result after building SAP HANA container image 67 | debug: 68 | var: outmsg_hdb.stdout_lines 69 | ignore_errors: true 70 | - name: show stderr when rc!=0 after building SAP HANA container image 71 | fail: 72 | msg: "Building SAP HANA container image failed" 73 | when: outmsg.rc != 0 74 | - name: delete old logs 75 | file: 76 | path: "{{ path_to_ocp_tool }}/ansible/log" 77 | state: absent 78 | 79 | - name: verify the images 80 | shell: "podman images soos" 81 | register: out_img 82 | - name: show image building result 83 | debug: 84 | var: out_img.stdout_lines 85 | -------------------------------------------------------------------------------- /ansible/roles/copy-hdb-nfs/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: create a snapshot copy of the SAP HANA on the NFS server 18 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/nfs-hdb-copy -c ./config.yaml -q ./creds.yaml -w" 19 | register: outmsg 20 | - name: show status of copy hdb 21 | debug: var=outmsg.stdout 22 | -------------------------------------------------------------------------------- /ansible/roles/create-overlay-share/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: creating HANA DB overlay share on the NFS server 18 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/nfs-overlay-setup -c ./config.yaml -q ./creds.yaml" 19 | register: uuid_status 20 | - debug: var=uuid_status.stdout 21 | - name: store uuid for the deployment file 22 | set_fact: 23 | overlay_share_name: "{{ uuid_status.stdout }}" 24 | uuid_value: "{{ uuid_status.stdout.split('-') | last }}" 25 | -------------------------------------------------------------------------------- /ansible/roles/deploy-images/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: generating the deployment file using {{ overlay_share_name }} 18 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-deployment --gen-yaml -c ./config.yaml -q ./creds.yaml -u {{ overlay_share_name }}" 19 | register: outmsg 20 | - debug: var=outmsg.stdout 21 | - set_fact: 22 | deployment_file: "soos-{{ nws4_sid | lower}}-{{ uuid_value }}-deployment.yaml" 23 | # start deployment 24 | - name: apply the deployment file {{ deployment_file }} 25 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-deployment --start -f ./{{ deployment_file }} -c ./config.yaml -q ./creds.yaml " 26 | - import_tasks: ../../../tasks/wait_for_pod_running.yml 27 | - name: show pod mem info 28 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-pod-meminfo -c ./config.yaml -q ./creds.yaml" 29 | register: out_msg 30 | - debug: var=out_msg 31 | - import_tasks: ../../../tasks/wait_for_system_running.yml 32 | - name: show SAP system status 33 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/sap-system-status -c ./config.yaml -q ./creds.yaml -w" 34 | register: outmsg 35 | - debug: var=outmsg.stdout 36 | -------------------------------------------------------------------------------- /ansible/roles/ocp-prerequisites/tasks/generate_ocp_secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # generate ocp secret 19 | - name: show status of the secret name 20 | fail: 21 | msg: "secret name in the variable `containers_di_secret` must be defined" 22 | when: distributed_sap_system == 'yes' and containers_di_secret == '' 23 | 24 | - name: show status of the hdbconnect password 25 | fail: 26 | msg: "password in the variable `nws4_hdbconnect_password` must be defined" 27 | when: distributed_sap_system == 'yes' and nws4_hdbconnect_password == '' 28 | 29 | - name: show status of the hdbconnect name 30 | fail: 31 | msg: "password in the variable `nws4_hdbconnect_password` must be defined" 32 | when: distributed_sap_system == 'yes' and nws4_hdbconnect_name == '' 33 | 34 | - name: generate ocp secret if SAP HANA and SAP S/4HANA are distributed 35 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-hdb-secret-gen -c ./config.yaml -q ./creds.yaml -w" 36 | register: outmsg 37 | when: distributed_sap_system == 'yes' 38 | 39 | - debug: var=outmsg 40 | 41 | -------------------------------------------------------------------------------- /ansible/roles/ocp-prerequisites/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | - import_tasks: ../../../tasks/oc-user-login.yml 19 | 20 | - name: "set oc_project: {{ ocp_project_name }}" 21 | set_fact: 22 | oc_project: "{{ ocp_project_name }}" 23 | - name: check if the project "{{ ocp_project_name }}" is already existing 24 | shell: "oc get projects" 25 | register: oc_all_projects 26 | 27 | - name: create a new project if "{{ ocp_project_name }}" does not exist 28 | shell: "oc new-project {{ocp_project_name}}" 29 | register: outmsg 30 | when: oc_project not in oc_all_projects.stdout 31 | - name: show new-project 32 | debug: var=outmsg 33 | 34 | - name: choose your project 35 | shell: "oc project {{ocp_project_name}}" 36 | - name: get service account 37 | shell: "oc get serviceaccount" 38 | register: outmsg 39 | - debug: var=outmsg.stdout 40 | when: outmsg.rc==0 41 | - debug: 42 | msg: "outmsg.stderr" 43 | failed_when: outmsg.rc != 0 44 | 45 | - import_tasks: ../../../tasks/oc-admin-login.yml 46 | 47 | - name: enable the Image Registry default route, patch the Image Registry Operator 48 | shell: "oc patch configs.imageregistry.operator.openshift.io/cluster --type merge -p '{\"spec\":{\"defaultRoute\":true}}'" 49 | register: r_msg 50 | - name: show Image Registry default route 51 | debug: var=r_msg 52 | 53 | - name: add permission 54 | shell: "oc adm policy add-scc-to-group anyuid 'system:serviceaccounts:{{ocp_project_name}}'" 55 | register: out_p 56 | - name: show permission settings 57 | debug: var=out_p.stdout 58 | 59 | - name: generate ocp service-account 60 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-service-account-gen -c ./config.yaml -q ./creds.yaml -o {{path_to_ocp_tool}}/{{ocp_project_name}}-service-account.yaml -w" 61 | register: out_b 62 | - name: show output after generating oc service account 63 | debug: var=out_b.stdout 64 | 65 | - import_tasks: ../../../tasks/oc-admin-login.yml 66 | 67 | - name: add the required security context constraints to the service account 68 | shell: "oc adm policy add-scc-to-user hostmount-anyuid system:serviceaccount:{{ocp_project_name}}:{{ocp_project_name}}-sa" 69 | register: out_msg 70 | - name: show result after add-scc-to-user 71 | debug: var=out_msg 72 | 73 | # generate secret for Distributed Reference System after OCP project is checked, created 74 | - import_tasks: generate_ocp_secret.yml 75 | 76 | - name: verify configuration settings of config.yaml and creds.yaml 77 | shell: "source {{path_to_ocp_tool}}/venv/bin/activate && {{ path_to_ocp_tool }}/tools/verify-config -c {{ path_to_ocp_tool }}/config.yaml -q {{ path_to_ocp_tool }}/creds.yaml -w" 78 | register: result_msg 79 | ignore_errors: true 80 | - debug: var=result_msg.stdout_lines 81 | - name: check missing verify configuration parameters 82 | debug: var=result_msg.stderr_lines 83 | failed_when: result_msg.rc != 0 84 | when: result_msg.rc != 0 85 | 86 | # Checking security context constraints, checking worker nodes 87 | - name: verify ocp settings 88 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/verify-ocp-settings -c ./config.yaml -q ./creds.yaml -w" 89 | register: outmsg 90 | ignore_errors: true 91 | - debug: var=outmsg.stdout_lines 92 | - name: check missing verify ocp settings 93 | debug: var=outmsg.stderr_lines 94 | failed_when: outmsg.rc != 0 95 | when: outmsg.rc != 0 96 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/check_connection_to_ocp4_cluster.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # check connection to OCP4 cluster 19 | - name: check connection to api.{{ ocp_cluster_domain }} hostname 20 | shell: "ssh -o StrictHostKeyChecking=no root@api.{{ ocp_cluster_domain }} ls" 21 | register: outmsg_api 22 | ignore_errors: true 23 | - name: check connection to oauth-openshift.apps.{{ ocp_cluster_domain }} hostname 24 | shell: "ssh -o StrictHostKeyChecking=no root@oauth-openshift.apps.{{ ocp_cluster_domain }} ls" 25 | register: outmsg_oauth 26 | ignore_errors: true 27 | - name: check connection to default-route-openshift-image-registry.apps.{{ ocp_cluster_domain }} hostname 28 | shell: "ssh -o StrictHostKeyChecking=no root@default-route-openshift-image-registry.apps.{{ ocp_cluster_domain }} ls" 29 | register: outmsg_route 30 | ignore_errors: true 31 | - name: show status of checking connection to OCP4 cluster 32 | fail: 33 | msg: "Insert the ` api. oauth-openshift.apps. default-route-openshift-image-registry.apps.` into the /etc/hosts file on your build LPAR. Check that password-less access is possible for user root to these hosts." 34 | when: outmsg_api.rc != 0 or outmsg_oauth.rc != 0 or outmsg_route.rc != 0 35 | 36 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/check_oc_tool.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # check if oc tool is installed and copy it from helper node if not installed 19 | - name: verify local oc tool 20 | command: which oc 21 | ignore_errors: true 22 | register: outmsg 23 | - name: verify oc tool on the OCP4 helper node "{{ ocp_cluster_domain }}" 24 | command: ssh -o StrictHostKeyChecking=no root@api.{{ ocp_cluster_domain }} "which oc" 25 | register: outmsg_helper 26 | ignore_errors: true 27 | when: outmsg.rc !=0 28 | - name: copy oc tool from OCP4 helper node to build LPAR 29 | command: scp -o StrictHostKeyChecking=no root@api.{{ ocp_cluster_domain }}:{{ outmsg_helper.stdout }} {{ outmsg_helper.stdout }} 30 | register: outmsg_scp 31 | when: outmsg.rc != 0 and outmsg_helper is defined and outmsg_helper.rc == 0 32 | - name: check if oc tool is installed 33 | debug: msg="{{ outmsg_scp.stderr }}" 34 | failed_when: outmsg_scp.rc != 0 35 | when: outmsg_scp.stderr is defined and outmsg_scp.rc != 0 36 | 37 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/gen-config-creds.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: generate config.yaml 18 | template: 19 | #source directory of config.j2.template 20 | src: "{{ template_config_file }}" 21 | dest: "{{ path_to_ocp_tool }}/config.yaml" 22 | register: out_msg 23 | - name: show result 24 | debug: var=out_msg 25 | 26 | - name: generate creds.yaml 27 | template: 28 | #source directory of creds.j2.template 29 | src: "{{ template_creds_file }}" 30 | dest: "{{ path_to_ocp_tool }}/creds.yaml" 31 | register: out_msg 32 | - name: show result 33 | debug: var=out_msg 34 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # check if oc tool is installed and copy it from helper node if not installed 19 | - import_tasks: check_oc_tool.yml 20 | 21 | # check temp directory for image builds 22 | - name: create temp directory for image builds 23 | file: 24 | path: "{{ tmp_root }}" 25 | state: directory 26 | 27 | # verify connection to NFS server and create directories for HDB copy 28 | - import_tasks: verify_nfs_server.yml 29 | 30 | # verify NFS directories on NFS server for HDB copy and overlay share 31 | - import_tasks: verify_nfs_hdb_directories.yml 32 | 33 | # install all required libraries 34 | - name: install podman 35 | package: 36 | name: podman 37 | state: "{{ package_state }}" 38 | - name: install a "{{ package_state }}" version of git 39 | package: 40 | name: git 41 | state: "{{ package_state }}" 42 | - name: install {{ python3x_version }} 43 | package: 44 | name: "{{ python3x_version }}" 45 | state: "{{ package_state }}" 46 | - name: install "{{ python3x_version }}-devel" 47 | package: 48 | name: "{{ python3x_version }}-devel" 49 | state: "{{ package_state }}" 50 | - name: install "{{ python3x_version }}-pip" 51 | package: 52 | name: "{{ python3x_version }}-pip" 53 | state: "{{ package_state }}" 54 | 55 | - name: set up a Python virtual environment with all Python modules 56 | shell: "cd {{ path_to_ocp_tool }} && ./tools/venv-setup " 57 | register: outmsg 58 | ignore_errors: true 59 | - debug: var=outmsg.stdout_lines 60 | - name: show debug message if the venv setup doesn't work 61 | debug: var=outmsg.stderr_lines 62 | failed_when: outmsg.rc != 0 63 | when: outmsg.rc != 0 64 | 65 | - name: activate virtual environment 66 | shell: "source {{ path_to_ocp_tool }}/venv/bin/activate" 67 | register: outmsg 68 | - debug: var=outmsg 69 | 70 | # generate config.yml and verify its parameters 71 | - import_tasks: gen-config-creds.yml 72 | 73 | - name: add cluster ip to /etc/hosts 74 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-etc-hosts -c ./config.yaml -q ./creds.yaml -w" 75 | register: outmsg 76 | - debug: var=outmsg 77 | 78 | # check connection to OCP4 cluster 79 | - import_tasks: check_connection_to_ocp4_cluster.yml 80 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/verify_nfs_hdb_directories.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # verify NFS directories on NFS server for HDB copy and overlay share 19 | - name: create NFS hdb directory on NFS server if NFS host name is defined 20 | command: ssh -o StrictHostKeyChecking=no {{ nfs_user_name }}@{{ nfs_host_name }} "mkdir -p {{ nfs_path_to_hdb_copy }}" 21 | when: nfs_host_name|length > 0 22 | 23 | - name: create NFS hdb directory on helper node if NFS host name isn't defined 24 | command: ssh -o StrictHostKeyChecking=no {{ ocp_helper_node_user_name }}@{{ ocp_helper_node }} "mkdir -p {{ nfs_path_to_hdb_copy }}" 25 | when: nfs_host_name == '' 26 | 27 | - name: create NFS overlay directory on NFS server if NFS host name is defined 28 | command: ssh -o StrictHostKeyChecking=no {{ nfs_user_name }}@{{ nfs_host_name }} "mkdir -p {{ nfs_path_to_overlay }}" 29 | when: nfs_host_name|length > 0 30 | 31 | - name: create NFS overlay directory on helper node if NFS host name isn't defined 32 | command: ssh -o StrictHostKeyChecking=no {{ ocp_helper_node_user_name }}@{{ ocp_helper_node }} "mkdir -p {{ nfs_path_to_overlay }}" 33 | when: nfs_host_name == '' 34 | 35 | -------------------------------------------------------------------------------- /ansible/roles/os-prerequisites/tasks/verify_nfs_server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | 18 | # check NFS server connections 19 | - name: show status of NFS user name and OCP helper node 20 | fail: 21 | msg: "NFS user name and OCP helper node must be defined" 22 | when: ocp_helper_node == '' and nfs_user_name == '' 23 | 24 | - name: check ssh connection to NFS server {{ nfs_user_name }}@{{ nfs_host_name }} 25 | shell: "ssh -o StrictHostKeyChecking=no {{ nfs_user_name }}@{{ nfs_host_name }} ls" 26 | when: nfs_host_name !='' 27 | 28 | - name: check ssh connection to NFS server on a helper node {{ nfs_user_name }}@{{ ocp_helper_node }} 29 | shell: "ssh -o StrictHostKeyChecking=no {{ ocp_helper_node_user_name }}@{{ ocp_helper_node }} ls" 30 | when: nfs_host_name == '' 31 | -------------------------------------------------------------------------------- /ansible/roles/push-images/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: push INIT image into ocp cluster 18 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/image-push -c ./config.yaml -q ./creds.yaml -f init -w" 19 | register: outmsg_init 20 | - name: show result after pushing INIT image 21 | debug: 22 | var: outmsg_init.stdout 23 | - name: push NWS4 image into ocp cluster 24 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/image-push -c ./config.yaml -q ./creds.yaml -f nws4 -w" 25 | register: outmsg_nws4 26 | - name: show result after pushing NWS4 image 27 | debug: 28 | var: outmsg_nws4.stdout 29 | - name: push SAP HANA container image 30 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/image-push -c ./config.yaml -q ./creds.yaml -f hdb -w" 31 | register: outmsg_hdb 32 | - name: show result after pushing SAP HANA container 33 | debug: 34 | var: outmsg_hdb.stdout 35 | - import_tasks: ../../../tasks/oc-user-login.yml 36 | - name: verify whether the images are available in the local registry of the OpenShift cluster 37 | command: oc get imagestream 38 | register: out_image_stream 39 | - debug: var=out_image_stream.stdout_lines 40 | -------------------------------------------------------------------------------- /ansible/tasks/copy-git-repo.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: install a "{{ package_state }}" version of git 18 | package: 19 | name: git 20 | state: "{{ package_state }}" 21 | - name: Download the tool containerization-for-sap-s4hana from the GitHub repository 22 | git: repo="{{ github_repo_url }}" dest="{{ path_to_ocp_tool }}" accept_hostkey=yes key_file="{{ github_key_file }}" 23 | when: github_key_file is defined 24 | - name: Download the tool containerization-for-sap-s4hana from the GitHub repository 25 | git: repo="{{ github_repo_url }}" dest="{{ path_to_ocp_tool }}" accept_hostkey=yes 26 | when: github_key_file is not defined 27 | -------------------------------------------------------------------------------- /ansible/tasks/oc-admin-login.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | #oc login -u -p 18 | - name: Login as admin to OCP cluster 19 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-login -c ./config.yaml -q ./creds.yaml -a -w" 20 | register: login_adm 21 | - name: show login result info 22 | debug: var=login_adm.stdout 23 | -------------------------------------------------------------------------------- /ansible/tasks/oc-user-login.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: Login as user "{{ ocp_user_name }}" to OCP cluster 18 | shell: "cd {{path_to_ocp_tool}} && source ./venv/bin/activate && ./tools/ocp-login -c ./config.yaml -q ./creds.yaml -u --project-ignore -w" 19 | register: login_ocp_msg 20 | - debug: var=login_ocp_msg.stdout 21 | -------------------------------------------------------------------------------- /ansible/tasks/rhel8.x-prerequisites.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: install libffi 18 | package: 19 | name: libffi 20 | state: "{{package_state}}" 21 | - name: install libffi-devel 22 | package: 23 | name: libffi-devel 24 | state: "{{package_state}}" 25 | - name: install gcc 26 | package: 27 | name: gcc 28 | state: "{{package_state}}" 29 | - name: install openssl-devel 30 | package: 31 | name: openssl-devel 32 | state: "{{package_state}}" 33 | - name: install make utility 34 | package: 35 | name: make 36 | state: "{{package_state}}" 37 | 38 | -------------------------------------------------------------------------------- /ansible/tasks/stop-deployment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - import_tasks: oc-user-login.yml 18 | - name: Stopping deployment on the OCP cluster 19 | command: "oc delete -f {{path_to_ocp_tool}}/soos-{{ nws4_sid | lower}}-{{ uuid_value }}-deployment.yaml" 20 | register: stop_status 21 | - debug: var=stop_status 22 | 23 | -------------------------------------------------------------------------------- /ansible/tasks/wait_for_n_min.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | #pause for 2 minutes 18 | - name: wait for 2 minutes 19 | pause: 20 | minutes: 2 21 | -------------------------------------------------------------------------------- /ansible/tasks/wait_for_pod_running.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: verify pod status every 30 seconds and maximum 30 minutes or until stdout contains string "Running" 18 | shell: "cd {{path_to_ocp_tool}} && source {{path_to_ocp_tool}}/venv/bin/activate && {{path_to_ocp_tool}}/tools/ocp-pod-status -c {{path_to_ocp_tool}}/config.yaml -q {{path_to_ocp_tool}}/creds.yaml" 19 | register: outmsg 20 | ignore_errors: yes 21 | until: outmsg.stdout.find("Running") != -1 22 | retries: 60 23 | delay: 30 24 | -------------------------------------------------------------------------------- /ansible/tasks/wait_for_system_running.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------------------------------------ 3 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # ------------------------------------------------------------------------ 17 | - name: verify system status every 30 seconds and maximum 30 minutes or until stdout contains string "running" 18 | shell: "cd {{path_to_ocp_tool}} && source {{path_to_ocp_tool}}/venv/bin/activate && {{path_to_ocp_tool}}/tools/sap-system-status -c {{path_to_ocp_tool}}/config.yaml -q {{path_to_ocp_tool}}/creds.yaml" 19 | register: outmsg 20 | ignore_errors: yes 21 | until: (outmsg.stdout | regex_findall(' running') | length) == 3 22 | retries: 60 23 | delay: 30 24 | -------------------------------------------------------------------------------- /config.yaml.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | build: 18 | description: Build machine 19 | repo: 20 | description: Github repository 'https://github.com/IBM/containerization-for-sap-s4hana' 21 | root: 22 | description: Path to the root directory of the repository clone 23 | on the build machine 24 | required: true 25 | value: '' 26 | 27 | refsys: 28 | description: Reference SAP NetWeaver or SAP S/4HANA system 29 | nws4: 30 | description: ASCS and Dialog instance 31 | sid: 32 | description: SAP system ID 33 | required: true 34 | value: '' 35 | 36 | host: 37 | description: Host on which the system is installed 38 | name: 39 | description: Name of the host 40 | required: true 41 | value: '' 42 | 43 | ocp: 44 | description: OpenShift Container Platform (OCP) cluster 45 | project: 46 | description: Project under which the generated images 47 | are stored and the containers are started 48 | required: true 49 | value: '' 50 | 51 | domain: 52 | description: Cluster domain name (used for 'oc' operations) 53 | required: true 54 | value: '' 55 | 56 | helper: 57 | description: Cluster helper node 58 | host: 59 | description: Host on which the helper node is installed 60 | name: 61 | description: Name of the host as seen in the intranet 62 | (*not* in the cluster network) 63 | required: true 64 | value: '' 65 | 66 | containers: 67 | description: Container instances 68 | di: 69 | description: SAP dialog instance 70 | secret: 71 | description: Name of the OCP secret in which credentials 72 | of the SAP HANA database user (see creds.yaml) 73 | are stored for use within the Pod; 74 | *required* if the reference system is not a 75 | standard system 76 | required: false 77 | value: '' 78 | 79 | resources: 80 | requests: 81 | memory: 82 | description: Requested memory 83 | required: false 84 | value: '' 85 | limits: 86 | memory: 87 | description: Memory limit; must be >= requested memory 88 | required: false 89 | value: '' 90 | 91 | ascs: 92 | description: SAP ASCS instance 93 | resources: 94 | requests: 95 | memory: 96 | description: Requested memory 97 | required: true 98 | value: 10Gi 99 | limits: 100 | memory: 101 | description: Memory limit; must be >= requested memory 102 | required: true 103 | value: 10Gi 104 | 105 | hdb: 106 | description: SAP HANA instance 107 | resources: 108 | requests: 109 | memory: 110 | description: Requested memory; will be derived from the 111 | original database size if not supplied 112 | required: false 113 | value: '' 114 | limits: 115 | memory: 116 | description: Memory limit; must be >= requested memory; 117 | will be derived from the original database 118 | size if not supplied 119 | required: false 120 | value: '' 121 | 122 | nfs: 123 | description: NFS server 124 | host: 125 | description: Host on which the NFS server is running 126 | name: 127 | description: Name of host; if not specified 128 | ocp.helper.host.name is used 129 | required: false 130 | value: '' 131 | 132 | bases: 133 | description: Base directories 134 | copy: 135 | description: Path where directories {data,log} of the original 136 | SAP HANA system are copied to 137 | required: true 138 | value: '' 139 | 140 | overlay: 141 | description: Path under which overlay file systems for container 142 | instances are created 143 | required: true 144 | value: '' 145 | -------------------------------------------------------------------------------- /creds.yaml.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | build: 18 | description: Build machine 19 | user: 20 | description: User on the build machine which is used for 21 | executing build, deploy and maintenance operations 22 | sshid: 23 | description: Absolute path to the private SSH ID file which is 24 | used for SSH connect operations from the build machine 25 | to remote systems 26 | required: false 27 | value: '' 28 | 29 | refsys: 30 | description: Reference SAP NetWeaver or SAP S/4HANA system 31 | nws4: 32 | description: ASCS and Dialog instance 33 | sidadm: 34 | description: adm-user 35 | name: 36 | description: Name 37 | required: true 38 | value: '' 39 | 40 | password: 41 | description: Password 42 | required: false 43 | value: '' 44 | 45 | hdbconnect: 46 | description: SAP HANA database user which is used by the 47 | Dialog instance to connect to the database; 48 | *required* if the reference system is not a 49 | standard system 50 | name: 51 | description: Name 52 | required: false 53 | value: SAPHANADB 54 | 55 | password: 56 | description: Password 57 | required: false 58 | value: '' 59 | 60 | hdb: 61 | description: SAP HANA database instance 62 | sidadm: 63 | description: adm-user 64 | name: 65 | description: Name 66 | required: true 67 | value: '' 68 | 69 | password: 70 | description: Password 71 | required: false 72 | value: '' 73 | 74 | nfs: 75 | description: NFS server 76 | user: 77 | description: User on the NFS server which is used for accessing 78 | the NFS host via SSH (needs root permissions) 79 | name: 80 | description: Name 81 | required: true 82 | value: root 83 | 84 | password: 85 | description: Password 86 | required: false 87 | value: '' 88 | 89 | ocp: 90 | description: OpenShift Container Platform (OCP) cluster 91 | user: 92 | description: OCP cluster user which is used for non-admin 93 | 'oc' operations 94 | name: 95 | description: Name 96 | required: true 97 | value: '' 98 | 99 | password: 100 | description: Password 101 | required: true 102 | value: '' 103 | 104 | admin: 105 | description: OCP cluster user which is used for admin 106 | 'oc' operations 107 | name: 108 | description: Name 109 | required: true 110 | value: kubeadmin 111 | 112 | password: 113 | description: Password 114 | required: true 115 | value: '' 116 | 117 | helper: 118 | description: Cluster helper node 119 | user: 120 | description: User on the OCP helper host which is used for accessing 121 | the helper host via SSH (needs root permissions) 122 | 123 | name: 124 | description: Name 125 | required: true 126 | value: root 127 | 128 | password: 129 | description: Password 130 | required: false 131 | value: '' 132 | 133 | sshid: 134 | description: Absolute path to the private SSH ID file which is 135 | used for SSH connect operations from the OCP helper 136 | node to the OCP worker nodes 137 | required: false 138 | value: '' 139 | -------------------------------------------------------------------------------- /docs/ANSIBLE-TOWER.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | # Building Images and Starting Deployments with Red Hat® Ansible Tower® 19 | 20 | In the following we describe how to build the images and deploy 21 | containers based on the images for running an SAP® system in a Red 22 | Hat® OpenShift® Container Platform using Red Hat Ansible Tower. 23 | 24 | 25 | 26 | ## Contents 27 | 28 |
29 | Table of Contents 30 | 31 | - [Getting Started with Red Hat Ansible Tower](#getting-started-with-red-hat-ansible-tower) 32 | - [Performing Manual Tasks](#performing-manual-tasks) 33 | - [Creating a New Red Hat Ansible Tower Project](#creating-a-new-red-hat-ansible-tower-project) 34 | - [Creating the Inventory](#creating-the-inventory) 35 | - [Creating the Job Template](#creating-the-job-template) 36 | - [Building the Images and Starting the SAP System](#building-the-images-and-starting-the-sap-system) 37 | - [Connecting to the Deployed SAP System](#connecting-to-the-deployed-sap-system) 38 | 39 |
40 | 41 | 42 | 43 | ## Getting Started with Red Hat Ansible Tower 44 | 45 | 46 | In the following we assume that you have installed and configured Red 47 | Hat Ansible Tower on your build LPAR. 48 | 49 | The basic installation of Ansible Tower is described in the [Ansible 50 | Automation Platform Quick Installation 51 | Guide](https://docs.ansible.com/ansible-tower/latest/html/quickinstall/index.html). 52 | 53 | More detailed information is available in the [Ansible Automation 54 | Platform Installation and Reference 55 | Guide](https://docs.ansible.com/ansible-tower/3.8.0/html/installandreference/index.html#ir-start). 56 | 57 | ## Performing Manual Tasks 58 | 59 | The tasks that need to be performed manually are described in section 60 | [*Performing manual tasks before running the 61 | playbook*](ANSIBLE.md#performing-manual-tasks-before-running-the-playbook). 62 | 63 | ## Creating a New Red Hat Ansible Tower Project 64 | 65 | You need to set up a project that will be used in a job template for 66 | building and deploying images. 67 | 68 | To define a new project, log into the Red Hat Ansible Tower web 69 | interface using *admin-level* credentials. Select *Projects* in the left 70 | navigation bar and click a green plus-button in the right top 71 | corner. You will get a new project view in which you need to fill in 72 | all required fields: 73 | 74 | + Define a project name. 75 | + Add a description. 76 | + Select organization - as an example `Default` can be used. 77 | + Select `Git` as __SCM TYPE__. 78 | + Specify __SCM BRANCH/TAG/COMMIT__ to checkout source code, as example `main` can be defined. 79 | + Select __SCM UPDATE OPTIONS__ check boxes such as `clean`, `delete on update` and `update revision on launch`. 80 | 81 | You do not need credentials to access our GitHub repository since the 82 | provided URL is public - just copy it into the field __SCM URL__ of the 83 | *Projects* template as shown: 84 | 85 | __SCM URL__: `https://github.com/IBM/containerization-for-sap-s4hana.git` 86 | 87 | ![New Project view](images/ansible_tower_projects_view.png) 88 | 89 | ## Creating the Inventory 90 | 91 | Before creating a job template you need to set up your inventory 92 | defining the build host and credentials. Refer to chapter 93 | [Inventories](https://docs.ansible.com/ansible-tower/latest/html/userguide/inventories.html) 94 | of the *Ansible Tower User Guide* for detailed instructions. 95 | 96 | ## Creating the Job Template 97 | 98 | Next, select *Templates* on the left side of the navigation panel. You 99 | will see a list of job templates, if there are any. To define a new 100 | job template click the green plus on the top right corner as shown: 101 | 102 | ![How to add a new job template](images/ansible_tower_add_new_job_template.png) 103 | 104 | Fill in all required fields and the desired optional fields. Detailed 105 | explanations about job templates are described in chapter [Job 106 | Templates](https://docs.ansible.com/ansible-tower/latest/html/userguide/job_templates.html) 107 | of the *Ansible Tower User Guide*. 108 | 109 | Add your variables as specified in file `vars/ocp-extra-vars.yml` to 110 | field __Extra Variables__. See section [*Specifying your 111 | settings*](ANSIBLE.md#specifying-your-settings) for all required variables. 112 | 113 | Select playbook `ansible/ocp-deployment-ansible-tower.yml` in field __Playbook__. 114 | 115 | Finally save the job template. 116 | 117 | ## Building the Images and Starting the SAP System 118 | 119 | Launch the job. A green status of the job run indicates that the three 120 | images were successfully built and the deployment of the SAP system 121 | was successfully started. 122 | 123 | Verify whether your SAP system was correctly started by performing the 124 | steps described in section [*Verifying 125 | Deployments*](VERIFYING-MANAGING.md#verifying-deployments). 126 | 127 | ## Connecting to the Deployed SAP System 128 | 129 | To connect to the deployed SAP system refer to section [*Managing 130 | Deployments*](VERIFYING-MANAGING.md#managing-deployments). 131 | -------------------------------------------------------------------------------- /docs/ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | # Architecture 19 | 20 | The following describes the general architecture of how to build 21 | container images from existing reference SAP® systems and deploying 22 | containers in a Red Hat® OpenShift® Container Platform. 23 | 24 | 25 | 26 | ## Contents 27 | 28 |
29 | Table of Contents 30 | 31 | - [General Architecture and Workflow](#general-architecture-and-workflow) 32 | 33 |
34 | 35 | 36 | 37 | ## General Architecture and Workflow 38 | 39 | The following picture describes the steps that are executed during 40 | image build and container deployment: 41 | 42 | 43 | workflow 45 | 46 | During the build phase three different images are created: 47 | 48 | - *Init* image: This image is independent from the reference SAP system 49 | and is used during the initialization of the deployment in the 50 | cluster. 51 | 52 | - *SAP AppServer* image: This image contains all relevant components 53 | of the reference SAP system that are needed to start both the *ABAP SAP Central Services* (ASCS) 54 | and the *Dialog instance* (DI) containers. 55 | 56 | - *SAP HANA* image: This image contains the SAP HANA® instance 57 | directories. It does not contain the `data/` and the `log/` 58 | directory trees of the database. A snapshot of these two directory 59 | trees is copied to the NFS file server during the build phase. At 60 | deployment time an overlay file system is created on top of the 61 | snapshot and mounted into the SAP HANA container. 62 | 63 | The images are pushed into the internal cluster registry. At 64 | deployment time the images are copied to the cluster helper node on 65 | which the deployment is started. At deployment start the *init* 66 | container sets up the environments for the application containers 67 | (ASCS, DI and SAP HANA containers). These are started after the *init* 68 | container has terminated. During start up of the SAP HANA container the 69 | overlay file system is mounted into the container. 70 | 71 | -------------------------------------------------------------------------------- /docs/SCENARIOS.md: -------------------------------------------------------------------------------- 1 | 17 | 18 | # Customer Scenarios 19 | 20 | This document describes the scenarios for which containerization of 21 | reference SAP® systems was developed and tested. 22 | 23 | 24 | 25 | ## Contents 26 | 27 |
28 | Table of Contents 29 | 30 | - [Supported Reference SAP Systems for Containerization](#supported-reference-sap-systems-for-containerization) 31 | - [Supported OS Distributions](#supported-os-distributions) 32 | - [What is an SAP Instance?](#what-is-an-sap-instance) 33 | - [What is a Reference SAP System?](#what-is-a-reference-sap-system) 34 | 35 |
36 | 37 | 38 | 39 | ## Supported Reference SAP Systems for Containerization 40 | 41 | Containerization of the [reference SAP 42 | system](#what-is-a-reference-sap-system) was developed and tested 43 | with the following scope of scenarios: 44 | 45 | * Standard system (former "Central System") 46 | 47 | In a standard SAP system, all main [SAP 48 | instances](#what-is-an-sap-instance) run on a single host. All the 49 | SAP system instances from the *Primary Application Server* and *ABAP Central 50 | Services* reside on the same host as the SAP HANA® database. 51 | 52 | * Distributed System 53 | 54 | In a distributed system, the SAP instances can run on multiple 55 | hosts: 56 | 57 | * one host running the *ABAP Central Services* instance (ASCS) and the 58 | *Primary Application Server* instance (PAS), 59 | 60 | * one host running the *SAP HANA® DB* instance 61 | 62 | - SAP system installed with virtual hostnames 63 | 64 | The SAP instance installation is not bound to the physical hostname 65 | of the host, but references to an additional IP label (virtual 66 | hostname). The virtual hostname either has an own unique IP address, 67 | or is realized as IP alias (DNS CNAME). All virtual hostnames need 68 | to be resolvable on all hosts attempting to communicate with them - 69 | either via DNS entries, or via local resolution. 70 | 71 | The containerization was tested for a SAP system installed with 72 | virtual hostnames using 73 | 74 | * one IP alias name for the SAP HANA database, 75 | * one IP alias name for both *ASCS* instance and *PAS* instance. 76 | 77 | ## Supported OS Distributions 78 | 79 | Reference SAP systems installed on 80 | 81 | * RHEL 8.2 (or higher) 82 | * SLES 12 SP4 (or higher), and SLES15 SP1 (or higher) 83 | 84 | can be used for containerization. 85 | 86 | ## What is an SAP Instance? 87 | 88 | An SAP instance is a group of processes that are started and stopped 89 | at the same time. Those instances can be deployed with certain 90 | variants. 91 | 92 | ## What is a Reference SAP System? 93 | 94 | The reference SAP system is the source system for containerization. It 95 | consists out of the following main SAP instances: 96 | 97 | * *ABAP Central Services* instance (ASCS instance) 98 | * *Primary Application Server* instance (DI instance aka PAS instance) 99 | * *SAP HANA Database* instance (HDB instance) 100 | -------------------------------------------------------------------------------- /docs/images/ArchitecturalOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ArchitecturalOverview.png -------------------------------------------------------------------------------- /docs/images/BuildingImages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/BuildingImages.png -------------------------------------------------------------------------------- /docs/images/PowerSystemsVirtualServers_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/PowerSystemsVirtualServers_1.png -------------------------------------------------------------------------------- /docs/images/PowerSystemsVirtualServers_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/PowerSystemsVirtualServers_2.png -------------------------------------------------------------------------------- /docs/images/PowerSystemsVirtualServers_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/PowerSystemsVirtualServers_3.png -------------------------------------------------------------------------------- /docs/images/PowerSystemsVirtualServers_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/PowerSystemsVirtualServers_4.png -------------------------------------------------------------------------------- /docs/images/PowerSystemsVirtualServers_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/PowerSystemsVirtualServers_5.png -------------------------------------------------------------------------------- /docs/images/ansible_tower_add_new_job_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ansible_tower_add_new_job_template.png -------------------------------------------------------------------------------- /docs/images/ansible_tower_projects_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ansible_tower_projects_view.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_1.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_10.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_11.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_2.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_3.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_4.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_5.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_6.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_7.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_8.png -------------------------------------------------------------------------------- /docs/images/howto/hana_studio_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/howto/hana_studio_9.png -------------------------------------------------------------------------------- /docs/images/ocp-haproxy-cleanup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ocp-haproxy-cleanup.png -------------------------------------------------------------------------------- /docs/images/ocp-haproxy-forwarding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ocp-haproxy-forwarding.png -------------------------------------------------------------------------------- /docs/images/ocp-port-forwarding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/ocp-port-forwarding.png -------------------------------------------------------------------------------- /docs/images/sshkeyscopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/containerization-for-sap-s4hana/f11085ddc10f468d14e9a83ed9623cd803b8dafe/docs/images/sshkeyscopy.png -------------------------------------------------------------------------------- /openshift/images/hdb/containerfile.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | FROM registry.access.redhat.com/ubi8/ubi-init:latest 18 | 19 | # label 20 | 21 | LABEL soos.containerfile.description="{{IMAGE_DESCRIPTION}}" \ 22 | soos.containerfile.date="{{IMAGE_DATE}}" \ 23 | soos.containerfile.version="{{IMAGE_VERSION}}" \ 24 | soos.containerfile.commit="{{IMAGE_COMMIT}}" \ 25 | soos.containerfile.branch="{{IMAGE_BRANCH}}" 26 | 27 | #RUN dnf -y makecache 28 | 29 | RUN \ 30 | # Install packages needed for image build 31 | dnf -y install --setopt=install_weak_deps=False util-linux-user && \ 32 | # Install packages needed for container operation 33 | dnf -y install --setopt=install_weak_deps=False csh hostname && \ 34 | # Install prerequisite packages for running SAP products (SAP Note #2772999) 35 | dnf -y install --setopt=install_weak_deps=False uuidd libnsl tcsh psmisc nfs-utils bind-utils && \ 36 | # Need to be installed for SAP HANA 37 | dnf -y install --setopt=install_weak_deps=False expect graphviz iptraf-ng krb5-workstation libatomic libcanberra-gtk2 libibverbs libicu libpng12 libssh2 lm_sensors ncurses numactl PackageKit-gtk3-module xorg-x11-xauth && \ 38 | # Need to be installed for the "Server" environment group 39 | dnf -y install --setopt=install_weak_deps=False cairo libaio krb5-libs net-tools openssl rsyslog sudo xfsprogs && \ 40 | # Need to be installed for mounting NFS shares for HANA 41 | dnf -y install --setopt=install_weak_deps=False nfs-utils 42 | 43 | # Install optional packages 44 | 45 | {{INSTALL_OPT_PACKAGES}} 46 | 47 | {{COPY_OPT_PACKAGE_FILES}} 48 | {{INSTALL_OPT_PACKAGE_FILES}} 49 | 50 | RUN dnf -y clean all 51 | 52 | # Create needed users and groups 53 | 54 | RUN groupadd --gid {{SAPSYS_GID}} sapsys && \ 55 | useradd --no-create-home --uid {{SAPADM_UID}} --gid {{SAPSYS_GID}} --comment "{{SAPADM_COMMENT}}" --home-dir {{SAPADM_HOME}} --shell {{SAPADM_SHELL}} sapadm && \ 56 | useradd --no-create-home --uid {{SIDADM_UID}} --gid {{SAPSYS_GID}} --comment "{{SIDADM_COMMENT}}" --home-dir {{SIDADM_HOME}} --shell {{SIDADM_SHELL}} {{sid}}adm 57 | 58 | # Copy HANA system related files 59 | 60 | COPY ./etc_services_sap ./etc_security_limits.conf / 61 | COPY ./etc/pam.d/sapstartsrv /etc/pam.d/sapstartsrv 62 | COPY ./etc/security/limits.d/99-sapsys.conf /etc/security/limits.d/99-sapsys.conf 63 | COPY --chown={{SIDADM_UID}}:{{SAPSYS_GID}} .{{USR_SAP_REAL}} {{USR_SAP_REAL}}/ 64 | COPY --chown={{SIDADM_UID}}:{{SAPSYS_GID}} .{{HANA_SHARED_SID}} {{HANA_SHARED_SID}}/ 65 | 66 | # Copy systemd and HANA license manager related files 67 | 68 | COPY ./soos.service /etc/systemd/system/ 69 | COPY ./soos-start.sh ./soos-stop.sh ./soos-hdblcm.tmp /root/ 70 | 71 | 72 | # Setup HANA system and and enable required systemd services 73 | 74 | RUN {{USR_SAP_LINK_CMD}} && \ 75 | cat /etc_services_sap >> /etc/services && rm /etc_services_sap && \ 76 | cat /etc_security_limits.conf >> /etc/security/limits.conf && rm /etc_security_limits.conf && \ 77 | chown root:{{SAPSYS_GID}} /usr/sap {{USR_SAP_REAL}} {{USR_SAP_REAL}}/sapservices && \ 78 | mkdir -p {{VAR_LIB_HDB_SID}} && chown {{SIDADM_UID}}:{{SAPSYS_GID}} {{VAR_LIB_HDB_SID}} && \ 79 | chgrp -R {{SAPSYS_GID}} {{USR_SAP_REAL}}/sapservices && \ 80 | chmod +x /root/soos-start.sh && \ 81 | chmod +x /root/soos-stop.sh && \ 82 | systemctl enable soos && \ 83 | systemctl enable uuidd && \ 84 | systemctl unmask systemd-logind 85 | 86 | # Cleanup 87 | 88 | # XXX TBD 89 | 90 | # Container startup 91 | 92 | # In ubi-init images CMD is /sbin/init by default 93 | # In ubi images we need to specify a CMD 94 | #CMD /root/soos-start.sh && tail -f /dev/null 95 | -------------------------------------------------------------------------------- /openshift/images/hdb/image-content/hdblcm-config.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | [Action] 18 | 19 | # Execution scenario 20 | action=register_rename_system 21 | 22 | [Rename] 23 | 24 | # Skip all SAP Host Agent calls 25 | skip_hostagent_calls=n 26 | 27 | # Execute checks, do not rename SAP HANA System 28 | check_only=n 29 | 30 | # Clean up system replication configuration on the target system 31 | sr_cleanup=n 32 | 33 | # Remote Execution 34 | remote_execution=ssh 35 | 36 | # Enable the installation or upgrade of the SAP Host Agent 37 | install_hostagent=n 38 | 39 | # Use Existing System Administrator () 40 | init_user=n 41 | 42 | # Do not start SAP HANA Database System but start service (sapstartsrv) instead 43 | nostart={{SOOS_HDB_RENAME}} 44 | 45 | # Installation Path 46 | sapmnt={{SOOS_HDB_BASE_DIR}}/shared 47 | 48 | # Source System ID 49 | source_sid={{SID}} 50 | 51 | # Host Name 52 | hostmap={{SRC_HOST}}={{SOOS_HDB_HOST}} 53 | 54 | # System Usage 55 | system_usage=development 56 | 57 | # Execution Scope 58 | scope=system 59 | 60 | # SAP HANA System is already offline 61 | system_is_offline=n 62 | 63 | # Certificate Host Names 64 | # certificates_hostmap={{SRC_HOST}}={{SOOS_HDB_HOST}} 65 | certificates_hostmap={{SOOS_HDB_HOST}}={{SOOS_HDB_HOST}} 66 | 67 | # Target System ID 68 | target_sid={{SID}} 69 | 70 | # Target Instance Number 71 | number={{INST_NO}} 72 | 73 | # Location of Data Volumes 74 | datapath={{SOOS_HDB_BASE_DATA_DIR}}/data/{{SID}} 75 | 76 | # Location of Log Volumes 77 | logpath={{SOOS_HDB_BASE_LOG_DIR}}/log/{{SID}} 78 | 79 | # Location of Data Backups 80 | databackuppath={{SOOS_HDB_BASE_DIR}}/shared/{{SID}}/HDB{{INST_NO}}/backup/data 81 | 82 | # Location of Log Backups 83 | logbackuppath={{SOOS_HDB_BASE_DIR}}/shared/{{SID}}/HDB{{INST_NO}}/backup/log 84 | 85 | # Location of Catalog Backups 86 | catalogbackuppath={{SOOS_HDB_BASE_DIR}}/shared/{{SID}}/HDB{{INST_NO}}/backup/log 87 | 88 | # Init Existing Home Directory of System Administrator () 89 | init_user_home_dir=n 90 | 91 | # System Administrator Home Directory 92 | home={{SIDADM_HOME}} 93 | 94 | # System Administrator Login Shell 95 | shell={{SIDADM_SHELL}} 96 | 97 | # System Administrator User ID 98 | userid={{SIDADM_UID}} 99 | 100 | # ID of User Group (sapsys) 101 | groupid={{SAPSYS_GID}} 102 | 103 | # Do not Modify '/etc/sudoers' File 104 | skip_modify_sudoers=n 105 | 106 | # Do not Remove XS Advanced OS Users 107 | keep_xs_os_users=n 108 | 109 | # Change the password of the System Database user 110 | change_system_user_password=n 111 | 112 | # Restart system after machine reboot? 113 | autostart=n 114 | -------------------------------------------------------------------------------- /openshift/images/hdb/image-content/soos-stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | # Stop Instances 20 | #su - ${SOOS_HDB_SID,,}adm -c "HDB stop" 21 | -------------------------------------------------------------------------------- /openshift/images/hdb/image-content/soos.service: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | [Unit] 18 | Description=Startup service for SAP HANA 19 | Wants=network.target network-online.target 20 | After=network.target network-online.target 21 | 22 | [Service] 23 | Type=oneshot 24 | EnvironmentFile=/etc/sysconfig/soos/soos-env 25 | ExecStart=/root/soos-start.sh 26 | RemainAfterExit=true 27 | ExecStop=/root/soos-stop.sh 28 | TimeoutSec=6000 29 | Restart=no 30 | 31 | [Install] 32 | WantedBy=multi-user.target 33 | -------------------------------------------------------------------------------- /openshift/images/init/containerfile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | FROM registry.access.redhat.com/ubi8/ubi-init:latest 18 | 19 | # Install packages needed for image build 20 | 21 | RUN dnf -y install --setopt=install_weak_deps=False util-linux-user 22 | 23 | # Install packages needed for container operation 24 | 25 | RUN dnf -y install --setopt=install_weak_deps=False csh hostname 26 | 27 | # Copy and enable shell script 28 | 29 | COPY ./soos-create-envdir.sh /root/ 30 | 31 | RUN chmod +x /root/soos-create-envdir.sh 32 | 33 | CMD /root/soos-create-envdir.sh 34 | -------------------------------------------------------------------------------- /openshift/images/init/image-content/soos-create-envdir.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | # Write env-file with variables for all instances 20 | env | grep SOOS_GLOBAL | sort > /root/global-env 21 | 22 | # Write env-file for both ASCS and DI instance 23 | env | grep SOOS_NWS4 | sort > /root/nws4-env 24 | 25 | # Write env-file for ASCS instance 26 | env | grep SOOS_ASCS | sort > /root/ascs-env 27 | 28 | sed -e "s/SOOS_ASCS_PROFILE/SOOS_NWS4_PROFILE/g" \ 29 | -e "s/SOOS_ASCS_INSTNO/SOOS_NWS4_INSTNO/g" \ 30 | -e "1iSOOS_NWS4_INSTTYPE=ASCS" \ 31 | /root/ascs-env > /root/ascs-env-mod 32 | 33 | cat /root/global-env /root/nws4-env /root/ascs-env-mod > /envdir-ascs/soos-env 34 | 35 | # Write env-file for DI instance 36 | env | grep SOOS_DI | sort > /root/di-env 37 | 38 | sed -e "s/SOOS_DI_PROFILE/SOOS_NWS4_PROFILE/g" \ 39 | -e "s/SOOS_DI_INSTNO/SOOS_NWS4_INSTNO/g" \ 40 | -e "1iSOOS_NWS4_INSTTYPE=DI" \ 41 | /root/di-env > /root/di-env-mod 42 | 43 | cat /root/global-env /root/nws4-env /root/di-env-mod > /envdir-di/soos-env 44 | 45 | # Write env-file for HDB instance 46 | env | grep SOOS_HDB | sort > /root/hdb-env 47 | cat /root/global-env /root/hdb-env > /envdir-hdb/soos-env 48 | -------------------------------------------------------------------------------- /openshift/images/nws4/containerfile.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | FROM registry.access.redhat.com/ubi8/ubi-init:latest 18 | 19 | # label 20 | 21 | LABEL soos.containerfile.description="{{IMAGE_DESCRIPTION}}" \ 22 | soos.containerfile.date="{{IMAGE_DATE}}" \ 23 | soos.containerfile.version="{{IMAGE_VERSION}}" \ 24 | soos.containerfile.commit="{{IMAGE_COMMIT}}" \ 25 | soos.containerfile.branch="{{IMAGE_BRANCH}}" 26 | 27 | #RUN dnf -y makecache 28 | 29 | RUN \ 30 | # Install packages needed for image build 31 | dnf -y install --setopt=install_weak_deps=False util-linux-user && \ 32 | # Install packages needed for container operation 33 | dnf -y install --setopt=install_weak_deps=False csh hostname && \ 34 | # Install prerequisite packages for running SAP products (SAP Note #2772999) 35 | dnf -y install --setopt=install_weak_deps=False uuidd libnsl tcsh psmisc nfs-utils bind-utils && \ 36 | # Need to be installed for SAP HANA 37 | dnf -y install --setopt=install_weak_deps=False expect graphviz iptraf-ng krb5-workstation libatomic libcanberra-gtk2 libibverbs libicu libpng12 libssh2 lm_sensors numactl PackageKit-gtk3-module xorg-x11-xauth && \ 38 | # Need to be installed for the "Server" environment group 39 | dnf -y install --setopt=install_weak_deps=False cairo libaio krb5-libs net-tools openssl rsyslog sudo xfsprogs && \ 40 | dnf -y clean all 41 | 42 | # Create needed users and groups 43 | 44 | RUN groupadd --gid {{SAPSYS_GID}} sapsys && \ 45 | useradd --no-create-home --uid {{SAPADM_UID}} --gid {{SAPSYS_GID}} --comment "{{SAPADM_COMMENT}}" --home-dir {{SAPADM_HOME}} --shell {{SAPADM_SHELL}} sapadm && \ 46 | useradd --no-create-home --uid {{SIDADM_UID}} --gid {{SAPSYS_GID}} --comment "{{SIDADM_COMMENT}}" --home-dir {{SIDADM_HOME}} --shell {{SIDADM_SHELL}} {{sid}}adm 47 | 48 | # Copy SAP system related files 49 | 50 | COPY ./etc_services_sap ./etc_security_limits.conf / 51 | COPY --chown={{SIDADM_UID}}:{{SAPSYS_GID}} .{{USR_SAP_REAL}} {{USR_SAP_REAL}}/ 52 | COPY --chown={{SIDADM_UID}}:{{SAPSYS_GID}} .{{SAPMNT}} {{SAPMNT}}/ 53 | # COPY --chown={{SAPADM_UID}}:{{SAPSYS_GID}} .{{SAPADM_HOME}} {{SAPADM_HOME}}/ 54 | COPY --chown={{SIDADM_UID}}:{{SAPSYS_GID}} .{{SIDADM_HOME}} {{SIDADM_HOME}}/ 55 | 56 | # Copy systemd related files 57 | 58 | COPY ./soos.service /etc/systemd/system/ 59 | COPY ./soos-start.sh ./soos-stop.sh /root/ 60 | 61 | # Setup SAP system and and enable required systemd services 62 | 63 | RUN {{USR_SAP_LINK_CMD}} && \ 64 | cat /etc_services_sap >> /etc/services && rm /etc_services_sap && \ 65 | cat /etc_security_limits.conf >> /etc/security/limits.conf && rm /etc_security_limits.conf && \ 66 | mv {{USR_SAP_REAL}}/sapservices {{USR_SAP_REAL}}/sapservices.orig && \ 67 | chown root:{{SAPSYS_GID}} /usr/sap {{USR_SAP_REAL}} {{USR_SAP_REAL}}/sapservices.orig {{SAPMNT}} && \ 68 | chown -R root:{{SAPSYS_GID}} {{USR_SAP_REAL}}/trans && \ 69 | # SJ 20 Aug: remove hostagent 70 | # chown -R {{SAPADM_UID}}:{{SAPSYS_GID}} {{USR_SAP_REAL}}/hostctrl && \ 71 | #chgrp -R {{SAPSYS_GID}} {{USR_SAP_REAL}}/trans && \ 72 | chmod +x /root/soos-start.sh && \ 73 | chmod +x /root/soos-stop.sh && \ 74 | systemctl enable soos && \ 75 | systemctl enable uuidd && \ 76 | systemctl unmask systemd-logind 77 | 78 | # Cleanup 79 | 80 | # XXX TBD 81 | 82 | # Container startup 83 | 84 | # In ubi-init images CMD is /sbin/init by default 85 | # In ubi images we need to specify a CMD 86 | #CMD /root/soos-start.sh && tail -f /dev/null 87 | -------------------------------------------------------------------------------- /openshift/images/nws4/image-content/soos-stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | # Stop Instances 20 | 21 | # for i in $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances | cut -d- -f2); do 22 | echo "Stopping instance $i" 23 | # /usr/sap/hostctrl/exe/sapcontrol -nr "$i" -function Stop 24 | su - ${SOOS_NWS4_SID,,}adm -c "/usr/sap/$SOOS_NWS4_SID/SYS/exe/run/sapcontrol -nr "${SOOS_NWS4_INSTNO}" -function Stop" 25 | # done 26 | -------------------------------------------------------------------------------- /openshift/images/nws4/image-content/soos.service: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2021 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | [Unit] 18 | Description=Startup service for SAP S/4HANA 19 | Wants=network.target network-online.target 20 | After=network.target network-online.target 21 | 22 | [Service] 23 | Type=oneshot 24 | EnvironmentFile=/etc/sysconfig/soos/soos-env 25 | ExecStart=/root/soos-start.sh 26 | RemainAfterExit=true 27 | ExecStop=/root/soos-stop.sh 28 | TimeoutSec=900 29 | 30 | [Install] 31 | WantedBy=multi-user.target 32 | -------------------------------------------------------------------------------- /openshift/secret.yaml.template: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: {{secret-name}} 5 | namespace: {{project}} 6 | type: Opaque 7 | stringData: 8 | HDB_DBUSER: {{User}} 9 | HDB_DBUSERPWD: {{Password}} 10 | -------------------------------------------------------------------------------- /openshift/service-nodeport.yaml.template: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | apiVersion: v1 18 | kind: Service 19 | metadata: 20 | namespace: {{PROJECT}} 21 | name: {{DEPLOYMENT_NAME}}-np 22 | spec: 23 | type: NodePort 24 | ports: 25 | - name: di-32xx 26 | port: 32{{NWS4_DI_INSTNO}} 27 | targetPort: 32{{NWS4_DI_INSTNO}} 28 | protocol: TCP 29 | - name: hdb-3xx13 30 | port: 3{{HDB_INSTNO}}13 31 | targetPort: 3{{HDB_INSTNO}}13 32 | protocol: TCP 33 | - name: hdb-3xx15 34 | port: 3{{HDB_INSTNO}}15 35 | targetPort: 3{{HDB_INSTNO}}15 36 | protocol: TCP 37 | selector: 38 | app: {{DEPLOYMENT_NAME}} 39 | -------------------------------------------------------------------------------- /tools/config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Configuration management """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import yaml 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgsParser 30 | from modules.config import Config 31 | from modules.context import getContext 32 | from modules.nestedns import nestedNsToObj 33 | from modules.startup import startup 34 | 35 | except ModuleNotFoundError as mnfex: 36 | from modules.exceptions import setExceptHook 37 | setExceptHook() 38 | raise mnfex 39 | 40 | 41 | # Functions 42 | 43 | def _getArgs(): 44 | """ Get command line arguments """ 45 | parser = getCommonArgsParser( 46 | 'Configuration management' 47 | ) 48 | 49 | parser.add_argument( 50 | '-n', 51 | '--new', 52 | required = False, 53 | action = 'store_true', 54 | help = "Create a new configuration file" 55 | ) 56 | 57 | parser.add_argument( 58 | '-e', 59 | '--edit', 60 | required = False, 61 | action = 'store_true', 62 | help = "Change configuration in an existing configuration file" 63 | ) 64 | 65 | parser.add_argument( 66 | '-d', 67 | '--dump', 68 | required = False, 69 | action = 'store_true', 70 | help = "Dump configuration to stdout" 71 | ) 72 | 73 | parser.add_argument( 74 | '--non-interactive', 75 | required = False, 76 | action = 'store_true', 77 | help = "Perform '-n' and '-e' non-interactively" 78 | ' (reading values from environment)' 79 | ) 80 | 81 | parser.add_argument( 82 | '-s', 83 | '--suppress-descriptions', 84 | required = False, 85 | action = 'store_true', 86 | help = "Don't show detailed descriptions during edit" 87 | ) 88 | 89 | return parser.parse_args() 90 | 91 | 92 | # ---------------------------------------------------------------------- 93 | 94 | def _main(): 95 | 96 | ctx = getContext(_getArgs(), withCreds=True, withConfig=False) 97 | 98 | if ctx.ar.new: 99 | config = Config(ctx, create=True, failOnDiscoveryError=False) 100 | else: 101 | config = Config(ctx, create=False, failOnDiscoveryError=False) 102 | 103 | if ctx.ar.new: 104 | config.create(ctx.ar.suppress_descriptions) 105 | 106 | elif ctx.ar.edit: 107 | config.edit(ctx.ar.suppress_descriptions) 108 | 109 | elif ctx.ar.dump: 110 | print(yaml.dump(nestedNsToObj(config.get()))) 111 | 112 | else: 113 | print('\nUse option\n\n' 114 | " '-n' to create a new configuration file\n" 115 | " '-e' to edit an existing configuration file\n" 116 | " '-d' to dump an existing configuration file\n" 117 | " '-h' to get more help\n\n" 118 | "NEVER CHANGE FILE 'config.yaml.template'" 119 | " - OTHERWISE THIS TOOL WON'T WORK AS EXPECTED\n") 120 | 121 | 122 | # ---------------------------------------------------------------------- 123 | 124 | if __name__ == '__main__': 125 | startup(_main) 126 | -------------------------------------------------------------------------------- /tools/creds: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Credentials management """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import yaml 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgsParser 30 | from modules.context import getContext 31 | from modules.creds import Creds 32 | from modules.nestedns import nestedNsToObj 33 | from modules.startup import startup 34 | 35 | except ModuleNotFoundError as mnfex: 36 | from modules.exceptions import setExceptHook 37 | setExceptHook() 38 | raise mnfex 39 | 40 | 41 | # Functions 42 | 43 | def _getArgs(): 44 | """ Get command line arguments """ 45 | parser = getCommonArgsParser( 46 | 'Credentials management' 47 | ) 48 | 49 | parser.add_argument( 50 | '-n', 51 | '--new', 52 | required = False, 53 | action = 'store_true', 54 | help = "Create a new credentials file" 55 | ) 56 | 57 | parser.add_argument( 58 | '-e', 59 | '--edit', 60 | required = False, 61 | action = 'store_true', 62 | help = "Change credentials in an existing credentials file" 63 | ) 64 | 65 | parser.add_argument( 66 | '-d', 67 | '--dump', 68 | required = False, 69 | action = 'store_true', 70 | help = "Dump credentials to stdout (DISPLAYS SECRETS IN CLEAR TEXT)" 71 | ) 72 | 73 | parser.add_argument( 74 | '--non-interactive', 75 | required = False, 76 | action = 'store_true', 77 | help = "Perform '-n' and '-e' non-interactively" 78 | ' (reading values from environment)' 79 | ) 80 | 81 | parser.add_argument( 82 | '-s', 83 | '--suppress-descriptions', 84 | required = False, 85 | action = 'store_true', 86 | help = "Don't show detailed descriptions during edit" 87 | ) 88 | 89 | parser.add_argument( 90 | '-u', 91 | '--unencrypted', 92 | required = False, 93 | default = False, 94 | action = 'store_true', 95 | help = "If '-n' is specified: Don't encrypt a newly" 96 | ' created credentials file' 97 | ) 98 | 99 | parser.add_argument( 100 | '-r', 101 | '--recipient', 102 | metavar = '', 103 | required = False, 104 | default = None, 105 | help = "If '-n' is specified and '-u' is not specified:" 106 | ' Owner e-mail address or key fingerprint of GPG key' 107 | ' which will be used for encrypting a newly created' 108 | ' credentials file. If not specified, symmetric AES256' 109 | ' encryption is used.' 110 | ) 111 | 112 | return parser.parse_args() 113 | 114 | 115 | # ---------------------------------------------------------------------- 116 | 117 | def _main(): 118 | 119 | ctx = getContext(_getArgs(), withCreds=False, withConfig=False) 120 | 121 | if ctx.ar.new: 122 | creds = Creds(ctx, create=True) 123 | else: 124 | creds = Creds(ctx, create=False) 125 | 126 | if ctx.ar.new: 127 | creds.create(ctx.ar.suppress_descriptions) 128 | 129 | elif ctx.ar.edit: 130 | creds.edit(ctx.ar.suppress_descriptions) 131 | 132 | elif ctx.ar.dump: 133 | print(yaml.dump(nestedNsToObj(creds.get(), hideSecrets=False))) 134 | 135 | else: 136 | print('\nUse option\n\n' 137 | " '-n' to create a new credentials file\n" 138 | " '-e' to edit an existing credentials file\n" 139 | " '-d' to dump an existing credentials file (DISPLAYS SECRETS IN CLEAR TEXT)\n" 140 | " '-h' to get more help\n\n" 141 | "NEVER CHANGE FILE 'creds.yaml.template'" 142 | " - OTHERWISE THIS TOOL WON'T WORK AS EXPECTED\n") 143 | 144 | 145 | # ---------------------------------------------------------------------- 146 | 147 | if __name__ == '__main__': 148 | startup(_main) 149 | -------------------------------------------------------------------------------- /tools/gpg-key-gen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Generate a GPG private / public key pair """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import getpass 26 | import os 27 | import pwd 28 | import socket 29 | import sys 30 | 31 | import gnupg 32 | 33 | # Local modules 34 | 35 | from modules.args import getCommonArgs 36 | from modules.context import getContext 37 | from modules.logger import logging 38 | from modules.startup import startup 39 | 40 | except ModuleNotFoundError as mnfex: 41 | from modules.exceptions import setExceptHook 42 | setExceptHook() 43 | raise mnfex 44 | 45 | 46 | # Functions 47 | 48 | 49 | # ---------------------------------------------------------------------- 50 | 51 | def _main(): 52 | 53 | getContext(getCommonArgs( 54 | 'Generate a GPG private / public key pair' 55 | ), withCreds=False, withConfig=False) 56 | 57 | user = getpass.getuser() 58 | host = socket.gethostname() 59 | gecos = pwd.getpwnam(user).pw_gecos 60 | 61 | recipient = f'{user}@{host}' 62 | 63 | gpg = gnupg.GPG() 64 | 65 | logging.getLogger("gnupg").setLevel(logging.ERROR) 66 | 67 | # Set gpg tty to make console pinentry reliably working 68 | 69 | try: 70 | # os.ttyname() fails when we are not running interactivly 71 | os.environ['GPG_TTY'] = os.ttyname(sys.stdin.fileno()) 72 | except OSError: 73 | logging.info('Not setting GPG_TTY environment variable') 74 | 75 | # Generate the key 76 | 77 | key = gpg.gen_key(gpg.gen_key_input( 78 | key_type = 'RSA', 79 | key_length = 3072, 80 | name_real = gecos, 81 | name_comment = 'GPG key for SAP on OCP', 82 | name_email = recipient 83 | )) 84 | 85 | print(f"\nGenerated GPG private / public key pair for recipient '{recipient}'\n\n" 86 | f"Run\n\n" 87 | f" gpg --list-keys\n\n" 88 | f"to list your GPG keys.\n\n" 89 | f"Run\n\n" 90 | f" KEY={key}\n" 91 | f" gpg --delete-secret-key ${{KEY}} && gpg --delete-key ${{KEY}}\n\n" 92 | f"to remove the secret and public key from your keyring\n") 93 | 94 | 95 | # ---------------------------------------------------------------------- 96 | 97 | if __name__ == '__main__': 98 | startup(_main) 99 | -------------------------------------------------------------------------------- /tools/image-build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Build a container image of a given flavor """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgImageFlavor, 31 | getCommonArgsParser 32 | ) 33 | from modules.command import CmdShell 34 | from modules.context import getContext 35 | from modules.imagebuilder import getBuilder 36 | from modules.startup import startup 37 | from modules.tools import pushd 38 | 39 | except ModuleNotFoundError as mnfex: 40 | from modules.exceptions import setExceptHook 41 | setExceptHook() 42 | raise mnfex 43 | 44 | 45 | # Functions 46 | 47 | def _getArgs(): 48 | """ Get command line arguments """ 49 | parser = getCommonArgsParser( 50 | 'Build a container image of a given flavor' 51 | ) 52 | 53 | addArgImageFlavor(parser) 54 | 55 | parser.add_argument( 56 | '-t', 57 | '--temp-root', 58 | metavar = '', 59 | required = False, 60 | default = '/data/tmp', 61 | help = "Use as root for temporary files generated during build") 62 | 63 | parser.add_argument( 64 | '-d', 65 | '--build-directory', 66 | metavar = '', 67 | required = False, 68 | help = "Use as build directory; " 69 | "if not specified, a new build directory is created under ''") 70 | 71 | parser.add_argument( 72 | '-k', 73 | '--keep-files', 74 | required = False, 75 | action = 'store_true', 76 | help = "Keep existing files in which were copied from in a " 77 | "previous run; has no effect if '-d' is not specified" 78 | ) 79 | 80 | return parser.parse_args() 81 | 82 | 83 | # ---------------------------------------------------------------------- 84 | 85 | def _main(): 86 | 87 | ctx = getContext(_getArgs()) 88 | 89 | if ctx.ar.image_flavor == 'init': 90 | with pushd(f'{ctx.cf.build.repo.root}/openshift/images/init'): 91 | imageName = ctx.cf.images.init.names.local 92 | CmdShell().run(f'podman build -t {imageName} -f ./containerfile ./image-content') 93 | else: 94 | sidU = getattr(ctx.cf.refsys, ctx.ar.image_flavor).sidU 95 | host = getattr(ctx.cf.refsys, ctx.ar.image_flavor).host.name 96 | user = getattr(ctx.cr.refsys, ctx.ar.image_flavor).sidadm 97 | 98 | getBuilder(ctx).buildImage(sidU, host, user) 99 | 100 | 101 | # ---------------------------------------------------------------------- 102 | 103 | if __name__ == '__main__': 104 | startup(_main) 105 | -------------------------------------------------------------------------------- /tools/image-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Push a container image of a given flavor to the internal cluster registry """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgImageFlavor, 31 | getCommonArgsParser 32 | ) 33 | from modules.command import CmdShell 34 | from modules.context import getContext 35 | from modules.ocp import Ocp 36 | from modules.startup import startup 37 | 38 | except ModuleNotFoundError as mnfex: 39 | from modules.exceptions import setExceptHook 40 | setExceptHook() 41 | raise mnfex 42 | 43 | 44 | # Functions 45 | 46 | def _getArgs(): 47 | """ Get command line arguments """ 48 | parser = getCommonArgsParser( 49 | 'Push a container image of a given flavor to the internal cluster registry' 50 | ) 51 | 52 | addArgImageFlavor(parser) 53 | 54 | return parser.parse_args() 55 | 56 | 57 | def _tagImage(ctx, flavor): 58 | names = getattr(ctx.cf.images, flavor).names 59 | CmdShell().run(f'podman tag {names.local} {names.ocp}') 60 | 61 | 62 | def _pushImage(ctx, flavor): 63 | names = getattr(ctx.cf.images, flavor).names 64 | cmd = 'podman push' 65 | cmd += ' --tls-verify=false' 66 | cmd += f' {names.ocp}' 67 | CmdShell().run(cmd) 68 | 69 | 70 | # ---------------------------------------------------------------------- 71 | 72 | def _main(): 73 | 74 | ctx = getContext(_getArgs()) 75 | 76 | ocp = Ocp(ctx) 77 | 78 | ocp.podmanOcpRegistryLogin() 79 | 80 | _tagImage(ctx, ctx.ar.image_flavor) 81 | 82 | _pushImage(ctx, ctx.ar.image_flavor) 83 | 84 | del ocp 85 | 86 | 87 | # ---------------------------------------------------------------------- 88 | 89 | if __name__ == '__main__': 90 | startup(_main) 91 | -------------------------------------------------------------------------------- /tools/modules/__init__.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Init file for package 'modules' """ 18 | 19 | # DO NOT ERASE THIS FILE 20 | -------------------------------------------------------------------------------- /tools/modules/argsdoc.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Generate documentation from CLI command definitions """ 18 | 19 | 20 | # Global modules 21 | 22 | import argparse 23 | import html 24 | import sys 25 | 26 | 27 | # Classes 28 | 29 | # The follwowing classes partly rely on internal 30 | # implementation details of the Python argparse module 31 | # 32 | # See https://github.com/python/cpython/blob/main/Lib/argparse.py 33 | 34 | # The following classes were inspired by the GitHub Gist 35 | # 36 | # https://gist.githubusercontent.com/parajain/772e138f7604c0ecb7e57898e45a903a/raw/e7e8e4d5544e337cbfa1ec527d093e287da23045/generate_doc.py 37 | # 38 | # This Gist contains the following note: 39 | # 40 | # > MARKDOWN boilerplate 41 | # > 42 | # > Copyright 2016 The Chromium Authors. All rights reserved. 43 | # > Use of this source code is governed by a BSD-style license that can be 44 | # > found in the LICENSE file. 45 | # 46 | # XXX TO BE SOLVED BEFORE PUBLICATION ON github.com: 47 | # - DO WE HAVE TO MENTION THE GIST SINCE THE CODE WAS CONSIDERABLY CHANGED? 48 | # - IF YES, WHAT DO WE HAVE TO DO IN DETAIL TO FULFILL THE ABOVE COPYRIGHT STATEMENT 49 | 50 | 51 | class ArgsDocsGfmAction(argparse.Action): 52 | """ Python argparse action for generating a 53 | GitHub Flavored Markdown (GFM) document snippet """ 54 | 55 | def __call__(self, parser, namespace, values, option_string=None): 56 | 57 | parser.formatter_class = _ArgsDocsGfmFormatter 58 | 59 | # Format the GFM snippet from the argparse definitions 60 | 61 | gfm = parser.format_help() 62 | 63 | # Remove trailing ':' at end of table definition line 64 | # emitted by argparse._Section().format_help() 65 | # There seems to be no other was of getting rid of the ':' 66 | 67 | gfm = gfm.replace(':--------|:\n', ':--------|\n') 68 | 69 | print(gfm) 70 | 71 | sys.exit(0) 72 | 73 | 74 | class _ArgsDocsGfmFormatter(argparse.HelpFormatter): 75 | """ Python argparse help formatter for generating a 76 | GitHub Flavored Markdown (GFM) document snippet """ 77 | 78 | def format_help(self): 79 | # Generate GFM snippet by means of parent class formatter 80 | # Prepend GFM heading 81 | 82 | return f'## Tool `{self._prog}`\n\n{super().format_help()}' 83 | 84 | def _format_usage(self, usage, actions, groups, prefix): 85 | # Generate GFM for usage section by means of parent class formatter 86 | 87 | usage = super()._format_usage(usage, actions, groups, prefix='') 88 | 89 | # Trim the received string by removing all unwanted whitespaces 90 | 91 | usage = ' '.join(s.strip() for s in usage.split()) 92 | 93 | # Prepend the heading for the 'Usage' section 94 | # Also append the heading for the 'Purpose' section since there 95 | # seems to be no other way to get it into the final GFM snippet 96 | 97 | usage = f'### Usage\n\n`{usage}`\n\n### Purpose\n\n' 98 | 99 | return usage 100 | 101 | def start_section(self, heading): 102 | # Formatter for head of each section 103 | # 'heading': 'positional arguments', 'optional arguments', ... 104 | 105 | # Capitalize the first character of each word in heading 106 | # and HTML escape the heading 107 | 108 | heading = ' '.join(s.capitalize() for s in heading.split()) 109 | heading = html.escape(heading) 110 | 111 | # Start the section by means of the parent class formatter 112 | # Pass the table head in addition to the heading 113 | 114 | super().start_section( 115 | f'### {heading}\n' 116 | f'\n' 117 | f'| Argument | Description | Default |\n' 118 | f'|:---------|:------------|:--------|' 119 | ) 120 | 121 | def _format_action(self, action): 122 | # Formatter for a single CLI argument 123 | 124 | argument = f'`{super()._format_action_invocation(action)}`' 125 | description = html.escape(self._expand_help(action)) 126 | default = f'`{action.default}`' if action.default != argparse.SUPPRESS else '' 127 | 128 | return f'| {argument} | {description} | {default} |\n' 129 | -------------------------------------------------------------------------------- /tools/modules/constants.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Constants """ 18 | 19 | 20 | # Global modules 21 | 22 | import types 23 | 24 | 25 | # Functions 26 | 27 | def getConstants(): 28 | """ Get constants """ 29 | const = types.SimpleNamespace() 30 | 31 | # Constants for config.yaml file handling 32 | const.configCacheTimeout = 600 # seconds 33 | 34 | # optional packages to be installed depending on the SPS Level of the HANA DB 35 | 36 | compatSapPkg9 = types.SimpleNamespace() 37 | 38 | compatSapPkg9.minSpsLevel = 50 39 | compatSapPkg9.maxSpsLevel = 59 40 | # packageName is part of the package metadata, it is not the rpm filename 41 | compatSapPkg9.packageName = "compat-sap-c++-9" 42 | compatSapPkg9.dependencies = ["libgomp"] 43 | compatSapPkg9.distribution = "rhel" 44 | compatSapPkg9.repository = "rhel-8-for-ppc64le-sap-netweaver-rpms" 45 | 46 | compatSapPkg10 = types.SimpleNamespace() 47 | 48 | compatSapPkg10.minSpsLevel = 60 49 | compatSapPkg10.maxSpsLevel = 69 50 | # packageName is part of the package metadata, it is not the rpm filename 51 | compatSapPkg10.packageName = "compat-sap-c++-10" 52 | compatSapPkg10.dependencies = ["libgomp"] 53 | compatSapPkg10.distribution = "rhel" 54 | compatSapPkg10.repository = "rhel-8-for-ppc64le-sap-netweaver-rpms" 55 | 56 | const.optionalHdbPkgs = [compatSapPkg9, compatSapPkg10] 57 | 58 | # default location for packages to be downloaded 59 | const.defaultPackagesDir = "/tmp/soos/rpm-packages" 60 | 61 | # additional free space to be added for HANA DB 62 | const.additionalFreeSpaceHdbGiB = 5 63 | # minimum memory size of Dialog Instance Container 64 | const.minMemSizeDIGiB = 32 65 | 66 | # length of the uuid 67 | # uuid is used for overlay fs name, deployment file name and deployment app name 68 | const.uuidLen = 10 69 | 70 | # HA Proxy configuration file 71 | const.haproxyCfg = '/etc/haproxy/haproxy.cfg' 72 | 73 | # Constants for argument names 74 | const.argAdd = 'add' 75 | const.argAppName = 'app-name' 76 | const.argConfigFile = 'config-file' 77 | const.argContainerFlavor = 'container-flavor' 78 | const.argCredsFile = 'creds-file' 79 | const.argDeploymentFile = 'deployment-file' 80 | const.argDumpContext = 'dump-context' 81 | const.argGenDocGfm = 'gen-doc-gfm' 82 | const.argGenYaml = 'gen-yaml' 83 | const.argImageFlavor = 'image-flavor' 84 | const.argList = 'list' 85 | const.argLogFileDir = 'logfile-dir' 86 | const.argLogLevel = 'loglevel' 87 | const.argLogToTerminal = 'log-to-terminal' 88 | const.argLoop = 'loop' 89 | const.argNumber = 'number' 90 | const.argOutputFile = 'output-file' 91 | const.argOverlayUuid = 'overlay-uuid' 92 | const.argRemove = 'remove' 93 | const.argSleepTime = 'sleep-time' 94 | const.argStart = 'start' 95 | const.argStop = 'stop' 96 | 97 | # Constants for different deployment types 98 | const.deployAll = 'all' 99 | const.deployRunning = 'running' 100 | const.deployDeployed = 'deployed' 101 | const.deployNotDeployed = 'not deployed' 102 | 103 | return const 104 | -------------------------------------------------------------------------------- /tools/modules/context.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Context """ 18 | 19 | 20 | # Global modules 21 | 22 | import sys 23 | import types 24 | import yaml 25 | 26 | 27 | # Local modules 28 | 29 | from modules.config import Config 30 | from modules.creds import Creds 31 | from modules.constants import getConstants 32 | from modules.fail import fail 33 | from modules.logger import setupLogging 34 | from modules.nestedns import nestedNsToObj 35 | 36 | 37 | # Functions 38 | 39 | def _printHeader(msg): 40 | sep = '-' * len(msg) 41 | print(f'# {sep}\n# {msg}\n# {sep}\n') 42 | 43 | 44 | def getContext(args, withCreds=True, withConfig=True, failOnDiscoveryError=True): 45 | """ Get context """ 46 | 47 | setupLogging(args) 48 | 49 | ctx = types.SimpleNamespace() 50 | 51 | ctx.ar = args 52 | ctx.cr = None 53 | ctx.cf = None 54 | ctx.cs = getConstants() 55 | 56 | if withCreds: 57 | ctx.creds = Creds(ctx) 58 | ctx.cr = ctx.creds.get() 59 | if withConfig: 60 | ctx.config = Config(ctx, failOnDiscoveryError=failOnDiscoveryError) 61 | ctx.cf = ctx.config.getFull() 62 | elif withConfig: 63 | fail("Can't get configuration without credentials") 64 | 65 | if args.dump_context: 66 | _printHeader('COMMAND LINE ARGUMENTS') 67 | print(yaml.dump({'ar': nestedNsToObj(ctx.ar)})) 68 | _printHeader('CREDENTIALS') 69 | print(yaml.dump({'cr': nestedNsToObj(ctx.cr)})) 70 | _printHeader('CONFIGURATION') 71 | print(yaml.dump({'cf': nestedNsToObj(ctx.cf)})) 72 | sys.exit(0) 73 | 74 | return ctx 75 | -------------------------------------------------------------------------------- /tools/modules/exceptions.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Exceptions """ 18 | 19 | 20 | # Global modules 21 | 22 | import sys 23 | 24 | 25 | # Local modules 26 | 27 | from modules.messages import getMessage 28 | from modules.times import ( 29 | saveCurrentTime, 30 | printTimes 31 | ) 32 | 33 | 34 | # Classes 35 | 36 | class RpmFileNotFoundException(Exception): 37 | """ Raises if RPM File for specific package could not be found """ 38 | 39 | def __init__(self, path, packageName, err): 40 | super().__init__() 41 | self.errorText = getMessage("msgE001", path, packageName, err) 42 | 43 | 44 | # Functions 45 | 46 | def setExceptHook(): 47 | """ Set the global exception hook """ 48 | 49 | sys.excepthook = _exceptHook 50 | 51 | 52 | def _exceptHook(extype, exinstance, traceback): 53 | """ Handle an exception depending on the type of the exception """ 54 | 55 | # Print times recorded during program execution 56 | 57 | saveCurrentTime('Exception', traceback) 58 | printTimes(traceback) 59 | 60 | # Handle exception 61 | 62 | if extype == KeyboardInterrupt: 63 | _exceptHookKeyboardInterrupt(extype, exinstance, traceback) 64 | 65 | elif extype == ModuleNotFoundError: 66 | _exceptHookModuleNotFoundError(extype, exinstance, traceback) 67 | 68 | else: 69 | sys.__excepthook__(extype, exinstance, traceback) 70 | 71 | 72 | def _exceptHookKeyboardInterrupt(extype, exinstance, traceback): 73 | # pylint: disable=unused-argument 74 | print() 75 | 76 | 77 | def _exceptHookModuleNotFoundError(extype, exinstance, traceback): 78 | # pylint: disable=unused-argument 79 | hrule = '\n' + '='*50 + '\n' 80 | print(f'{hrule}\n', 81 | f' GOT THE FOLLOWING EXCEPTION:\n\n' 82 | f' {exinstance}\n', 83 | sep = '', 84 | file=sys.stderr 85 | ) 86 | 87 | if sys.prefix != sys.base_prefix: 88 | # Running in a virtual environment 89 | print(' YOUR VIRTUAL PYTHON ENVIRONMENT SEEMS NOT TO BE\n' 90 | ' SET UP AS EXPECTED.\n\n' 91 | ' LEAVE YOUR VIRTUAL ENVIRONMENT BY EXECUTING\n\n' 92 | ' deactivate\n\n' 93 | ' AND REMOVE IT BY EXECUTING\n\n' 94 | ' rm -rf ./venv/\n\n' 95 | ' RECREATE THE VIRTUAL ENVIRONMENT BY RUNNING\n\n' 96 | ' tools/venv-setup\n\n' 97 | ' AND ACTIVATE IT BY EXECUTING\n\n' 98 | ' source ./venv/bin/activate', 99 | file=sys.stderr 100 | ) 101 | 102 | else: 103 | # Not running in a virtual environment 104 | print(' NOT RUNNING IN A VIRTUAL PYTHON ENVIRONMENT.\n\n' 105 | ' CREATE A VIRTUAL PYTHON ENVIRONMENT BY RUNNING\n\n' 106 | ' tools/venv-setup\n\n' 107 | ' AND ACTIVATE IT BY EXECUTING\n\n' 108 | ' source ./venv/bin/activate\n\n' 109 | ' OR MAKE SURE THAT YOUR CURRENT PYTHON RUNTIME\n' 110 | ' ENVIRONMENT PROVIDES ALL REQUIRED PYTHON MODULES\n' 111 | " (SEE ERROR MESSAGE ABOVE).", 112 | file=sys.stderr 113 | ) 114 | 115 | print(hrule, file=sys.stderr) 116 | -------------------------------------------------------------------------------- /tools/modules/fail.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Helper tools """ 18 | 19 | 20 | # Global modules 21 | 22 | import logging 23 | import sys 24 | 25 | 26 | # Local modules 27 | 28 | from modules.times import ( 29 | saveCurrentTime, 30 | printTimes 31 | ) 32 | 33 | 34 | # Functions 35 | 36 | def fail(msg, exitCode=1): 37 | """ Print error message and recorded times and exit """ 38 | logging.error(msg) 39 | print(msg, file=sys.stderr) 40 | 41 | saveCurrentTime('Failure') 42 | printTimes() 43 | 44 | sys.exit(exitCode) 45 | 46 | 47 | def warn(msg): 48 | """ Print warning message but don't exit """ 49 | logging.warning(msg) 50 | print(msg, file=sys.stderr) 51 | -------------------------------------------------------------------------------- /tools/modules/logger.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Logging setup """ 18 | 19 | 20 | # Global modules 21 | 22 | import logging 23 | import os 24 | import sys 25 | import time 26 | 27 | 28 | # Functions 29 | 30 | def _getScriptName(): 31 | scriptName = os.path.basename(sys.argv[0]) 32 | if scriptName.endswith('.py'): 33 | scriptName = scriptName[:-3] 34 | return scriptName 35 | 36 | 37 | def _getLogFilePath(logfileDir, infix=''): 38 | prefix = _getScriptName() 39 | if len(infix) > 0: 40 | prefix += '-'+infix 41 | return f'{logfileDir}/{prefix}-{str(time.time()).replace(".","")}.log' 42 | 43 | 44 | def setupLogging(args, infix=''): 45 | """ Set up logging """ 46 | 47 | # Delete existing root handlers 48 | 49 | for handler in logging.root.handlers[:]: 50 | logging.root.removeHandler(handler) 51 | 52 | # Custom formatting 53 | 54 | class _LogRecordFactory(logging.LogRecord): 55 | # pylint: disable=too-few-public-methods 56 | def __init__(self, *args, **kwargs): 57 | super().__init__(*args, **kwargs) 58 | self.origin = f"{self.filename}:{self.funcName}()" 59 | logging.setLogRecordFactory(_LogRecordFactory) 60 | 61 | logFormat = '[{origin:25}] {message}' 62 | 63 | # Configure logging 64 | 65 | loglevel = getattr(logging, args.loglevel.upper()) 66 | 67 | if args.log_to_terminal: 68 | logging.basicConfig(format=logFormat, style='{', level=loglevel) 69 | else: 70 | if not os.path.exists(args.logfile_dir): 71 | os.makedirs(args.logfile_dir) 72 | logFilePath = _getLogFilePath(args.logfile_dir, infix=infix) 73 | logging.basicConfig(format=logFormat, style='{', level=loglevel, 74 | filename=logFilePath, filemode='w') 75 | print(f"Logging to '{logFilePath}'", file=sys.stderr) 76 | -------------------------------------------------------------------------------- /tools/modules/messages.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Helper tools for message formatting """ 18 | 19 | 20 | # Global modules 21 | 22 | import textwrap 23 | 24 | 25 | # Functions 26 | 27 | def formatMessageParagraphs(paragraphs, width, prefix, indentLevel): 28 | """ Format a list of paragraphs """ 29 | return _formatMessage(paragraphs, width, prefix*indentLevel, prefix*indentLevel) 30 | 31 | 32 | def formatMessageList(listItems, width, prefix, indentLevel): 33 | """ Format a list of list items """ 34 | return _formatMessage(listItems, width, prefix*indentLevel+'- ', prefix*indentLevel+' ') 35 | 36 | 37 | def getMessage(*parmList): 38 | """ returns the message text for given message number """ 39 | msgNo = parmList[0] 40 | # First entry in parmList is the msgNo, ignore it! 41 | nmbrOfParmsPassed = len(parmList) - 1 42 | messageText = "" 43 | msgObj = msgList[msgNo] 44 | 45 | if msgObj["noOfParms"] != nmbrOfParmsPassed: 46 | # Throw exception? 47 | return messageText 48 | # Replacing placeholders 49 | for element in msgObj["msg"]: 50 | messageText += _formatMessageElement(element, parmList) 51 | return messageText 52 | 53 | 54 | def _formatMessage(paragraphs, width, initialPrefix, subsequentPrefix): 55 | msg = '' 56 | first = True 57 | for paragraph in paragraphs: 58 | if first: 59 | first = False 60 | else: 61 | msg += '\n' 62 | msg += '\n'.join(textwrap.wrap(paragraph, 63 | width=width, 64 | initial_indent=initialPrefix, 65 | subsequent_indent=subsequentPrefix 66 | ) 67 | ) 68 | return msg 69 | 70 | 71 | def _formatMessageElement(element, parmList): 72 | if "index" in element.keys(): 73 | return element["msg"].format(parmList[element["index"]]) 74 | return element["msg"] 75 | 76 | 77 | def _setNumberOfParms(msgObj): 78 | highestNo = 0 79 | for element in msgObj: 80 | if "index" in element.keys(): 81 | if element["index"] > highestNo: 82 | highestNo = element["index"] 83 | return highestNo 84 | 85 | 86 | # Message definitions 87 | 88 | # Messages printed by logging 89 | 90 | # parmList: 91 | # 1: type of the resource (limits/requests) 92 | # 2: containerType 93 | # 3: memory size 94 | msgL001 = [{"msg": "Caution: You did not specify a value for the {} ", 95 | "index": 1}, 96 | {"msg": "memory size for the "}, 97 | {"msg": "{} container.\n", 98 | "index": 2}, 99 | {"msg": "The memory size is set to its default value {}.\n", 100 | "index": 3}, 101 | {"msg": "If the 'limits' memory size is smaller than the value "}, 102 | {"msg": "of the 'requested' memory size, \n"}, 103 | {"msg": "the generation of the deployment will fail "}, 104 | {"msg": "and the process is stopped. \n"}, 105 | {"msg": "Use the 'verify-config' tool to make sure "}, 106 | {"msg": "that your memory settings are valid.\n"}] 107 | 108 | # Messages printed by Exceptions 109 | 110 | # parmList: 111 | # 1: path to rpm file 112 | # 2: packageName 113 | # 3: additional error text 114 | msgE001 = [{"msg": "The default package file path '{}' ", 115 | "index": 1}, 116 | {"msg": "{} \n", 117 | "index": 3}, 118 | {"msg": "Provide the rpm package file for package '{}' ", 119 | "index": 2}, 120 | {"msg": "at the local directory {}. \n", 121 | "index": 1}, 122 | {"msg": "For more information about additionally required RPM packages "}, 123 | {"msg": "see the documentation."}] 124 | 125 | # parmList: 126 | # 1: limits memory size 127 | # 2: containerType 128 | # 3: requests memory size 129 | msgE002 = [{"msg": "The specified 'limits' memory value {} ", 130 | "index": 1}, 131 | {"msg": "for the {} container \n", 132 | "index": 2}, 133 | {"msg": "is less than the specified 'requests' memory value {}.\n", 134 | "index": 3}, 135 | {"msg": "The Container cannot be started."}] 136 | 137 | msgList = {"msgE001": {"msg": msgE001, "noOfParms": _setNumberOfParms(msgE001)}, 138 | "msgE002": {"msg": msgE002, "noOfParms": _setNumberOfParms(msgE002)}, 139 | "msgL001": {"msg": msgL001, "noOfParms": _setNumberOfParms(msgL001)} 140 | } 141 | -------------------------------------------------------------------------------- /tools/modules/nestedns.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Implementation of nested namespaces based on types.SimpleNamespace """ 18 | 19 | 20 | # Global modules 21 | 22 | import argparse 23 | import types 24 | 25 | 26 | # Local modules 27 | 28 | # None 29 | 30 | 31 | # Functions 32 | 33 | def objToNestedNs(obj): 34 | """ Convert an object into a (potentially) nested namespaces """ 35 | 36 | if isinstance(obj, dict): 37 | nnObj = {} 38 | for k, v in obj.items(): # pylint: disable=invalid-name 39 | nnObj[k] = objToNestedNs(v) 40 | nestedNs = types.SimpleNamespace(**nnObj) 41 | 42 | elif isinstance(obj, list): 43 | nestedNs = [] 44 | for i in obj: 45 | nestedNs.append(objToNestedNs(i)) 46 | 47 | else: 48 | nestedNs = obj 49 | 50 | return nestedNs 51 | 52 | 53 | def nestedNsToObj(nestedNs, hideSecrets=True): 54 | """ Convert a (potentially) nested namespaces into an object """ 55 | 56 | if isinstance(nestedNs, (types.SimpleNamespace, argparse.Namespace)): 57 | hideList = [] 58 | if hideSecrets: 59 | hideList += ['password'] 60 | obj = {} 61 | for k in vars(nestedNs).keys(): 62 | if k in hideList: 63 | obj[k] = '' 64 | else: 65 | obj[k] = nestedNsToObj(getattr(nestedNs, k), hideSecrets) 66 | 67 | elif isinstance(nestedNs, list): 68 | obj = [] 69 | for child in nestedNs: 70 | obj.append(nestedNsToObj(child, hideSecrets)) 71 | 72 | else: 73 | obj = nestedNs 74 | 75 | return obj 76 | -------------------------------------------------------------------------------- /tools/modules/nfs-ping-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Ping test from worker node: Get 1st reachable ip address out of a list """ 20 | 21 | import sys 22 | import subprocess 23 | 24 | rtc = 'None' 25 | 26 | if len(sys.argv) > 2: 27 | worker = sys.argv[1] 28 | 29 | for ip in sys.argv[2:]: 30 | 31 | sshcmd = f'ping -c 1 {ip} 2>&1 >/dev/null && echo True || echo False' 32 | cmd = f'ssh core@{worker} {sshcmd}' 33 | 34 | output = subprocess.check_output(f'{cmd}', shell=True).decode("utf-8").split()[0] 35 | if output == 'True': 36 | rtc = ip 37 | break 38 | 39 | print(rtc) 40 | -------------------------------------------------------------------------------- /tools/modules/quantity.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ OCP quantities """ 18 | 19 | # pylint: disable=line-too-long 20 | # See https://docs.openshift.com/container-platform/4.7/rest_api/objects/index.html#quantity-api-resource 21 | 22 | # Global modules 23 | 24 | import logging 25 | import re 26 | 27 | 28 | # Local modules 29 | 30 | from modules.fail import fail 31 | 32 | 33 | # Constants 34 | 35 | _scale = { 36 | '': 1, 37 | 38 | 'K': 1000**1, 39 | 'M': 1000**2, 40 | 'G': 1000**3, 41 | 'T': 1000**4, 42 | 'P': 1000**5, 43 | 'E': 1000**6, 44 | 45 | 'Ki': 1024**1, 46 | 'Mi': 1024**2, 47 | 'Gi': 1024**3, 48 | 'Ti': 1024**4, 49 | 'Pi': 1024**5, 50 | 'Ei': 1024**6, 51 | } 52 | 53 | 54 | # Classes 55 | 56 | class Quantity(): 57 | """ OCP quantities """ 58 | 59 | def __init__(self, quantityStr): 60 | 61 | self._quantityStr = quantityStr if quantityStr else '0' 62 | 63 | # Extract value and scale 64 | 65 | match = re.match(r'\s*(\d+)\s*(\S*)\s*', self._quantityStr) 66 | if not match: 67 | fail(f"Quantity '{self._quantityStr}' format is invalid") 68 | 69 | self._valueInt = int(match.groups()[0]) 70 | self._scale = match.groups()[1] 71 | self._checkScale() 72 | 73 | self._valueIntNormalized = self._valueInt * _scale[self._scale] 74 | 75 | logging.debug(f'({self._quantityStr}, {self._valueInt},' 76 | f' {self._scale}, {self._valueIntNormalized})') 77 | 78 | def __str__(self): 79 | return self._quantityStr 80 | 81 | def __ge__(self, other): 82 | return self._valueIntNormalized >= other._valueIntNormalized 83 | 84 | def __lt__(self, other): 85 | return self._valueIntNormalized < other._valueIntNormalized 86 | 87 | def _checkScale(self): 88 | if self._scale not in _scale.keys(): 89 | fail(f"Unknown scale '{self._scale}' in '{self._quantityStr}'") 90 | 91 | def valueIntScaled(self, scale): 92 | """ returns int value scaled to unit """ 93 | if scale not in _scale.keys(): 94 | fail(f"Unknown scale '{scale}' specified. Cannot continue.") 95 | return self._valueIntNormalized / _scale[scale] 96 | 97 | def valueIntNormalized(self): 98 | """ returns the value normed to bytes """ 99 | return self._valueIntNormalized 100 | -------------------------------------------------------------------------------- /tools/modules/startup.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Common startup sequence for all tools """ 18 | 19 | 20 | # Global Modules 21 | 22 | import sys 23 | 24 | 25 | # Local Modules 26 | 27 | from modules.exceptions import setExceptHook 28 | from modules.times import ( 29 | printTimes, 30 | saveEndTime, 31 | saveStartTime 32 | ) 33 | 34 | 35 | # Functions 36 | 37 | def startup(mainFunc): 38 | """ Execute common startup sequence and start main function """ 39 | 40 | # Handle specifc uncaught exceptions in a particular way 41 | # and print all saved times in case of an uncaught exception 42 | 43 | setExceptHook() 44 | 45 | # Save the program start time 46 | 47 | saveStartTime() 48 | 49 | # Run the program 50 | 51 | retCode = mainFunc() 52 | 53 | # Save the program termination time 54 | 55 | saveEndTime() 56 | 57 | # Print all saved times 58 | 59 | printTimes() 60 | 61 | exitCode = 0 if not retCode else retCode 62 | 63 | sys.exit(exitCode) 64 | -------------------------------------------------------------------------------- /tools/modules/times.py: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------ 2 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ------------------------------------------------------------------------ 16 | 17 | """ Record time stamps during program execution and print them at program termination """ 18 | 19 | 20 | # Global Modules 21 | 22 | import datetime 23 | import inspect 24 | import logging 25 | import types 26 | 27 | 28 | # Local Modules 29 | 30 | from modules.table import Table 31 | 32 | 33 | # Functions 34 | 35 | def saveStartTime(): 36 | """ Save program start time """ 37 | saveCurrentTime('Program Start') 38 | 39 | 40 | def saveEndTime(): 41 | """ Save program termination time """ 42 | saveCurrentTime('Program End') 43 | 44 | 45 | def saveCurrentTime(label, traceback=None): 46 | """ Save current time together with a descriptive label """ 47 | 48 | time = types.SimpleNamespace() 49 | time.label = label 50 | time.time = datetime.datetime.now() 51 | 52 | _getTimes(traceback).append(time) 53 | 54 | 55 | def printTimes(traceback=None): 56 | """ Print all saved times """ 57 | 58 | times = _getTimes(traceback) 59 | 60 | if len(times) > 0: 61 | table = Table(title = 'Elapsed Times', 62 | headings = ['Step', 'Date', 'Time', 'Δt Prev. Step'], 63 | ) 64 | 65 | startTime = times[0].time 66 | prevTime = startTime 67 | 68 | for time in times: 69 | 70 | curTime = time.time 71 | delta = curTime-prevTime if curTime != prevTime else '' 72 | 73 | table.appendRow([time.label, curTime.date(), curTime.time(), delta]) 74 | 75 | prevTime = curTime 76 | 77 | logging.critical(f'\n{table.render()}\n') # Always log times 78 | 79 | 80 | def _getTimes(traceback): 81 | 82 | # We store the times in the local variables section of the main module 83 | # For accessing them we first need to get the frame for the main module 84 | 85 | frame = _getModuleFrame(traceback) 86 | 87 | # Now we can retrieve the times from the local variable section of the main module 88 | 89 | if not frame: 90 | logging.debug("Could not find frame for ''") 91 | times = [] 92 | 93 | else: 94 | timesKey = '_soos_times' 95 | 96 | if timesKey not in frame.f_locals.keys(): 97 | 98 | # This is the first time _getTimes() is called. 99 | # Add an empty times array to the local 100 | # variable section of the main module. 101 | 102 | frame.f_locals[timesKey] = [] 103 | 104 | times = frame.f_locals[timesKey] 105 | 106 | return times 107 | 108 | 109 | def _getModuleFrame(traceback): 110 | 111 | # Get the start frame for searching the main module frame 112 | # See https://docs.python.org/3/library/inspect.html 113 | 114 | if not traceback: 115 | # Retrieve the start frame via inspect() 116 | frame = inspect.currentframe() 117 | 118 | else: 119 | # Retrieve the start frame from the traceback 120 | # See https://www.oreilly.com/library/view/python-cookbook/0596001673/ch14s05.html 121 | 122 | while traceback.tb_next: 123 | traceback = traceback.tb_next 124 | frame = traceback.tb_frame 125 | 126 | # Search the main module frame starting from the start frame 127 | 128 | while frame and frame.f_code.co_name != '': 129 | frame = frame.f_back 130 | 131 | return frame 132 | -------------------------------------------------------------------------------- /tools/nfs-hdb-copy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Copy an SAP HANA DB snapshot to the NFS server """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import logging 26 | from pathlib import Path 27 | 28 | # Local modules 29 | 30 | from modules.args import getCommonArgs 31 | from modules.command import ( 32 | CmdSsh, 33 | CmdShell 34 | ) 35 | from modules.context import getContext 36 | from modules.fail import fail 37 | from modules.nfstools import ( 38 | getHdbCopyBase, 39 | getHdbSubDirs 40 | ) 41 | from modules.startup import startup 42 | from modules.tools import getNumRunningSapProcs 43 | 44 | except ModuleNotFoundError as mnfex: 45 | from modules.exceptions import setExceptHook 46 | setExceptHook() 47 | raise mnfex 48 | 49 | 50 | # Functions 51 | 52 | def _getCopyCmd(cmdSshDb, cmdSshNfs, sourceDir, targetDir): 53 | # Copy using tar shell command running on SAPDBHOST, 54 | # redirecting the output to 55 | # and piping it then to the tar command running on the 56 | # NFS server. 57 | 58 | # ssh command Build Server -> SAPDBHOST 59 | sshDb = cmdSshDb.getSshCmdAndSecrets()[0] 60 | # ssh command Build Server -> NFS Server 61 | sshNfs = cmdSshNfs.getSshCmdAndSecrets()[0] 62 | 63 | tarCmd = f"tar cf - {sourceDir}" 64 | 65 | # --strip-components= is an argument used during extracting the tar file 66 | # Its value is set to the number of existing subdirs of the source to 67 | # strip the number of leading components from the extracted file name 68 | noOfSubdirs = _getNoOfSubdirs(sourceDir) 69 | 70 | untarCmd = f"tar xf - -C {targetDir} --strip-components={noOfSubdirs} --same-owner" 71 | return f"{sshDb} {tarCmd} | {sshNfs} {untarCmd}" 72 | 73 | 74 | def _getNoOfSubdirs(directory): 75 | parentDir = Path(directory) 76 | count = 0 77 | rootDir = parentDir.anchor 78 | while str(parentDir) != str(rootDir): 79 | parentDir = parentDir.parent 80 | count = count+1 81 | return count 82 | 83 | 84 | def _getFileSizeSet(cmdSsh, directory): 85 | cmd = f'cd {directory}; find . -type f -printf "%s %p$"' 86 | result = cmdSsh.run(cmd) 87 | if result.rc != 0: 88 | fail("Error: could not get file list") 89 | 90 | sizeList = result.out.split("$") 91 | sizeSet = set() 92 | for element in sizeList: 93 | sizeSet.add(tuple(element.split(" "))) 94 | return sizeSet 95 | 96 | 97 | def _checkCopyStep(cmdSshDb, cmdSshNfs, sourceDir, targetDir): 98 | sourceSizes = _getFileSizeSet(cmdSshDb, sourceDir) 99 | targetSizes = _getFileSizeSet(cmdSshNfs, targetDir) 100 | 101 | # get differences: 102 | diffs = sourceSizes - targetSizes 103 | 104 | # if the set of diffs is not empty, there is a mismatch between source and target 105 | if len(diffs) > 0: 106 | for obj in diffs: 107 | # obj looks like: [, ] 108 | print(f"Missing file or file with wrong size: {obj[1]} on {targetDir}") 109 | return False 110 | return True 111 | 112 | # ---------------------------------------------------------------------- 113 | 114 | 115 | def _main(): 116 | 117 | ctx = getContext(getCommonArgs( 118 | 'Copy an SAP HANA DB snapshot the NFS server' 119 | )) 120 | 121 | hdbSid = ctx.cf.refsys.hdb.sidU 122 | hdbHost = ctx.cf.refsys.hdb.host 123 | hdbUser = ctx.cr.refsys.hdb.sidadm 124 | 125 | nfsHost = ctx.cf.nfs.host 126 | nfsUser = ctx.cr.nfs.user 127 | cmdSshNfs = CmdSsh(ctx, nfsHost.name, nfsUser) 128 | cmdSshDb = CmdSsh(ctx, hdbHost.name, hdbUser) 129 | 130 | logging.debug('Checking if HDB is stopped') 131 | 132 | # Check if HDB is stopped 133 | 134 | if getNumRunningSapProcs(ctx, 'hdb') != '0': 135 | fail(f"Error: HANA Database '{hdbSid}' is running on host {hdbHost.name}.\n" 136 | f"Stop the database then restart the nfs-hdb-copy step.") 137 | 138 | # Copy HDB content 139 | 140 | for obj in getHdbSubDirs(ctx): 141 | 142 | subDir = obj.path 143 | base = obj.base 144 | sourceDir = f"{base}/{subDir}/{hdbSid}" 145 | targetDir = f"{getHdbCopyBase(ctx)}/{subDir}/{hdbSid}" 146 | 147 | cmdSshNfs.run(f'mkdir -p "{targetDir}"') 148 | 149 | copyCmd = _getCopyCmd(cmdSshDb, cmdSshNfs, sourceDir, targetDir) 150 | 151 | print(f"Copying '{sourceDir}' to '{targetDir}' on host '{ctx.cf.nfs.host.name}'") 152 | CmdShell().run(copyCmd) 153 | 154 | if not _checkCopyStep(cmdSshDb, cmdSshNfs, sourceDir, targetDir): 155 | print(f"Copying '{sourceDir}' to '{targetDir}' was not successful.") 156 | 157 | 158 | # ---------------------------------------------------------------------- 159 | 160 | if __name__ == '__main__': 161 | startup(_main) 162 | -------------------------------------------------------------------------------- /tools/nfs-overlay-list: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ List availabe overlay shares on NFS server """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgs 30 | from modules.context import getContext 31 | from modules.nfstools import Overlays 32 | from modules.startup import startup 33 | 34 | except ModuleNotFoundError as mnfex: 35 | from modules.exceptions import setExceptHook 36 | setExceptHook() 37 | raise mnfex 38 | 39 | 40 | # Functions 41 | 42 | 43 | # ---------------------------------------------------------------------- 44 | 45 | def _main(): 46 | 47 | ctx = getContext(getCommonArgs( 48 | 'List availabe overlay shares on NFS server' 49 | )) 50 | 51 | print("Overlay Share" + " "*32 + "Added at") 52 | print("-"*63) 53 | for overlay in Overlays(ctx).get(): 54 | print(overlay) 55 | 56 | 57 | # ---------------------------------------------------------------------- 58 | 59 | if __name__ == '__main__': 60 | startup(_main) 61 | -------------------------------------------------------------------------------- /tools/nfs-overlay-setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Setup overlay file system on NFS server """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | getCommonArgsParser, 31 | addArgOverlayUuid 32 | ) 33 | from modules.context import getContext 34 | from modules.nfstools import Overlay 35 | from modules.startup import startup 36 | from modules.deployment import Deployment 37 | 38 | except ModuleNotFoundError as mnfex: 39 | from modules.exceptions import setExceptHook 40 | setExceptHook() 41 | raise mnfex 42 | 43 | 44 | # Functions 45 | def _getArgs(): 46 | """ Get command line arguments """ 47 | parser = getCommonArgsParser( 48 | 'Setup overlay file system on NFS server' 49 | ) 50 | addArgOverlayUuid(parser, required = False) 51 | return parser.parse_args() 52 | 53 | 54 | # ---------------------------------------------------------------------- 55 | 56 | def _main(): 57 | 58 | ctx = getContext(_getArgs()) 59 | 60 | overlayUuid = ctx.ar.overlay_uuid 61 | 62 | if not ctx.ar.overlay_uuid: 63 | overlayUuid = Deployment(ctx).get().overlayUuid 64 | 65 | print(f'{Overlay.create(ctx, overlayUuid).uuid}') 66 | 67 | 68 | # ---------------------------------------------------------------------- 69 | 70 | if __name__ == '__main__': 71 | startup(_main) 72 | -------------------------------------------------------------------------------- /tools/nfs-overlay-teardown: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Tear down overlay file system on NFS server """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgOverlayUuid, 31 | getCommonArgsParser 32 | ) 33 | from modules.context import getContext 34 | from modules.nfstools import Overlays 35 | from modules.startup import startup 36 | 37 | except ModuleNotFoundError as mnfex: 38 | from modules.exceptions import setExceptHook 39 | setExceptHook() 40 | raise mnfex 41 | 42 | 43 | # Functions 44 | 45 | def _getArgs(): 46 | """ Get command line arguments """ 47 | parser = getCommonArgsParser( 48 | 'Tear down overlay file system on NFS server' 49 | ) 50 | 51 | addArgOverlayUuid(parser) 52 | 53 | return parser.parse_args() 54 | 55 | 56 | # ---------------------------------------------------------------------- 57 | 58 | def _main(): 59 | 60 | ctx = getContext(_getArgs()) 61 | 62 | overlay = Overlays(ctx).find(ctx.ar.overlay_uuid) 63 | 64 | print(f"Deleting overlay share '{overlay}'") 65 | 66 | overlay.delete() 67 | 68 | 69 | # ---------------------------------------------------------------------- 70 | 71 | if __name__ == '__main__': 72 | startup(_main) 73 | -------------------------------------------------------------------------------- /tools/ocp-container-login: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Interactively log into a container running in an OpenShift cluster """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # none 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgContainerFlavor, 31 | getCommonArgsParser, 32 | addArgAppName 33 | ) 34 | from modules.context import getContext 35 | from modules.ocp import Ocp 36 | from modules.deployment import Deployments 37 | from modules.startup import startup 38 | 39 | except ModuleNotFoundError as mnfex: 40 | from modules.exceptions import setExceptHook 41 | setExceptHook() 42 | raise mnfex 43 | 44 | 45 | # Functions 46 | 47 | def _getArgs(): 48 | """ Get command line arguments """ 49 | parser = getCommonArgsParser( 50 | 'Interactively log into a container running in an OpenShift cluster' 51 | ) 52 | 53 | addArgContainerFlavor(parser, ('di', 'ascs', 'hdb'), False) 54 | addArgAppName(parser) 55 | 56 | return parser.parse_args() 57 | 58 | 59 | # ---------------------------------------------------------------------- 60 | 61 | def _main(): 62 | 63 | ctx = getContext(_getArgs()) 64 | ocp = Ocp(ctx) 65 | deployments = Deployments(ctx, ocp, deploymentType = ctx.cs.deployRunning) 66 | ocp.setAppName(deployments.getValidAppName()) 67 | 68 | ocp.containerLogin() 69 | 70 | 71 | # ---------------------------------------------------------------------- 72 | 73 | if __name__ == '__main__': 74 | startup(_main) 75 | -------------------------------------------------------------------------------- /tools/ocp-container-run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Run a command in a container running in an OpenShift cluster """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import sys 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgContainerFlavor, 31 | getCommonArgsParser, 32 | addArgAppName 33 | ) 34 | from modules.context import getContext 35 | from modules.ocp import Ocp 36 | from modules.startup import startup 37 | from modules.deployment import Deployments 38 | from modules.times import ( 39 | printTimes, 40 | saveEndTime 41 | ) 42 | 43 | except ModuleNotFoundError as mnfex: 44 | from modules.exceptions import setExceptHook 45 | setExceptHook() 46 | raise mnfex 47 | 48 | 49 | # Functions 50 | 51 | def _getArgs(): 52 | """ Get command line arguments """ 53 | parser = getCommonArgsParser( 54 | 'Log into a container running in an OpenShift cluster' 55 | ) 56 | 57 | addArgContainerFlavor(parser, ('di', 'ascs', 'hdb'), False) 58 | addArgAppName(parser) 59 | 60 | parser.add_argument('command', 61 | help='Command to be executed inside the container' 62 | ) 63 | 64 | return parser.parse_args() 65 | 66 | 67 | # ---------------------------------------------------------------------- 68 | 69 | def _main(): 70 | 71 | ctx = getContext(_getArgs()) 72 | 73 | ocp = Ocp(ctx) 74 | deployments = Deployments(ctx, ocp, deploymentType = ctx.cs.deployRunning) 75 | ocp.setAppName(deployments.getValidAppName()) 76 | containerName = ocp.getContainerName(ctx.ar.container_flavor) 77 | podName = ocp.getPodName() 78 | command = ctx.ar.command 79 | 80 | print(f"Executing command '{command}' in container '{containerName}' of pod '{podName}'", 81 | file=sys.stderr) 82 | 83 | res = ocp.containerRun(containerName, command) 84 | 85 | print(res.out, file=sys.stdout) 86 | print(res.err, file=sys.stderr) 87 | 88 | del ocp 89 | 90 | saveEndTime() 91 | printTimes() 92 | 93 | return res.rc 94 | 95 | 96 | # ---------------------------------------------------------------------- 97 | 98 | if __name__ == '__main__': 99 | startup(_main) 100 | -------------------------------------------------------------------------------- /tools/ocp-etc-hosts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Add OpenShift cluster domain entries to '/etc/hosts' """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import shutil 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgs 30 | from modules.context import getContext 31 | from modules.startup import startup 32 | from modules.fail import fail 33 | 34 | except ModuleNotFoundError as mnfex: 35 | from modules.exceptions import setExceptHook 36 | setExceptHook() 37 | raise mnfex 38 | 39 | 40 | # Functions 41 | 42 | 43 | # ---------------------------------------------------------------------- 44 | 45 | def _main(): 46 | 47 | ctx = getContext(getCommonArgs( 48 | "Add OpenShift cluster domain entries to '/etc/hosts'" 49 | )) 50 | 51 | ocpDomain = ctx.cf.ocp.domain 52 | helperIp = ctx.cf.ocp.helper.host.ip 53 | 54 | fqdns = ( 55 | f'api.{ocpDomain}', 56 | f'oauth-openshift.apps.{ocpDomain}', 57 | f'default-route-openshift-image-registry.apps.{ocpDomain}', 58 | f'console-openshift-console.apps.{ocpDomain}', 59 | f'downloads-openshift-console.apps.{ocpDomain}' 60 | ) 61 | 62 | etcHosts = '/etc/hosts' 63 | hostEntry = f'{helperIp}\t'+' '.join(fqdns) 64 | 65 | found = [] 66 | try: 67 | # pylint: disable=invalid-name, unspecified-encoding 68 | with(open(etcHosts, 'r')) as fh: 69 | for line in fh.readlines(): 70 | if line.strip().startswith('#'): 71 | continue 72 | if ocpDomain in line: 73 | found.append(line) 74 | except IOError: 75 | fail(f"Error reading from file {etcHosts}") 76 | 77 | if found: 78 | print(f"\nThe following line(s) in '{etcHosts}' already" 79 | f" contain(s) entries for domain '{ocpDomain}':\n") 80 | for line in found: 81 | print(f"{line}") 82 | print("Please check whether the following FQDN's are active and add all missing FQDN's:\n") 83 | for fqdn in fqdns: 84 | print(f" '{fqdn}'") 85 | print() 86 | else: 87 | backup = f'{etcHosts}.orig' 88 | shutil.copy2(etcHosts, backup) 89 | try: 90 | # pylint: disable=invalid-name, unspecified-encoding 91 | with open(etcHosts, 'a') as fh: 92 | print(f'\n# Added by ocp-etc-hosts:\n{hostEntry}', file=fh) 93 | except IOError: 94 | fail(f"Error writing to file {etcHosts}") 95 | print(f"\nAdded the following line to file '{etcHosts}'\n\n{hostEntry}\n") 96 | print(f"Stored backup of original '{etcHosts}' in '{backup}'\n") 97 | 98 | 99 | # ---------------------------------------------------------------------- 100 | 101 | if __name__ == '__main__': 102 | startup(_main) 103 | -------------------------------------------------------------------------------- /tools/ocp-hdb-secret-gen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Generate OpenShift HANA secret YAML file """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgs 30 | from modules.command import CmdShell 31 | from modules.context import getContext 32 | from modules.fail import fail 33 | from modules.ocp import Ocp 34 | from modules.startup import startup 35 | from modules.tools import genFileFromTemplate 36 | 37 | except ModuleNotFoundError as mnfex: 38 | from modules.exceptions import setExceptHook 39 | setExceptHook() 40 | raise mnfex 41 | 42 | 43 | # Functions 44 | 45 | 46 | # ---------------------------------------------------------------------- 47 | 48 | def _main(): 49 | 50 | ctx = getContext(getCommonArgs( 51 | 'Generate OpenShift HANA secret YAML file' 52 | )) 53 | 54 | secretName = ctx.cf.ocp.containers.di.secret 55 | 56 | if not secretName: 57 | fail(f"Secret name is not specified in file '{ctx.ar.config_file}'" 58 | f" - not generating secret") 59 | 60 | templateDir = f'{ctx.cf.build.repo.root}/openshift' 61 | templateFile = f'{templateDir}/secret.yaml.template' 62 | secretFile = f'{templateDir}/{secretName}.yaml' 63 | 64 | params = { 65 | 'secret-name': secretName, 66 | 'project': ctx.cf.ocp.project, 67 | 'User': ctx.cr.refsys.nws4.hdbconnect.name, 68 | 'Password': ctx.cr.refsys.nws4.hdbconnect.password 69 | } 70 | 71 | genFileFromTemplate(templateFile, secretFile, params) 72 | 73 | ocp = Ocp(ctx) 74 | result = ocp.ocApply(secretFile) 75 | 76 | if result.rc > 0: 77 | fail(result.err) 78 | CmdShell().run(f'rm -f {secretFile}') 79 | print(f'Secret {secretName} created for project {ctx.cf.ocp.project}') 80 | 81 | del ocp 82 | 83 | 84 | # ---------------------------------------------------------------------- 85 | 86 | if __name__ == '__main__': 87 | startup(_main) 88 | -------------------------------------------------------------------------------- /tools/ocp-login: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Log into an OpenShift cluster as regular user or as admin user """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgsParser 30 | from modules.command import CmdShell 31 | from modules.context import getContext 32 | from modules.fail import fail 33 | from modules.ocp import Ocp 34 | from modules.startup import startup 35 | 36 | except ModuleNotFoundError as mnfex: 37 | from modules.exceptions import setExceptHook 38 | setExceptHook() 39 | raise mnfex 40 | 41 | 42 | # Functions 43 | 44 | def _getArgs(): 45 | """ Get command line arguments """ 46 | parser = getCommonArgsParser( 47 | 'Log into OCP' 48 | ) 49 | 50 | parser.add_argument( 51 | '-u', 52 | '--user', 53 | required = False, 54 | action ='store_true', 55 | help = "Log into OCP as regular user" 56 | ) 57 | 58 | parser.add_argument( 59 | '-a', 60 | '--admin', 61 | required = False, 62 | action ='store_true', 63 | help = "Log into OCP as admin user" 64 | ) 65 | 66 | parser.add_argument( 67 | '--project-ignore', 68 | required = False, 69 | action ='store_true', 70 | help = "Errors during setProject are ignored if set to False" 71 | ) 72 | 73 | return parser.parse_args() 74 | 75 | 76 | # ---------------------------------------------------------------------- 77 | 78 | def _main(): 79 | 80 | ctx = getContext(_getArgs()) 81 | 82 | msg = "Specify excactly one of '-u' or '-a' ('-h' for help)" 83 | 84 | setProject = True 85 | 86 | if ctx.ar.project_ignore: 87 | setProject = False 88 | 89 | if ctx.ar.user: 90 | if not ctx.ar.admin: 91 | ocp = Ocp(ctx, login="user", logout=False, setProject = setProject) 92 | result = ocp.ocLogin() 93 | del ocp 94 | print(result.out) 95 | else: 96 | fail(msg) 97 | 98 | elif ctx.ar.admin: 99 | if not ctx.ar.user: 100 | ocp = Ocp(ctx, login="admin", logout=False, setProject = setProject) 101 | result = ocp.ocLogin() 102 | del ocp 103 | print(result.out) 104 | else: 105 | fail(msg) 106 | 107 | else: 108 | fail(msg) 109 | 110 | print(f'\nActive user: {CmdShell().run("oc whoami").out}\n') 111 | 112 | 113 | # ---------------------------------------------------------------------- 114 | 115 | if __name__ == '__main__': 116 | startup(_main) 117 | -------------------------------------------------------------------------------- /tools/ocp-pod-meminfo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Get SAP system memory consumption information """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import logging 26 | import math 27 | import time 28 | 29 | # Local modules 30 | 31 | from modules.args import ( 32 | addCommonArgsString, 33 | getCommonArgsParser, 34 | addArgAppName, 35 | addArgLoop, 36 | addArgSleepTime 37 | ) 38 | from modules.context import getContext 39 | from modules.ocp import Ocp 40 | from modules.deployment import Deployments 41 | from modules.quantity import Quantity 42 | from modules.startup import startup 43 | from modules.tools import getTimestamp 44 | from modules.fail import fail 45 | 46 | except ModuleNotFoundError as mnfex: 47 | from modules.exceptions import setExceptHook 48 | setExceptHook() 49 | raise mnfex 50 | 51 | 52 | # Functions 53 | 54 | def _getArgs(): 55 | """ Get command line arguments """ 56 | parser = getCommonArgsParser( 57 | 'Get SAP system memory consumption information' 58 | ) 59 | 60 | addArgAppName(parser) 61 | addArgLoop(parser) 62 | addArgSleepTime(parser) 63 | 64 | return parser.parse_args() 65 | 66 | 67 | def _getMeminfoGiB(ocp, instance): 68 | # Returns a float, may return math.nan 69 | 70 | containerName = ocp.getContainerName(instance) 71 | meminfoCmd = "cat /sys/fs/cgroup/memory/memory.usage_in_bytes" 72 | 73 | res = ocp.containerRun(containerName, meminfoCmd) 74 | 75 | if res.rc != 0: 76 | logging.debug(f"Execution of command '{meminfoCmd}' in container '{containerName}'" 77 | f" returned rc {res.rc} (reason: {res.err})") 78 | 79 | try: 80 | memUsage = float(res.out.strip())/(1024**3) 81 | except ValueError: 82 | memUsage = math.nan 83 | 84 | return memUsage 85 | 86 | 87 | def _getLimitGiB(ctx, instance): 88 | # Returns an int 89 | 90 | limit = getattr(ctx.cf.ocp.containers, instance).resources.limits.memory 91 | 92 | # Scale the limit value to GiB 93 | 94 | return Quantity(limit).valueIntScaled("Gi") 95 | 96 | 97 | def _printResult(instance, memUsage, limit, percentage): 98 | # memUsage and percentage might be math.nan, if a problem occurred 99 | # during containerRun() in function _getMeminfoGiB() 100 | 101 | limitStr = f'{limit:4.1f}' 102 | memUsageStr = f'{memUsage:6.3f}' if not math.isnan(memUsage) else ' ?' 103 | percentageStr = f'{percentage:4.2f}' if not math.isnan(percentage) else ' ?' 104 | print(f'{instance.upper():10} {memUsageStr:7} {limitStr:5} {percentageStr}') 105 | 106 | 107 | # ---------------------------------------------------------------------- 108 | 109 | def _main(): 110 | 111 | ctx = getContext(_getArgs()) 112 | 113 | addCommonArgsString(ctx) 114 | 115 | instances = ctx.config.getContainerFlavors() 116 | instances.remove('init') 117 | 118 | ocp = Ocp(ctx) 119 | 120 | deployments = Deployments(ctx, ocp, deploymentType = ctx.cs.deployRunning) 121 | 122 | appNames = None 123 | if not ctx.ar.app_name: 124 | appNames = deployments.getAppNames() 125 | else: 126 | appName = deployments.getValidAppName() 127 | appNames = [appName] 128 | 129 | if len(appNames) == 0: 130 | fail("No running deployments found.") 131 | 132 | while True: 133 | if ctx.ar.loop: 134 | print(getTimestamp(withDecorator=True)) 135 | 136 | print(' Used Limit Used') 137 | print('Instance GiB GiB %') 138 | print('='*30) 139 | 140 | first = True 141 | 142 | for appName in appNames: 143 | ocp.setAppName(appName) 144 | 145 | if not first: 146 | print('-'*len('Deployment ' + appName)) 147 | first = False 148 | print(f'App-Name {appName}') 149 | print('-'*len('Deployment ' + appName)) 150 | 151 | for instance in instances: 152 | memUsage = _getMeminfoGiB(ocp, instance) 153 | limit = _getLimitGiB(ctx, instance) 154 | _printResult(instance, memUsage, limit, memUsage * 100 / limit) 155 | 156 | if ctx.ar.loop: 157 | time.sleep(ctx.ar.sleep_time) 158 | else: 159 | break 160 | 161 | del ocp 162 | 163 | # ---------------------------------------------------------------------- 164 | 165 | 166 | if __name__ == '__main__': 167 | startup(_main) 168 | -------------------------------------------------------------------------------- /tools/ocp-pod-status: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Get the status of a pod """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | import time 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | getCommonArgsParser, 31 | addArgAppName, 32 | addArgLoop, 33 | addArgSleepTime 34 | ) 35 | from modules.context import getContext 36 | from modules.ocp import Ocp 37 | from modules.deployment import Deployments 38 | from modules.startup import startup 39 | from modules.tools import getTimestamp 40 | from modules.fail import fail 41 | 42 | except ModuleNotFoundError as mnfex: 43 | from modules.exceptions import setExceptHook 44 | setExceptHook() 45 | raise mnfex 46 | 47 | 48 | # Functions 49 | 50 | def _getArgs(): 51 | """ Get command line arguments """ 52 | parser = getCommonArgsParser( 53 | 'Get the status of a pod' 54 | ) 55 | addArgAppName(parser) 56 | addArgLoop(parser) 57 | addArgSleepTime(parser) 58 | return parser.parse_args() 59 | 60 | 61 | def _printHeader(): 62 | print('Pod' + ' '*40 + 'Status') 63 | print('-'*50) 64 | 65 | # ---------------------------------------------------------------------- 66 | 67 | 68 | def _main(): 69 | 70 | ctx = getContext(_getArgs()) 71 | 72 | ocp = Ocp(ctx) 73 | 74 | deployments = Deployments(ctx, ocp, deploymentType = ctx.cs.deployDeployed) 75 | 76 | appNames = None 77 | 78 | if not ctx.ar.app_name: 79 | appNames = deployments.getAppNames() 80 | else: 81 | appName = deployments.getValidAppName() 82 | appNames = [appName] 83 | 84 | if len(appNames) == 0: 85 | fail("No deployments found.") 86 | 87 | while True: 88 | if ctx.ar.loop: 89 | print(getTimestamp(withDecorator=True)) 90 | _printHeader() 91 | 92 | if len(appNames) > 0: 93 | for appName in appNames: 94 | ocp.setAppName(appName) 95 | podName = ocp.getPodName() 96 | podStatus = ocp.getPodStatus() 97 | 98 | if not podName: 99 | print(f"No pod found for {appName}") 100 | else: 101 | print(f'{podName}' + ' '*7 + f'{podStatus}') 102 | else: 103 | print("None") 104 | break 105 | if ctx.ar.loop: 106 | time.sleep(ctx.ar.sleep_time) 107 | else: 108 | break 109 | 110 | 111 | # ---------------------------------------------------------------------- 112 | 113 | if __name__ == '__main__': 114 | startup(_main) 115 | -------------------------------------------------------------------------------- /tools/ocp-service-account-gen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Generate YAML file for service account creation """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import ( 30 | addArgOutputFile, 31 | getCommonArgsParser 32 | ) 33 | from modules.context import getContext 34 | from modules.fail import fail 35 | from modules.ocp import Ocp 36 | from modules.startup import startup 37 | from modules.command import CmdShell 38 | 39 | 40 | except ModuleNotFoundError as mnfex: 41 | from modules.exceptions import setExceptHook 42 | setExceptHook() 43 | raise mnfex 44 | 45 | 46 | # Functions 47 | 48 | def _getArgs(): 49 | """ Get command line arguments """ 50 | parser = getCommonArgsParser( 51 | 'Generate YAML file for service account creation' 52 | ) 53 | 54 | addArgOutputFile(parser, None) 55 | 56 | return parser.parse_args() 57 | 58 | 59 | # ---------------------------------------------------------------------- 60 | 61 | def _main(): 62 | 63 | ctx = getContext(_getArgs()) 64 | 65 | outputFile = ctx.ar.output_file 66 | if not outputFile: 67 | outputFile = ctx.cf.ocp.sa.file 68 | 69 | try: 70 | # pylint: disable=invalid-name, unspecified-encoding 71 | with open(outputFile, 'w') as fh: 72 | print(f'apiVersion: v1\n' 73 | f'kind: ServiceAccount\n' 74 | f'metadata:\n' 75 | f' name: {ctx.cf.ocp.sa.name}\n' 76 | f' namespace: {ctx.cf.ocp.project}', 77 | file=fh 78 | ) 79 | except IOError: 80 | fail(f"Error writing to file {outputFile}") 81 | 82 | ocp = Ocp(ctx) 83 | result = ocp.ocApply(outputFile) 84 | del ocp 85 | 86 | CmdShell().run(f'rm -f {outputFile}') 87 | if result.rc > 0: 88 | fail(result.err) 89 | else: 90 | print(result.out) 91 | 92 | 93 | # ---------------------------------------------------------------------- 94 | 95 | if __name__ == '__main__': 96 | startup(_main) 97 | -------------------------------------------------------------------------------- /tools/ssh-key-gen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Generate a passphrase-less SSH private / public key pair """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | from pathlib import Path 26 | import getpass 27 | import socket 28 | import subprocess 29 | 30 | # Local modules 31 | 32 | from modules.args import getCommonArgsParser 33 | from modules.context import getContext 34 | from modules.startup import startup 35 | from modules.tools import readInput 36 | 37 | except ModuleNotFoundError as mnfex: 38 | from modules.exceptions import setExceptHook 39 | setExceptHook() 40 | raise mnfex 41 | 42 | 43 | # Functions 44 | 45 | def _getArgs(): 46 | """ Get command line arguments """ 47 | parser = getCommonArgsParser( 48 | 'Generate a passphrase-less SSH private / public key pair' 49 | ) 50 | 51 | parser.add_argument( 52 | '-i', 53 | '--ssh-id', 54 | metavar = '', 55 | required = False, 56 | help = "Path to the SSH ID private key file" 57 | ) 58 | 59 | return parser.parse_args() 60 | 61 | 62 | def _getDefaultId(ctx): 63 | 64 | sshId = ctx.ar.ssh_id 65 | 66 | if not sshId: 67 | sshId = ctx.cr.build.user.sshid 68 | 69 | if not sshId: 70 | sshId = f'{Path.home()}/.ssh/id_rsa' 71 | 72 | return sshId 73 | 74 | 75 | def _getDefaultComment(): 76 | return f'{getpass.getuser()}@{socket.gethostname()}' 77 | 78 | 79 | # ---------------------------------------------------------------------- 80 | 81 | def _main(): 82 | 83 | ctx = getContext(_getArgs(), withConfig=False) 84 | 85 | sshId = readInput('Enter file in which to save the key', 86 | _getDefaultId(ctx), False, False, False) 87 | 88 | comment = readInput('Enter comment which is stored with the key', 89 | _getDefaultComment(), False, False, False) 90 | 91 | subprocess.run(['ssh-keygen', '-f', sshId, '-C', comment], check=False) 92 | 93 | 94 | # ---------------------------------------------------------------------- 95 | 96 | if __name__ == '__main__': 97 | startup(_main) 98 | -------------------------------------------------------------------------------- /tools/tool-shortcuts: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | SCRIPT_PATH=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd) 20 | SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}") 21 | export SOOS_TOOLS_PATH=$(dirname $SCRIPT_PATH) 22 | 23 | if [[ $# == 1 && "$1" == "--add" ]]; then 24 | if [[ "$(grep -c $SCRIPT_NAME ~/.bashrc)" == "0" ]]; then 25 | SCRIPT_FQN=$SCRIPT_PATH/$SCRIPT_NAME 26 | printf "\n# Added soos $SCRIPT_NAME ($(date))\nsource $SCRIPT_FQN\n" >> ~/.bashrc 27 | echo "Added command \"source $SCRIPT_NAME\" in ~/.bashrc" 28 | else 29 | echo "Command \"$SCRIPT_NAME\" already found in ~/.bashrc" 30 | fi 31 | fi 32 | if [[ -d $SOOS_TOOLS_PATH/tools ]]; then 33 | SOOS_TOOLS_LIST=$(ls $SOOS_TOOLS_PATH/tools|grep -v -E "modules|venv-setup|codingstyle|$SCRIPT_NAME|^creds|^config") 34 | fi 35 | for TOOL in $SOOS_TOOLS_LIST; do 36 | eval "function soos-$TOOL() 37 | { export ARGS=\$@ && sh -c 'tool-shortcut $TOOL; exit \$?' 38 | }" 39 | export -f soos-$TOOL 40 | done 41 | function tool-shortcut() 42 | { 43 | echo "Using SOOS_TOOLS_PATH=$SOOS_TOOLS_PATH" 44 | if [[ "$1" == "" ]];then 45 | echo "Error: Call tool-shortcut not direct." && return 1 46 | fi 47 | if [[ ! -x $SOOS_TOOLS_PATH/tools/$1 ]]; then 48 | echo "Error: Tool $SOOS_TOOLS_PATH/tools/$1 not found in dir $SOOS_TOOLS_PATH/tools, change environment variable SOOS_TOOLS_PATH." && return 1 49 | fi 50 | if [[ ! -r $SOOS_TOOLS_PATH/venv/bin/activate ]]; then 51 | cd $SOOS_TOOLS_PATH && $SOOS_TOOLS_PATH/tools/venv-setup || return $? 52 | fi 53 | if [[ -r $SOOS_TOOLS_PATH/config.yaml ]]; then 54 | if [[ -r $SOOS_TOOLS_PATH/creds.yaml ]]; then 55 | cd $SOOS_TOOLS_PATH && source $SOOS_TOOLS_PATH/venv/bin/activate && \ 56 | $SOOS_TOOLS_PATH/tools/$1 $ARGS -c $SOOS_TOOLS_PATH/config.yaml -q $SOOS_TOOLS_PATH/creds.yaml || return $? 57 | elif [[ -r $SOOS_TOOLS_PATH/creds.yaml.gpg ]]; then 58 | cd $SOOS_TOOLS_PATH && source $SOOS_TOOLS_PATH/venv/bin/activate && \ 59 | $SOOS_TOOLS_PATH/tools/$1 $ARGS -c $SOOS_TOOLS_PATH/config.yaml -q $SOOS_TOOLS_PATH/creds.yaml.gpg || return $? 60 | else 61 | echo "Error: Credential file $SOOS_TOOLS_PATH/creds.yaml or $SOOS_TOOLS_PATH/creds.yaml.gpg not found, run tools/creds first." && return 1 62 | fi 63 | else 64 | echo "Error: Config file $SOOS_TOOLS_PATH/config.yaml not found, run tools/config first." && return 1 65 | fi 66 | } 67 | export -f tool-shortcut 68 | -------------------------------------------------------------------------------- /tools/venv-setup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2021, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | # Set up a virtual Python environment with all modules 20 | # required to run the tools in directory tools/ 21 | 22 | set -euo pipefail 23 | 24 | function gen_doc_gfm() { 25 | 26 | cat <<'EOF' 27 | ## Tool `venv-setup` 28 | 29 | ### Usage 30 | 31 | `venv-setup` 32 | 33 | ### Purpose 34 | 35 | Set up a Python virtual environment with all modules that are required 36 | to run the tools. 37 | 38 | Once the virtual environment is prepared, activate it by executing 39 | `source venv/bin/activate` out of the repository clone root directory 40 | before running any of the other tools. 41 | 42 | EOF 43 | } 44 | 45 | if [ $# -eq 1 ]; then 46 | if [ $1 == '--gen-doc-gfm' ]; then 47 | gen_doc_gfm 48 | exit 0 49 | fi 50 | fi 51 | 52 | if [ $# -ge 1 ]; then 53 | echo 54 | echo "$0:" 55 | echo 56 | echo " Set up a virtual Python environment with all modules" 57 | echo " required to run the tools in directory tools/" 58 | echo 59 | echo "Doesn't require any command line arguments" 60 | echo 61 | exit 1 62 | fi 63 | 64 | # Check OS version 65 | 66 | major () { echo ${1%.*}; } 67 | minor () { echo ${1#*.}; } 68 | 69 | MIN_RHEL="8.2" 70 | 71 | source /etc/os-release # Sets ${ID} and ${VERSION_ID} 72 | 73 | if [ ${ID} == "rhel" ]; then 74 | if [ $(major ${VERSION_ID}) -lt $(major ${MIN_RHEL}) \ 75 | -o $(major ${VERSION_ID}) -eq $(major ${MIN_RHEL}) \ 76 | -a $(minor ${VERSION_ID}) -lt $(minor ${MIN_RHEL}) ]; then 77 | echo "Minimal required RHEL version to run this script: ${MIN_RHEL}" 78 | exit 1 79 | fi 80 | fi 81 | 82 | # Ensure required RPM packages on OS level are installed 83 | 84 | echo 85 | echo "Checking / installing required RPM packages" 86 | echo 87 | 88 | PKG_REQ="" 89 | PKG_REQ="${PKG_REQ} python38" 90 | 91 | PKG_INST="" 92 | 93 | for PKG in ${PKG_REQ}; do 94 | echo -n "${PKG} - " 95 | if dnf list installed ${PKG} >/dev/null 2>&1; then 96 | echo "installed" 97 | else 98 | echo "missing" 99 | PKG_INST="${PKG_INST} ${PKG}" 100 | fi 101 | done 102 | 103 | if [ -n "${PKG_INST}" ]; then 104 | INSTALL_CMD="dnf install -y ${PKG_INST}" 105 | 106 | if [ $(id -u) != 0 ]; then 107 | echo "Provide root user password for installing package(s)${PKG_INST}" 108 | su root -c "${INSTALL_CMD}" 109 | else 110 | ${INSTALL_CMD} 111 | fi 112 | fi 113 | 114 | # Set up the virtual environment 115 | 116 | echo 117 | echo "Setting up virtual environment" 118 | echo 119 | 120 | PYTHON="/usr/bin/env python3.8" 121 | VENV="$(pwd)/venv" 122 | 123 | ${PYTHON} -m venv "${VENV}" 124 | source ${VENV}/bin/activate 125 | 126 | pip install --upgrade pip 127 | 128 | MODULES="" 129 | MODULES="${MODULES} autopep8" # tools/codingstyle only 130 | MODULES="${MODULES} pyaml" 131 | MODULES="${MODULES} pylint" # tools/codingstyle only 132 | MODULES="${MODULES} python-gnupg" 133 | MODULES="${MODULES} termcolor" 134 | 135 | pip install --no-cache-dir ${MODULES} 136 | 137 | SEP='------------------------------------------------------------------------' 138 | 139 | echo ${SEP} 140 | echo 141 | echo ' Setup of virtual python environment finished.' 142 | echo 143 | echo ' Execute' 144 | echo 145 | echo ' source ./venv/bin/activate' 146 | echo 147 | echo ' to activate the virtual environment' 148 | echo 149 | echo ' Execute' 150 | echo 151 | echo ' deactivate' 152 | echo 153 | echo ' inside the virtual environment to deactivate the environment.' 154 | echo 155 | echo ${SEP} 156 | -------------------------------------------------------------------------------- /tools/verify-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Verify parameter settings in configuration YAML file """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgsParser 30 | from modules.context import getContext 31 | from modules.fail import fail 32 | from modules.startup import startup 33 | from modules.verify import Verify 34 | 35 | except ModuleNotFoundError as mnfex: 36 | from modules.exceptions import setExceptHook 37 | setExceptHook() 38 | raise mnfex 39 | 40 | 41 | # Functions 42 | 43 | def _getArgs(): 44 | """ Get command line arguments """ 45 | parser = getCommonArgsParser( 46 | 'Verify parameter settings in configuration YAML file' 47 | ) 48 | parser.add_argument( 49 | '-func', 50 | '--function', 51 | required = False, 52 | help = 'single test mode for function' 53 | ) 54 | return parser.parse_args() 55 | 56 | 57 | # ---------------------------------------------------------------------- 58 | 59 | def _main(): 60 | 61 | ctx = getContext(_getArgs(), failOnDiscoveryError=True) 62 | print('-'*72) 63 | print(f"Verifying configuration parameters in file '{ctx.ar.config_file}'") 64 | print('-'*72) 65 | 66 | if not Verify(ctx).verify(): 67 | print('-'*72) 68 | fail('VERIFICATION ERRORS OCCURED - SEE ABOVE MESSAGES FOR MORE DETAILS\n') 69 | 70 | print('-'*72) 71 | print('Verification successful.\n') 72 | 73 | 74 | # ---------------------------------------------------------------------- 75 | 76 | if __name__ == '__main__': 77 | startup(_main) 78 | -------------------------------------------------------------------------------- /tools/verify-ocp-settings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # ------------------------------------------------------------------------ 4 | # Copyright 2020, 2022 IBM Corp. All Rights Reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # ------------------------------------------------------------------------ 18 | 19 | """ Verify OpenShift cluster setup related settings """ 20 | 21 | 22 | try: 23 | # Global modules 24 | 25 | # None 26 | 27 | # Local modules 28 | 29 | from modules.args import getCommonArgsParser 30 | from modules.context import getContext 31 | from modules.fail import fail 32 | from modules.startup import startup 33 | from modules.verify import VerifyOcp 34 | 35 | except ModuleNotFoundError as mnfex: 36 | from modules.exceptions import setExceptHook 37 | setExceptHook() 38 | raise mnfex 39 | 40 | # Functions 41 | 42 | 43 | def _getArgs(): 44 | """ Get command line arguments """ 45 | parser = getCommonArgsParser( 46 | 'Verify OpenShift cluster setup related settings' 47 | ) 48 | parser.add_argument( 49 | '-func', 50 | '--function', 51 | required = False, 52 | help = 'single test mode for function' 53 | ) 54 | return parser.parse_args() 55 | 56 | 57 | # ---------------------------------------------------------------------- 58 | 59 | 60 | def _main(): 61 | 62 | ctx = getContext(_getArgs()) 63 | 64 | # Check settings for OpenShift project and service account 65 | 66 | print('-'*72) 67 | print('Verifying OpenShift Cluster Setup related settings') 68 | print('-'*72) 69 | 70 | if not VerifyOcp(ctx).verify(): 71 | print('-'*72) 72 | fail('VERIFICATION ERRORS OCCURED - SEE ABOVE MESSAGES FOR MORE DETAILS\n') 73 | 74 | print('-'*72) 75 | print('Verification successful.\n') 76 | 77 | 78 | # ---------------------------------------------------------------------- 79 | 80 | if __name__ == '__main__': 81 | startup(_main) 82 | --------------------------------------------------------------------------------