├── .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 | 
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 |
--------------------------------------------------------------------------------