├── .gitattributes ├── .gitignore ├── LICENSE ├── OWNERS ├── README.md ├── ansible.cfg ├── apply-patch.sh ├── asm_disk_config.json ├── brute-cleanup.yml ├── check-instance.yml ├── check-oracle.sh ├── check-oracle.yml ├── check-swlib.sh ├── check-swlib.yml ├── cleanup-oracle.sh ├── cluster_config.json ├── config-db.yml ├── config-rac-db.yml ├── data_mounts_config.json ├── docs ├── _config.yml ├── code-of-conduct.md ├── compute-vm-quickstart.md ├── compute-vm-user-guide.md ├── contributing.md ├── host-provision-logical-fork-points.png ├── host-provisioning.md ├── index.html ├── oracle-toolkit-bm-architecture.png ├── oracle-toolkit-vm-architecture.png ├── patch-metadata.md ├── terraform.md ├── troubleshooting_guide.md └── user-guide.md ├── group_vars └── all.yml ├── host-provision.sh ├── host-provision.yml ├── install-oracle.sh ├── install-sw.yml ├── manage_devices_on_vm.sh ├── patch.yml ├── prep-host.yml ├── presubmit_tests ├── rac-on-bms.sh └── single-instance-on-bms.sh ├── roles ├── base-provision │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ └── tasks │ │ ├── main.yml │ │ └── swap.yml ├── brute-ora-cleanup │ ├── README.md │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── check-oracle │ ├── files │ │ ├── login.sql │ │ └── orachk-quicktest.sh │ ├── meta │ │ └── main.yml │ └── vars │ │ └── main.yml ├── check-swlib │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── common │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ └── tasks │ │ ├── populate-asm-disks.yml │ │ ├── populate-swap-partition-id.yml │ │ ├── populate-user-data-mounts.yml │ │ └── populate-vars.yml ├── db-adjustments │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ │ ├── archivelog_mode.sh.j2 │ │ └── db_modifications.sh.j2 ├── db-backups │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── gcsfuse.yml │ │ ├── gcsmanual.yml │ │ ├── main.yml │ │ └── nfs.yml │ └── templates │ │ ├── rman_arch_backup.sh.j2 │ │ ├── rman_full_backup.sh.j2 │ │ └── rman_restore_example.sh.j2 ├── db-copy │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── active-copy.yml │ └── templates │ │ ├── duplicate.cmd.j2 │ │ └── initaux.ora.j2 ├── db-create │ ├── defaults │ │ └── main.yml │ ├── files │ │ └── pwgen.sh │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ └── rac-db-create.yml │ └── templates │ │ ├── dbca.rsp.sh.j2 │ │ ├── rac-dbca.rsp.11.2.0.4.0.sh.j2 │ │ └── rac-dbca.rsp.sh.j2 ├── dg-config │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── dg_mode.yml │ │ └── main.yml │ └── templates │ │ └── dg-create.j2 ├── gi-setup │ ├── files │ │ └── expect_rsp.sh │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── asm-create.yml │ │ ├── gi-install.yml │ │ └── main.yml │ └── templates │ │ ├── grid_install.rsp.sh.j2 │ │ └── init.ora.j2 ├── host-provision │ ├── tasks │ │ ├── config-tasks.yml │ │ ├── proxy.yml │ │ ├── rhel-config-tasks.yml │ │ ├── ssh-keygen.yml │ │ └── user-setup.yml │ └── templates │ │ └── hostprovision_ansible_user.j2 ├── host-storage │ ├── defaults │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── lsnr-create │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── ora-host │ ├── defaults │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── hugepages.yml │ │ ├── kernel_parameters.yml │ │ └── main.yml │ └── templates │ │ ├── bash_profile_gi.j2 │ │ └── bash_profile_rdbms.j2 ├── patch-vulns │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── patch │ ├── files │ │ └── expect_rsp.sh │ ├── meta │ │ └── main.yml │ └── tasks │ │ ├── main.yml │ │ ├── opatch_apply.yml │ │ ├── rac-dbpatch.yml │ │ ├── rac-ins-opatch.yml │ │ ├── rac-opatch.yml │ │ └── sql_patch.yml ├── pwgen │ ├── files │ │ └── pwgen.sh │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── rac-db-setup │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── rac-db-install-11.2-12.1.yml │ │ └── rac-db-install.yml │ └── templates │ │ ├── db_install.rsp.11.2.0.4.0.j2 │ │ ├── db_install.rsp.12.1.0.2.0.j2 │ │ ├── db_install.rsp.12.2.0.1.0.j2 │ │ ├── db_install.rsp.18.0.0.0.0.j2 │ │ └── db_install.rsp.19.3.0.0.0.j2 ├── rac-gi-setup │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── rac-asm-create.yml │ │ └── rac-gi-install.yml │ └── templates │ │ ├── gridsetup.rsp.12.2.0.1.0.j2 │ │ ├── gridsetup.rsp.18.0.0.0.0.j2 │ │ └── gridsetup.rsp.19.3.0.0.0.j2 ├── rac-lsnr-firewall │ ├── meta │ │ └── main.yml │ └── tasks │ │ └── main.yml ├── rdbms-setup │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── main.yml │ │ ├── rdbms-install.yml │ │ └── rdbms-rpm-install.yml │ └── templates │ │ ├── db_install.rsp.sh.j2 │ │ └── sqlnet.ora.j2 ├── ssh-setup │ └── tasks │ │ └── main.yml ├── swlib │ ├── meta │ │ └── main.yml │ └── tasks │ │ ├── gcloud.yml │ │ ├── gcscopy.yml │ │ ├── gcsfuse.yml │ │ ├── main.yml │ │ └── nfs.yml └── validation-scripts │ ├── defaults │ └── main.yml │ ├── meta │ └── main.yml │ ├── tasks │ └── main.yml │ └── templates │ ├── asm_disks.sh.j2 │ ├── cluvfy_checks.sh.j2 │ └── crs_check.sh.j2 ├── terraform ├── README.md ├── backend.tf.example ├── main.tf.example └── modules │ └── oracle_toolkit_module │ ├── main.tf │ ├── scripts │ └── setup.sh.tpl │ ├── variables.tf │ └── versions.tf └── tools ├── README.md └── gen_patch_metadata.py /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.png -text 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ansible_cache 2 | .ansible_vault_pass 3 | .ansible-lint* 4 | .terraform* 5 | .vault_pass.txt 6 | .yamllint 7 | *.encrypted 8 | *.vault 9 | **/.retry 10 | **/.bundle 11 | **/.DS_Store 12 | **/.vagrant 13 | **/.vscode 14 | **/*.bak 15 | **/*.key 16 | **/*.pem 17 | **/*.pub 18 | **/*.pwd 19 | **/*.swp 20 | **/*.tmp 21 | **/nohup.out 22 | **/typescript 23 | **/vault.yml 24 | hosts.yml 25 | inventory 26 | inventory_files/ 27 | logs/ 28 | secrets.yml 29 | secrets/ 30 | terraform/*sh-key* 31 | vars/ 32 | vault_password_file 33 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # See the OWNERS docs at https://go.k8s.io/owners 2 | # oracle-toolkit leverages the above to interact with prow 3 | 4 | approvers: 5 | - mfielding 6 | - alexbasinov 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # oracle-toolkit 2 | 3 | Toolkit for managing Oracle databases on Google Cloud. 4 | 5 | Supports usage with: 6 | 7 | - [Bare Metal Solution](https://cloud.google.com/bare-metal) 8 | - [Google Compute Engine](https://cloud.google.com/products/compute) 9 | 10 | ## Quick Start 11 | 12 | 1. Create a Google Cloud VM to act as a [control node](/docs/user-guide.md#control-node-requirements); it should be on a VPC network that has SSH access to the database hosts. 13 | 1. [Extract the toolkit code](/docs/user-guide.md#installing-the-toolkit) on the control node. 14 | 1. Create a Cloud Storage bucket to host Oracle software images. 15 | ```bash 16 | gsutil mb -b on gs://installation-media-1234 17 | ``` 18 | 1. [Download software](/docs/user-guide.md#downloading-and-staging-the-oracle-software) from Oracle and populate the bucket. Use [check-swlib.sh](/docs/user-guide.md#validating-media) to determine which files are required for your Oracle version. 19 | 20 | 1. Create an SSH key, and populate to an Ansible user on each database host. 21 | 1. Create a JSON file `db1_asm.json` with ASM disk devices: 22 | ```json 23 | [ 24 | { 25 | "diskgroup": "DATA", 26 | "disks": [ 27 | { 28 | "name": "DATA_1", 29 | "blk_device": "/dev/mapper/3600a098038314352502b4f782f446155" 30 | } 31 | ] 32 | }, 33 | { 34 | "diskgroup": "RECO", 35 | "disks": [ 36 | { 37 | "name": "RECO_1", 38 | "blk_device": "/dev/mapper/3600a098038314352502b4f782f446162" 39 | } 40 | ] 41 | } 42 | ] 43 | ``` 44 | 1. Create a JSON file `db1_mounts.json` with disk mounts: 45 | ```json 46 | [ 47 | { 48 | "purpose": "software", 49 | "blk_device": "/dev/mapper/3600a098038314352502b4f782f446161", 50 | "name": "u01", 51 | "fstype": "xfs", 52 | "mount_point": "/u01", 53 | "mount_opts": "nofail" 54 | } 55 | ] 56 | ``` 57 | 1. Execute `install-oracle.sh`: 58 | ```bash 59 | bash install-oracle.sh \ 60 | --ora-swlib-bucket gs://installation-media-1234 \ 61 | --instance-ssh-user ansible \ 62 | --instance-ssh-key ~/.ssh/id_rsa \ 63 | --backup-dest /u01/rman \ 64 | --ora-swlib-path /u01/oracle_install \ 65 | --ora-version 19 \ 66 | --ora-swlib-type gcs \ 67 | --ora-asm-disks db1_asm.json \ 68 | --ora-data-mounts db1_mounts.json \ 69 | --ora-data-destination DATA \ 70 | --ora-reco-destination RECO \ 71 | --ora-db-name orcl \ 72 | --instance-ip-addr 172.16.1.1 73 | ``` 74 | 75 | Full documentation is available in the [user guide](/docs/user-guide.md) 76 | 77 | ## Destructive cleanup 78 | 79 | An Ansible role and playbook performs a [destructive brute-force removal](/docs/user-guide.md#destructive-cleanup) of Oracle software and configuration. It does not remove other host prerequisites. 80 | 81 | Run the destructive brute-force Oracle software removal with `cleanup-oracle.sh` or `ansible-playbook brute-cleanup.yml` 82 | 83 | ## Contributing to the project 84 | 85 | Contributions and pull requests are welcome. See [docs/contributing.md](docs/contributing.md) and [docs/code-of-conduct.md](docs/code-of-conduct.md) for details. 86 | 87 | ## The fine print 88 | 89 | This product is [licensed](LICENSE) under the Apache 2 license. This is not an officially supported Google project 90 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = ./inventory 3 | deprecation_warnings = False 4 | become_method = sudo 5 | retry_files_enabled = False 6 | #display_skipped_hosts = False 7 | #stdout_callback = debug 8 | #stderr_callback = debug 9 | #allow_world_readable_tmpfiles = true 10 | #remote_tmp = /tmp/ansible 11 | interpreter_python = auto_legacy_silent 12 | command_warnings = False 13 | -------------------------------------------------------------------------------- /asm_disk_config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "diskgroup": "DATA", 4 | "disks": [ 5 | { 6 | "blk_device": "/dev/BOGUS", 7 | "name": "DATA1" 8 | } 9 | ] 10 | }, 11 | { 12 | "diskgroup": "RECO", 13 | "disks": [ 14 | { 15 | "blk_device": "/dev/BOGUS", 16 | "name": "RECO1" 17 | } 18 | ] 19 | }, 20 | { 21 | "diskgroup": "DEMO", 22 | "disks": [ 23 | { 24 | "blk_device": "/dev/BOGUS", 25 | "name": "DEMO1" 26 | } 27 | ] 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /brute-cleanup.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - hosts: dbasm 17 | become: true 18 | become_user: root 19 | pre_tasks: 20 | - name: Verify that Ansible on control node meets the version requirements 21 | assert: 22 | that: "ansible_version.full is version_compare('2.8', '>=')" 23 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 24 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 25 | roles: 26 | - brute-ora-cleanup 27 | -------------------------------------------------------------------------------- /check-instance.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - hosts: dbasm 17 | gather_facts: false 18 | pre_tasks: 19 | - name: Verify that Ansible on control node meets the version requirements 20 | assert: 21 | that: "ansible_version.full is version_compare('2.8', '>=')" 22 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 23 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 24 | - block: 25 | - name: Confirm JSON parsing works 26 | assert: 27 | that: "{{ '{}' | json_query('[0]') == None }}" 28 | rescue: 29 | - name: Check for JSON parse failure 30 | fail: 31 | msg: "You probably need to install Python jmespath on the control node" 32 | 33 | tasks: 34 | - name: Test connectivity to target instance via ping 35 | ping: 36 | register: pingrc 37 | 38 | - name: Abort if ping module fails 39 | assert: 40 | that: "pingrc.ping == 'pong'" 41 | fail_msg: >- 42 | The instance does not have an usable python distribution 43 | success_msg: >- 44 | The instance has an usable python installation, continuing 45 | 46 | - name: Collect facts from target 47 | setup: 48 | 49 | - name: Test privilege escalation on target 50 | raw: sudo -u root whoami 51 | register: rawrc 52 | changed_when: false 53 | 54 | - name: Fail if unable to sudo to root on target 55 | assert: 56 | that: "'root' in rawrc.stdout_lines" 57 | fail_msg: "The account {{ ansible_user }} used to connect does not have sudo privileges to root" 58 | success_msg: "The account {{ ansible_user }} used to connect has sudo root privileges, continuing" 59 | 60 | - name: Check for Python installation 61 | raw: test -e /usr/bin/python || test -e /usr/bin/python3 62 | changed_when: false 63 | failed_when: false 64 | register: check_python 65 | 66 | - name: Install Python if required 67 | raw: sudo yum -y install python3 68 | when: check_python.rc != 0 69 | -------------------------------------------------------------------------------- /check-swlib.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Set correct RDBMS release 17 | hosts: localhost 18 | connection: local 19 | gather_facts: false 20 | pre_tasks: 21 | - name: Verify that Ansible on control node meets the version requirements 22 | assert: 23 | that: "ansible_version.full is version_compare('2.8', '>=')" 24 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 25 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 26 | tasks: 27 | - include_role: 28 | name: common 29 | tasks_from: populate-vars.yml 30 | tags: check-swlib 31 | 32 | - name: Check swlib 33 | hosts: localhost 34 | connection: local 35 | gather_facts: false 36 | tasks: 37 | - include_role: 38 | name: check-swlib 39 | tasks_from: main.yml 40 | tags: check-swlib 41 | -------------------------------------------------------------------------------- /cluster_config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "scan_name": "scan-cluster", 4 | "scan_port": "1521", 5 | "cluster_name": "cluster", 6 | "cluster_domain": "home", 7 | "public_net": "public_interface", 8 | "private_net": "private", 9 | "scan_ip1": "10.0.1.256", 10 | "scan_ip2": "10.0.1.257", 11 | "scan_ip3": "10.0.1.258", 12 | "dg_name": "DG_NAME", 13 | "nodes": [ 14 | { 15 | "node_name": "host_name", 16 | "host_ip": "10.0.0.256", 17 | "vip_name": "host_name-vip", 18 | "vip_ip": "192.168.0.256" 19 | }, 20 | { 21 | "node_name": "host_name", 22 | "host_ip": "10.0.0.257", 23 | "vip_name": "host_name-vip", 24 | "vip_ip": "192.168.0.257" 25 | } 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /config-db.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - hosts: dbasm 17 | remote_user: "{{ oracle_user }}" 18 | become: true 19 | become_user: root 20 | pre_tasks: 21 | - name: Verify that Ansible on control node meets the version requirements 22 | assert: 23 | that: "ansible_version.full is version_compare('2.8', '>=')" 24 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 25 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 26 | tasks: 27 | - include_role: 28 | name: lsnr-create 29 | when: create_listener | bool 30 | tags: lsnr-create 31 | 32 | - include_role: 33 | name: "{{ role_item }}" 34 | tasks_from: main 35 | loop: 36 | - db-create 37 | - db-adjustments 38 | - db-backups 39 | - validation-scripts 40 | loop_control: 41 | loop_var: role_item 42 | when: 43 | - create_db | bool 44 | - cluster_type != "RAC" 45 | - lookup('env', 'PRIMARY_IP_ADDR') is not defined or lookup('env', 'PRIMARY_IP_ADDR') | length == 0 46 | tags: primary-db 47 | 48 | - include_role: 49 | name: db-copy 50 | tasks_from: active-copy 51 | when: 52 | - create_db | bool 53 | - cluster_type != "RAC" 54 | - lookup('env', 'PRIMARY_IP_ADDR') is defined 55 | - lookup('env', 'PRIMARY_IP_ADDR') | length > 0 56 | tags: active-duplicate 57 | 58 | - include_role: 59 | name: dg-config 60 | tasks_from: main 61 | when: cluster_type == "DG" 62 | tags: dg-create 63 | 64 | - include_role: 65 | name: dg-config 66 | tasks_from: dg_mode 67 | when: cluster_type == "DG" 68 | tags: dg-create,dg-mode 69 | -------------------------------------------------------------------------------- /config-rac-db.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - hosts: dbasm[0] 17 | tasks: 18 | - include_role: 19 | name: db-create 20 | tasks_from: rac-db-create.yml 21 | - include_role: 22 | name: "{{ role_item }}" 23 | tasks_from: main 24 | loop: 25 | - db-adjustments 26 | - db-backups 27 | - validation-scripts 28 | loop_control: 29 | loop_var: role_item 30 | when: create_db | bool 31 | tags: rac-db-adjustments,rac-db-backups,rac-validation-scripts 32 | -------------------------------------------------------------------------------- /data_mounts_config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "purpose": "software", 4 | "blk_device": "replace_with_block_device_like_/dev/mapper/db-sw", 5 | "name": "u01", 6 | "fstype": "xfs", 7 | "mount_point": "/u01", 8 | "mount_opts": "nofail" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | title: oracle-toolkit 17 | description: Toolkit for managing Oracle databases on Google Cloud 18 | remote_theme: pages-themes/cayman 19 | plugins: 20 | - jekyll-remote-theme 21 | markdown: kramdown 22 | defaults: 23 | - 24 | scope: 25 | path: "" # an empty string here means all files in the project 26 | values: 27 | layout: "default" 28 | -------------------------------------------------------------------------------- /docs/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | --- 2 | published: True 3 | --- 4 | 5 | # Google Open Source Community Guidelines 6 | 7 | At Google, we recognize and celebrate the creativity and collaboration of open 8 | source contributors and the diversity of skills, experiences, cultures, and 9 | opinions they bring to the projects and communities they participate in. 10 | 11 | Every one of Google's open source projects and communities are inclusive 12 | environments, based on treating all individuals respectfully, regardless of 13 | gender identity and expression, sexual orientation, disabilities, 14 | neurodiversity, physical appearance, body size, ethnicity, nationality, race, 15 | age, religion, or similar personal characteristic. 16 | 17 | We value diverse opinions, but we value respectful behavior more. 18 | 19 | Respectful behavior includes: 20 | 21 | - Being considerate, kind, constructive, and helpful. 22 | - Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or 23 | physically threatening behavior, speech, and imagery. 24 | - Not engaging in unwanted physical contact. 25 | 26 | Some Google open source projects [may adopt][] an explicit project code of 27 | conduct, which may have additional detailed expectations for participants. Most 28 | of those projects will use our [modified Contributor Covenant][]. 29 | 30 | [may adopt]: https://opensource.google/docs/releasing/preparing/#conduct 31 | [modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ 32 | 33 | ## Resolve peacefully 34 | 35 | We do not believe that all conflict is necessarily bad; healthy debate and 36 | disagreement often yields positive results. However, it is never okay to be 37 | disrespectful. 38 | 39 | If you see someone behaving disrespectfully, you are encouraged to address the 40 | behavior directly with those involved. Many issues can be resolved quickly and 41 | easily, and this gives people more control over the outcome of their dispute. 42 | If you are unable to resolve the matter for any reason, or if the behavior is 43 | threatening or harassing, report it. We are dedicated to providing an 44 | environment where participants feel welcome and safe. 45 | 46 | ## Reporting problems 47 | 48 | Some Google open source projects may adopt a project-specific code of conduct. 49 | In those cases, a Google employee will be identified as the Project Steward, 50 | who will receive and handle reports of code of conduct violations. In the event 51 | that a project hasn’t identified a Project Steward, you can report problems by 52 | emailing opensource@google.com. 53 | 54 | We will investigate every complaint, but you may not receive a direct response. 55 | We will use our discretion in determining when and how to follow up on reported 56 | incidents, which may range from not taking action to permanent expulsion from 57 | the project and project-sponsored spaces. We will notify the accused of the 58 | report and provide them an opportunity to discuss it before any action is 59 | taken. The identity of the reporter will be omitted from the details of the 60 | report supplied to the accused. In potentially harmful situations, such as 61 | ongoing harassment or threats to anyone's safety, we may take action without 62 | notice. 63 | 64 | _This document was adapted from the [IndieWeb Code of Conduct][] and can also 65 | be found at ._ 66 | 67 | [IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct 68 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | published: True 3 | --- 4 | 5 | # How to Contribute 6 | 7 | We'd love to accept your patches and contributions to this project. There are 8 | just a few small guidelines you need to follow. 9 | 10 | ## Contributor License Agreement 11 | 12 | Contributions to this project must be accompanied by a Contributor License 13 | Agreement. You (or your employer) retain the copyright to your contribution; 14 | this simply gives us permission to use and redistribute your contributions as 15 | part of the project. Head over to to see 16 | your current agreements on file or to sign a new one. 17 | 18 | You generally only need to submit a CLA once, so if you've already submitted one 19 | (even if it was for a different project), you probably don't need to do it 20 | again. 21 | 22 | ## Code reviews 23 | 24 | All submissions, including submissions by project members, require review. We 25 | use GitHub pull requests for this purpose. Consult 26 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 27 | information on using pull requests. 28 | 29 | ## Community Guidelines 30 | 31 | This project follows [Google's Open Source Community 32 | Guidelines](https://opensource.google/conduct/). 33 | -------------------------------------------------------------------------------- /docs/host-provision-logical-fork-points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/oracle-toolkit/faa420a61498ea553de64512cf752f4635038503/docs/host-provision-logical-fork-points.png -------------------------------------------------------------------------------- /docs/host-provisioning.md: -------------------------------------------------------------------------------- 1 | # Host provisioning 2 | 3 | `host-provision.sh` takes a newly-delivered BMS host to a state where `install-oracle.sh` can be run, including: 4 | 5 | * Creating a user on the BMS host to run automation code, including SSH authentication and sudo access 6 | * Optionally configure Internet access through a proxy server 7 | * If running Red Hat Enterprise Linux, register the BMS host using Red Hat's subscription manager 8 | * Optionally use Linux LVM to create a volume for local Oracle software 9 | 10 | For a RAC cluster, run `host-provision.sh` on each cluster node. 11 | 12 | ## Pre-requisities 13 | 14 | * Follow BMS [planning](https://cloud.google.com/bare-metal/docs/bms-planning) and [implementation](https://cloud.google.com/bare-metal/docs/bms-setup) steps, including testing ssh connectivity as the `customeradmin` user. 15 | * Obtain the `customeradmin` password, which will be prompted for in the `host-provision.sh` run. 16 | * If running Red Hat Enterprise Linux, obtain Red Hat credentials to request licenses. 17 | * Choose or create a host to run `bms-toolkit` from; this is typically the same [jump host](https://cloud.google.com/bare-metal/docs/bms-setup#bms-create-jump-host) as created as part of BMS implementation. It will act as the ansible control node. 18 | * On the control node, download and extract `bms-toolkit`; in this example we take a zip file of the master branch: 19 | 20 | ```bash 21 | curl -LO https://github.com/google/bms-toolkit/archive/refs/heads/master.zip 22 | unzip master.zip 23 | cd bms-toolkit-master 24 | ``` 25 | 26 | ## Parameters 27 | 28 | * `--instance-ip-addr`: IP address of the BMS host to provision. 29 | * `--instance-ssh-user`: username on the BMS host to run `bms-toolkit` commands as. The default is `ansible`. 30 | * `--proxy-setup`: configure a [proxy server](#proxy-server) on the control node to provide BMS host Internet access; by default no proxy server will be configured. 31 | * `--u01-lun`: optionally configure [Linux LVM](#linux-lvm) for the software mount in Oracle RAC installs, for use in `install-oracle.sh`'s `--ora-data-mounts` option. 32 | 33 | ## Sample invocations 34 | 35 | * To provision BMS host `172.16.30.1` to run as user `ansible9` and to configure a proxy server: 36 | ```bash 37 | ./host-provision.sh --instance-ip-addr 172.16.30.1 --instance-ssh-user ansible9 --proxy-setup true 38 | ``` 39 | 40 | * To provision BMS host `172.16.30.1` to run as user `ansible9` without a proxy server, and also to configure Linux LVM on device `/dev/mapper/3600a098038314473792b51456555712f`: 41 | ```bash 42 | ./host-provision.sh --instance-ip-addr 172.16.30.1 --instance-ssh-user ansible9 \ 43 | --u01-lun /dev/mapper/3600a098038314344372b4f75392d3850 44 | ``` 45 | 46 | ## Proxy server 47 | 48 | If the BMS host requires outgoing Internet access (to access Red Hat license servers, for example), there are [several options](https://cloud.google.com/bare-metal/docs/bms-setup#bms-access-internet). `host-provision.sh` can optionally configure Internet access through a proxy server on the control node. A proxy server can improve network security by restricting which Internet sites can be accessed, as well as auditing such access. 49 | 50 | ## Linux LVM 51 | 52 | BMS disk devices are presented as multipathed device nodes with the full world-wide name (WWN) of the device, such as `/dev/mapper/3600a098038314344372b4f75392d3850`. This presents an issue when configuring the [data mount configuration file](https://github.com/google/bms-toolkit/blob/master/docs/user-guide.md#data-mount-configuration-file) when running `install-oracle.sh` for RAC clusters, as each nodes will have separate software mounts with their own WWNs. The `--u01-lun` parameter addresses this issue by creating a Linux LVM volume with a consistent name `/dev/mapper/db-sw` that can be included in the data mount configuration file. 53 | 54 | ## Schematic 55 | 56 | * With the caveat that code structure can quickly go out of date, the following represents the host-provision utility as it existed when this document was created. 57 | 58 | ![Shows codeflow from host-utility.sh command line to the host-provision.yml entry point and on to the leaf scripts.](host-provision-logical-fork-points.png) 59 | 60 | The aim of publishing the above code flow is not accuracy or up-to-date codemap, 61 | but rather function as a helpful start so the user can gain the basic understanding of the layout. 62 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Oracle Toolkit for GCP 4 | 5 | -------------------------------------------------------------------------------- /docs/oracle-toolkit-bm-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/oracle-toolkit/faa420a61498ea553de64512cf752f4635038503/docs/oracle-toolkit-bm-architecture.png -------------------------------------------------------------------------------- /docs/oracle-toolkit-vm-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/oracle-toolkit/faa420a61498ea553de64512cf752f4635038503/docs/oracle-toolkit-vm-architecture.png -------------------------------------------------------------------------------- /docs/patch-metadata.md: -------------------------------------------------------------------------------- 1 | # A note on patch metadata 2 | 3 | The patching code derives the patch metadata from the following blocks in the file `role/common/default/main.yml`: 4 | 5 | ```yaml 6 | gi_patches: 7 | ... 8 | - { category: "RU", base: "19.3.0.0.0", release: "19.9.0.0.201020", patchnum: "31720429", patchfile: "p31720429_190000_Linux-x86-64.zip", patch_subdir: "/31750108", prereq_check: FALSE, method: "opatchauto apply", ocm: FALSE, upgrade: FALSE, md5sum: "tTZDYSasdnt7lrNJ/MYm1g==" } 9 | 10 | 11 | rdbms_patches: 12 | ... 13 | - { category: "RU_Combo", base: "19.3.0.0.0", release: "19.9.0.0.201020", patchnum: "31720429", patchfile: "p31720429_190000_Linux-x86-64.zip", patch_subdir: "/31668882", prereq_check: TRUE, method: "opatch apply", ocm: FALSE, upgrade: TRUE, md5sum: "tTZDYSasdnt7lrNJ/MYm1g==" } 14 | ``` 15 | 16 | These metadata numbers can be taken from consulting appropriate MOS Notes, such as: 17 | - [Assistant: Download Reference for Oracle Database/GI Update, Revision, PSU, SPU(CPU), Bundle Patches, Patchsets and Base Releases (Doc ID 2118136.2)](https://support.oracle.com/epmos/faces/DocContentDisplay?id=2118136.2) 18 | - [Master Note for Database Proactive Patch Program (Doc ID 888.1)](https://support.oracle.com/epmos/faces/DocContentDisplay?id=888.1) 19 | - [Oracle Database 19c Proactive Patch Information (Doc ID 2521164.1)](https://support.oracle.com/epmos/faces/DocContentDisplay?id=2521164.1) 20 | - [Database 18c Proactive Patch Information (Doc ID 2369376.1)](https://support.oracle.com/epmos/faces/DocContentDisplay?id=2369376.1) 21 | - [Database 12.2.0.1 Proactive Patch Information (Doc ID 2285557.1)](https://support.oracle.com/epmos/faces/DocContentDisplay?id=2285557.1) 22 | 23 | The md5sum can be determined by listing the file once in a GCS bucket: 24 | 25 | ```bash 26 | $ gsutil ls -L gs://example-bucket/p32578973_190000_Linux-x86-64.zip | grep md5 27 | Hash (md5): YLEOruyjCOdDvUOMBUazNQ== 28 | ``` 29 | 30 | Bearing in mind that the GI RU's patch zipfile contains the patch molecules that go both into the GI_HOME as well as the RDBMS_HOME, the Combo patch of OJVM+GI is self-contained as to the necessary patches needed to patch a given host for a given quarter. For example: the patch zipfile `p31720429_190000_Linux-x86-64.zip` contains the following patch directories: 31 | 32 | ``` 33 | ├── 31720429 34 | │   ├── 31668882 <================ this is the OJVM RU for that quarter 35 | │   │   ├── etc 36 | │   │   ├── files 37 | │   │   ├── README.html 38 | │   │   └── README.txt 39 | │   ├── 31750108 <================ this is GI RU for the given quarter 40 | │   │   ├── 31771877 41 | │   │   ├── 31772784 42 | │   │   ├── 31773437 43 | │   │   ├── 31780966 44 | │   │   ├── automation 45 | │   │   ├── bundle.xml 46 | │   │   ├── README.html 47 | │   │   └── README.txt 48 | │   ├── PatchSearch.xml 49 | │   └── README.html 50 | └── PatchSearch.xml 51 | 52 | ``` 53 | Accordingly the `patch_subdir` values can be edited, as noted in the foregoing. 54 | -------------------------------------------------------------------------------- /host-provision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | echo Command used: 17 | echo "$0 $@" 18 | echo 19 | 20 | shopt -s nocasematch 21 | 22 | # Check if we're using the Mac stock getopt and fail if true 23 | out="$(getopt -T)" 24 | if [ $? != 4 ]; then 25 | echo -e "Your getopt does not support long parameters, possibly you're on a Mac, if so please install gnu-getopt with brew" 26 | echo -e "\thttps://brewformulas.org/Gnu-getopt" 27 | exit 28 | fi 29 | 30 | GETOPT_MANDATORY="instance-ip-addr:" 31 | GETOPT_OPTIONAL="instance-ssh-user:,proxy-setup:,u01-lun:,help" 32 | GETOPT_LONG="${GETOPT_MANDATORY},${GETOPT_OPTIONAL}" 33 | GETOPT_SHORT="h" 34 | 35 | INSTANCE_SSH_USER="${INSTANCE_SSH_USER:-'ansible'}" 36 | 37 | options="$(getopt --longoptions "$GETOPT_LONG" --options "$GETOPT_SHORT" -- "$@")" 38 | 39 | [ $? -eq 0 ] || { 40 | echo "Invalid options provided: $@" >&2 41 | exit 1 42 | } 43 | 44 | # echo "PARSED COMMAND LINE FLAGS: $options" 45 | 46 | eval set -- "$options" 47 | 48 | while true; do 49 | case "$1" in 50 | --u01-lun) 51 | ORA_U01_LUN="$2" 52 | shift 53 | ;; 54 | --proxy-setup) 55 | ORA_PROXY_SETUP="$2" 56 | shift 57 | ;; 58 | --instance-ssh-user) 59 | INSTANCE_SSH_USER="$2" 60 | shift 61 | ;; 62 | --instance-ip-addr) 63 | ORA_CS_HOSTS="$2" 64 | shift 65 | ;; 66 | --help | -h) 67 | echo -e "\tUsage: $(basename $0)" >&2 68 | echo "${GETOPT_MANDATORY}" | sed 's/,/\n/g' | sed 's/:/ /' | sed 's/\(.\+\)/\t --\1/' 69 | echo "${GETOPT_OPTIONAL}" | sed 's/,/\n/g' | sed 's/:/ /' | sed 's/\(.\+\)/\t [ --\1 ]/' 70 | exit 2 71 | ;; 72 | --) 73 | shift 74 | break 75 | ;; 76 | esac 77 | shift 78 | done 79 | 80 | export INSTANCE_SSH_USER 81 | export ORA_CS_HOSTS 82 | export ORA_PROXY_SETUP 83 | export ORA_U01_LUN 84 | export INVENTORY_FILE="$ORA_CS_HOSTS," 85 | 86 | echo -e "Running with parameters from command line or environment variables:\n" 87 | set | grep -E '^(ORA_|INVENTORY_|INSTANCE_)' | grep -v '_PARAM=' 88 | echo 89 | 90 | ANSIBLE_PARAMS="-i ${INVENTORY_FILE} ${ANSIBLE_PARAMS}" 91 | ANSIBLE_EXTRA_PARAMS="${*}" 92 | 93 | export ANSIBLE_DISPLAY_SKIPPED_HOSTS=false 94 | 95 | ANSIBLE_PLAYBOOK="ansible-playbook" 96 | if ! type ansible-playbook >/dev/null 2>&1; then 97 | echo "Ansible executable not found in path" 98 | exit 3 99 | else 100 | echo "Found Ansible: $(type ansible-playbook)" 101 | fi 102 | 103 | # exit on any error from the following scripts 104 | set -e 105 | 106 | PLAYBOOK="host-provision.yml" 107 | ANSIBLE_COMMAND="${ANSIBLE_PLAYBOOK} ${ANSIBLE_PARAMS} ${ANSIBLE_EXTRA_PARAMS} ${PLAYBOOK}" 108 | echo 109 | echo "Running Ansible playbook: ${ANSIBLE_COMMAND}" 110 | eval ${ANSIBLE_COMMAND} 111 | -------------------------------------------------------------------------------- /host-provision.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | # Assumption: 17 | # First time connection is not through public private key pair 18 | # First time connection is always through {{ firsttime_connect_user }} credentials password authentication 19 | # Consequentially, to start with, inventory file will not have details about SSH private key 20 | 21 | # Logic: 22 | # First using the {{ firsttime_connect_user }} credentials, keypair is generated 23 | # The tasks in host provisioning will be done using {{ firsttime_connect_user }} 24 | # For running subsequent install-oracle.sh, customer can then ssh using the ansible user created 25 | # Inventory file may be updated with: ansible_ssh_private_key_file and ansible_ssh_user=ansible 26 | # Prior to calling the next steps (i.e.: install-oracle.sh) 27 | 28 | - name: Create private public key pair locally 29 | hosts: localhost 30 | tasks: 31 | - include_role: 32 | name: host-provision 33 | tasks_from: ssh-keygen.yml 34 | tags: host-provision 35 | 36 | - name: Create user and transfer public key to set up ssh equivalence 37 | hosts: all 38 | vars_prompt: 39 | - name: ansible_password 40 | prompt: Enter customeradmin password 41 | vars: 42 | # ansible_ssh_extra_args can be input as a command line or the following reasonable default may be used: 43 | ansible_ssh_extra_args: "-o IdentityAgent=no" 44 | become: true 45 | pre_tasks: 46 | - name: Verify that Ansible on control node meets the version requirements 47 | assert: 48 | that: "ansible_version.full is version_compare('2.8', '>=')" 49 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 50 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 51 | tasks: 52 | - include_role: 53 | name: host-provision 54 | tasks_from: user-setup.yml 55 | remote_user: "{{ firsttime_connect_user }}" 56 | tags: host-provision 57 | 58 | - name: Perform config tasks (SSH equivalence validation, LVM setup, etc) 59 | hosts: all 60 | vars: 61 | ansible_ssh_private_key_file: "{{ control_node_key_file }}" 62 | # ansible_ssh_extra_args can be input as a command line or the following reasonable default may be used: 63 | ansible_ssh_extra_args: "-o IdentityAgent=no" 64 | become: true 65 | tasks: 66 | - include_role: 67 | name: host-provision 68 | tasks_from: config-tasks.yml 69 | remote_user: "{{ instance_ssh_user }}" 70 | tags: host-provision 71 | 72 | # Not clubbing this play inside the main play that performs all config tasks 73 | # Reason: need to first connect as a non-sudo user (become: false) to get to the fact ansible_env['SSH_CLIENT'] 74 | - name: Proxy setup [optional] 75 | hosts: all 76 | vars: 77 | ansible_ssh_private_key_file: "{{ control_node_key_file }}" 78 | # ansible_ssh_extra_args can be input as a command line or the following reasonable default may be used: 79 | ansible_ssh_extra_args: "-o IdentityAgent=no" 80 | become: false 81 | tasks: 82 | - include_role: 83 | name: host-provision 84 | tasks_from: proxy.yml 85 | when: proxy_setup | bool 86 | remote_user: "{{ instance_ssh_user }}" 87 | tags: host-provision 88 | 89 | - name: Perform RHEL-specific config tasks (subscription-manager, etc) 90 | hosts: all 91 | vars: 92 | ansible_ssh_private_key_file: "{{ control_node_key_file }}" 93 | # ansible_ssh_extra_args can be input as a command line or the following reasonable default may be used: 94 | ansible_ssh_extra_args: "-o IdentityAgent=no" 95 | become: true 96 | tasks: 97 | - include_role: 98 | name: host-provision 99 | tasks_from: rhel-config-tasks.yml 100 | when: 101 | - ansible_distribution == 'RedHat' 102 | remote_user: "{{ instance_ssh_user }}" 103 | tags: host-provision 104 | -------------------------------------------------------------------------------- /patch.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Populate variables 17 | hosts: dbasm 18 | tasks: 19 | - include_role: 20 | name: common 21 | tasks_from: populate-vars.yml 22 | 23 | - name: Download patches 24 | hosts: dbasm 25 | pre_tasks: 26 | - name: Verify that Ansible on control node meets the version requirements 27 | assert: 28 | that: "ansible_version.full is version_compare('2.8', '>=')" 29 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 30 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 31 | tasks: 32 | - include_role: 33 | name: swlib 34 | tasks_from: main.yml 35 | vars: 36 | patch_only: true 37 | become: false 38 | tags: download-patches 39 | 40 | - name: OPatch Restart patch 41 | hosts: dbasm 42 | tasks: 43 | - include_role: 44 | name: patch 45 | tasks_from: main.yml 46 | when: hostvars[groups['dbasm'].0]['cluster_name']|default('', true)|length == 0 47 | remote_user: "{{ oracle_user }}" 48 | become: true 49 | become_user: root 50 | tags: opatch_restart 51 | 52 | - name: RAC install opatch 53 | hosts: dbasm 54 | tasks: 55 | - include_role: 56 | name: patch 57 | tasks_from: rac-ins-opatch.yml 58 | vars: 59 | db_config_type: RAC 60 | when: hostvars[groups['dbasm'].0]['cluster_name']|default('', true)|length > 0 61 | tags: rac-ins-opatch 62 | 63 | - name: RAC patch apply 64 | hosts: dbasm 65 | serial: 1 66 | order: inventory 67 | tasks: 68 | - include_role: 69 | name: patch 70 | tasks_from: rac-opatch.yml 71 | vars: 72 | db_config_type: RAC 73 | when: hostvars[groups['dbasm'].0]['cluster_name']|default('', true)|length > 0 74 | tags: rac-opatch 75 | 76 | - name: RAC database patch 77 | hosts: dbasm[0] 78 | tasks: 79 | - include_role: 80 | name: patch 81 | tasks_from: rac-dbpatch.yml 82 | vars: 83 | db_config_type: RAC 84 | when: hostvars[groups['dbasm'].0]['cluster_name']|default('', true)|length > 0 85 | tags: rac-dbpatch 86 | -------------------------------------------------------------------------------- /prep-host.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Populate variables 17 | hosts: dbasm 18 | tasks: 19 | - include_role: 20 | name: common 21 | tasks_from: populate-vars.yml 22 | tags: populate-vars 23 | 24 | - hosts: dbasm 25 | become: true 26 | become_user: root 27 | pre_tasks: 28 | - name: Verify that Ansible on control node meets the version requirements 29 | assert: 30 | that: "ansible_version.full is version_compare('2.8', '>=')" 31 | fail_msg: "You must update Ansible to at least 2.8 to use these playbooks" 32 | success_msg: "Ansible version is {{ ansible_version.full }}, continuing" 33 | roles: 34 | - { role: base-provision, tags: base-provision } 35 | - { role: host-storage, tags: host-storage } 36 | - { role: ora-host, tags: ora-host } 37 | 38 | - hosts: dbasm[0] 39 | become: false 40 | roles: 41 | - { role: swlib, tags: swlib } 42 | -------------------------------------------------------------------------------- /presubmit_tests/rac-on-bms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | node1_ip=172.16.128.1 17 | node2_ip=172.16.128.2 18 | 19 | install -d -m 0700 ~/.ssh 20 | ssh-keyscan "${node1_ip}" > ~/.ssh/known_hosts 21 | ssh-keyscan "${node2_ip}" > ~/.ssh/known_hosts 22 | 23 | sed -i \ 24 | -e '/^baseurl=/s/^/#/' \ 25 | -e '/^mirrorlist=/s/^/#/' \ 26 | -e '$a baseurl=http://vault.centos.org/8-stream/AppStream/x86_64/os/' \ 27 | /etc/yum.repos.d/CentOS-Stream-AppStream.repo 28 | 29 | # install pre-reqs 30 | pip install jmespath 31 | cp /etc/files_needed_for_tk/google-cloud-sdk.repo /etc/yum.repos.d/google-cloud-sdk.repo 32 | yum --disablerepo=* --enablerepo=google-cloud-sdk -y install google-cloud-sdk 33 | # jq is required for RAC installation 34 | yum --disablerepo=* --enablerepo=appstream -y install jq 35 | 36 | pwd 37 | ./cleanup-oracle.sh --ora-version 19 \ 38 | --inventory-file /etc/files_needed_for_tk/rac-inventory \ 39 | --yes-i-am-sure --ora-disk-mgmt udev --ora-swlib-path /u01/oracle_install \ 40 | --ora-asm-disks /etc/files_needed_for_tk/rac-asm.json \ 41 | --ora-data-mounts /etc/files_needed_for_tk/rac-data-mounts.json 42 | 43 | if [[ $? -ne 0 ]]; then 44 | echo "cleanup-oracle.sh failed, fix and rerun prowjob" 45 | exit 1 46 | fi 47 | 48 | ./install-oracle.sh --ora-swlib-bucket gs://bmaas-testing-oracle-software \ 49 | --instance-ssh-user ansible --instance-ssh-key /etc/files_needed_for_tk/ansible_private_ssh_key \ 50 | --backup-dest "+RECO" --ora-swlib-path /u01/oracle_install --ora-version 19 --ora-swlib-type gcs \ 51 | --ora-asm-disks /etc/files_needed_for_tk/rac-asm.json \ 52 | --ora-data-mounts /etc/files_needed_for_tk/rac-data-mounts.json --cluster-type RAC \ 53 | --cluster-config /etc/files_needed_for_tk/rac-config.json --ora-data-destination DATA \ 54 | --ora-reco-destination RECO --ora-db-name orcl --ora-db-container false 55 | -------------------------------------------------------------------------------- /presubmit_tests/single-instance-on-bms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | node_ip=172.16.117.3 17 | 18 | install -d -m 0700 ~/.ssh 19 | ssh-keyscan "${node_ip}" > ~/.ssh/known_hosts 20 | 21 | sed -i \ 22 | -e '/^baseurl=/s/^/#/' \ 23 | -e '/^mirrorlist=/s/^/#/' \ 24 | -e '$a baseurl=http://vault.centos.org/8-stream/AppStream/x86_64/os/' \ 25 | /etc/yum.repos.d/CentOS-Stream-AppStream.repo 26 | 27 | # install pre-reqs 28 | pip install jmespath 29 | cp /etc/files_needed_for_tk/google-cloud-sdk.repo /etc/yum.repos.d/google-cloud-sdk.repo 30 | yum --disablerepo=* --enablerepo=google-cloud-sdk -y install google-cloud-sdk 31 | 32 | pwd 33 | ./cleanup-oracle.sh --ora-version 19 \ 34 | --inventory-file /etc/files_needed_for_tk/single-instance-inventory \ 35 | --yes-i-am-sure --ora-disk-mgmt udev --ora-swlib-path /u01/oracle_install \ 36 | --ora-asm-disks /etc/files_needed_for_tk/single-instance-asm.json \ 37 | --ora-data-mounts /etc/files_needed_for_tk/single-instance-data-mounts.json 38 | 39 | if [[ $? -ne 0 ]]; then 40 | echo "cleanup-oracle.sh failed, fix and rerun prowjob" 41 | exit 1 42 | fi 43 | 44 | ./install-oracle.sh --ora-swlib-bucket gs://bmaas-testing-oracle-software \ 45 | --instance-ssh-user ansible --instance-ssh-key /etc/files_needed_for_tk/ansible_private_ssh_key \ 46 | --backup-dest "+RECO" --ora-swlib-path /u01/oracle_install --ora-version 19 --ora-swlib-type gcs \ 47 | --ora-asm-disks /etc/files_needed_for_tk/single-instance-asm.json \ 48 | --ora-data-mounts /etc/files_needed_for_tk/single-instance-data-mounts.json --cluster-type NONE \ 49 | --ora-data-destination DATA --ora-reco-destination RECO --ora-db-name orcl --ora-db-container false \ 50 | --instance-ip-addr "${node_ip}" --instance-hostname g322234287-s002 51 | -------------------------------------------------------------------------------- /roles/base-provision/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | os_family_supported: "RedHat" 17 | os_min_supported_version: "{% if free_edition %}8{% else %}7.3{% endif %}" 18 | 19 | etc_hosts_ip: "{% if 'virtualbox' in ansible_virtualization_type %}{{ ansible_all_ipv4_addresses[1] }}{% else %}{{ ansible_default_ipv4.address }}{% endif %}" 20 | install_os_packages: true 21 | 22 | required_packages: 23 | - chrony 24 | - bind-utils 25 | - unzip 26 | - expect 27 | - wget 28 | - net-tools 29 | - parted 30 | 31 | swap_blk_device: "" 32 | ntp_preferred: "" 33 | ntp_options: "-g" 34 | -------------------------------------------------------------------------------- /roles/base-provision/handlers/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | # handlers file for init 17 | - name: restart dnsmasq 18 | service: 19 | name: dnsmasq 20 | state: restarted 21 | 22 | - name: restart chronyd 23 | service: 24 | name: chronyd 25 | state: restarted 26 | -------------------------------------------------------------------------------- /roles/base-provision/tasks/swap.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: swap | Create swap partition 17 | parted: 18 | device: "{{ swap_blk_device }}" 19 | number: 1 20 | state: present 21 | become: true 22 | register: swapfile_register_create 23 | when: "'mapper' not in swap_blk_device" 24 | # Logical volumes managed by LVM do not require 25 | # partitioning like traditional block devices because they are already abstracted 26 | # volumes that can be resized or moved without repartitioning the physical disks. 27 | 28 | - include_role: 29 | name: common 30 | tasks_from: populate-swap-partition-id.yml 31 | 32 | - name: swap | Initialize swap on standard partition 33 | command: mkswap -f {{ swap_partition_id }} 34 | become: true 35 | when: 36 | - swapfile_register_create is changed 37 | - swap_partition_id is defined 38 | - "'mapper' not in swap_blk_device" 39 | 40 | - name: swap | Initialize swap on LVM logical volume 41 | command: mkswap -f {{ swap_blk_device }} 42 | become: true 43 | when: "'mapper' in swap_blk_device" 44 | 45 | - name: swap | Enable swap on standard partition 46 | command: swapon {{ swap_partition_id }} 47 | become: true 48 | when: 49 | - swapfile_register_create is changed 50 | - swap_partition_id is defined 51 | - "'mapper' not in swap_blk_device" 52 | 53 | - name: swap | Enable swap on LVM logical volume 54 | command: swapon {{ swap_blk_device }} 55 | become: true 56 | when: "'mapper' in swap_blk_device" 57 | 58 | - name: swap | Add non-LVM swap entry to /etc/fstab 59 | mount: 60 | src: "{{ swap_partition_id }}" 61 | name: "none" 62 | fstype: "swap" 63 | opts: "sw,nofail" 64 | dump: "0" 65 | passno: "0" 66 | state: "present" 67 | become: true 68 | when: 69 | - swap_partition_id is defined 70 | - "'mapper' not in swap_blk_device" 71 | 72 | - name: swap | Add LVM swap entry to /etc/fstab 73 | mount: 74 | src: "{{ swap_blk_device }}" 75 | name: "none" 76 | fstype: "swap" 77 | opts: "sw,nofail" 78 | dump: "0" 79 | passno: "0" 80 | state: "present" 81 | become: true 82 | when: "'mapper' in swap_blk_device" 83 | -------------------------------------------------------------------------------- /roles/brute-ora-cleanup/README.md: -------------------------------------------------------------------------------- 1 | # Oracle Brute Force Clean-up 2 | 3 | _Caution - destructive tasks - will permanently erase software_ 4 | 5 | Role to do a brute force removal of all Oracle software on server. Run with Oracle/GI services up. 6 | 7 | Objective is to return the target server to the pre-Oracle software installation state. Consequently all files, directories, and databases are permanently removed. 8 | 9 | Sample execution: 10 | 11 | ```bash 12 | ansible-playbook brute-cleanup.yml --extra-vars "oracle_ver=11.2.0.4.0" 13 | ``` 14 | 15 | ## Free Edition Clean-up 16 | 17 | Oracle Database Free Edition is exclusively an RPM installation and supports numerous [versions](../../docs/user-guide.md#free-edition-version-details) without patches. 18 | 19 | Therefore, to run a brute force removal of an Oracle Database Free Edition installation, specify the appropriate version with the `--ora-version` command line argument, and also include `--ora-edition FREE` to differentiate from a commercial edition installation of the same version. 20 | 21 | A brute force cleanup of a Free Edition database will attempt to first remove the existing database/listener and uninstall the software cleanly. Should that process fail or be unable to run due to a broken installation, forceful removal steps will be taken to ensure that the target server is left in an clean state. 22 | 23 | Sample brute force clean-up for Free Edition using the included shell script: 24 | 25 | ```bash 26 | ./cleanup-oracle.sh \ 27 | --ora-edition FREE \ 28 | --ora-version 23.7.0.25.01 \ 29 | --inventory-file inventory_files/inventory_10.2.80.54_FREE \ 30 | --yes-i-am-sure 31 | ``` 32 | -------------------------------------------------------------------------------- /roles/brute-ora-cleanup/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/check-oracle/files/login.sql: -------------------------------------------------------------------------------- 1 | /* 2 | # Copyright 2025 Google LLC 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 | SET HEADING ON ECHO OFF TERMOUT ON TAB OFF TRIMOUT ON TRIMS ON NEWPAGE 1 PAGES 32767 LINES 500 18 | SET LONG 20000000 LONGCHUNKSIZE 50000 FEEDBACK OFF VERIFY OFF TIMING OFF SQLPROMPT \"SQL> \" COLSEP '|' 19 | ALTER SESSION SET CURSOR_SHARING=EXACT; 20 | 21 | -------------------------------------------------------------------------------- /roles/check-oracle/files/orachk-quicktest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : << 'EXPEDITED_TESTING' 4 | 5 | When developing playbooks and scripts, it may not be important to run orachk. 6 | 7 | What is needed during development is to have a facsimile that provides the outputs 8 | needed for testing, but takes seconds rather than minutes 9 | 10 | Enable this with by adding this parameter to check-oracle.sh: ' --extra-vars "expedited_testing=true" ' 11 | 12 | EXPEDITED_TESTING 13 | 14 | 15 | timestamp=$(date +%Y-%m-%d_%H-%m-%S) 16 | 17 | # not really a zip file 18 | testRptFile="/tmp/orachk-quick-test_${timestamp}.zip" 19 | 20 | echo "this is a dummy orachk report" > $testRptFile 21 | 22 | echo "UPLOAD this file if necessary $testRptFile" 23 | -------------------------------------------------------------------------------- /roles/check-oracle/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/check-oracle/vars/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | --- 15 | oratab_path: "/etc/oratab" 16 | ahf_extract_path: "/u01/AHF" 17 | orachk_script_dir: "/u01/orachk" 18 | extended_path: "/usr/local/bin:{{ ansible_env.PATH | default('/usr/bin:/usr/sbin') }}" 19 | # Default is to NOT uninstall AHF 20 | uninstall_ahf: false 21 | # default is to NOT run orachk 22 | run_orachk: false 23 | expedited_testing: false 24 | 25 | ORAENV_ASK: "NO" 26 | RAT_TIMEOUT: "240" 27 | ORACHK_BASE: "/opt/oracle.ahf" 28 | AHFCTL_PATH: "{{ ORACHK_BASE }}/bin/ahfctl" 29 | SQLPATH: "{{ ORACHK_BASE }}" 30 | ORACLE_PATH: "{{ ORACHK_BASE }}" 31 | ORACLE_OWNER: "oracle" 32 | ORACLE_GROUP: "oinstall" 33 | RAT_OUTPUT: "{{ ORACHK_BASE }}/{{ check_name }}" 34 | -------------------------------------------------------------------------------- /roles/check-swlib/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/check-swlib/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: check-swlib | Validate base software release 17 | shell: | 18 | set -o pipefail 19 | if gsutil -q stat gs://"{{ swlib_mount_src }}"/"{{ item.1.name }}"; then 20 | f_name="{{ item.1.name }}" 21 | expected_md5="{{ item.1.md5sum }}" 22 | else 23 | f_name="{{ item.1.alt_name | default('x') }}" 24 | expected_md5="{{ item.1.alt_md5sum | default('x') }}" 25 | fi 26 | actual_md5=$(gsutil ls -L gs://"{{ swlib_mount_src }}"/"${f_name}" | awk '/md5/ { print $3 }') 27 | if [[ "$?" -ne "0" ]] ; then 28 | echo "ERROR locating {{ item.1.name }}{% if item.1.alt_name is defined and item.1.alt_name | length > 0 %} or {{ item.1.alt_name }}{% endif %}" 29 | else 30 | if [[ "$actual_md5" != "$expected_md5" ]]; then 31 | echo "ERROR in {{ item.0.name }} md5: expected $expected_md5, but got $actual_md5 for ${f_name}" 32 | fi 33 | fi 34 | args: 35 | executable: /bin/bash 36 | failed_when: "'ERROR' in base_repo_files.stdout" 37 | changed_when: false 38 | ignore_errors: true 39 | loop: "{{ (gi_software + gi_interim_patches + rdbms_software) | subelements('files') }}" 40 | when: item.0.version == oracle_ver 41 | register: base_repo_files 42 | 43 | - name: check-swlib | Validate patchsets 44 | shell: | 45 | set -o pipefail 46 | gsutil ls -L gs://{{ swlib_mount_src }}/{{ item.patchfile }} | \ 47 | awk '/md5/ { print $3 }' 48 | args: 49 | executable: /bin/bash 50 | failed_when: item.md5sum != patch_repo_files.stdout 51 | changed_when: false 52 | ignore_errors: true 53 | with_items: 54 | - "{{ gi_patches }}" 55 | - "{{ rdbms_patches }}" 56 | when: 57 | - item.base == oracle_ver 58 | - item.release == oracle_rel 59 | register: patch_repo_files 60 | 61 | # We can't reliably check hashes for opatch, as the same file name 62 | # can have different values based on version. 63 | - name: check-swlib | Validate opatch patches 64 | shell: | 65 | set -o pipefail 66 | gsutil ls -L gs://{{ swlib_mount_src }}/{{ item.patchfile }} | \ 67 | awk '/Content-Length/ { print $2 }' 68 | args: 69 | executable: /bin/bash 70 | failed_when: opatch_repo_files.stdout <= "0" 71 | changed_when: false 72 | ignore_errors: true 73 | with_items: 74 | - "{{ opatch_patches }}" 75 | when: 76 | - item.release == oracle_ver 77 | - oracle_rel != "base" 78 | register: opatch_repo_files 79 | 80 | - name: check-swlib | Report gsutil failures (base) 81 | fail: 82 | msg: "ERROR locating {{ item.item.0.name }} {{ item.item.1.name }}: {{ item.stdout }}" 83 | when: item.failed_when_result is defined and item.failed_when_result == true 84 | with_items: 85 | - "{{ base_repo_files.results }}" 86 | 87 | - name: check-swlib | Report gsutil failures (patch) 88 | fail: 89 | msg: "ERROR locating {{ item.item.category }} patch {{ item.item.patchfile }}: {{ item.stderr_lines }}" 90 | when: item.rc is defined and item.rc != 0 91 | with_items: 92 | - "{{ patch_repo_files.results }}" 93 | - "{{ opatch_repo_files.results }}" 94 | 95 | - name: check-swlib | Report MD5 mismatches (patch) 96 | fail: 97 | msg: | 98 | MD5 mismatch: expected {{ item.item.md5sum }} got {{ item.stdout_lines }} 99 | for {{ item.item.category }} patch {{ item.item.patchfile }} 100 | when: item.failed is defined and item.failed 101 | with_items: 102 | - "{{ patch_repo_files.results }}" 103 | - "{{ opatch_repo_files.results }}" 104 | -------------------------------------------------------------------------------- /roles/common/handlers/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Run systemctl daemon-reload 17 | command: systemctl daemon-reload 18 | become: true 19 | become_user: root 20 | 21 | - name: Reset failed systemd services 22 | command: systemctl reset-failed 23 | become: true 24 | become_user: root 25 | -------------------------------------------------------------------------------- /roles/common/tasks/populate-asm-disks.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Identify the first partition of the block device based on its persistent identifier (/dev/disk/by-id/) 17 | ansible.builtin.shell: > 18 | set -o pipefail; 19 | part_path=""; 20 | case "{{ item.blk_device }}" in 21 | # If the block device is specified by a persistent identifier, append '-part1' to form the path to the first partition. 22 | /dev/disk/by-id/*) 23 | part_path="{{ item.blk_device }}"-part1; 24 | ;; 25 | # Skip /dev/mapper devices since they are typically managed by LVM and do not require partitioning (partitioning logical LVM volumes is not practical). 26 | /dev/mapper/*) 27 | part_path=""; 28 | ;; 29 | # For other devices (E.g.: /dev/sda, /dev/nvme0n1), find the corresponding /dev/disk/by-id/ path and add '-part1' to denote the first partition. 30 | /dev/*) 31 | by_id_link=$(find /dev/disk/by-id/ -type l -exec sh -c 'echo $1 $(readlink -f $1)' _ {} \; | awk -v dev="{{ item.blk_device }}" '$2==dev {print $1}' | grep -vE '/dev/disk/by-id/(nvme-|scsi-|wwn-)' | head -n 1); 32 | part_path="${by_id_link}"-part1; 33 | ;; 34 | esac; 35 | if [[ -e "$part_path" ]] && [[ "$part_path" != "" ]]; then 36 | echo "$part_path" 37 | else 38 | echo "" 39 | fi 40 | loop: "{{ asm_disks | json_query('[].disks[]') }}" 41 | register: disk_paths 42 | tags: populate-asm-disks 43 | 44 | - name: Update asm_disks with partition paths 45 | vars: 46 | blk_device_to_partition: >- 47 | {%- set mapping = {} -%} 48 | {%- for res in disk_paths.results -%} 49 | {%- if res.stdout != '' -%} 50 | {%- set _ = mapping.update({res.item.blk_device: res.stdout}) -%} 51 | {%- endif -%} 52 | {%- endfor -%} 53 | {{ mapping }} 54 | set_fact: 55 | asm_disks: >- 56 | {%- set updated_disk_groups = [] -%} 57 | {%- for group in asm_disks -%} 58 | {%- set updated_disks = [] -%} 59 | {%- for disk in group.disks -%} 60 | {%- set part_result = blk_device_to_partition.get(disk.blk_device, '') -%} 61 | {%- set updated_disk = disk | combine({'first_partition_id': part_result}) -%} 62 | {{ updated_disks.append(updated_disk) }} 63 | {%- endfor -%} 64 | {%- set updated_group = group | combine({'disks': updated_disks}) -%} 65 | {{ updated_disk_groups.append(updated_group) }} 66 | {%- endfor -%} 67 | {{ updated_disk_groups }} 68 | tags: populate-asm-disks 69 | -------------------------------------------------------------------------------- /roles/common/tasks/populate-swap-partition-id.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Identify the first partition of the swap block device 17 | ansible.builtin.shell: > 18 | set -o pipefail; 19 | part_path=""; 20 | case "{{ swap_blk_device }}" in 21 | # If the block device is specified by a persistent identifier, append '-part1' to form the path to the first partition. 22 | /dev/disk/by-id/*) 23 | part_path="{{ swap_blk_device }}"-part1; 24 | ;; 25 | # Skip /dev/mapper devices since they are typically managed by LVM and do not require partitioning (partitioning logical LVM volumes is not practical). 26 | /dev/mapper/*) 27 | part_path=""; 28 | ;; 29 | # For other devices (E.g.: /dev/sda, /dev/nvme0n1), find the corresponding /dev/disk/by-id/ path and add '-part1' to denote the first partition. 30 | /dev/*) 31 | by_id_link=$(find /dev/disk/by-id/ -type l -exec sh -c 'echo $1 $(readlink -f $1)' _ {} \; | awk -v dev="{{ swap_blk_device }}" '$2==dev {print $1}' | grep -vE '/dev/disk/by-id/(nvme-|scsi-|wwn-)' | head -n 1); 32 | part_path="${by_id_link}"-part1; 33 | ;; 34 | esac; 35 | if [[ -e "$part_path" ]]; then 36 | echo "$part_path" 37 | else 38 | echo "" 39 | fi 40 | register: swap_first_partition 41 | when: 42 | - swap_blk_device is defined 43 | - "'mapper' not in swap_blk_device" 44 | tags: populate-swap-partition-id 45 | 46 | - name: Set swap_partition_id 47 | set_fact: 48 | swap_partition_id: "{{ swap_first_partition.stdout }}" 49 | when: 50 | - swap_blk_device is defined 51 | - "'mapper' not in swap_blk_device" 52 | tags: populate-swap-partition-id 53 | 54 | - name: (debug) Display the swap partition ID 55 | debug: 56 | msg: "{{ swap_partition_id }}" 57 | tags: populate-swap-partition-id 58 | -------------------------------------------------------------------------------- /roles/common/tasks/populate-user-data-mounts.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Identify the first partition of the block device based on its persistent identifier (/dev/disk/by-id/) 17 | ansible.builtin.shell: > 18 | set -o pipefail; 19 | part_path=""; 20 | case "{{ item.blk_device }}" in 21 | # If the block device is specified by a persistent identifier, append '-part1' to form the path to the first partition. 22 | /dev/disk/by-id/*) 23 | part_path="{{ item.blk_device }}"-part1; 24 | ;; 25 | # Skip /dev/mapper devices since they are typically managed by LVM and do not require partitioning (partitioning logical LVM volumes is not practical). 26 | /dev/mapper/*) 27 | part_path=""; 28 | ;; 29 | # For other devices (E.g.: /dev/sda, /dev/nvme0n1), find the corresponding /dev/disk/by-id/ path and add '-part1' to denote the first partition. 30 | /dev/*) 31 | by_id_link=$(find /dev/disk/by-id/ -type l -exec sh -c 'echo $1 $(readlink -f $1)' _ {} \; | awk -v dev="{{ item.blk_device }}" '$2==dev {print $1}' | grep -vE '/dev/disk/by-id/(nvme-|scsi-|wwn-)' | head -n 1); 32 | part_path="${by_id_link}"-part1; 33 | ;; 34 | esac; 35 | if [[ -e "$part_path" ]] && [[ "$part_path" != "" ]]; then 36 | echo "$part_path" 37 | else 38 | echo "" 39 | fi 40 | loop: "{{ oracle_user_data_mounts }}" 41 | register: disk_paths 42 | tags: populate-user-mounts 43 | 44 | - name: Update oracle_user_data_mounts with partition paths 45 | vars: 46 | blk_device_to_partition: >- 47 | {%- set mapping = {} -%} 48 | {%- for res in disk_paths.results -%} 49 | {%- if res.stdout != '' -%} 50 | {%- set _ = mapping.update({res.item.blk_device: res.stdout}) -%} 51 | {%- endif -%} 52 | {%- endfor -%} 53 | {{ mapping }} 54 | set_fact: 55 | oracle_user_data_mounts: >- 56 | {%- set updated_mounts = [] -%} 57 | {%- for mount in oracle_user_data_mounts -%} 58 | {%- set part_result = blk_device_to_partition.get(mount.blk_device, '') -%} 59 | {%- set updated_mount = mount | combine({'first_partition_id': part_result}) -%} 60 | {{ updated_mounts.append(updated_mount) }} 61 | {%- endfor -%} 62 | {{ updated_mounts }} 63 | tags: populate-user-mounts 64 | -------------------------------------------------------------------------------- /roles/common/tasks/populate-vars.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: populate-vars | Resolve software release 17 | set_fact: 18 | oracle_rel: "{{ found_rel | trim }}" 19 | vars: 20 | found_rel: >- 21 | {% if oracle_rel == "latest" %} 22 | {{ (gi_patches | selectattr('base', 'equalto', oracle_ver) | list | last | default({})).release | default('base') }} 23 | {% else %} 24 | {% set matched_patch = gi_patches | selectattr('base', 'equalto', oracle_ver) | selectattr('release', 'equalto', oracle_rel) | list | first %} 25 | {{ matched_patch.release | default((gi_patches | selectattr('base', 'equalto', oracle_ver) | list | last | default({})).release) if matched_patch is defined else (gi_patches | selectattr('base', 'equalto', oracle_ver) | list | last | default({})).release }} 26 | {% endif %} 27 | when: 28 | - not free_edition 29 | - oracle_rel is defined 30 | - oracle_rel != "base" 31 | tags: oracle-rel 32 | 33 | - name: populate-vars | Resolve Free Edition software release 34 | set_fact: 35 | oracle_ver: "{{ 36 | (oracle_rel == 'latest') and (free_versions | last) or 37 | (oracle_rel == 'base') and (free_versions | first) or 38 | (oracle_rel in free_versions) and oracle_rel or 39 | (free_versions | last) 40 | }}" 41 | vars: 42 | free_versions: "{{ rdbms_software | selectattr('edition', 'equalto', 'FREE') | map(attribute='version') | sort | list }}" 43 | when: 44 | - free_edition 45 | - oracle_ver == "23.0.0.0.0" 46 | tags: oracle-rel 47 | 48 | - name: populate-vars | Show resolved release 49 | debug: 50 | var: oracle_rel 51 | tags: oracle-rel 52 | -------------------------------------------------------------------------------- /roles/db-adjustments/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | db_script_files: 17 | - archivelog_mode.sh 18 | - db_modifications.sh 19 | -------------------------------------------------------------------------------- /roles/db-adjustments/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/db-adjustments/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Copy database adjustment scripts to target server 17 | template: 18 | src: "{{ item }}.j2" 19 | dest: "{{ swlib_unzip_path }}/{{ item }}" 20 | owner: "{{ oracle_user }}" 21 | group: "{{ oracle_group }}" 22 | mode: u=rwx,go=r 23 | with_items: 24 | - "{{ db_script_files }}" 25 | become: true 26 | become_user: "{{ oracle_user }}" 27 | tags: db-adjustments 28 | 29 | - name: Run database adjustment scripts on target server 30 | shell: "{{ swlib_unzip_path }}/{{ item }}" 31 | environment: 32 | PATH: /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin 33 | with_items: 34 | - "{{ db_script_files }}" 35 | register: scripts_output 36 | ignore_errors: true 37 | become: true 38 | become_user: "{{ oracle_user }}" 39 | tags: db-adjustments 40 | 41 | - name: Database adjustment scripts output 42 | debug: 43 | msg: "{{ scripts_output }}" 44 | verbosity: 1 45 | tags: db-adjustments 46 | 47 | - name: Script cleanup on target server 48 | file: 49 | path: "{{ swlib_unzip_path }}/{{ item }}" 50 | state: absent 51 | with_items: 52 | - "{{ db_script_files }}" 53 | become: true 54 | become_user: "{{ oracle_user }}" 55 | tags: db-adjustments 56 | -------------------------------------------------------------------------------- /roles/db-adjustments/templates/archivelog_mode.sh.j2: -------------------------------------------------------------------------------- 1 | source oraenv <<< {{ oracle_sid }} 2 | 3 | srvctl_status="$(srvctl status database -d {{ db_name }})" 4 | 5 | if [[ "${srvctl_status}" =~ "is running" ]]; then 6 | srvctl stop db -d {{ db_name }} -o immediate 7 | else 8 | echo "shutdown immediate" | sqlplus -s -L / as sysdba 9 | fi 10 | 11 | sqlplus -s -L / as sysdba << EOF 12 | startup mount 13 | alter database archivelog; 14 | alter database open; 15 | archive log list 16 | 17 | set pages 32767 lines 180 trims on tab off 18 | column name format a32 19 | column display_value format a64 20 | column status format a32 21 | column filename format a64 22 | 23 | alter database enable block change tracking; 24 | select status, filename from v\$block_change_tracking; 25 | 26 | select name, display_value from ( 27 | select name, display_value from v\$system_parameter2 where name like 'log_archive%' and isdefault != 'TRUE' 28 | union 29 | select name, display_value from v\$system_parameter2 where name like 'db_recovery%' 30 | ) 31 | order by 1,2; 32 | EOF 33 | 34 | {% if groups['dbasm'] | length > 1 %} 35 | srvctl start db -d {{ db_name }} 36 | {% endif %} 37 | -------------------------------------------------------------------------------- /roles/db-adjustments/templates/db_modifications.sh.j2: -------------------------------------------------------------------------------- 1 | source oraenv <<< {{ oracle_sid }} 2 | 3 | sqlplus -s -L / as sysdba << EOF 4 | set pages 32767 lines 180 trims on tab off 5 | column name format a32 6 | column display_value format a64 7 | 8 | alter database force logging; 9 | alter database add supplemental log data; 10 | alter database flashback on; 11 | 12 | select name, db_unique_name, force_logging, supplemental_log_data_min, flashback_on from v\$database; 13 | select name, display_value from v\$system_parameter2 where name like '%flashback%'; 14 | EOF 15 | -------------------------------------------------------------------------------- /roles/db-backups/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | scripts_dir: "/home/{{ oracle_user }}/scripts" 17 | logs_dir: "/home/{{ oracle_user }}/logs" 18 | 19 | rman_db_bu_redundancy: 2 20 | rman_arch_redundancy: 2 21 | rman_archs_online_days: 7 22 | 23 | full_bu_level0_day: "0" 24 | full_bu_level1_days: "1-6" 25 | full_bu_start_hour: "01" 26 | full_bu_start_min: "00" 27 | arch_bu_start_min: "30" 28 | 29 | gcsfuse_backup_temp_prefix: "gcsfusetmp" 30 | gcsfuse_backup_mount_prefix: "gcsfuse" 31 | gcsfuse_bucket_prefix: "fusebackup" 32 | 33 | nfs_mount_params: "user,_netdev,rsize=32768,wsize=32768,timeo=14,intr" 34 | 35 | # backup_mount_src: "" 36 | # backup_mount_path: "" 37 | -------------------------------------------------------------------------------- /roles/db-backups/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/db-backups/tasks/gcsfuse.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # gcsfuse rpm repo has the same name for RedHat based versions, link to installation below 16 | # 17 | # https://cloud.google.com/storage/docs/cloud-storage-fuse/install#centosred-hatrocky-linux 18 | # 19 | 20 | --- 21 | - name: gcsfuse | Add Google Cloud gcsfuse repo 22 | become: true 23 | become_user: root 24 | yum_repository: 25 | name: gcsfuse 26 | description: Google cloud gcsfuse 27 | baseurl: https://packages.cloud.google.com/yum/repos/gcsfuse-el7-x86_64 28 | gpgkey: 29 | - https://packages.cloud.google.com/yum/doc/yum-key.gpg 30 | - https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg 31 | gpgcheck: true 32 | 33 | - name: gcloud | Install latest gcloud gcsfuse package 34 | become: true 35 | become_user: root 36 | package: 37 | name: gcsfuse 38 | state: present 39 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 40 | -------------------------------------------------------------------------------- /roles/db-backups/tasks/gcsmanual.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: gcsfuse | gcsfuse install 17 | include_tasks: gcsfuse.yml 18 | 19 | - name: gcsfuse create temp directory | GCE gcsfuse create temp directory 20 | become: true 21 | file: 22 | path: "{{ gcsfuse_backup_temp_path }}/{{ gcsfuse_backup_temp_prefix }}/{{ db_name }}" 23 | state: directory 24 | mode: 0760 25 | owner: "{{ oracle_user }}" 26 | group: "{{ oracle_group }}" 27 | 28 | - name: gcsfuse create bucket mount directory | GCE gcsfuse create bucket mount directory 29 | become: true 30 | file: 31 | path: "{{ gcsfuse_backup_mount_path }}/{{ gcsfuse_backup_mount_prefix }}/{{ db_name }}" 32 | state: directory 33 | mode: 0760 34 | owner: "{{ oracle_user }}" 35 | group: "{{ oracle_group }}" 36 | 37 | - name: gcsfuse mount bucket values | GCE gcsfuse mount directory values 38 | debug: 39 | msg: 40 | - "gcsfuse_backup_mount_path: {{ gcsfuse_backup_mount_path }}" 41 | - "gcsfuse_backup_mount_prefix: {{ gcsfuse_backup_mount_prefix }}" 42 | - "gcsfuse_backup_bucket: {{ gcsfuse_backup_bucket }}" 43 | - "gcsfuse_backup_bucket_folder: {{ gcsfuse_backup_bucket_folder }}" 44 | 45 | - name: gcsfuse mount bucket | GCE gcsfuse mount bucket 46 | become: true 47 | mount: 48 | path: "{{ gcsfuse_backup_mount_path }}/{{ gcsfuse_backup_mount_prefix }}/{{ db_name }}" 49 | src: "{{ gcsfuse_backup_bucket }}" 50 | fstype: gcsfuse 51 | opts: _netdev,temp_dir={{ gcsfuse_backup_temp_path }}/{{ gcsfuse_backup_temp_prefix }}/{{ db_name }},rw,dir_mode=777,uid={{ oracle_user }},gid={{ oracle_group }},noexec,nodev,allow_other 52 | state: mounted 53 | when: gcsfuse_backup_bucket_folder == "" 54 | 55 | - name: gcsfuse mount bucket directory | GCE gcsfuse mount bucket directory 56 | become: true 57 | mount: 58 | path: "{{ gcsfuse_backup_mount_path }}/{{ gcsfuse_backup_mount_prefix }}/{{ db_name}}" 59 | src: "{{ gcsfuse_backup_bucket }}" 60 | fstype: gcsfuse 61 | opts: _netdev,only_dir={{gcsfuse_backup_bucket_folder}},temp_dir={{ gcsfuse_backup_temp_path }}/{{ gcsfuse_backup_temp_prefix }}/{{ db_name }},rw,dir_mode=777,uid={{ oracle_user }},gid={{ oracle_group }},noexec,nodev,allow_other 62 | state: mounted 63 | when: gcsfuse_backup_bucket_folder != "" 64 | 65 | - name: gcsfuse set backup directory | GCE gcsfuse set backup directory 66 | set_fact: 67 | backup_dest: "{{ gcsfuse_backup_mount_path }}/{{ gcsfuse_backup_mount_prefix }}/{{ db_name }}" 68 | -------------------------------------------------------------------------------- /roles/db-backups/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Create required directories 17 | become: true 18 | become_user: "{{ oracle_user }}" 19 | file: 20 | path: "{{ item }}" 21 | state: directory 22 | owner: "{{ oracle_user }}" 23 | group: "{{ oracle_group }}" 24 | mode: u=wrx,go= 25 | with_items: 26 | - "{{ scripts_dir }}" 27 | - "{{ logs_dir }}" 28 | tags: db-backups,add-backups 29 | 30 | - name: backup location | nfs mount 31 | include_tasks: nfs.yml 32 | when: 33 | - nfs_backup_config | length > 0 34 | - nfs_backup_mount | length > 0 35 | tags: db-backups,add-backups 36 | 37 | - name: gcs backup location | gcs backup 38 | include_tasks: gcsmanual.yml 39 | when: gcsfuse_backup_config == "manual" 40 | tags: db-backups,add-backups 41 | 42 | - name: Copy backup scripts to target server 43 | become: true 44 | become_user: "{{ oracle_user }}" 45 | template: 46 | src: "{{ item }}.j2" 47 | dest: "{{ scripts_dir }}/{{ item }}" 48 | owner: "{{ oracle_user }}" 49 | group: "{{ oracle_group }}" 50 | mode: u=wrx,go= 51 | with_items: 52 | - "rman_full_backup.sh" 53 | - "rman_arch_backup.sh" 54 | - "rman_restore_example.sh" 55 | tags: db-backups,add-backups 56 | 57 | - name: Schedule full backups 58 | become: true 59 | become_user: "{{ oracle_user }}" 60 | cron: 61 | name: "{{ oracle_sid }} RMAN weekly LEVEL={{ item.level }}" 62 | weekday: "{{ item.days }}" 63 | hour: "{{ full_bu_start_hour }}" 64 | minute: "{{ full_bu_start_min }}" 65 | user: "{{ oracle_user }}" 66 | job: "{{ scripts_dir }}/rman_full_backup.sh {{ oracle_sid }} {{ item.level }} {{ rman_db_bu_redundancy }} {{ rman_arch_redundancy }}" 67 | with_items: 68 | - { level: 0, days: '{{ full_bu_level0_day }}' } 69 | - { level: 1, days: '{{ full_bu_level1_days }}' } 70 | tags: db-backups,add-backups 71 | 72 | - name: Schedule archived redo log backups 73 | become: true 74 | become_user: "{{ oracle_user }}" 75 | cron: 76 | name: "{{ oracle_sid }} ARCH backups" 77 | minute: "{{ arch_bu_start_min }}" 78 | user: "{{ oracle_user }}" 79 | job: "{{ scripts_dir }}/rman_arch_backup.sh {{ oracle_sid }} {{ rman_arch_redundancy }} {{ rman_archs_online_days }}" 80 | tags: db-backups,add-backups 81 | 82 | - name: Run initial full backup 83 | become: true 84 | become_user: "{{ oracle_user }}" 85 | shell: | 86 | export PATH={{ oracle_home }}/bin:/usr/local/bin:${PATH} 87 | {{ scripts_dir }}/rman_full_backup.sh {{ oracle_sid }} 0 {{ rman_db_bu_redundancy }} {{ rman_arch_redundancy }} 88 | when: run_initial_bu|bool 89 | register: full_backup 90 | tags: db-backups,run-backups 91 | 92 | - name: Run initial archivelog backup 93 | become: true 94 | become_user: "{{ oracle_user }}" 95 | shell: | 96 | export PATH={{ oracle_home }}/bin:/usr/local/bin:${PATH} 97 | {{ scripts_dir }}/rman_arch_backup.sh {{ oracle_sid }} {{ rman_arch_redundancy }} {{ rman_archs_online_days }} 98 | when: run_initial_bu|bool 99 | register: arch_backup 100 | tags: db-backups,run-backups 101 | 102 | - name: Backup execution results 103 | debug: 104 | msg: "{{ item }}" 105 | verbosity: 1 106 | when: run_initial_bu|bool 107 | with_items: 108 | - "{{ full_backup }}" 109 | - "{{ arch_backup }}" 110 | tags: db-backups,run-backups 111 | -------------------------------------------------------------------------------- /roles/db-backups/tasks/nfs.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: nfs_backups | Install NFS mount utility 17 | become: true 18 | become_user: root 19 | package: 20 | name: nfs-utils 21 | state: present 22 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 23 | when: ansible_os_family == "RedHat" 24 | 25 | - name: nfs_backups | Ensure rpcbind is running as configured. 26 | become: true 27 | become_user: root 28 | service: 29 | name: rpcbind 30 | state: started 31 | enabled: true 32 | when: ansible_os_family == "RedHat" 33 | 34 | - name: nfs_backups | Create a nfs backups mount folder 35 | file: 36 | path: "{{ backup_dest }}/{{ db_name }}" 37 | state: directory 38 | mode: u=rwx,go=rx 39 | owner: "{{ oracle_user}}" 40 | group: backupdba 41 | 42 | - name: NFS values | Display NFS values 43 | debug: 44 | msg: 45 | - "{{ backup_dest }}/{{ db_name }}" 46 | - "{{ nfs_backup_config }},{{ nfs_mount_params }}" 47 | - "{{ nfs_backup_mount }}" 48 | 49 | - name: nfs_backups | Mount NFS share (backup) 50 | become: true 51 | become_user: root 52 | mount: 53 | fstype: nfs 54 | name: "{{ backup_dest }}/{{ db_name }}" 55 | opts: "{{ nfs_backup_config }},{{ nfs_mount_params }}" 56 | src: "{{ nfs_backup_mount }}" 57 | state: mounted 58 | 59 | - name: nfs set backup directory | NFS set backup directory 60 | set_fact: 61 | backup_dest: "{{ backup_dest }}/{{ db_name }}" 62 | -------------------------------------------------------------------------------- /roles/db-backups/templates/rman_arch_backup.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Example: ./rman_arch_backup.sh ORCL 2 7 4 | # 5 | # Variables 6 | # 7 | ora_inst_name=${1} # Instance name-- should match /etc/oratab 8 | arch_redundancy=${2} # Archivelog redundancy 9 | arch_day_online=${3} # Number of days to keep 10 | ts="date +%Y-%m-%d_%H-%M-%S" # Timestamp format 11 | start_ts="$($ts)" # Start timestamp 12 | log_dir="{{ logs_dir }}" # A directory for the logs 13 | type="ARCH" # Type is archivelog backup 14 | conn_str="{% if oracle_ver == "11.2.0.4.0" %}/{% else %}/ AS SYSBACKUP{% endif %}" # Oracle connection string 15 | backup_dest="{{ backup_dest }}" # Backup destination path 16 | fra_dest="{{ reco_destination }}" # Fast recovery area location 17 | export NLS_DATE_FORMAT="YYYY-MM-DD HH24:MI:SS" 18 | # 19 | if [[ $# -ne 3 ]]; then 20 | echo "Usage: $0 ora_inst_name arch_redundancy arch_day_online" >&1 21 | exit 1 22 | fi 23 | 24 | # 25 | # Check if $log_dir exists; if not, we create it 26 | # 27 | if [[ ! -d "${log_dir}" ]]; then 28 | if mkdir -p "${log_dir}"; then 29 | printf "\n\t%s\n\n" "INFO -- $($ts) -- ${log_dir} successfully created." 30 | else 31 | printf "\n\t%s\n\n" "ERROR -- $($ts) -- Impossible to create ${log_dir}; we wont be able to log this backup." 32 | fi 33 | fi 34 | # If FRA is not a file system, add the ASM "+" sign (if not already added) 35 | if [[ "${fra_dest:0:1}" != "/" && "${fra_dest:0:1}" != "+" ]]; then 36 | fra_dest="+${fra_dest}" 37 | fi 38 | if [[ "${backup_dest:0:1}" == "/" ]]; then 39 | # Filesystem destination 40 | autobackup_format="${backup_dest}/${ora_inst_name}_%F" 41 | channel_format="${backup_dest}/${ora_inst_name}_${type}_level_${rman_level}_%U" 42 | else 43 | # ASM destination, no need for format specifiers; Add the ASM "+" sign (if not already added) 44 | if [[ "${backup_dest:0:1}" != "+" ]]; then 45 | backup_dest="+${backup_dest}" 46 | fi 47 | autobackup_format="${backup_dest}" 48 | channel_format="${backup_dest}" 49 | fi 50 | # 51 | # We can now build the output file and log file names 52 | # 53 | outfile="${log_dir}/rman_${start_ts}_${type}.out" 54 | logfile="${log_dir}/rman_${start_ts}_${type}.log" 55 | # 56 | # Set the Oracle env 57 | # 58 | export ORACLE_SID="${ora_inst_name}" 59 | source oraenv <<<"${ora_inst_name}" >/dev/null 2>&1 60 | # 61 | # RMAN backup 62 | # 63 | if "${ORACLE_HOME}/bin/rman" >>"${outfile}" <&1 19 | exit 1 20 | fi 21 | # 22 | # A tag for the log file and output file depending on the backup level 23 | # 24 | if [[ "${rman_level}" = "0" ]]; then 25 | type="FULL" # Full backup 26 | else 27 | type="INCR" # Incremental 28 | fi 29 | # 30 | # Check if $log_dir exists; if not, we create it 31 | # 32 | if [[ ! -d "${log_dir}" ]]; then 33 | if mkdir -p "${log_dir}"; then 34 | printf "\n\t%s\n\n" "INFO -- $($ts) -- ${log_dir} successfully created." 35 | else 36 | printf "\n\t%s\n\n" "ERROR -- $($ts) -- Impossible to create ${log_dir}; we wont be able to log this backup." 37 | fi 38 | fi 39 | # If FRA is not a file system, add the ASM "+" sign (if not already added) 40 | if [[ "${fra_dest:0:1}" != "/" && "${fra_dest:0:1}" != "+" ]]; then 41 | fra_dest="+${fra_dest}" 42 | fi 43 | if [[ "${backup_dest:0:1}" == "/" ]]; then 44 | # Filesystem destination 45 | autobackup_format="${backup_dest}/${ora_inst_name}_%F" 46 | channel_format="${backup_dest}/${ora_inst_name}_${type}_level_${rman_level}_%U" 47 | else 48 | # ASM destination, no need for format specifiers; Add the ASM "+" sign (if not already added) 49 | if [[ "${backup_dest:0:1}" != "+" ]]; then 50 | backup_dest="+${backup_dest}" 51 | fi 52 | autobackup_format="${backup_dest}" 53 | channel_format="${backup_dest}" 54 | fi 55 | # 56 | # We can now build the output file and log file names 57 | # 58 | outfile="${log_dir}/rman_${start_ts}_${type}.out" 59 | logfile="${log_dir}/rman_${start_ts}_${type}.log" 60 | # 61 | # Set the Oracle env 62 | # 63 | export ORACLE_SID="${ora_inst_name}" 64 | source oraenv <<<"${ora_inst_name}" >/dev/null 2>&1 65 | # 66 | # RMAN backup 67 | # 68 | if "${ORACLE_HOME}/bin/rman" >>"${outfile}" < 0 -%}.{{ hostvars[groups['dbasm'].0]['cluster_domain'] }}{% endif -%}{% endmacro -%} 2 | dbca -silent -createDatabase -gdbName {{ db_name }}{{ domain() }} \ 3 | -databaseType {{ db_type }} \ 4 | -nodelist {% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} \ 5 | -templateName General_Purpose.dbc \ 6 | -emConfiguration none \ 7 | -storageType ASM \ 8 | -diskGroupName {{ data_destination }} \ 9 | -recoveryGroupName {{ reco_destination }} \ 10 | -redoLogFileSize {{ redologsize }} \ 11 | -initParams pga_aggregate_target='{{ pga_aggtar_bytes }}',sga_target='{{ sga_target_bytes }}',streams_pool_size=64M,use_large_pages=ONLY,db_domain='{{ db_domain }}',diagnostic_dest='{{ oracle_base }}' \ 12 | -continueOnNonFatalErrors true 13 | -------------------------------------------------------------------------------- /roles/db-create/templates/rac-dbca.rsp.sh.j2: -------------------------------------------------------------------------------- 1 | {% macro domain() -%}{% if hostvars[groups['dbasm'].0]['cluster_domain'] is defined and hostvars[groups['dbasm'].0]['cluster_domain']|length > 0 -%}.{{ hostvars[groups['dbasm'].0]['cluster_domain'] }}{% endif -%}{% endmacro -%} 2 | dbca -silent -createDatabase -gdbName {{ db_name }}{{ domain() }} \ 3 | -databaseType {{ db_type }} \ 4 | -createAsContainerDatabase {{ container_db }} \ 5 | -numberOfPDBs {{ pdb_count }} \ 6 | -pdbName {{ pdb_prefix }} \ 7 | -{% if oracle_ver == '12.1.0.2.0' %}databaseConfType{% else %}databaseConfigType{% endif %} {{ db_config_type }} \ 8 | -nodelist {% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} \ 9 | -templateName General_Purpose.dbc \ 10 | -emConfiguration none \ 11 | -storageType ASM \ 12 | -diskGroupName {{ data_destination }} \ 13 | -recoveryGroupName {{ reco_destination }} \ 14 | -redoLogFileSize {{ redologsize }} \ 15 | -initParams pga_aggregate_target='{{ pga_aggtar_bytes }}',sga_target='{{ sga_target_bytes }}',streams_pool_size=64M,use_large_pages=ONLY,db_domain='{{ db_domain }}',diagnostic_dest='{{ oracle_base }}' \ 16 | -ignorePreReqs {% if oracle_ver != '12.1.0.2.0' %}-ignorePrereqFailure{% endif %} 17 | -------------------------------------------------------------------------------- /roles/dg-config/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | # Specify one of the Data Guard protection modes: "Maximum Performance", "Maximum Availability", or "Maximum Protection" 17 | data_guard_protection_mode: "Maximum Availability" 18 | real_time_apply: true 19 | log_transport_mode: "{{ 'ASYNC' if data_guard_protection_mode | upper == 'MAXIMUM PERFORMANCE' else 'SYNC' }}" 20 | -------------------------------------------------------------------------------- /roles/dg-config/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/dg-config/templates/dg-create.j2: -------------------------------------------------------------------------------- 1 | CREATE CONFIGURATION dg_{{ db_name }} AS 2 | PRIMARY DATABASE IS {{ db_name }} 3 | CONNECT IDENTIFIER IS "//{{ hostvars['primary1'].ansible_ssh_host }}:{{ listener_port | default(1521, true) }}/{{ db_name }}{% if db_domain|default('', true)|length > 0 %}.{{ db_domain }}{% endif %}"; 4 | 5 | ADD DATABASE {{ standby_name }} 6 | AS CONNECT IDENTIFIER IS "//{{ ansible_ssh_host }}:{{ listener_port | default(1521, true) }}/{{ standby_name }}{% if db_domain|default('', true)|length > 0 %}.{{ db_domain }}{% endif %}"; 7 | 8 | ENABLE CONFIGURATION; 9 | HOST sleep 60; 10 | 11 | SHOW CONFIGURATION VERBOSE; 12 | SHOW DATABASE VERBOSE {{ standby_name }}; 13 | -------------------------------------------------------------------------------- /roles/gi-setup/files/expect_rsp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | # Create OCM response file using expect 18 | # Accepts two passed parameters: 19 | # 20 | # $1: ORACLE_BASE 21 | # $2: ORACLE_HOME 22 | # $3: Destination for the response file 23 | # 24 | 25 | export ORACLE_BASE=${1} 26 | export ORACLE_HOME=${2} 27 | export RSP_PATH=${3} 28 | 29 | if [ -f "${ORACLE_HOME}/OPatch/ocm/bin/emocmrsp" ]; then 30 | cat < ${RSP_PATH}/ocm.sh 31 | #!/usr/bin/expect -f 32 | set timeout -1 33 | spawn ${ORACLE_HOME}/OPatch/ocm/bin/emocmrsp -no_banner -output ${RSP_PATH}/ocm.rsp 34 | expect "Email address/User Name:" 35 | send "\n" 36 | expect "Do you wish to remain uninformed of security issues*" 37 | send "Y\n" 38 | expect eof 39 | EOF 40 | chmod 700 ${RSP_PATH}/ocm.sh 41 | ${RSP_PATH}/ocm.sh 42 | rm ${RSP_PATH}/ocm.sh 43 | fi 44 | -------------------------------------------------------------------------------- /roles/gi-setup/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/gi-setup/tasks/asm-create.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: asm-create | Create ASM initialization file 17 | template: 18 | src: init.ora.j2 19 | dest: "{{ grid_home }}/dbs/init{{ asm_sid }}.ora" 20 | become: true 21 | become_user: "{{ grid_user }}" 22 | tags: gi-setup,start-asm 23 | 24 | - name: asm-create | Change ASM LV permissions 25 | file: 26 | path: "{{ item.1.blk_device }}" 27 | state: link 28 | mode: ug=rw,o= 29 | owner: "{{ grid_user }}" 30 | group: asmdba 31 | when: "'mapper' in item.1.blk_device" 32 | with_subelements: 33 | - "{{ asm_disks }}" 34 | - disks 35 | 36 | - name: asm-create | Start ASM instance 37 | shell: | 38 | set -o pipefail 39 | ${ORACLE_HOME}/bin/srvctl add asm -d '{{ asm_diskstring }}' 40 | ${ORACLE_HOME}/bin/srvctl start asm 41 | sqlplus -s / as sysasm <<< "create spfile from pfile;" 42 | ${ORACLE_HOME}/bin/srvctl stop asm 43 | ${ORACLE_HOME}/bin/srvctl start asm 44 | environment: 45 | ORACLE_HOME: "{{ grid_home }}" 46 | PATH: "{{ grid_home }}/bin:${PATH}" 47 | ORACLE_SID: "{{ asm_sid }}" 48 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 49 | register: start_asm 50 | become: true 51 | become_user: "{{ grid_user }}" 52 | tags: gi-setup,start-asm 53 | 54 | - name: asm-create | Start ASM ouput 55 | debug: 56 | msg: "{{ start_asm }}" 57 | verbosity: 1 58 | tags: gi-setup,start-asm 59 | 60 | - name: asm-create | (asmlib) Create disk groups 61 | shell: | 62 | set -o pipefail 63 | sqlplus -s / as sysasm << EOF 64 | CREATE DISKGROUP {{ item.diskgroup }} EXTERNAL REDUNDANCY 65 | {% for i in item.disks %} DISK 'ORCL:{{ i.name }}' 66 | {% endfor %} 67 | ATTRIBUTE 68 | 'compatible.asm' = '{{ diskgroup_compatible_asm }}', 69 | 'compatible.rdbms' = '{{ diskgroup_compatible_rdbms }}'; 70 | EOF 71 | environment: 72 | ORACLE_HOME: "{{ grid_home }}" 73 | PATH: "{{ grid_home }}/bin:${PATH}" 74 | ORACLE_VERSION: "{{ oracle_ver }}" 75 | ORACLE_SID: "{{ asm_sid }}" 76 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 77 | when: asm_disk_management == "asmlib" 78 | with_items: 79 | - "{{ asm_disks }}" 80 | register: create_dg 81 | failed_when: "'ERROR' in create_dg.stdout" 82 | become: true 83 | become_user: "{{ grid_user }}" 84 | tags: gi-setup,start-asm 85 | 86 | - name: asm-create | (udev) Create disk groups 87 | shell: | 88 | set -o pipefail 89 | sqlplus -s / as sysasm << EOF 90 | CREATE DISKGROUP {{ item.diskgroup }} EXTERNAL REDUNDANCY 91 | {% for i in item.disks %} DISK '/dev/{{ path_udev }}/{{ i.name }}' 92 | {% endfor %} 93 | ATTRIBUTE 94 | 'compatible.asm' = '{{ diskgroup_compatible_asm }}', 95 | 'compatible.rdbms' = '{{ diskgroup_compatible_rdbms }}'; 96 | EOF 97 | environment: 98 | ORACLE_HOME: "{{ grid_home }}" 99 | PATH: "{{ grid_home }}/bin:${PATH}" 100 | ORACLE_VERSION: "{{ oracle_ver }}" 101 | ORACLE_SID: "{{ asm_sid }}" 102 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 103 | when: asm_disk_management == "udev" 104 | with_items: 105 | - "{{ asm_disks }}" 106 | register: create_dg 107 | failed_when: "'ERROR' in create_dg.stdout" 108 | become: true 109 | become_user: "{{ grid_user }}" 110 | tags: gi-setup,start-asm 111 | 112 | - name: asm-create | Debug ASM disk group creation 113 | debug: 114 | msg: "{{ create_dg }}" 115 | verbosity: 1 116 | tags: gi-setup,start-asm 117 | -------------------------------------------------------------------------------- /roles/gi-setup/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Check if software is already installed 17 | shell: cat "{{ oracle_inventory }}/ContentsXML/inventory.xml" 2>&1 | ( grep -w {{ grid_home }} || true ) | wc -l 18 | register: existing_dbhome 19 | become: true 20 | become_user: root 21 | ignore_errors: true 22 | changed_when: false 23 | failed_when: false 24 | tags: gi-setup 25 | 26 | - name: OH Confirmation 27 | debug: 28 | msg: "Installing GRID_HOME - {{ grid_home }}" 29 | when: existing_dbhome.stdout == "0" 30 | tags: gi-setup 31 | 32 | - include_tasks: gi-install.yml 33 | with_items: 34 | - "{{ gi_software }}" 35 | loop_control: 36 | loop_var: osw 37 | when: existing_dbhome.stdout == "0" and osw.version == oracle_ver 38 | tags: gi-setup 39 | 40 | - name: Configure HAS 41 | command: "{{ grid_home }}/perl/bin/perl -I {{ grid_home }}/perl/lib -I {{ grid_home }}/crs/install {{ grid_home }}/crs/install/roothas.pl" 42 | register: has_config 43 | become: true 44 | become_user: root 45 | failed_when: "('Successfully configured Oracle Restart' not in has_config.stdout ) and 46 | ('Successfully configured Oracle Grid Infrastructure' not in has_config.stdout ) and not 47 | ('Operation successful.' in has_config.stdout and 'CLSRSC-400: A system reboot is required' in has_config.stdout)" 48 | when: existing_dbhome.stdout == "0" 49 | tags: gi-setup,has-config 50 | 51 | - name: HAS config output 52 | debug: 53 | msg: 54 | - "{{ has_config.cmd }}" 55 | - "{{ has_config.stdout_lines }}" 56 | verbosity: 1 57 | when: existing_dbhome.stdout == "0" 58 | tags: gi-setup,has-config 59 | 60 | - name: Check ASM status 61 | shell: "( {{ grid_home }}/bin/srvctl status asm ) || true" 62 | register: asm_status 63 | changed_when: false 64 | become: true 65 | become_user: "{{ grid_user }}" 66 | failed_when: asm_status.rc >= 2 67 | tags: gi-setup,start-asm 68 | 69 | - include_tasks: asm-create.yml 70 | when: '"ASM is running" not in asm_status.stdout' 71 | tags: gi-setup,start-asm 72 | 73 | - name: Check cluster resources 74 | shell: "( {{ grid_home }}/bin/crsctl stat res -t ) || true" 75 | register: crsctl_res 76 | become: true 77 | become_user: "{{ grid_user }}" 78 | changed_when: false 79 | tags: gi-setup,crsctl 80 | 81 | - name: crsctl stat res -t output 82 | debug: 83 | msg: 84 | - "{{ crsctl_res.cmd }}" 85 | - "{{ crsctl_res.stdout_lines }}" 86 | # verbosity: 1 87 | tags: gi-setup,crsctl 88 | 89 | - name: Final GI permission adjustments 90 | file: 91 | path: "{{ item.name }}" 92 | state: directory 93 | owner: "{{ item.owner }}" 94 | group: "{{ oracle_group }}" 95 | mode: "{{ item.mode }}" 96 | recurse: "{{ item.recurse }}" 97 | with_items: 98 | - { name: "{{ oracle_base }}/diag", owner: "{{ oracle_user }}", mode: "ug=rwx,o=rx", recurse: "no" } 99 | - { name: "{{ oracle_base }}/diag/crs", owner: "{{ grid_user }}", mode: "g+w", recurse: "yes" } 100 | - { name: "{{ oracle_base }}/diag/kfod", owner: "{{ grid_user }}", mode: "g+w", recurse: "yes" } 101 | - { name: "{{ oracle_base }}/admin", owner: "{{ oracle_user }}", mode: "g+w", recurse: "yes" } 102 | become: true 103 | become_user: root 104 | tags: gi-setup 105 | -------------------------------------------------------------------------------- /roles/gi-setup/templates/grid_install.rsp.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | {% if oracle_ver == "11.2.0.4.0" or oracle_ver == "12.1.0.2.0" %} 4 | cp {{ swlib_unzip_path }}/grid/response/grid_install.rsp {{ swlib_unzip_path }}/grid_install.rsp 5 | {% else %} 6 | cp {{ grid_home }}/inventory/response/grid_install.rsp {{ swlib_unzip_path }}/grid_install.rsp 7 | {% endif %} 8 | 9 | sed -i '/^oracle.install.option/ s~oracle.install.option=$~oracle.install.option=CRS_SWONLY~' {{ swlib_unzip_path }}/grid_install.rsp 10 | sed -i '/^ORACLE_HOSTNAME/ s~ORACLE_HOSTNAME=$~ORACLE_HOSTNAME=`hostname -A`~' {{ swlib_unzip_path }}/grid_install.rsp 11 | sed -i '/^INVENTORY_LOCATION/ s~INVENTORY_LOCATION=$~INVENTORY_LOCATION='{{ oracle_root }}'/oraInventory~' {{ swlib_unzip_path }}/grid_install.rsp 12 | sed -i '/^ORACLE_BASE/ s~ORACLE_BASE=$~ORACLE_BASE='{{ oracle_base }}'~' {{ swlib_unzip_path }}/grid_install.rsp 13 | sed -i '/^ORACLE_HOME/ s~ORACLE_HOME=$~ORACLE_HOME='{{ grid_home }}'~' {{ swlib_unzip_path }}/grid_install.rsp 14 | sed -i '/^oracle.install.asm.OSDBA/ s~oracle.install.asm.OSDBA=$~oracle.install.asm.OSDBA=asmdba~' {{ swlib_unzip_path }}/grid_install.rsp 15 | sed -i '/^oracle.install.asm.OSOPER/ s~oracle.install.asm.OSOPER=$~oracle.install.asm.OSOPER=asmoper~' {{ swlib_unzip_path }}/grid_install.rsp 16 | sed -i '/^oracle.install.asm.OSASM/ s~oracle.install.asm.OSASM=$~oracle.install.asm.OSASM=asmadmin~' {{ swlib_unzip_path }}/grid_install.rsp 17 | -------------------------------------------------------------------------------- /roles/gi-setup/templates/init.ora.j2: -------------------------------------------------------------------------------- 1 | {{ asm_sid }}.instance_type=ASM 2 | {{ asm_sid }}.asm_diskstring='{{ asm_diskstring }}' 3 | {{ asm_sid }}.large_pool_size=12M 4 | {{ asm_sid }}.remote_login_passwordfile='EXCLUSIVE' 5 | {{ asm_sid }}.memory_target=0 6 | #{{ asm_sid }}.sga_target=3G 7 | #{{ asm_sid }}.pga_aggregate_target=400M 8 | {{ asm_sid }}.processes=1024 9 | -------------------------------------------------------------------------------- /roles/host-provision/tasks/config-tasks.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: config-tasks | Validate ssh equivalence (passwordless connection) and sudo escalation for new user 17 | ping: 18 | tags: host-provision 19 | 20 | # LVM creation 21 | # The net result will be that `/dev/mapper/db-sw` can be input into `install-oracle.sh` for local u01 storage 22 | - name: config-tasks | Create LVM layer - vgcreate 23 | # added vgremove for idempotency of the script 24 | # vgremove -y 25 | # vgcreate -y 26 | shell: | 27 | vgremove -y db 28 | vgcreate -y db {{ u01_lun }} 29 | when: 30 | - u01_lun | length > 0 31 | ignore_errors: true # to ignore when vgremove tries to remove non-existent vg the very first time this is run 32 | tags: host-provision 33 | 34 | - name: config-tasks | Create LVM layer - lvcreate 35 | # lvcreate -l 100%FREE -n 36 | shell: lvcreate -l 100%FREE -n sw db 37 | when: 38 | - u01_lun | length > 0 39 | tags: host-provision 40 | -------------------------------------------------------------------------------- /roles/host-provision/tasks/proxy.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # The tasks in this file are dependent on the fact that the control-node 16 | # has a HTTP proxy server like Squid installed and can act as the gateway 17 | # For more background, please refer: 18 | # https://cloud.google.com/vpc/docs/special-configurations#proxyvm 19 | 20 | --- 21 | - name: proxy | Get control node IP 22 | set_fact: 23 | proxy_ip: "{{ ansible_env['SSH_CLIENT'].split() | first }}" 24 | # debug: 25 | # var: proxy_ip 26 | tags: host-provision 27 | 28 | - name: proxy | Validate proxy connectivity via control node 29 | uri: 30 | url: https://www.google.com 31 | status_code: 200 32 | environment: 33 | https_proxy: "http://{{ proxy_ip }}:3128" 34 | tags: host-provision 35 | 36 | - name: proxy | Add control node as gateway-instance to /etc/hosts 37 | become: true 38 | lineinfile: 39 | dest: /etc/hosts 40 | regexp: ".*gateway-instance.*" 41 | line: "{{ proxy_ip }} gateway-instance gateway-instance." 42 | backup: true 43 | tags: host-provision 44 | 45 | - name: proxy | Add client side proxy environment variables to /etc/profile.d 46 | become: true 47 | copy: 48 | dest: /etc/profile.d/proxy.sh 49 | content: | 50 | export http_proxy="http://gateway-instance:3128" 51 | export https_proxy="http://gateway-instance:3128" 52 | export ftp_proxy="http://gateway-instance:3128" 53 | backup: true 54 | tags: host-provision 55 | 56 | - name: proxy | Update proxy in sudoers 57 | become: true 58 | lineinfile: 59 | dest: /etc/sudoers 60 | regexp: ".*env_keep.*proxy.*" 61 | line: 'Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"' 62 | validate: "visudo -cf %s" 63 | backup: true 64 | tags: host-provision 65 | -------------------------------------------------------------------------------- /roles/host-provision/tasks/rhel-config-tasks.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | # We check and evaluate subscription status 17 | # Only if the system is not subscribed (Status: Unknown), then we prompt for RedHat credentials 18 | - name: rhel-config-tasks | Get current registration status 19 | become: true 20 | shell: | 21 | /sbin/subscription-manager list 22 | register: rhsm_status 23 | tags: host-provision 24 | 25 | - name: rhel-config-tasks | Print current RHSM status 26 | debug: 27 | var: rhsm_status.stdout 28 | tags: host-provision 29 | 30 | - name: rhel-config-tasks | Get RHEL username 31 | pause: 32 | prompt: Enter username for RHEL support 33 | register: rhel_username 34 | when: 35 | - '"Status: Subscribed" not in rhsm_status.stdout' 36 | tags: host-provision 37 | 38 | - name: rhel-config-tasks | Get RHEL password 39 | pause: 40 | prompt: Enter password for RHEL support 41 | echo: false 42 | register: rhel_password 43 | when: 44 | - '"Status: Subscribed" not in rhsm_status.stdout' 45 | tags: host-provision 46 | 47 | - name: rhel-config-tasks | Register host 48 | become: true 49 | redhat_subscription: 50 | state: present 51 | username: "{{ rhel_username.user_input }}" 52 | password: "{{ rhel_password.user_input }}" 53 | auto_attach: true 54 | force_register: true 55 | when: 56 | - '"Status: Subscribed" not in rhsm_status.stdout' 57 | tags: host-provision 58 | -------------------------------------------------------------------------------- /roles/host-provision/tasks/ssh-keygen.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: ssh-keygen | Creates .ssh directory in control node if it does not exist 17 | file: 18 | path: ~/.ssh 19 | state: directory 20 | mode: 0700 21 | tags: host-provision 22 | 23 | - name: ssh-keygen | Create SSH key pair locally in control node 24 | openssh_keypair: 25 | # id_rsa is common name, name in a way to avoid overwriting it by chance 26 | # control_node_key_file set to "~/.ssh/id_rsa_oracle_toolkit" 27 | path: "{{ control_node_key_file }}" 28 | comment: "#generated by oracle-toolkit" 29 | tags: host-provision 30 | -------------------------------------------------------------------------------- /roles/host-provision/tasks/user-setup.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: user-setup | Create ansible user 17 | user: 18 | name: "{{ instance_ssh_user }}" 19 | comment: "User created for oracle-toolkit github.com/oracle-toolkit" 20 | tags: host-provision 21 | 22 | # the following 2 tasks are required so as not to hard code the public key file path 23 | # and derive it from group_vars.yml's: instance_ssh_user: "~/.ssh/id_rsa_oracle_toolkit" 24 | - name: user-setup | Slurp public key contents 25 | slurp: 26 | src: "{{ control_node_key_file }}.pub" 27 | register: public_key_content_scrambled 28 | delegate_to: localhost 29 | connection: local 30 | become: false 31 | tags: host-provision 32 | 33 | - name: user-setup | Store public key contents to be transferred from control node to DB hosts 34 | set_fact: 35 | public_key_content: "{{ public_key_content_scrambled['content'] | b64decode }}" 36 | tags: host-provision 37 | 38 | - name: user-setup | Transfer public key from control node to DB hosts 39 | authorized_key: 40 | user: "{{ instance_ssh_user }}" 41 | state: present 42 | key: "{{ public_key_content }}" 43 | tags: host-provision 44 | 45 | - name: user-setup | Add sudoers file for ansible 46 | template: 47 | src: hostprovision_ansible_user.j2 48 | dest: "/etc/sudoers.d/{{ instance_ssh_user }}" 49 | tags: host-provision 50 | -------------------------------------------------------------------------------- /roles/host-provision/templates/hostprovision_ansible_user.j2: -------------------------------------------------------------------------------- 1 | # the sudo escalation is for oracle-toolkit runs needed for initial provisioning and patching only 2 | {{ instance_ssh_user }} ALL=(ALL) NOPASSWD: ALL 3 | -------------------------------------------------------------------------------- /roles/host-storage/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | oracle_user_data_mounts: 17 | - { purpose: software, blk_device: /dev/sdb, fstype: xfs, mount_point: /u01, mount_opts: nofail } 18 | - { purpose: other, blk_device: /dev/sdc, fstype: xfs, mount_point: /u02, mount_opts: nofail } 19 | -------------------------------------------------------------------------------- /roles/host-storage/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Partition Oracle user mount devices 17 | parted: 18 | device: "{{ item.blk_device }}" 19 | number: 1 20 | state: present 21 | label: gpt 22 | when: "'mapper' not in item.blk_device" 23 | with_items: 24 | - "{{ oracle_user_data_mounts }}" 25 | tags: ora-mounts 26 | 27 | - include_role: 28 | name: common 29 | tasks_from: populate-user-data-mounts.yml 30 | 31 | - name: Add filesystem on Oracle user mount raw devices 32 | filesystem: 33 | fstype: "{{ item.fstype }}" 34 | dev: "{{ item.first_partition_id }}" 35 | when: "'mapper' not in item.blk_device" 36 | with_items: 37 | - "{{ oracle_user_data_mounts }}" 38 | tags: ora-mounts 39 | 40 | - name: Add filesystem on Oracle user mount LV devices 41 | filesystem: 42 | fstype: "{{ item.fstype }}" 43 | dev: "{{ item.blk_device }}" 44 | when: "'mapper' in item.blk_device" 45 | with_items: 46 | - "{{ oracle_user_data_mounts }}" 47 | tags: ora-mounts 48 | 49 | - name: Mount Oracle user mount raw devices 50 | mount: 51 | fstype: "{{ item.fstype }}" 52 | src: "{{ item.first_partition_id }}" 53 | path: "{{ item.mount_point }}" 54 | opts: "{{ item.mount_opts }}" 55 | state: mounted 56 | when: "'mapper' not in item.blk_device" 57 | with_items: 58 | - "{{ oracle_user_data_mounts }}" 59 | tags: ora-mounts 60 | 61 | - name: Mount Oracle user mount LV devices 62 | mount: 63 | fstype: "{{ item.fstype }}" 64 | src: "{{ item.blk_device }}" 65 | path: "{{ item.mount_point }}" 66 | opts: "{{ item.mount_opts }}" 67 | state: mounted 68 | when: "'mapper' in item.blk_device" 69 | with_items: 70 | - "{{ oracle_user_data_mounts }}" 71 | tags: ora-mounts 72 | 73 | # - name: This iteration to get all blk_devices regardless of their diskgroup - used for partitioning all asm disks 74 | # debug: msg="Running parted {{ item.1.blk_device }}" 75 | # with_subelements: 76 | # - "{{ asm_disks }}" 77 | # - disks 78 | 79 | # - name: This iteration to create asm disks with their asm name and block_device 80 | # debug: msg="Running create asmdisk {{ item.1.name }} with disk {{ item.1.blk_device }}" 81 | # with_subelements: 82 | # - "{{ asm_disks }}" 83 | # - disks 84 | 85 | # - name: This iteration to create asm diskgroup 86 | # debug: 87 | # msg: | 88 | # CREATE DISKGROUP DATA EXTERNAL REDUNDANCY 89 | # {% for i in item.disks %} DISK 'ORCL: {{ i.name }}' 90 | # {% endfor %} 91 | # ATTRIBUTE 92 | # 'compatible.asm' = '"${ORACLE_VERSION}"', 93 | # 'compatible.rdbms' = '11.2.0.4.0'; 94 | # with_items: 95 | # - "{{ asm_disks }}" 96 | -------------------------------------------------------------------------------- /roles/lsnr-create/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/lsnr-create/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Open listener port in firewall 17 | firewalld: 18 | port: "{{ listener_port }}/tcp" 19 | permanent: true 20 | immediate: true 21 | state: enabled 22 | become: true 23 | register: firewall_output 24 | failed_when: 25 | - "'firewall is not currently running' not in firewall_output.msg" 26 | - "'Permanent and Non-Permanent(immediate) operation' not in firewall_output.msg" 27 | when: not disable_firewall|bool 28 | tags: lsnr-create 29 | 30 | - name: Test whether port is free 31 | become: true 32 | become_user: root 33 | shell: "set -o pipefail; netstat -lnpt | ( grep {{ listener_port }} || true ) | wc -l" 34 | changed_when: false 35 | when: create_listener 36 | register: lsnr_port_check 37 | tags: lsnr-create 38 | 39 | - name: Check if listener has already been created 40 | become: true 41 | become_user: root 42 | shell: "set -o pipefail; ps -ef | ( grep [t]ns ||true ) | ( grep -w {{ listener_name }} || true ) | wc -l" 43 | changed_when: false 44 | when: create_listener 45 | register: lsnr_name_check 46 | tags: lsnr-create 47 | 48 | - name: Listener check results 49 | debug: 50 | msg: "{{ item }}" 51 | verbosity: 1 52 | with_items: 53 | - "{{ lsnr_port_check }}" 54 | - "{{ lsnr_name_check }}" 55 | when: create_listener 56 | tags: lsnr-create 57 | 58 | - name: Create listener via srvctl 59 | become: true 60 | become_user: "{{ grid_user }}" 61 | shell: | 62 | export PATH={{ grid_home }}/bin:${PATH} 63 | srvctl add listener -l {{ listener_name }} -p {{ listener_port }} -o {{ grid_home }} 64 | srvctl start listener -l {{ listener_name }} 65 | srvctl config listener -l {{ listener_name }} 66 | srvctl status listener -l {{ listener_name }} 67 | register: lsnr_output 68 | when: 69 | - create_listener 70 | - lsnr_port_check.stdout == "0" 71 | - lsnr_name_check.stdout == "0" 72 | - not free_edition 73 | tags: lsnr-create 74 | 75 | - name: Listener creation output 76 | debug: 77 | msg: 78 | - "{{ lsnr_output.cmd }}" 79 | - "{{ lsnr_output.stdout_lines }}" 80 | # verbosity: 1 81 | when: lsnr_output.cmd is defined 82 | tags: lsnr-create 83 | 84 | - name: Create listener via netca 85 | become: true 86 | become_user: "{{ oracle_user }}" 87 | shell: | 88 | set -o pipefail 89 | {{ oracle_home }}/bin/netca \ 90 | /orahome {{ oracle_home }} \ 91 | /instype typical \ 92 | /inscomp client,oraclenet,javavm,server,ano \ 93 | /insprtcl tcp \ 94 | /cfg local \ 95 | /authadp NO_VALUE \ 96 | /responseFile {{ oracle_home }}/network/install/netca_typ.rsp \ 97 | /silent \ 98 | /listenerparameters DEFAULT_SERVICE={{ oracle_sid }} \ 99 | /lisport {{ listener_port }} 100 | register: lsnr_output_netca 101 | when: 102 | - create_listener 103 | - lsnr_port_check.stdout == "0" 104 | - lsnr_name_check.stdout == "0" 105 | - free_edition 106 | tags: lsnr-create 107 | 108 | - name: Listener creation output from netca 109 | debug: 110 | msg: 111 | - "{{ lsnr_output_netca.cmd }}" 112 | - "{{ lsnr_output_netca.stdout_lines }}" 113 | # verbosity: 1 114 | when: lsnr_output_netca.cmd is defined 115 | tags: lsnr-create 116 | -------------------------------------------------------------------------------- /roles/ora-host/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/ora-host/tasks/hugepages.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: hugepages | get Hugepagesize from memory 17 | shell: set -o pipefail; ( cat /proc/meminfo | ( grep Hugepagesize || true ) | cut -d " " -f8 ) || true 18 | register: v_Hugepagesize 19 | changed_when: false 20 | 21 | - name: hugepages | Update the vm.nr_hugepages sysctl value 22 | sysctl: 23 | name: "vm.nr_hugepages" 24 | value: "{{ (((ansible_memtotal_mb + 1) * (ram_pct_used | int) / 100) * 1024 / (v_Hugepagesize.stdout | int)) | round(0,'ceil') | int }}" 25 | state: present 26 | sysctl_set: true 27 | reload: true 28 | ignoreerrors: true 29 | 30 | - name: hugepages | Capture transparent hugepage status 31 | shell: ( cat /sys/kernel/mm/transparent_hugepage/enabled ) || true 32 | register: checkTPH 33 | ignore_errors: true 34 | changed_when: false 35 | 36 | - name: hugepages | Update Grub default config and disable at run-time 37 | shell: | 38 | grubby --args="transparent_hugepage=never" --update-kernel=ALL 39 | echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled 40 | echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag 41 | when: checkTPH.stdout == "[always] madvise never" or checkTPH.stdout == "always [madvise] never" 42 | 43 | - name: hugepages | Check THPs are allocated 44 | shell: grep -q -E '^AnonHugePages:[[:space:]]+0[[:space:]]kB$' /proc/meminfo || echo reboot 45 | register: checkTHPreboot 46 | ignore_errors: true 47 | changed_when: false 48 | 49 | - name: hugepages | Recommend reboot if THPs are allocated 50 | debug: 51 | msg: "WARNING: A reboot is required to disable transparent huge pages" 52 | verbosity: 0 53 | when: checkTHPreboot.stdout == "reboot" 54 | -------------------------------------------------------------------------------- /roles/ora-host/tasks/kernel_parameters.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: kernel_parameters | Capture existing sysctl values 17 | shell: 18 | cmd: "sysctl -e {{ sysctl_params | join(' ') }} | sed 's/\t/ /g' || true" 19 | register: sysctl_out 20 | changed_when: false 21 | 22 | - name: kernel_parameters | Existing sysctl kernel parameter values 23 | debug: 24 | msg: "{{ sysctl_out.stdout_lines }}" 25 | verbosity: 1 26 | 27 | - name: kernel_parameters | Convert existing sysctl values to a list of dictionaries 28 | set_fact: 29 | sysctl_settings: >- 30 | {{ 31 | sysctl_out.stdout_lines | map('regex_replace', '^(\S*)\s*=\s*(\S+.*)$', '{ "parameter": "\1", "value": "\2" }') | map('from_json') | list 32 | }} 33 | 34 | - name: kernel_parameters | Update the shmall sysctl value (if less than "ram_pct_used" the size of physical memory) 35 | sysctl: 36 | name: "kernel.shmall" 37 | value: "{{ ((ansible_memtotal_mb + 1) * 256 * (ram_pct_used | int) / 100) | round(0, 'ceil') | int }}" # (MB->bytes)/pagesize: 1024*1024/4096=256 38 | state: present 39 | sysctl_set: true 40 | reload: true 41 | ignoreerrors: true 42 | vars: 43 | current_shmall: "{{ (sysctl_settings | selectattr('parameter', 'equalto', 'kernel.shmall') | map(attribute='value') | first) | default('0') }}" 44 | calculated_shmall: "{{ ((ansible_memtotal_mb + 1) * 256 * (ram_pct_used | int) / 100) | round(0, 'ceil') }}" 45 | when: current_shmall | int < calculated_shmall | int or current_shmall | int > ((ansible_memtotal_mb + 1 ) * 256) # Must cast to int at this stage for Ansible 2.9 46 | 47 | - name: kernel_parameters | Update other sysctl values 48 | sysctl: 49 | name: "{{ item.parameter }}" 50 | value: "{{ item.value }}" 51 | state: present 52 | sysctl_set: true 53 | reload: true 54 | ignoreerrors: true 55 | with_items: "{{ sysctl_param_values }}" 56 | -------------------------------------------------------------------------------- /roles/ora-host/templates/bash_profile_gi.j2: -------------------------------------------------------------------------------- 1 | export ORACLE_SID={{ asm_sid }} 2 | export GRID_HOME={{ grid_home }} 3 | export ORACLE_HOME={{ grid_home }} 4 | export PATH=${ORACLE_HOME}/bin:${PATH} 5 | export SWLIB={{ swlib_path }} 6 | -------------------------------------------------------------------------------- /roles/ora-host/templates/bash_profile_rdbms.j2: -------------------------------------------------------------------------------- 1 | export ORACLE_SID={{ oracle_sid }} 2 | export ORACLE_BASE={{ oracle_base }} 3 | export ORACLE_HOME={{ oracle_home }} 4 | export GRID_HOME={{ grid_home }} 5 | export PATH=${ORACLE_HOME}/bin:${PATH} 6 | export SWLIB={{ swlib_path }} 7 | -------------------------------------------------------------------------------- /roles/patch-vulns/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/patch-vulns/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Remove known log4j files / folders 17 | become: true 18 | become_user: root 19 | file: 20 | path: "{{ item }}" 21 | state: absent 22 | with_items: 23 | - "{{ grid_home }}/tfa/{{ inventory_hostname_short }}/tfa_home/jlib/log4j-core-2.9.1.jar" 24 | - "{{ grid_home }}/tfa/{{ inventory_hostname_short }}/tfa_home/jlib/tfa.war" 25 | - "{{ grid_home }}/suptools/tfa/release/tfa_home/jlib/log4j-core-2.9.1.jar" 26 | - "{{ grid_home }}/suptools/tfa/release/tfa_home/jlib/tfa.war" 27 | - "{{ grid_home }}/.patch_storage/34419443_Oct_14_2022_05_25_14/files/suptools/tfa.zip" 28 | - "{{ oracle_home }}/suptools/tfa/release/tfa_home/jlib/log4j-core-2.9.1.jar" 29 | - "{{ oracle_home }}/suptools/tfa/release/tfa_home/jlib/tfa.war" 30 | - "{{ oracle_home }}/md/property_graph/lib" 31 | - "{{ oracle_home }}/md/property_graph/pgx" 32 | - "{{ oracle_home }}/.patch_storage/34419443_Oct_14_2022_05_25_14/files/md/property_graph.zip" 33 | - "{{ oracle_home }}/.patch_storage/34419443_Oct_14_2022_05_25_14/files/suptools/tfa.zip" 34 | tags: patch-vulns 35 | -------------------------------------------------------------------------------- /roles/patch/files/expect_rsp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | # Create OCM response file using expect 18 | # Accepts two passed parameters: 19 | # 20 | # $1: ORACLE_BASE 21 | # $2: ORACLE_HOME 22 | # $3: Destination for the response file 23 | # 24 | 25 | export ORACLE_BASE=${1} 26 | export ORACLE_HOME=${2} 27 | export RSP_PATH=${3} 28 | 29 | if [ -f "${ORACLE_HOME}/OPatch/ocm/bin/emocmrsp" ]; then 30 | cat < ${RSP_PATH}/ocm.sh 31 | #!/usr/bin/expect -f 32 | set timeout -1 33 | spawn ${ORACLE_HOME}/OPatch/ocm/bin/emocmrsp -no_banner -output ${RSP_PATH}/ocm.rsp 34 | expect "Email address/User Name:" 35 | send "\n" 36 | expect "Do you wish to remain uninformed of security issues*" 37 | send "Y\n" 38 | expect eof 39 | EOF 40 | chmod 700 ${RSP_PATH}/ocm.sh 41 | ${RSP_PATH}/ocm.sh 42 | rm ${RSP_PATH}/ocm.sh 43 | fi 44 | -------------------------------------------------------------------------------- /roles/patch/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/patch/tasks/opatch_apply.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: opatch_apply | Run prerequisite check 17 | command: "{{ sw_home }}/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./" 18 | register: opatch_prereq 19 | args: 20 | chdir: "{{ swlib_unzip_path }}/{{ patch.patchnum }}/{{ patch.patch_subdir }}" 21 | when: patch.prereq_check 22 | failed_when: opatch_prereq.rc != 0 23 | become: true 24 | become_user: "{{ sw_user }}" 25 | tags: opatch-prereq 26 | 27 | - name: opatch_apply | Prerequisite check output 28 | debug: 29 | msg: "{{ opatch_prereq }}" 30 | verbosity: 1 31 | when: patch.prereq_check 32 | 33 | - name: opatch_apply | Run OPatch analyze 34 | command: "{{ sw_home }}/OPatch/{{ patch.method }} -analyze {{ silent }}" 35 | register: opatch_analyze 36 | args: 37 | chdir: "{{ swlib_unzip_path }}/{{ patch.patchnum }}/{{ patch.patch_subdir }}" 38 | when: not patch.prereq_check and oracle_ver != '11.2.0.4.0' 39 | failed_when: opatch_analyze.rc != 0 40 | become: true 41 | become_user: "{{ sw_user }}" 42 | tags: opatch-analyze 43 | 44 | - name: opatch_apply | OPatch analyze output 45 | debug: 46 | msg: "{{ opatch_analyze }}" 47 | verbosity: 1 48 | when: not patch.prereq_check and oracle_ver != '11.2.0.4.0' 49 | 50 | - name: opatch_apply | Set OCM command 51 | set_fact: 52 | response_command: "{{ '-ocmrf {{ swlib_unzip_path }}/ocm.rsp' if patch.ocm else '' }}" 53 | tags: set-ocm 54 | 55 | - name: opatch_apply | Run opatch apply 56 | command: "{{ sw_home }}/OPatch/{{ patch.method }} {{ silent }} {{ response_command }}" 57 | when: 58 | - patch.release == oracle_rel 59 | args: 60 | chdir: "{{ swlib_unzip_path }}/{{ patch.patchnum }}{{ patch.patch_subdir }}" 61 | register: opatch_apply 62 | failed_when: opatch_apply.rc != 0 63 | become: true 64 | become_user: "{{ sw_user }}" 65 | tags: opatch-apply 66 | 67 | - name: opatch_apply | opatch apply results 68 | debug: 69 | msg: "{{ opatch_apply }}" 70 | # verbosity: 1 71 | tags: opatch-apply 72 | 73 | - name: opatch_apply | 12.1 bug resolution - group of oracle binary set incorrectly by opatch - MOS (Doc ID 1084186.1) 74 | shell: | 75 | set -o pipefail 76 | setasmgidwrap o={{ oracle_home }}/bin/oracle 77 | environment: 78 | ORACLE_HOME: "{{ grid_home }}" 79 | ORACLE_SID: "{{ asm_sid }}" 80 | PATH: "{{ grid_home }}/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin" 81 | args: 82 | chdir: "{{ grid_home }}/bin" 83 | when: oracle_ver == '12.1.0.2.0' 84 | register: setasmgidwrap_output 85 | become: true 86 | become_user: "{{ grid_user }}" 87 | tags: opatch-apply 88 | 89 | - name: opatch_apply | 12.1 bug resolution results 90 | debug: 91 | msg: "{{ setasmgidwrap_output }}" 92 | verbosity: 1 93 | tags: opatch-apply 94 | 95 | - name: opatch_apply | Pause for 90 seconds due to delayed startup after opatch on 12c 96 | wait_for: 97 | timeout: 90 98 | delegate_to: localhost 99 | when: oracle_ver in ['12.1.0.2.0','12.2.0.1.0'] and home_type == 'GRID' 100 | 101 | - name: opatch_apply | SQL patching steps 102 | include_tasks: sql_patch.yml 103 | when: 104 | - home_type == 'DB' or patch.method == 'opatch apply' 105 | - not (standby_db | default(false) | bool) 106 | tags: patch-rdbms,opatch-apply 107 | -------------------------------------------------------------------------------- /roles/patch/tasks/rac-ins-opatch.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: rac-ins-opatch | Create OCM response file 17 | script: expect_rsp.sh {{ oracle_base }} {{ oracle_home }} {{ swlib_unzip_path }} 18 | args: 19 | creates: "{{ swlib_unzip_path }}/ocm.rsp" 20 | with_items: 21 | - "{{ rdbms_patches }}" 22 | - "{{ gi_patches }}" 23 | when: 24 | - item.ocm 25 | - item.release == oracle_ver 26 | become: true 27 | become_user: "{{ oracle_user }}" 28 | tags: rac-ins-opatch 29 | 30 | - name: rac-ins-opatch | 12.2 bug resolution - MOS (Doc ID 2401455.1) 31 | copy: 32 | src: "{{ oracle_root }}/oraInventory/oraInst.loc" 33 | dest: "{{ grid_home }}/oraInst.loc" 34 | remote_src: true 35 | owner: "{{ grid_user }}" 36 | group: "{{ oracle_group }}" 37 | mode: u=rw,g=r,o= 38 | when: oracle_ver == '12.2.0.1.0' 39 | become: true 40 | become_user: root 41 | 42 | - name: rac-ins-opatch | Update GI OPatch 43 | unarchive: 44 | src: "{{ swlib_path }}/{{ item.patchfile }}" 45 | dest: "{{ grid_home }}" 46 | remote_src: true 47 | with_items: 48 | - "{{ opatch_patches }}" 49 | when: 50 | - item.release == oracle_ver 51 | - item.category == "OPatch" 52 | become: true 53 | become_user: "{{ grid_user }}" 54 | tags: rac-ins-opatch 55 | 56 | - name: rac-ins-opatch | Update RDBMS OPatch 57 | unarchive: 58 | src: "{{ swlib_path }}/{{ item.patchfile }}" 59 | dest: "{{ oracle_home }}" 60 | remote_src: true 61 | with_items: 62 | - "{{ opatch_patches }}" 63 | when: 64 | - item.release == oracle_ver 65 | - item.category == "OPatch" 66 | become: true 67 | become_user: "{{ oracle_user }}" 68 | tags: rac-ins-opatch 69 | -------------------------------------------------------------------------------- /roles/pwgen/files/pwgen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2020 Google LLC 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 | # disable globbing 18 | set -f 19 | # password length or 1st parameter 20 | PWLEN="${1:-16}" 21 | # password symbol set or 2nd parameter 22 | PWSYM="${2:-@+~*}" 23 | 24 | # must start with alpha 25 | FCHAR="$(cat /dev/urandom | tr -dc [:alpha:] | head -c1)" 26 | # have a symbol 27 | SCHAR="$(cat /dev/urandom | tr -dc ${PWSYM} | head -c1)" 28 | # upper, lower, digit, some symbols 29 | RCHAR="$(cat /dev/urandom | tr -dc [:alnum:]${PWSYM} | head -c$((PWLEN - 3)))" 30 | # wrap the symbol into the password 31 | RPASS="$(echo "${SCHAR}${RCHAR}" | fold -c -w1 | shuf | tr -d '\n')" 32 | 33 | echo "${FCHAR}${RPASS}${FCHAR}" 34 | -------------------------------------------------------------------------------- /roles/pwgen/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/pwgen/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Copy pwgen script 17 | copy: 18 | src: "{{ pwgen_file }}" 19 | dest: "{{ pwgen_path }}/{{ pwgen_file }}" 20 | owner: root 21 | mode: u=rwx,go=rx 22 | become: true 23 | become_user: root 24 | 25 | - name: Generate random password 26 | command: "{{ pwgen_path }}/{{ pwgen_file }} '{{ pwgen_len | default('') }}' '{{ pwgen_chars | default('@+~*') }}'" 27 | register: pwgen_output 28 | -------------------------------------------------------------------------------- /roles/rac-db-setup/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/rac-db-setup/templates/db_install.rsp.11.2.0.4.0.j2: -------------------------------------------------------------------------------- 1 | oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v11_2_0 2 | oracle.install.option=INSTALL_DB_SWONLY 3 | UNIX_GROUP_NAME= 4 | INVENTORY_LOCATION={{ oracle_inventory }} 5 | ORACLE_HOME={{ oracle_home }} 6 | ORACLE_BASE={{ oracle_base }} 7 | oracle.install.db.InstallEdition={{ oracle_edition }} 8 | 9 | oracle.install.db.DBA_GROUP=dba 10 | oracle.install.db.OPER_GROUP=oper 11 | 12 | oracle.install.db.CLUSTER_NODES={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} 13 | 14 | SECURITY_UPDATES_VIA_MYORACLESUPPORT=false 15 | DECLINE_SECURITY_UPDATES=true 16 | 17 | oracle.install.db.isRACOneInstall= 18 | oracle.install.db.racOneServiceName= 19 | oracle.install.db.config.starterdb.type= 20 | oracle.install.db.config.starterdb.globalDBName= 21 | oracle.install.db.config.starterdb.SID= 22 | oracle.install.db.config.starterdb.characterSet=AL32UTF8 23 | oracle.install.db.config.starterdb.memoryOption=true 24 | oracle.install.db.config.starterdb.memoryLimit= 25 | oracle.install.db.config.starterdb.installExampleSchemas=false 26 | oracle.install.db.config.starterdb.enableSecuritySettings=true 27 | oracle.install.db.config.starterdb.password.ALL= 28 | oracle.install.db.config.starterdb.password.SYS= 29 | oracle.install.db.config.starterdb.password.SYSTEM= 30 | oracle.install.db.config.starterdb.password.SYSMAN= 31 | oracle.install.db.config.starterdb.password.DBSNMP= 32 | oracle.install.db.config.starterdb.control=DB_CONTROL 33 | oracle.install.db.config.starterdb.gridcontrol.gridControlServiceURL= 34 | oracle.install.db.config.starterdb.automatedBackup.enable=false 35 | oracle.install.db.config.starterdb.automatedBackup.osuid= 36 | oracle.install.db.config.starterdb.automatedBackup.ospwd= 37 | oracle.install.db.config.starterdb.storageType= 38 | oracle.install.db.config.starterdb.fileSystemStorage.dataLocation= 39 | oracle.install.db.config.starterdb.fileSystemStorage.recoveryLocation= 40 | oracle.install.db.config.asm.diskGroup= 41 | oracle.install.db.config.asm.ASMSNMPPassword= 42 | MYORACLESUPPORT_USERNAME= 43 | MYORACLESUPPORT_PASSWORD= 44 | PROXY_HOST= 45 | PROXY_PORT= 46 | PROXY_USER= 47 | PROXY_PWD= 48 | PROXY_REALM= 49 | COLLECTOR_SUPPORTHUB_URL= 50 | oracle.installer.autoupdates.option= 51 | oracle.installer.autoupdates.downloadUpdatesLoc= 52 | AUTOUPDATES_MYORACLESUPPORT_USERNAME= 53 | AUTOUPDATES_MYORACLESUPPORT_PASSWORD= 54 | -------------------------------------------------------------------------------- /roles/rac-db-setup/templates/db_install.rsp.12.1.0.2.0.j2: -------------------------------------------------------------------------------- 1 | oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v12.1.0 2 | oracle.install.option=INSTALL_DB_SWONLY 3 | UNIX_GROUP_NAME= 4 | INVENTORY_LOCATION={{ oracle_inventory }} 5 | ORACLE_HOME={{ oracle_home }} 6 | ORACLE_BASE={{ oracle_base }} 7 | oracle.install.db.InstallEdition={{ oracle_edition }} 8 | 9 | oracle.install.db.DBA_GROUP=dba 10 | oracle.install.db.OPER_GROUP=oper 11 | oracle.install.db.BACKUPDBA_GROUP=backupdba 12 | oracle.install.db.DGDBA_GROUP=dgdba 13 | oracle.install.db.KMDBA_GROUP=kmdba 14 | 15 | oracle.install.db.CLUSTER_NODES={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} 16 | 17 | SECURITY_UPDATES_VIA_MYORACLESUPPORT=false 18 | DECLINE_SECURITY_UPDATES=true 19 | -------------------------------------------------------------------------------- /roles/rac-db-setup/templates/db_install.rsp.12.2.0.1.0.j2: -------------------------------------------------------------------------------- 1 | oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v12.2.0 2 | oracle.install.option=INSTALL_DB_SWONLY 3 | UNIX_GROUP_NAME= 4 | INVENTORY_LOCATION={{ oracle_inventory }} 5 | ORACLE_HOME={{ oracle_home }} 6 | ORACLE_BASE={{ oracle_base }} 7 | oracle.install.db.InstallEdition={{ oracle_edition }} 8 | oracle.install.db.OSDBA_GROUP=dba 9 | oracle.install.db.OSOPER_GROUP=oper 10 | oracle.install.db.OSBACKUPDBA_GROUP=backupdba 11 | oracle.install.db.OSDGDBA_GROUP=dgdba 12 | oracle.install.db.OSKMDBA_GROUP=kmdba 13 | oracle.install.db.OSRACDBA_GROUP=racdba 14 | 15 | oracle.install.db.CLUSTER_NODES={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} 16 | -------------------------------------------------------------------------------- /roles/rac-db-setup/templates/db_install.rsp.18.0.0.0.0.j2: -------------------------------------------------------------------------------- 1 | oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v18.0.0 2 | oracle.install.option=INSTALL_DB_SWONLY 3 | UNIX_GROUP_NAME= 4 | INVENTORY_LOCATION={{ oracle_inventory }} 5 | ORACLE_HOME={{ oracle_home }} 6 | ORACLE_BASE={{ oracle_base }} 7 | oracle.install.db.InstallEdition={{ oracle_edition }} 8 | oracle.install.db.OSDBA_GROUP=dba 9 | oracle.install.db.OSOPER_GROUP=oper 10 | oracle.install.db.OSBACKUPDBA_GROUP=backupdba 11 | oracle.install.db.OSDGDBA_GROUP=dgdba 12 | oracle.install.db.OSKMDBA_GROUP=kmdba 13 | oracle.install.db.OSRACDBA_GROUP=racdba 14 | 15 | oracle.install.db.CLUSTER_NODES={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} 16 | -------------------------------------------------------------------------------- /roles/rac-db-setup/templates/db_install.rsp.19.3.0.0.0.j2: -------------------------------------------------------------------------------- 1 | oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0 2 | oracle.install.option=INSTALL_DB_SWONLY 3 | UNIX_GROUP_NAME= 4 | INVENTORY_LOCATION={{ oracle_inventory }} 5 | ORACLE_HOME={{ oracle_home }} 6 | ORACLE_BASE={{ oracle_base }} 7 | oracle.install.db.InstallEdition={{ oracle_edition }} 8 | oracle.install.db.OSDBA_GROUP=dba 9 | oracle.install.db.OSOPER_GROUP=oper 10 | oracle.install.db.OSBACKUPDBA_GROUP=backupdba 11 | oracle.install.db.OSDGDBA_GROUP=dgdba 12 | oracle.install.db.OSKMDBA_GROUP=kmdba 13 | oracle.install.db.OSRACDBA_GROUP=racdba 14 | 15 | oracle.install.db.CLUSTER_NODES={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{% endfor %} 16 | -------------------------------------------------------------------------------- /roles/rac-gi-setup/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/rac-gi-setup/tasks/rac-asm-create.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: rac-asm-create | Check available ASM disk groups 17 | shell: | 18 | set -o pipefail 19 | sqlplus -s / as sysasm <<< "select name from v\$asm_diskgroup;" 20 | environment: 21 | ORACLE_HOME: "{{ grid_home }}" 22 | PATH: "{{ grid_home }}/bin:${PATH}" 23 | ORACLE_VERSION: "{{ oracle_ver }}" 24 | ORACLE_SID: "{{ asm_sid }}" 25 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 26 | become: true 27 | become_user: "{{ grid_user }}" 28 | changed_when: false 29 | register: created_dg 30 | tags: rac-asm-create,check-dg 31 | 32 | - name: rac-asm-create | (asmlib) Create disk groups 33 | shell: | 34 | set -o pipefail 35 | sqlplus -s / as sysasm << EOF 36 | CREATE DISKGROUP {{ item.diskgroup }} EXTERNAL REDUNDANCY 37 | {% for i in item.disks %} DISK 'ORCL:{{ i.name }}' 38 | {% endfor %} 39 | ATTRIBUTE 40 | 'compatible.asm' = '{{ diskgroup_compatible_asm }}', 41 | 'compatible.rdbms' = '{{ diskgroup_compatible_rdbms }}'; 42 | EOF 43 | environment: 44 | ORACLE_HOME: "{{ grid_home }}" 45 | PATH: "{{ grid_home }}/bin:${PATH}" 46 | ORACLE_VERSION: "{{ oracle_ver }}" 47 | ORACLE_SID: "{{ asm_sid }}" 48 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 49 | when: 50 | - asm_disk_management == "asmlib" 51 | - created_dg is not search(item.diskgroup) 52 | with_items: 53 | - "{{ asm_disks }}" 54 | register: create_dg 55 | failed_when: "'ERROR' in create_dg.stdout" 56 | become: true 57 | become_user: "{{ grid_user }}" 58 | tags: rac-asm-create,create-dg 59 | 60 | - name: rac-asm-create | (udev) Create disk groups 61 | shell: | 62 | set -o pipefail 63 | sqlplus -s / as sysasm << EOF 64 | CREATE DISKGROUP {{ item.diskgroup }} EXTERNAL REDUNDANCY 65 | {% for i in item.disks %} DISK '/dev/{{ path_udev }}/{{ i.name }}' 66 | {% endfor %} 67 | ATTRIBUTE 68 | 'compatible.asm' = '{{ diskgroup_compatible_asm }}', 69 | 'compatible.rdbms' = '{{ diskgroup_compatible_rdbms }}'; 70 | EOF 71 | environment: 72 | ORACLE_HOME: "{{ grid_home }}" 73 | PATH: "{{ grid_home }}/bin:${PATH}" 74 | ORACLE_VERSION: "{{ oracle_ver }}" 75 | ORACLE_SID: "{{ asm_sid }}" 76 | LD_LIBRARY_PATH: "{{ grid_home }}/lib:${LD_LIBRARY_PATH}" 77 | when: 78 | - asm_disk_management == "udev" 79 | - created_dg is not search(item.diskgroup) 80 | with_items: 81 | - "{{ asm_disks }}" 82 | register: create_dg 83 | failed_when: "'ERROR' in create_dg.stdout" 84 | become: true 85 | become_user: "{{ grid_user }}" 86 | tags: rac-asm-create,create-dg 87 | 88 | - name: rac-asm-create | debug asm disk group creation 89 | debug: 90 | msg: "{{ create_dg }}" 91 | verbosity: 1 92 | tags: rac-asm-create,list-dg 93 | -------------------------------------------------------------------------------- /roles/rac-gi-setup/templates/gridsetup.rsp.12.2.0.1.0.j2: -------------------------------------------------------------------------------- 1 | {% macro domain() -%}{% if hostvars[groups['dbasm'].0]['cluster_domain'] is defined and hostvars[groups['dbasm'].0]['cluster_domain']|length > 0 -%}.{{ hostvars[groups['dbasm'].0]['cluster_domain'] }}{% endif -%}{% endmacro -%} 2 | oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v12.2.0 3 | INVENTORY_LOCATION={{ oracle_inventory }} 4 | oracle.install.option=CRS_CONFIG 5 | ORACLE_BASE={{ grid_base }} 6 | oracle.install.asm.OSDBA=asmdba 7 | oracle.install.asm.OSOPER=asmoper 8 | oracle.install.asm.OSASM=asmadmin 9 | 10 | oracle.install.crs.config.gpnp.scanName={{ hostvars[groups['dbasm'].0]['scan_name'] }}{{ domain() }} 11 | oracle.install.crs.config.gpnp.scanPort={{ hostvars[groups['dbasm'].0]['scan_port'] }} 12 | oracle.install.crs.config.ClusterConfiguration=STANDALONE 13 | oracle.install.crs.config.clusterName={{ hostvars[groups['dbasm'].0]['cluster_name'][:15] }} 14 | 15 | oracle.install.crs.config.autoConfigureClusterNodeVIP=false 16 | 17 | oracle.install.crs.config.clusterNodes={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{{ domain() }}:{{ hostvars[h]['vip_name'] }}{{ domain() }}:HUB{% endfor %} 18 | 19 | oracle.install.crs.config.networkInterfaceList={% set pub = hostvars[groups['dbasm'].0]['public_net']|regex_replace('@.*$', '') -%} 20 | {% set prv = hostvars[groups['dbasm'].0]['private_net']|regex_replace('@.*$', '') -%} 21 | {{ pub }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][pub]['ipv4']['network'] }}:1,{{ prv }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][prv]['ipv4']['network'] }}:5 22 | 23 | oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE 24 | 25 | oracle.install.asm.SYSASMPassword={{ pass_asmsys }} 26 | oracle.install.asm.diskGroup.name={{ hostvars[groups['dbasm'].0]['dg_name'] }} 27 | 28 | oracle.install.asm.diskGroup.redundancy=EXTERNAL 29 | oracle.install.asm.diskGroup.AUSize=4 30 | 31 | oracle.install.asm.diskGroup.disks={{ symlink | json_query('results[*].stdout') | join(',') }} 32 | 33 | oracle.install.asm.diskGroup.diskDiscoveryString={{ asm_diskstring }} 34 | oracle.install.asm.monitorPassword={{ pass_asmmon }} 35 | oracle.install.asm.configureAFD=false 36 | oracle.install.crs.configureRHPS=false 37 | -------------------------------------------------------------------------------- /roles/rac-gi-setup/templates/gridsetup.rsp.18.0.0.0.0.j2: -------------------------------------------------------------------------------- 1 | {% macro domain() -%}{% if hostvars[groups['dbasm'].0]['cluster_domain'] is defined and hostvars[groups['dbasm'].0]['cluster_domain']|length > 0 -%}.{{ hostvars[groups['dbasm'].0]['cluster_domain'] }}{% endif -%}{% endmacro -%} 2 | oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v18.0.0 3 | INVENTORY_LOCATION={{ oracle_inventory }} 4 | oracle.install.option=CRS_CONFIG 5 | ORACLE_BASE={{ grid_base }} 6 | oracle.install.asm.OSDBA=asmdba 7 | oracle.install.asm.OSOPER=asmoper 8 | oracle.install.asm.OSASM=asmadmin 9 | oracle.install.crs.config.scanType=LOCAL_SCAN 10 | oracle.install.crs.config.gpnp.scanName={{ hostvars[groups['dbasm'].0]['scan_name'] }}{{ domain() }} 11 | oracle.install.crs.config.gpnp.scanPort={{ hostvars[groups['dbasm'].0]['scan_port'] }} 12 | oracle.install.crs.config.ClusterConfiguration=STANDALONE 13 | oracle.install.crs.config.clusterName={{ hostvars[groups['dbasm'].0]['cluster_name'][:15] }} 14 | 15 | oracle.install.crs.config.autoConfigureClusterNodeVIP=false 16 | 17 | oracle.install.crs.config.clusterNodes={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{{ domain() }}:{{ hostvars[h]['vip_name'] }}{{ domain() }}:HUB{% endfor %} 18 | 19 | oracle.install.crs.config.networkInterfaceList={% set pub = hostvars[groups['dbasm'].0]['public_net']|regex_replace('@.*$', '') -%} 20 | {% set prv = hostvars[groups['dbasm'].0]['private_net']|regex_replace('@.*$', '') -%} 21 | {{ pub }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][pub]['ipv4']['network'] }}:1,{{ prv }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][prv]['ipv4']['network'] }}:5 22 | 23 | oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE 24 | 25 | oracle.install.asm.SYSASMPassword={{ pass_asmsys }} 26 | oracle.install.asm.diskGroup.name={{ hostvars[groups['dbasm'].0]['dg_name'] }} 27 | 28 | oracle.install.asm.diskGroup.redundancy=EXTERNAL 29 | oracle.install.asm.diskGroup.AUSize=4 30 | 31 | oracle.install.asm.diskGroup.disks={{ symlink | json_query('results[*].stdout') | join(',') }} 32 | 33 | oracle.install.asm.diskGroup.diskDiscoveryString={{ asm_diskstring }} 34 | oracle.install.asm.monitorPassword={{ pass_asmmon }} 35 | oracle.install.asm.configureAFD=false 36 | oracle.install.crs.configureRHPS=false 37 | -------------------------------------------------------------------------------- /roles/rac-gi-setup/templates/gridsetup.rsp.19.3.0.0.0.j2: -------------------------------------------------------------------------------- 1 | {% macro domain() -%}{% if hostvars[groups['dbasm'].0]['cluster_domain'] is defined and hostvars[groups['dbasm'].0]['cluster_domain']|length > 0 -%}.{{ hostvars[groups['dbasm'].0]['cluster_domain'] }}{% endif -%}{% endmacro -%} 2 | oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0 3 | INVENTORY_LOCATION={{ oracle_inventory }} 4 | oracle.install.option=CRS_CONFIG 5 | ORACLE_BASE={{ grid_base }} 6 | oracle.install.asm.OSDBA=asmdba 7 | oracle.install.asm.OSOPER=asmoper 8 | oracle.install.asm.OSASM=asmadmin 9 | oracle.install.crs.config.scanType=LOCAL_SCAN 10 | oracle.install.crs.config.gpnp.scanName={{ hostvars[groups['dbasm'].0]['scan_name'] }}{{ domain() }} 11 | oracle.install.crs.config.gpnp.scanPort={{ hostvars[groups['dbasm'].0]['scan_port'] }} 12 | oracle.install.crs.config.ClusterConfiguration=STANDALONE 13 | oracle.install.crs.config.clusterName={{ hostvars[groups['dbasm'].0]['cluster_name'][:15] }} 14 | 15 | oracle.install.crs.config.autoConfigureClusterNodeVIP=false 16 | 17 | oracle.install.crs.config.clusterNodes={% set c = joiner(",") %}{% for h in groups['dbasm'] %}{{ c() }}{{ h }}{{ domain() }}:{{ hostvars[h]['vip_name'] }}{{ domain() }}{% endfor %} 18 | 19 | oracle.install.crs.config.networkInterfaceList={% set pub = hostvars[groups['dbasm'].0]['public_net']|regex_replace('@.*$', '') -%} 20 | {% set prv = hostvars[groups['dbasm'].0]['private_net']|regex_replace('@.*$', '') -%} 21 | {{ pub }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][pub]['ipv4']['network'] }}:1,{{ prv }}:{{ hostvars[groups['dbasm'].0]['ansible_facts'][prv]['ipv4']['network'] }}:5 22 | 23 | oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE 24 | 25 | oracle.install.asm.SYSASMPassword={{ pass_asmsys }} 26 | oracle.install.asm.diskGroup.name={{ hostvars[groups['dbasm'].0]['dg_name'] }} 27 | 28 | oracle.install.asm.diskGroup.redundancy=EXTERNAL 29 | oracle.install.asm.diskGroup.AUSize=4 30 | 31 | oracle.install.asm.diskGroup.disks={{ symlink | json_query('results[*].stdout') | join(',') }} 32 | 33 | oracle.install.asm.diskGroup.diskDiscoveryString={{ asm_diskstring }} 34 | oracle.install.asm.monitorPassword={{ pass_asmmon }} 35 | oracle.install.asm.configureAFD=false 36 | oracle.install.crs.configureRHPS=false 37 | -------------------------------------------------------------------------------- /roles/rac-lsnr-firewall/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/rac-lsnr-firewall/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Open listener port in firewall 17 | firewalld: 18 | port: "{{ hostvars[groups['dbasm'].0]['scan_port'] }}/tcp" 19 | permanent: true 20 | immediate: true 21 | state: enabled 22 | become: true 23 | register: firewall_output 24 | failed_when: 25 | - "'firewall is not currently running' not in firewall_output.msg" 26 | - "'Permanent and Non-Permanent(immediate) operation' not in firewall_output.msg" 27 | when: not disable_firewall|bool 28 | tags: lsnr-firewall 29 | 30 | - name: Test whether port is free 31 | become: true 32 | become_user: root 33 | shell: "set -o pipefail; netstat -lnpt | ( grep {{ hostvars[groups['dbasm'].0]['scan_port'] }} || true ) | wc -l" 34 | changed_when: false 35 | when: create_listener 36 | register: scan_port_check 37 | tags: lsnr-firewall 38 | 39 | - name: Listener check results 40 | debug: 41 | msg: "{{ item }}" 42 | verbosity: 1 43 | with_items: 44 | - "{{ scan_port_check }}" 45 | when: create_listener 46 | tags: lsnr-firewall 47 | 48 | - name: Allow local networks for RAC 49 | firewalld: 50 | zone: public 51 | rich_rule: rule family=ipv4 source address="{{ item.value.ipv4.network }}/{{ item.value.ipv4.netmask }}" accept 52 | permanent: true 53 | immediate: true 54 | state: enabled 55 | become: true 56 | register: firewall_op_localnw 57 | failed_when: 58 | - "'firewall is not currently running' not in firewall_op_localnw.msg" 59 | - "'Permanent and Non-Permanent(immediate) operation' not in firewall_op_localnw.msg" 60 | when: not disable_firewall|bool 61 | with_items: 62 | - "{{ ansible_facts | dict2items | selectattr('value.ipv4.network', 'defined') | list }}" 63 | tags: lsnr-firewall 64 | 65 | - name: Allow HAIP networks 66 | firewalld: 67 | zone: public 68 | rich_rule: rule family=ipv4 source address="169.254.0.0/16" accept 69 | permanent: true 70 | immediate: true 71 | state: enabled 72 | become: true 73 | register: firewall_op_haipnw 74 | failed_when: 75 | - "'firewall is not currently running' not in firewall_op_haipnw.msg" 76 | - "'Permanent and Non-Permanent(immediate) operation' not in firewall_op_haipnw.msg" 77 | when: not disable_firewall|bool 78 | tags: lsnr-firewall 79 | -------------------------------------------------------------------------------- /roles/rdbms-setup/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/rdbms-setup/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Check if software is already installed 17 | shell: cat "{{ oracle_inventory }}/ContentsXML/inventory.xml" 2>&1 | ( grep -w {{ oracle_home }} || true ) | wc -l 18 | register: existing_dbhome 19 | become: true 20 | become_user: root 21 | ignore_errors: true 22 | changed_when: false 23 | failed_when: false 24 | tags: rdbms-setup 25 | 26 | - name: OH Confirmation 27 | debug: 28 | msg: "Installing ORACLE_HOME - {{ oracle_home }}" 29 | when: existing_dbhome.stdout == "0" 30 | tags: rdbms-setup 31 | 32 | - name: Validate directories (required for secondary home) 33 | file: 34 | path: "{{ item.name }}" 35 | state: directory 36 | owner: "{{ item.owner }}" 37 | group: "{{ item.group }}" 38 | mode: "{{ item.mode }}" 39 | when: home_name in item.name 40 | with_items: "{{ oracle_dirs + grid_dirs }}" 41 | tags: rdbms-setup,os-dirs 42 | 43 | - include_tasks: rdbms-install.yml 44 | with_items: 45 | - "{{ rdbms_software }}" 46 | loop_control: 47 | loop_var: osw 48 | when: 49 | - existing_dbhome.stdout == "0" 50 | - osw.version == oracle_ver 51 | - oracle_edition in osw.edition 52 | - not free_edition 53 | tags: rdbms-setup 54 | 55 | - include_tasks: rdbms-rpm-install.yml 56 | with_items: 57 | - "{{ rdbms_software }}" 58 | loop_control: 59 | loop_var: osw 60 | when: 61 | - existing_dbhome.stdout == "0" 62 | - osw.version == oracle_ver 63 | - oracle_edition in osw.edition 64 | - free_edition 65 | tags: rdbms-setup 66 | 67 | - name: Create sqlnet.ora file 68 | template: 69 | src: sqlnet.ora.j2 70 | dest: "{{ oracle_home }}/network/admin/sqlnet.ora" 71 | owner: "{{ oracle_user }}" 72 | group: "{{ oracle_group }}" 73 | mode: u=rw,g=r,o= 74 | become: true 75 | become_user: "{{ oracle_user }}" 76 | tags: rdbms-setup 77 | -------------------------------------------------------------------------------- /roles/rdbms-setup/tasks/rdbms-rpm-install.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Install Oracle RPM 17 | package: 18 | name: "{{ swlib_path }}/{{ item.name }}" 19 | state: present 20 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 21 | disable_gpg_check: true 22 | with_items: "{{ osw.files }}" 23 | register: rpm_install 24 | tags: rdbms-setup 25 | -------------------------------------------------------------------------------- /roles/rdbms-setup/templates/db_install.rsp.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | {% if oracle_ver == "11.2.0.4.0" or oracle_ver == "12.1.0.2.0" or oracle_ver == "12.2.0.1.0" %} 4 | [[ -r {{ swlib_unzip_path }}/database/response/db_install.rsp ]] || { echo "db_insetall.rsp.sh: cannot read {{ swlib_unzip_path }}/database/response/db_install.rsp"; exit 1; } 5 | cp {{ swlib_unzip_path }}/database/response/db_install.rsp {{ swlib_unzip_path }}/db_install.rsp 6 | {% else %} 7 | [[ -r {{ oracle_home }}/install/response/db_install.rsp ]] || { echo "db_insetall.rsp.sh: cannot read {{ oracle_home }}/install/response/db_install.rsp"; exit 1; } 8 | cp {{ oracle_home }}/install/response/db_install.rsp {{ swlib_unzip_path }}/db_install.rsp 9 | {% endif %} 10 | 11 | sed -i '/^oracle.install.option/ s~oracle.install.option=~oracle.install.option=INSTALL_DB_SWONLY~' {{ swlib_unzip_path }}/db_install.rsp 12 | sed -i '/^oracle.install.db.InstallEdition/ s~oracle.install.db.InstallEdition=~oracle.install.db.InstallEdition='{{ oracle_edition }}'~' {{ swlib_unzip_path }}/db_install.rsp 13 | sed -i '/^ORACLE_HOSTNAME/ s~ORACLE_HOSTNAME=~ORACLE_HOSTNAME=`hostname -A`~' {{ swlib_unzip_path }}/db_install.rsp 14 | sed -i '/^UNIX_GROUP_NAME/ s~UNIX_GROUP_NAME=~UNIX_GROUP_NAME=oinstall~' {{ swlib_unzip_path }}/db_install.rsp 15 | sed -i '/^INVENTORY_LOCATION/ s~INVENTORY_LOCATION=~INVENTORY_LOCATION='{{ oracle_root }}'/oraInventory~' {{ swlib_unzip_path }}/db_install.rsp 16 | sed -i '/^ORACLE_HOME/ s~ORACLE_HOME=~ORACLE_HOME='{{ oracle_home }}'~' {{ swlib_unzip_path }}/db_install.rsp 17 | sed -i '/^ORACLE_BASE/ s~ORACLE_BASE=~ORACLE_BASE='{{ oracle_base }}'~' {{ swlib_unzip_path }}/db_install.rsp 18 | sed -i '/^oracle.install.db.DBA_GROUP/ s~oracle.install.db.DBA_GROUP=~oracle.install.db.DBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 19 | sed -i '/^oracle.install.db.OPER_GROUP/ s~oracle.install.db.OPER_GROUP=~oracle.install.db.OPER_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 20 | sed -i '/^oracle.install.db.BACKUPDBA_GROUP/ s~oracle.install.db.BACKUPDBA_GROUP=~oracle.install.db.BACKUPDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 21 | sed -i '/^oracle.install.db.DGDBA_GROUP/ s~oracle.install.db.DGDBA_GROUP=~oracle.install.db.DGDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 22 | sed -i '/^oracle.install.db.KMDBA_GROUP/ s~oracle.install.db.KMDBA_GROUP=~oracle.install.db.KMDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 23 | sed -i '/^oracle.install.db.OSDBA_GROUP/ s~oracle.install.db.OSDBA_GROUP=~oracle.install.db.OSDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 24 | sed -i '/^oracle.install.db.OSOPER_GROUP/ s~oracle.install.db.OSOPER_GROUP=~oracle.install.db.OSOPER_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 25 | sed -i '/^oracle.install.db.OSBACKUPDBA_GROUP/ s~oracle.install.db.OSBACKUPDBA_GROUP=~oracle.install.db.OSBACKUPDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 26 | sed -i '/^oracle.install.db.OSDGDBA_GROUP/ s~oracle.install.db.OSDGDBA_GROUP=~oracle.install.db.OSDGDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 27 | sed -i '/^oracle.install.db.OSKMDBA_GROUP/ s~oracle.install.db.OSKMDBA_GROUP=~oracle.install.db.OSKMDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 28 | sed -i '/^oracle.install.db.OSRACDBA_GROUP/ s~oracle.install.db.OSRACDBA_GROUP=~oracle.install.db.OSRACDBA_GROUP=dba~' {{ swlib_unzip_path }}/db_install.rsp 29 | sed -i '/^SECURITY_UPDATES_VIA_MYORACLESUPPORT/ s~SECURITY_UPDATES_VIA_MYORACLESUPPORT=~SECURITY_UPDATES_VIA_MYORACLESUPPORT=false~' {{ swlib_unzip_path }}/db_install.rsp 30 | sed -i '/^DECLINE_SECURITY_UPDATES/ s~DECLINE_SECURITY_UPDATES=~DECLINE_SECURITY_UPDATES=TRUE~' {{ swlib_unzip_path }}/db_install.rsp 31 | -------------------------------------------------------------------------------- /roles/rdbms-setup/templates/sqlnet.ora.j2: -------------------------------------------------------------------------------- 1 | NAMES.DIRECTORY_PATH=(TNSNAMES,EZCONNECT) 2 | SQLNET.ENCRYPTION_SERVER=required 3 | {% if oracle_ver == "11.2.0.4.0" %} 4 | SQLNET.ALLOWED_LOGON_VERSION=12 5 | {% else %} 6 | SQLNET.ALLOWED_LOGON_VERSION_SERVER=12a 7 | {% endif %} 8 | -------------------------------------------------------------------------------- /roles/ssh-setup/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Ensure /home/{{ ssh_user }}/.ssh directory exists with correct permissions 17 | become: true 18 | become_user: "{{ ssh_user }}" 19 | file: 20 | path: /home/{{ ssh_user }}/.ssh 21 | state: directory 22 | mode: u=wrx,go= 23 | owner: "{{ ssh_user }}" 24 | group: "{{ user_group }}" 25 | tags: ssh-keys 26 | 27 | - name: Generate PKCS#1 RSA SSH key pair for user '{{ ssh_user }}' on first node 28 | become: true 29 | become_user: "{{ ssh_user }}" 30 | command: ssh-keygen -m PEM -t rsa -b 2048 -f "/home/{{ ssh_user }}/.ssh/id_rsa" -N '' 31 | args: 32 | creates: /home/{{ ssh_user }}/.ssh/id_rsa 33 | tags: ssh-keys 34 | 35 | - name: Read SSH public key for user '{{ ssh_user }}' 36 | become: true 37 | become_user: "{{ ssh_user }}" 38 | command: cat "/home/{{ ssh_user }}/.ssh/id_rsa.pub" 39 | register: user_ssh_pubkey 40 | tags: ssh-keys 41 | 42 | - name: Collect SSH host key 43 | become: true 44 | become_user: "{{ ssh_user }}" 45 | command: ssh-keyscan -tecdsa {{ inventory_hostname }},{{ inventory_hostname }}.{{ ansible_domain }} 46 | register: host_ssh_pubkey 47 | tags: ssh-keys 48 | 49 | - name: Add SSH public host key for user '{{ ssh_user }}' to known_hosts file on all nodes 50 | become: true 51 | become_user: "{{ ssh_user }}" 52 | delegate_to: "{{ item }}" 53 | lineinfile: 54 | name: ~/.ssh/known_hosts 55 | create: true 56 | line: "{{ host_ssh_pubkey.stdout }}" 57 | owner: "{{ ssh_user }}" 58 | group: "{{ user_group }}" 59 | loop: "{{ ssh_nodes }}" 60 | tags: ssh-keys 61 | 62 | - name: Add SSH public key for user '{{ ssh_user }}' to authorized_keys on all nodes 63 | become: true 64 | become_user: root 65 | delegate_to: "{{ item }}" 66 | authorized_key: 67 | key: "{{ user_ssh_pubkey.stdout }}" 68 | user: "{{ ssh_user }}" 69 | loop: "{{ ssh_nodes }}" 70 | tags: ssh-keys 71 | -------------------------------------------------------------------------------- /roles/swlib/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/swlib/tasks/gcloud.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: gcloud | Add Google Cloud SDK repo 17 | yum_repository: 18 | name: google-gcloud-sdk 19 | description: Google gcloud sdk 20 | baseurl: https://packages.cloud.google.com/yum/repos/cloud-sdk-el7-x86_64 21 | gpgkey: 22 | - https://packages.cloud.google.com/yum/doc/yum-key.gpg 23 | - https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg 24 | gpgcheck: true 25 | when: ansible_os_family == "RedHat" 26 | 27 | - name: gcloud | Install latest gcloud SDK package 28 | package: 29 | name: google-cloud-sdk 30 | state: present 31 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 32 | when: ansible_os_family == "RedHat" 33 | -------------------------------------------------------------------------------- /roles/swlib/tasks/gcsfuse.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: gcsfuse | gcloud install 17 | include_tasks: gcloud.yml 18 | 19 | - name: gcsfuse | Install gcsfuse dependencies 20 | become: true 21 | become_user: root 22 | package: 23 | name: fuse 24 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 25 | 26 | - name: gcsfuse | Install gcsfuse 27 | become: true 28 | become_user: root 29 | package: 30 | name: "https://github.com/GoogleCloudPlatform/gcsfuse/releases/download/v{{ gcsfuse_version }}/gcsfuse-{{ gcsfuse_version }}-1.x86_64.rpm" 31 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 32 | 33 | - name: gcsfuse | Copy service account key with owner and permissions 34 | copy: 35 | src: "{{ swlib_gcs_service_account_file }}" 36 | dest: /root/gcp-swlib-credentials.json 37 | owner: root 38 | group: root 39 | mode: a=rwx 40 | when: swlib_gcs_service_account_file != "" 41 | 42 | - name: gcsfuse | Mount gcs-swlib-storage using service_account 43 | mount: 44 | path: "{{ swlib_path }}" 45 | src: "{{ swlib_mount_src }}" 46 | fstype: gcsfuse 47 | opts: ro,user,allow_other,key_file=/root/gcp-swlib-credentials.json 48 | state: mounted 49 | when: swlib_gcs_service_account_file is defined 50 | 51 | - name: gcsfuse | Mount gcs-swlib-storage with instance service_account 52 | mount: 53 | path: "{{ swlib_path }}" 54 | src: "{{ swlib_mount_src }}" 55 | fstype: gcsfuse 56 | opts: ro,user,allow_other 57 | state: mounted 58 | when: swlib_gcs_service_account_file is not defined 59 | -------------------------------------------------------------------------------- /roles/swlib/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: swlib | setup 17 | become: true 18 | become_user: root 19 | block: 20 | - name: swlib | Create swlib folder 21 | file: 22 | path: "{{ swlib_path }}" 23 | state: directory 24 | mode: ug=rwx,o=r 25 | owner: "{{ ansible_ssh_user }}" 26 | group: dba 27 | when: swlib_mount_type != "nfs" 28 | - name: swlib | NFS mount 29 | include_tasks: nfs.yml 30 | when: swlib_mount_type == "nfs" 31 | - name: swlib | gcsfuse mount 32 | include_tasks: gcsfuse.yml 33 | when: swlib_mount_type == "gcsfuse" 34 | 35 | - name: swlib | gcscopy 36 | include_tasks: gcscopy.yml 37 | when: swlib_mount_type == "gcs" 38 | -------------------------------------------------------------------------------- /roles/swlib/tasks/nfs.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: nfs | Install NFS mount utility 17 | become: true 18 | become_user: root 19 | package: 20 | name: nfs-utils 21 | state: present 22 | lock_timeout: "{{ pkg_mgr_lock_timeout }}" 23 | when: ansible_os_family == "RedHat" 24 | 25 | - name: nfs | Ensure rpcbind is running as configured. 26 | service: 27 | name: rpcbind 28 | state: started 29 | enabled: true 30 | when: ansible_os_family == "RedHat" 31 | 32 | - name: nfs | Mount NFS share (swlib) 33 | become: true 34 | become_user: root 35 | mount: 36 | fstype: nfs 37 | name: "{{ swlib_path }}" 38 | opts: "vers=4,_netdev,rsize=8192,wsize=8192,timeo=14,intr,user" 39 | src: "{{ swlib_mount_src }}" 40 | state: mounted 41 | -------------------------------------------------------------------------------- /roles/validation-scripts/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | cluster_scripts: 17 | - asm_disks.sh 18 | - crs_check.sh 19 | - cluvfy_checks.sh 20 | 21 | common_scripts: [] 22 | -------------------------------------------------------------------------------- /roles/validation-scripts/meta/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | dependencies: 17 | - role: common 18 | -------------------------------------------------------------------------------- /roles/validation-scripts/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | --- 16 | - name: Build script list 17 | set_fact: 18 | script_list: "{{ common_scripts + (cluster_scripts if not free_edition else []) }}" 19 | tags: validation-scripts 20 | 21 | - name: Copy validation scripts to server 22 | template: 23 | src: "{{ item }}.j2" 24 | dest: "{{ scripts_dir }}/{{ item }}" 25 | owner: "{{ oracle_user }}" 26 | group: "{{ oracle_group }}" 27 | mode: u=rwx,go= 28 | with_items: 29 | - "{{ script_list }}" 30 | become: true 31 | become_user: "{{ oracle_user }}" 32 | tags: validation-scripts 33 | 34 | # - name: Run validation scripts 35 | # shell: | 36 | # {{ scripts_dir }}/{{ item }} {{ oracle_sid }} 37 | # with_items: 38 | # - "{{ script_list }}" 39 | # register: script_output 40 | # become: true 41 | # become_user: "{{ oracle_user }}" 42 | # tags: validation-scripts,run-validation-scripts 43 | 44 | # - name: Validation script execution results 45 | # debug: 46 | # msg: "{{ script_output.results }}" 47 | # verbosity: 1 48 | # tags: validation-scripts,run-validation-scripts 49 | -------------------------------------------------------------------------------- /roles/validation-scripts/templates/asm_disks.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Reference: "How to map device name to ASMLIB disk (Doc ID 1098682.1)" 5 | # 6 | # Run as oracle or grid software owner - must have kfed in path 7 | # 8 | 9 | export PATH={{ grid_home }}/bin:${PATH} 10 | export ORACLE_HOME={{ grid_home }} 11 | 12 | for device in `ls /dev/sd*` 13 | do 14 | asmdisk=`kfed read ${device} | grep ORCL | tr -s ' ' | cut -f2 -d' ' | cut -c1-4` 15 | asmname=`kfed read ${device} | grep dskname | tr -s ' '| cut -f2 -d' '` 16 | if [ "${asmdisk}" = "ORCL" ]; then 17 | echo "Disk device ${device} may be an ASM disk - Disk name: ${asmname}" 18 | fi 19 | done 20 | -------------------------------------------------------------------------------- /roles/validation-scripts/templates/cluvfy_checks.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | {{ grid_home }}/bin/cluvfy comp ha -verbose 4 | {{ grid_home }}/bin/cluvfy comp sys -p ha -verbose 5 | {{ grid_home }}/bin/cluvfy comp sys -p database -verbose 6 | -------------------------------------------------------------------------------- /roles/validation-scripts/templates/crs_check.sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo -e "\n\n***** CRS STATUS *****\n" 4 | {{ grid_home }}/bin/crsctl query has releaseversion 5 | {{ grid_home }}/bin/crsctl query has softwareversion 6 | {{ grid_home }}/bin/crsctl check has 7 | {{ grid_home }}/bin/crsctl check css 8 | echo -e "\n" 9 | {{ grid_home }}/bin/crsctl stat resource 10 | {{ grid_home }}/bin/crsctl stat res -t 11 | echo -e "\n\n\n\n***** SERVICE CONFIG *****\n" 12 | {{ grid_home }}/bin/srvctl config ASM ; echo -e "\n" 13 | {{ grid_home }}/bin/srvctl config LISTENER ; echo -e "\n" 14 | {{ grid_home }}/bin/srvctl config database -d {{ oracle_sid }} ; echo -e "\n" 15 | -------------------------------------------------------------------------------- /terraform/README.md: -------------------------------------------------------------------------------- 1 | # Terraform 2 | 3 | See https://google.github.io/oracle-toolkit/terraform.html for documentation and example usage of Terraform to provision Oracle Database on Google Cloud. 4 | -------------------------------------------------------------------------------- /terraform/backend.tf.example: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | terraform { 16 | required_version = ">= 1.10.5" 17 | 18 | required_providers { 19 | google = { 20 | source = "hashicorp/google" 21 | version = "~> 6.20.0" 22 | } 23 | } 24 | 25 | backend "gcs" { 26 | bucket = "BUCKET" # example my-state-bucket 27 | prefix = "PREFIX" # example dev 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /terraform/modules/oracle_toolkit_module/scripts/setup.sh.tpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -Eeuo pipefail 4 | 5 | control_node_name="$(curl -s http://metadata.google.internal/computeMetadata/v1/instance/name -H 'Metadata-Flavor: Google')" 6 | # The zone value from the metadata server is in the format 'projects/PROJECT_NUMBER/zones/ZONE'. 7 | # extracting the last part 8 | control_node_zone_full="$(curl -s http://metadata.google.internal/computeMetadata/v1/instance/zone -H 'Metadata-Flavor: Google')" 9 | control_node_zone="$(basename "$control_node_zone_full")" 10 | control_node_project_id="$(curl -s http://metadata.google.internal/computeMetadata/v1/project/project-id -H 'Metadata-Flavor: Google')" 11 | 12 | cleanup() { 13 | echo "Deleting '$control_node_name' GCE instance in zone '$control_node_zone' in project '$control_node_project_id'..." 14 | gcloud --quiet compute instances delete "$control_node_name" --zone="$control_node_zone" --project="$control_node_project_id" 15 | } 16 | 17 | trap cleanup EXIT 18 | 19 | DEST_DIR="/oracle-toolkit" 20 | 21 | apt-get update 22 | apt-get install -y ansible python3-jmespath unzip 23 | 24 | echo "Triggering SSH key creation via OS Login by running a one-time gcloud compute ssh command." 25 | echo "This ensures that a persistent SSH key pair is created and associated with your Google Account." 26 | echo "The private auto-generated ssh key (~/.ssh/google_compute_engine) will be used by Ansible to connect to the VM and run playbooks remotely." 27 | echo "Command:" 28 | echo "gcloud compute ssh '${instance_name}' --zone='${instance_zone}' --internal-ip --quiet --command whoami" 29 | 30 | timeout 2m bash -c 'until gcloud compute ssh "${instance_name}" --zone="${instance_zone}" --internal-ip --quiet --command whoami; do 31 | echo "Waiting for SSH to become available on '${instance_name}'..." 32 | sleep 5 33 | done' || { 34 | echo "ERROR: Timed out waiting for SSH" 35 | exit 1 36 | } 37 | 38 | control_node_sa="$(curl -s http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email -H 'Metadata-Flavor: Google')" 39 | echo "Downloading '${gcs_source}' to /tmp" 40 | if ! gsutil cp "${gcs_source}" /tmp/; then 41 | echo "ERROR: Failed to download '${gcs_source}'. Make sure the file exists and that the service account '$control_node_sa' has 'roles/storage.objectViewer' role on the bucket." 42 | exit 1 43 | fi 44 | zip_file="$(basename "${gcs_source}")" 45 | mkdir -p "$DEST_DIR" 46 | echo "Extracting files from '$zip_file' to '$DEST_DIR'" 47 | unzip -o "/tmp/$zip_file" -d "$DEST_DIR" 48 | 49 | ssh_user="$(gcloud compute os-login describe-profile --format='value(posixAccounts[0].username)')" 50 | if [[ -z "$ssh_user" ]]; then 51 | echo "ERROR: Failed to extract the POSIX username. This may be due to OS Login not being enabled or missing IAM permissions." 52 | exit 1 53 | fi 54 | 55 | cd "$DEST_DIR" 56 | 57 | bash install-oracle.sh \ 58 | --instance-ssh-user "$ssh_user" \ 59 | --instance-ssh-key /root/.ssh/google_compute_engine \ 60 | %{ if ip_addr != "" }--instance-ip-addr "${ip_addr}" %{ endif } \ 61 | %{ if asm_disk_config != "" }--ora-asm-disks-json '${asm_disk_config}' %{ endif } \ 62 | %{ if data_mounts_config != "" }--ora-data-mounts-json '${data_mounts_config}' %{ endif } \ 63 | %{ if swap_blk_device != "" }--swap-blk-device "${swap_blk_device}" %{ endif } \ 64 | %{ if ora_swlib_bucket != "" }--ora-swlib-bucket "${ora_swlib_bucket}" %{ endif } \ 65 | %{ if ora_version != "" }--ora-version "${ora_version}" %{ endif } \ 66 | %{ if ora_backup_dest != "" }--backup-dest "${ora_backup_dest}" %{ endif } \ 67 | %{ if ora_db_name != "" }--ora-db-name "${ora_db_name}" %{ endif } \ 68 | %{ if ora_db_container != "" }--ora-db-container "${ora_db_container}" %{ endif } \ 69 | %{ if ntp_pref != "" }--ntp-pref "${ntp_pref}" %{ endif } \ 70 | %{ if oracle_release != "" }--oracle-release "${oracle_release}" %{ endif } \ 71 | %{ if ora_edition != "" }--ora-edition "${ora_edition}" %{ endif } \ 72 | %{ if ora_listener_port != "" }--ora-listener-port "${ora_listener_port}" %{ endif } \ 73 | %{ if ora_redo_log_size != "" }--ora-redo-log-size "${ora_redo_log_size}" %{ endif } 74 | -------------------------------------------------------------------------------- /terraform/modules/oracle_toolkit_module/versions.tf: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | terraform { 16 | required_version = ">= 1.5.7" 17 | required_providers { 18 | google = { 19 | source = "hashicorp/google" 20 | version = "~> 6.20.0" 21 | } 22 | random = { 23 | source = "hashicorp/random" 24 | version = "~> 3.7.2" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # oracle-toolkit tools 2 | 3 | The `tools/` folder is intended for helpful tools and scripts that aren't 4 | part of the main oracle-toolkit codebase. 5 | 6 | ## gen_patch_metadata 7 | 8 | `gen_patch_metadata` retrieves patches from My Oracle Support, parses our 9 | version and hash information, and prepares `rdbms_patches` and `gi_patches` 10 | structures for `roles/common/defaults/main.yml`. 11 | 12 | ### Sample usage 13 | 14 | ``` 15 | $ python3 gen_patch_metadata.py --patch 33567274 --mosuser user@example.com 16 | MOS Password: 17 | INFO:root:Downloading https://updates.oracle.com/Orion/Download/process_form/p33567274_190000_Linux-x86-64.zip?file_id=113789887&aru=24594397&userid=O-mfielding@google.com&email=user@example.com&patch_password=&patch_file=p33567274_190000_Linux-x86-64.zip 18 | INFO:root:Abstract: COMBO OF OJVM RU COMPONENT 19.14.0.0.220118 + GI RU 19.14.0.0.220118 19 | INFO:root:Found release = 19.14.0.0.220118 base = 19.3.0.0.0 GI subdir = 33509923 OJVM subdir = 33561310 20 | INFO:root:Downloading OPatch 21 | INFO:root:Downloading https://updates.oracle.com/Orion/Download/process_form/p6880880_190000_Linux-x86-64.zip?aru=24740828&file_id=112014090&patch_file=p6880880_190000_Linux-x86-64.zip& 22 | Please copy the following files to your GCS bucket: p33567274_190000_Linux-x86-64.zip p6880880_190000_Linux-x86-64.zip 23 | Add the following to the appropriate sections of roles/common/defaults/main.yml: 24 | 25 | gi_patches: 26 | - { category: "RU", base: "19.3.0.0.0", release: "19.14.0.0.220118", patchnum: "33567274", patchfile: "p33567274_190000_Linux-x86-64.zip", patch_subdir: "/33509923", prereq_check: FALSE, method: "opatchauto apply", ocm: FALSE, upgrade: FALSE, md5sum: "JgJsqbGaGcxEPEP6j79BPQ==" } 27 | 28 | rdbms_patches: 29 | - { category: "RU_Combo", base: "19.3.0.0.0", release: "19.14.0.0.220118", patchnum: "33567274", patchfile: "p33567274_190000_Linux-x86-64.zip", patch_subdir: "/33561310", prereq_check: TRUE, method: "opatch apply", ocm: FALSE, upgrade: TRUE, md5sum: "JgJsqbGaGcxEPEP6j79BPQ==" } 30 | ``` 31 | 32 | ### Known issues 33 | 34 | - Only tested against 12.2, 18c, and 19c patches. 35 | - No support for multi-file patches. 36 | --------------------------------------------------------------------------------