├── ansible ├── roles │ ├── ordsserver │ │ ├── tasks │ │ │ ├── config_apex.yaml │ │ │ ├── main.yml │ │ │ ├── templates │ │ │ │ ├── ordsserver_bootstrap.j2 │ │ │ │ ├── egress_security_rules.yaml.j2 │ │ │ │ └── ingress_security_rules.yaml.j2 │ │ │ ├── config_ords.yaml │ │ │ ├── create_ords_subnet.yaml │ │ │ ├── create_ords_security_list.yaml │ │ │ ├── create_ords_servers.yaml │ │ │ └── check_ords_servers.yaml │ │ ├── files │ │ │ └── jetty │ │ │ │ ├── apex_inst_check.sql │ │ │ │ ├── pw_verify_null.sql │ │ │ │ ├── ords_pu_check.sql │ │ │ │ ├── pw_verify_base.sql │ │ │ │ ├── pw_prof_chk.sql │ │ │ │ ├── config_apex1.sql │ │ │ │ ├── config_apex2.sql │ │ │ │ ├── stop_ords.sh │ │ │ │ ├── config_jetty_init.sh │ │ │ │ ├── ords_validate_base.exp │ │ │ │ ├── start_ords.sh │ │ │ │ ├── config_jetty_ca-ssl.sh │ │ │ │ ├── config_cert.sh │ │ │ │ ├── apex_setup_base.exp │ │ │ │ ├── config_jetty_ords.sh │ │ │ │ ├── ords_setup_base.exp │ │ │ │ ├── dns_ocidns.sh │ │ │ │ ├── ords_add_db.sh │ │ │ │ ├── config_jetty_apex.sh │ │ │ │ └── apex_add_db.sh │ │ └── vars │ │ │ └── main.yml │ ├── oradb │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── templates │ │ │ │ ├── egress_security_list_ad1.yaml.j2 │ │ │ │ └── ingress_security_list_ad1.yaml.j2 │ │ │ ├── create_db_subnet.yaml │ │ │ ├── create_db_security_lists.yaml │ │ │ └── launch_instance_oradb.yaml │ │ └── vars │ │ │ └── main.yml │ ├── bastion │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── templates │ │ │ │ ├── bastion_ingress_security_rules.yaml.j2 │ │ │ │ └── bastion_egress_security_rules.yaml.j2 │ │ │ ├── create_subnet.yaml │ │ │ ├── get_bastion_details.yaml │ │ │ ├── create_server.yaml │ │ │ └── create_security_list.yaml │ │ └── vars │ │ │ └── main.yml │ ├── load_balancer │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── templates │ │ │ │ ├── lb_ingress_security_rules.yaml.j2 │ │ │ │ └── lb_egress_security_rules.yaml.j2 │ │ │ ├── create_lb_subnet.yaml │ │ │ ├── create_security_list.yaml │ │ │ ├── create_certificate.yaml │ │ │ └── create_loadbalancers.yaml │ │ └── vars │ │ │ └── main.yml │ └── common │ │ ├── vars │ │ └── main.yml │ │ └── tasks │ │ ├── create_ssh_key.yaml │ │ └── main.yml ├── Diagram.jpeg ├── sample.yaml ├── host_vars │ └── localhost └── README.md ├── terraform ├── outputs.tf ├── variables.tf ├── provider.tf ├── apex.tf ├── schema.yaml └── README.md ├── .gitignore ├── README.md └── LICENSE /ansible/roles/ordsserver/tasks/config_apex.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible/Diagram.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-quickstart/oci-apex/HEAD/ansible/Diagram.jpeg -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/apex_inst_check.sql: -------------------------------------------------------------------------------- 1 | set head off 2 | select status from dba_registry where comp_id = 'APEX'; 3 | exit 4 | -------------------------------------------------------------------------------- /terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | 2 | output "apex_url" { 3 | value = oci_database_autonomous_database.apex_instance.connection_urls[0].apex_url 4 | } -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/pw_verify_null.sql: -------------------------------------------------------------------------------- 1 | set head off feed off 2 | alter profile default limit password_verify_function null; 3 | exit 4 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/ords_pu_check.sql: -------------------------------------------------------------------------------- 1 | set head off feed off 2 | select count(*) from dba_users where username='ORDS_PUBLIC_USER'; 3 | exit 4 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/pw_verify_base.sql: -------------------------------------------------------------------------------- 1 | set head off feed off 2 | alter profile default limit password_verify_function ToBeUpdated_PW_VERIFY_FUNC; 3 | exit 4 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - import_tasks: create_db_security_lists.yaml 4 | - import_tasks: create_db_subnet.yaml 5 | - import_tasks: launch_instance_oradb.yaml 6 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/pw_prof_chk.sql: -------------------------------------------------------------------------------- 1 | set head off feed off 2 | select limit from dba_profiles where profile='DEFAULT' and resource_name='PASSWORD_VERIFY_FUNCTION'; 3 | exit 4 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - debug: msg="Inside bastion role" 4 | - import_tasks: create_security_list.yaml 5 | - import_tasks: create_subnet.yaml 6 | - import_tasks: get_bastion_details.yaml 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # .tfvars files 9 | *.tfvars 10 | .DS_Store 11 | terraform/.terraform.lock.hcl 12 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - debug: msg="Inside ordsserver role" 4 | 5 | - import_tasks: create_ords_security_list.yaml 6 | - import_tasks: create_ords_subnet.yaml 7 | - import_tasks: check_ords_servers.yaml 8 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - debug: msg="Inside lb role" 4 | - import_tasks: create_security_list.yaml 5 | - import_tasks: create_lb_subnet.yaml 6 | - import_tasks: create_certificate.yaml 7 | - import_tasks: create_loadbalancers.yaml 8 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "tenancy_ocid" {} 2 | variable "region" {} 3 | 4 | variable "fingerprint" {} 5 | variable "private_key_path" {} 6 | variable "user_ocid" {} 7 | 8 | variable "compartment_ocid" {} 9 | 10 | 11 | variable "autonomous_database_admin_password" { 12 | description = "Password for Apex Admin user." 13 | } 14 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/templates/bastion_ingress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # ingress rule for SSH 3 | bastion_ingress_security_rules: 4 | - source: "{{ quad_zero_route }}" 5 | protocol: "{{ TCP_protocol }}" 6 | tcp_options: 7 | destination_port_range: 8 | min: {{ SSH_port }} 9 | max: {{ SSH_port }} 10 | 11 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/templates/lb_ingress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # in this example we only allow https 3 | lb_ingress_security_rules: 4 | - source: "{{ quad_zero_route }}" 5 | protocol: "{{ TCP_protocol }}" 6 | tcp_options: 7 | destination_port_range: 8 | min: {{ HTTPS_port }} 9 | max: {{ HTTPS_port }} 10 | 11 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_apex1.sql: -------------------------------------------------------------------------------- 1 | set ver off 2 | alter user apex_public_user identified by "&1" account unlock; 3 | begin 4 | apex_util.set_security_group_id( 10 ); 5 | apex_util.create_user( 6 | p_user_name => 'ADMIN', 7 | p_email_address => 'change@later', 8 | p_web_password => '&1', 9 | p_developer_privs => 'ADMIN' ); 10 | apex_util.set_security_group_id( null ); 11 | commit; 12 | end; 13 | / 14 | exit 15 | -------------------------------------------------------------------------------- /terraform/provider.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_providers { 4 | 5 | oci = { 6 | source = "hashicorp/oci" 7 | } 8 | random = { 9 | source = "hashicorp/random" 10 | } 11 | 12 | } 13 | required_version = ">= 0.14" 14 | } 15 | 16 | provider "oci" { 17 | tenancy_ocid = var.tenancy_ocid 18 | region = var.region 19 | user_ocid = var.user_ocid 20 | fingerprint = var.fingerprint 21 | private_key_path = var.private_key_path 22 | } 23 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/templates/egress_security_list_ad1.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | ad1_egress_security_rules: 3 | - destination: "{{ quad_zero_route }}" 4 | protocol: "{{ TCP_protocol }}" 5 | tcp_options: 6 | destination_port_range: 7 | min: {{ HTTP_port }} 8 | max: {{ HTTP_port }} 9 | - destination: "{{ quad_zero_route }}" 10 | protocol: "{{ TCP_protocol }}" 11 | tcp_options: 12 | destination_port_range: 13 | min: {{ HTTPS_port }} 14 | max: {{ HTTPS_port }} -------------------------------------------------------------------------------- /terraform/apex.tf: -------------------------------------------------------------------------------- 1 | resource "oci_database_autonomous_database" "apex_instance" { 2 | compartment_id = var.compartment_ocid 3 | cpu_core_count = 1 4 | db_name = "apex${random_string.deploy_id.result}" 5 | data_storage_size_in_tbs = 1 6 | license_model = "LICENSE_INCLUDED" 7 | admin_password = var.autonomous_database_admin_password 8 | 9 | db_workload = "APEX" 10 | 11 | } 12 | 13 | resource "random_string" "deploy_id" { 14 | length = 4 15 | special = false 16 | } 17 | -------------------------------------------------------------------------------- /ansible/roles/bastion/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | bastion_image_ocid: "{{ demo_ol_image_ocid }}" 4 | bastion_shape: "VM.Standard2.1" 5 | bastion_availability_domain: "{{ demo_ad1_name }}" 6 | 7 | demo_bastion_subnet_name: "bastion_subnet" 8 | # no special chars, 1-15 chars only, start with alpha 9 | demo_bastion_subnet_dns_label: "bastion" 10 | 11 | demo_bastion_instance_name: "bastion_instance" 12 | # no underscores in host names 13 | demo_bastion_host_name: "bastion-host" 14 | 15 | demo_bastion_subnet_security_list_name: "bastion_subnet_sec_list" 16 | -------------------------------------------------------------------------------- /ansible/roles/oradb/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | availability_domain: "{{ demo_ad1_name }}" 4 | cluster_name: "{{ demo_db_cluster_name }}" 5 | db_edition: "STANDARD_EDITION" 6 | password: "{{ demo_db_password }}" 7 | db_name: "{{ demo_db_name }}" 8 | db_pdb_name: "{{ demo_db_pdb_name }}" 9 | db_version: "19.0.0.0" 10 | 11 | shape: "{{ demo_db_shape }}" 12 | 13 | db_subnet_id: "{{ db_subnet_id }}" 14 | db_subnet_name: "oradb_subnet" 15 | 16 | cidr_block_db: "{{ demo_db_subnet_cidr }}" 17 | 18 | db_sec_list_id: "{{ db_sec_list_id }}" 19 | db_subnet_sec_list_name: "db_sec_list" 20 | 21 | dns_label_db: 'dbad1' -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_apex2.sql: -------------------------------------------------------------------------------- 1 | declare 2 | l_acl_path varchar2(4000); 3 | l_apex_schema varchar2(100); 4 | begin 5 | for c1 in (select schema 6 | from sys.dba_registry 7 | where comp_id = 'APEX') loop 8 | l_apex_schema := c1.schema; 9 | end loop; 10 | sys.dbms_network_acl_admin.append_host_ace( 11 | host => '*', 12 | ace => xs$ace_type(privilege_list => xs$name_list('connect'), 13 | principal_name => l_apex_schema, 14 | principal_type => xs_acl.ptype_db)); 15 | commit; 16 | end; 17 | / 18 | exit 19 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/templates/lb_egress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # Loadbalancers are only allowed to have connection to the ords subnets 3 | 4 | lb_egress_security_rules: 5 | - destination: "{{ demo_ords_subnet_ad1_cidr }}" 6 | protocol: "{{ TCP_protocol }}" 7 | tcp_options: 8 | destination_port_range: 9 | min: {{ ORDS_port }} 10 | max: {{ ORDS_port }} 11 | - destination: "{{ demo_ords_subnet_ad2_cidr }}" 12 | protocol: "{{ TCP_protocol }}" 13 | tcp_options: 14 | destination_port_range: 15 | min: {{ ORDS_port }} 16 | max: {{ ORDS_port }} 17 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | demo_ordsserver_ad1: "{{ demo_ad1_name }}" 4 | demo_ordsserver_ad2: "{{ demo_ad2_name }}" 5 | demo_ordsserver_name: "ords" 6 | demo_ordsserver_name_1: "{{ demo_ordsserver_name }}1" 7 | demo_ordsserver_name_2: "{{ demo_ordsserver_name }}2" 8 | # no underscores in host names 9 | demo_ordsserver_host_name: "ordsserver" 10 | demo_ordsserver_host_name_1: "{{demo_ordsserver_host_name}}1" 11 | demo_ordsserver_host_name_2: "{{demo_ordsserver_host_name}}2" 12 | demo_ords_subnet_ad1_name: "ordsad1" 13 | demo_ords_subnet_ad2_name: "ordsad2" 14 | demo_ords_subnet_security_list_name: "ordsSL" 15 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/templates/ordsserver_bootstrap.j2: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | package_update: true 3 | 4 | runcmd: 5 | - yum -y install wget java git expect nkf screen 6 | - yum-config-manager --enable ol7_oci_included 7 | - yum install -y oracle-instantclient18.3-basic 8 | - yum install -y oracle-instantclient18.3-sqlplus 9 | - echo "export JAVA_HOME=$(readlink -e $(which java)|sed 's:/bin/java::')" > /etc/profile.d/java.sh 10 | - echo "PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile.d/java.sh 11 | - firewall-offline-cmd --zone=public --add-port="{{ ORDS_port }}"/tcp 12 | - systemctl restart firewalld -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/create_subnet.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create a bastion subnet 4 | oci_subnet: 5 | availability_domain: "{{ bastion_availability_domain }}" 6 | cidr_block: "{{ bastion_subnet_cidr_block }}" 7 | compartment_id: "{{ demo_compartment_ocid }}" 8 | display_name: "{{ demo_bastion_subnet_name }}" 9 | prohibit_public_ip_on_vnic: false 10 | security_list_ids: [ "{{ bastion_security_list_ocid }}" ] 11 | vcn_id: '{{ demo_vcn_ocid }}' 12 | dns_label: "{{ demo_bastion_subnet_dns_label }}" 13 | route_table_id: "{{ demo_core_rt_ig_ocid }}" 14 | register: result 15 | 16 | - set_fact: 17 | bastion_subnet_ocid: "{{ result.subnet.id }}" 18 | -------------------------------------------------------------------------------- /ansible/roles/common/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | demo_vcn_name: "{{ demo_var_prefix }}_vcn" 4 | # no special chars, 1-15 chars only, start with alpha 5 | demo_vcn_dns_label: "demo{{ random_suffix }}vcn" 6 | 7 | demo_ig_display_name: "{{ demo_var_prefix }}_ig" 8 | demo_nat_display_name: "{{ demo_var_prefix }}_nat" 9 | demo_core_route_table_name: "{{ demo_var_prefix }}_route_table" 10 | # route all access to our Internet Gateway 11 | demo_core_ig_route_table_rules: 12 | - cidr_block: "{{ quad_zero_route }}" 13 | network_entity_id: "{{ demo_ig_ocid }}" 14 | demo_core_nat_route_table_rules: 15 | - cidr_block: "{{ quad_zero_route }}" 16 | network_entity_id: "{{ demo_nat_ocid }}" 17 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/create_db_subnet.yaml: -------------------------------------------------------------------------------- 1 | 2 | #Task for creating private subnet for ad1 3 | 4 | - name: Create private subnet for Oracle database 5 | oci_subnet: 6 | display_name: '{{ db_subnet_name }}' 7 | availability_domain: "{{ availability_domain }}" 8 | cidr_block: "{{ cidr_block_db }}" 9 | compartment_id: "{{ demo_compartment_ocid }}" 10 | prohibit_public_ip_on_vnic: true 11 | vcn_id: "{{ demo_vcn_ocid }}" 12 | dns_label: "{{ dns_label_db }}" 13 | security_list_ids: ["{{ db_sec_list_id }}"] 14 | route_table_id: "{{ demo_core_rt_nat_ocid }}" 15 | register: result 16 | 17 | - set_fact: 18 | db_subnet_id: "{{ result.subnet.id }}" 19 | db_subnet_dns_label: "{{ result.subnet.dns_label }}" 20 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/templates/ingress_security_list_ad1.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | ad1_ingress_security_rules: 3 | - source: "{{ demo_ords_subnet_ad1_cidr }}" 4 | protocol: "{{ TCP_protocol }}" 5 | tcp_options: 6 | destination_port_range: 7 | min: {{ DB_port }} 8 | max: {{ DB_port }} 9 | - source: "{{ demo_ords_subnet_ad2_cidr }}" 10 | protocol: "{{ TCP_protocol }}" 11 | tcp_options: 12 | destination_port_range: 13 | min: {{ DB_port }} 14 | max: {{ DB_port }} 15 | - source: "{{ bastion_subnet_cidr_block }}" 16 | protocol: "{{ TCP_protocol }}" 17 | tcp_options: 18 | destination_port_range: 19 | min: {{ SSH_port }} 20 | max: {{ SSH_port }} 21 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/stop_ords.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | chk=`ps -ef | grep ords.war | grep -v grep | wc -l` 4 | if [ "${chk}" = "0" ]; then 5 | echo "ORDS is not running. Exsiting." 6 | exit 7 | elif [ "${chk}" = "1" ]; then 8 | pid=`ps -ef | grep ords.war | grep -v grep | awk '{print $2}'` 9 | echo "Stopping ORDS(pid=${pid}) ..." 10 | else 11 | echo "Looks several ORDS processes are running. Need to check them." 12 | ps -ef | grep ords.war | grep -v grep 13 | fi 14 | 15 | kill `ps -ef | grep ords.war | grep -v grep | awk '{print $2}'` 16 | sleep 2 17 | chk=`ps -ef | grep ords.war | grep -v grep | wc -l` 18 | if [ "${chk}" = "0" ]; then 19 | echo "Stopped successfully." 20 | else 21 | echo "Need to check ORDS process" 22 | fi 23 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/get_bastion_details.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: get bastion ID 4 | oci_instance_facts: 5 | availability_domain: "{{ bastion_availability_domain }}" 6 | compartment_id: "{{ demo_compartment_ocid }}" 7 | display_name: "{{ demo_bastion_instance_name }}" 8 | lifecycle_state: 'RUNNING' 9 | register: bastion 10 | 11 | - name: Include task list to create bastion server 12 | include_tasks: "create_server.yaml" 13 | when: bastion.instances|length==0 14 | 15 | - set_fact: 16 | ssh_extra_args: "-o StrictHostKeyChecking=no -i {{ demo_ssh_private_key }} -o ProxyCommand='ssh -o StrictHostKeyChecking=no -i {{ demo_ssh_private_key }} -W %h:%p -q opc@{{ bastion.instances[0].primary_public_ip }}'" 17 | when: bastion.instance|length==1 18 | -------------------------------------------------------------------------------- /ansible/sample.yaml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | --- 3 | # Original adapted from OCI ansible sample (secure-mongodb-deployment) 4 | # This will deploy a public load balancer ORDS using jetty and apex into the db 5 | 6 | # master playbook for the demo to setup the whole demo infrastrcture 7 | - name: Deploy demo infrastructure 8 | hosts: localhost 9 | connection: local 10 | roles: 11 | - { role: roles/common } 12 | - { role: roles/bastion } 13 | - { role: roles/oradb } 14 | - { role: roles/ordsserver } 15 | - { role: roles/load_balancer } 16 | tasks: 17 | - debug: 18 | msg: "The ordsserver is available at http://{{ public_load_balancer_ip_addresses[0].ip_address }}:80 and https://{{ public_load_balancer_ip_addresses[0].ip_address }}:443" 19 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/templates/bastion_egress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # egress rule to allow SSH connection to the database subnet and the ords subnet 3 | bastion_egress_security_rules: 4 | - destination: "{{ demo_ords_subnet_ad1_cidr }}" 5 | protocol: "{{ TCP_protocol }}" 6 | tcp_options: 7 | destination_port_range: 8 | min: {{ SSH_port }} 9 | max: {{ SSH_port }} 10 | - destination: "{{ demo_ords_subnet_ad2_cidr }}" 11 | protocol: "{{ TCP_protocol }}" 12 | tcp_options: 13 | destination_port_range: 14 | min: {{ SSH_port }} 15 | max: {{ SSH_port }} 16 | - destination: "{{ demo_db_subnet_cidr }}" 17 | protocol: "{{ TCP_protocol }}" 18 | tcp_options: 19 | destination_port_range: 20 | min: {{ SSH_port }} 21 | max: {{ SSH_port }} -------------------------------------------------------------------------------- /ansible/roles/load_balancer/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | availability_domain_1: "{{ demo_ad1_name }}" 4 | availability_domain_2: "{{ demo_ad2_name }}" 5 | 6 | lb_dns_label_ad1: 'lbdnsad1' 7 | lb_dns_label_ad2: 'lbdnsad2' 8 | 9 | lb_subnet_ad1: 'lb_subnet_ad1' 10 | lb_subnet_ad2: 'lb_subnet_ad2' 11 | demo_lb_security_list_name: "lb_subnet_sec_list" 12 | 13 | lb_name: "load_balancer" 14 | sample_shape: "100Mbps" 15 | sample_backend_set_name: 'sample_backend_set' 16 | sample_backend_set_policy: 'ROUND_ROBIN' 17 | 18 | # Initialize values for listeners 19 | https_listener_name: 'https_listener1' 20 | https_port: 443 21 | 22 | # Initialize values for certificates 23 | sample_ca_certificate: "{{cert_path}}/ca_cert.pem" 24 | sample_private_key: "{{cert_path}}/private_key.pem" 25 | sample_public_certificate: "{{cert_path}}/cert.pem" 26 | sample_certificate_name: "sample_certs" -------------------------------------------------------------------------------- /ansible/roles/common/tasks/create_ssh_key.yaml: -------------------------------------------------------------------------------- 1 | - name: Create a temporary directory to house a temporary SSH keypair to connect to bastion instance 2 | tempfile: 3 | state: directory 4 | suffix: cert 5 | register: result 6 | 7 | - set_fact: 8 | temp_certificates_path: "{{ result.path }}" 9 | 10 | - name: Generate a Private Key 11 | openssl_privatekey: 12 | path: "{{ temp_certificates_path }}/private_key.pem" 13 | type: RSA 14 | size: 2048 15 | 16 | - set_fact: 17 | demo_ssh_public_key: "{{ temp_certificates_path }}/public_key.pem" 18 | 19 | - name: Generate a Public Key 20 | openssl_publickey: 21 | path: "{{ demo_ssh_public_key }}" 22 | privatekey_path: "{{ temp_certificates_path }}/private_key.pem" 23 | format: OpenSSH 24 | 25 | - debug: 26 | msg: "Using generated keys at {{ temp_certificates_path }} to launch instances." 27 | 28 | - set_fact: 29 | demo_ssh_private_key: "{{ temp_certificates_path }}/private_key.pem" 30 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_jetty_init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 1 argument 4 | # Arg1 : port for access to ORDS 5 | 6 | ### Port for ORDS on Compute Instance 7 | ComPort=$1 8 | 9 | ### Debug 10 | #echo $ComPort 11 | 12 | ### Install and setup Jetty 13 | # Add User oracle by installing pre-install package 14 | yum install -y oracle-database-preinstall-18c 15 | mkdir /home/oracle/.ssh 16 | cp -f /home/opc/.ssh/authorized_keys /home/oracle/.ssh/ 17 | chown -R oracle:oinstall /home/oracle/.ssh 18 | 19 | # Environment Variable Setting 20 | cat <> /home/oracle/.bash_profile 21 | export LD_LIBRARY_PATH=/usr/lib/oracle/18.3/client64/lib:\$LD_LIBRARY_PATH 22 | export PATH=/usr/lib/oracle/18.3/client64/bin:\$PATH 23 | EOF 24 | 25 | # Copy files to tomcat home directory 26 | mv files_jetty.zip /home/oracle/ 27 | chown oracle:oinstall /home/oracle/files_jetty.zip 28 | 29 | # Open port 30 | firewall-cmd --zone=public --add-port=${ComPort}/tcp --permanent 31 | firewall-cmd --reload 32 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/ords_validate_base.exp: -------------------------------------------------------------------------------- 1 | #!/bin/expect 2 | 3 | set PW "ToBeUpdated_DBAdmPwd" 4 | set DBHOST "ToBeUpdated_DBSystemIP" 5 | set SRVNAME "ToBeUpdated_DBSrv" 6 | set Prompt "\[#$%>\]" 7 | set timeout 60 8 | 9 | spawn env LANG=C java -jar ords.war validate 10 | 11 | expect { 12 | -re "Enter the name of the database server \\\[.*\\\]:" { 13 | send -- "${DBHOST}\n" 14 | } 15 | } 16 | 17 | expect { 18 | -glob "Enter the database listen port \\\[1521\\\]:" { 19 | send -- "\n" 20 | } 21 | } 22 | 23 | expect { 24 | -re "Enter the database service name \\\[.*\\\]:" { 25 | send -- "${SRVNAME}\n" 26 | } 27 | "Enter the database service name:" { 28 | send -- "${SRVNAME}\n" 29 | } 30 | } 31 | 32 | expect { 33 | -glob "Enter the database password for SYS AS SYSDBA:" { 34 | send -- "${PW}\n" 35 | exp_continue 36 | } 37 | -glob "Confirm password:" { 38 | send -- "${PW}\n" 39 | } 40 | } 41 | 42 | expect { 43 | -glob "${Prompt}" { 44 | interact 45 | exit 0 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/create_lb_subnet.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create a subnet in AD1 4 | oci_subnet: 5 | availability_domain: "{{ availability_domain_1 }}" 6 | name: '{{ lb_subnet_ad1 }}' 7 | dns_label: '{{ lb_dns_label_ad1 }}' 8 | route_table_id: '{{ demo_core_rt_ig_ocid }}' 9 | security_list_ids: ['{{ lb_security_list_ocid }}'] 10 | cidr_block: "{{ demo_lb_subnet_ad1_cidr }}" 11 | compartment_id: "{{ demo_compartment_ocid }}" 12 | vcn_id: '{{ demo_vcn_ocid }}' 13 | register: result 14 | 15 | - set_fact: 16 | sample_subnet_id_ad1: "{{ result.subnet.id }}" 17 | 18 | - name: Create a subnet in AD2 19 | oci_subnet: 20 | availability_domain: "{{ availability_domain_2 }}" 21 | name: '{{ lb_subnet_ad2 }}' 22 | dns_label: '{{ lb_dns_label_ad2 }}' 23 | route_table_id: '{{ demo_core_rt_ig_ocid }}' 24 | security_list_ids: ['{{ lb_security_list_ocid }}'] 25 | cidr_block: "{{ demo_lb_subnet_ad2_cidr }}" 26 | compartment_id: "{{ demo_compartment_ocid }}" 27 | vcn_id: '{{ demo_vcn_ocid }}' 28 | register: result 29 | 30 | - set_fact: 31 | sample_subnet_id_ad2: "{{ result.subnet.id }}" 32 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/templates/egress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright (c) 2018, 2019 Oracle and/or its affiliates. 3 | # This software is made available to you under the terms of the GPL 3.0 license or the Apache 2.0 license. 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | # Apache License v2.0 6 | # See LICENSE.TXT for details. 7 | egress_security_rules: 8 | # Allow outbound Oracle connections 9 | - destination: "{{ demo_db_subnet_cidr }}" 10 | protocol: "{{ TCP_protocol }}" 11 | tcp_options: 12 | destination_port_range: 13 | min: {{ DB_port }} 14 | max: {{ DB_port }} 15 | # Allow access to HTTP(S) for cloud-init (yum, pip to work) 16 | - destination: "{{ quad_zero_route }}" 17 | protocol: "{{ TCP_protocol }}" 18 | tcp_options: 19 | destination_port_range: 20 | min: {{ HTTP_port }} 21 | max: {{ HTTP_port }} 22 | - destination: "{{ quad_zero_route }}" 23 | protocol: "{{ TCP_protocol }}" 24 | tcp_options: 25 | destination_port_range: 26 | min: {{ HTTPS_port }} 27 | max: {{ HTTPS_port }} 28 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/create_server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create bastion server 3 | oci_instance: 4 | availability_domain: "{{ bastion_availability_domain }}" 5 | compartment_id: "{{ demo_compartment_ocid }}" 6 | name: "{{ demo_bastion_instance_name }}" 7 | image_id: "{{ bastion_image_ocid }}" 8 | shape: "{{ bastion_shape }}" 9 | vnic: 10 | assign_public_ip: True 11 | hostname_label: "{{ demo_bastion_host_name }}" 12 | subnet_id: "{{ bastion_subnet_ocid }}" 13 | metadata: 14 | ssh_authorized_keys: "{{ lookup('file', demo_ssh_public_key)}}" 15 | freeform_tags: 16 | infra: "{{ infra_name }}" 17 | type: bastion 18 | state: 'running' 19 | register: bastion 20 | 21 | - name: Get details of a specific Compute instance 22 | oci_instance_facts: 23 | id: "{{ bastion.instance.id }}" 24 | register: newbastion 25 | 26 | - set_fact: 27 | ssh_extra_args: "-o StrictHostKeyChecking=no -i {{ demo_ssh_private_key }} -o ProxyCommand='ssh -o StrictHostKeyChecking=no -i {{ demo_ssh_private_key }} -W %h:%p -q opc@{{ newbastion.instances[0].primary_public_ip }}'" 28 | when: newbastion.instance|length==1 29 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/templates/ingress_security_rules.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright (c) 2018, 2019 Oracle and/or its affiliates. 3 | # This software is made available to you under the terms of the GPL 3.0 license or the Apache 2.0 license. 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | # Apache License v2.0 6 | # See LICENSE.TXT for details. 7 | ingress_security_rules: 8 | # Allow inbound Oracle connections from ords servers 9 | - source: "{{ demo_lb_subnet_ad1_cidr }}" 10 | protocol: "{{ TCP_protocol }}" 11 | tcp_options: 12 | destination_port_range: 13 | min: {{ ORDS_port }} 14 | max: {{ ORDS_port }} 15 | - source: "{{ demo_lb_subnet_ad2_cidr }}" 16 | protocol: "{{ TCP_protocol }}" 17 | tcp_options: 18 | destination_port_range: 19 | min: {{ ORDS_port }} 20 | max: {{ ORDS_port }} 21 | # Allow ssh access *only* from bastion subnet. 22 | - source: "{{ bastion_subnet_cidr_block }}" 23 | protocol: "{{ TCP_protocol }}" 24 | tcp_options: 25 | destination_port_range: 26 | min: {{ SSH_port }} 27 | max: {{ SSH_port }} 28 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/start_ords.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d ~/log ]; then 4 | mkdir ~/log 5 | fi 6 | LOGFILE=~/log/ords_`date +%Y%m%d_%H%M%S`.log 7 | 8 | APEX_DIR=~/apex 9 | if [ -d ${APEX_DIR} ]; then 10 | java_option="-Dorg.eclipse.jetty.server.Request.maxFormContentSize=3000000" 11 | apex_option="--apex-images ${APEX_DIR}/images" 12 | fi 13 | 14 | max_wait_in_sec=60 15 | count=0 16 | ret=0 17 | 18 | chk=`ps -ef | grep ords.war | grep -v grep | wc -l` 19 | if [ "${chk}" = "0" ]; then 20 | echo "Starting ORDS ..." 21 | else 22 | echo "Looks ORDS has been running already. Exsiting." 23 | exit 24 | fi 25 | 26 | cd ~/ 27 | nohup java ${java_option} -jar ords.war standalone ${apex_option} >> $LOGFILE 2>&1 & 28 | 29 | while [ ${count} -lt ${max_wait_in_sec} ] 30 | do 31 | ret=`grep "INFO:oejs.Server:main: Started" ${LOGFILE}|wc -l` 32 | if [ ${ret} -ne 0 ]; then 33 | pid=`ps -ef | grep ords.war | grep -v grep | awk '{print $2}'` 34 | echo "ORDS(pid=${pid}) has been started successfully!" 35 | break 36 | fi 37 | sleep 2 38 | count=`expr ${count} + 2` 39 | done 40 | 41 | if [ ${ret} -eq 0 ]; then 42 | echo "ORDS has not been started..." 43 | else 44 | : 45 | fi 46 | -------------------------------------------------------------------------------- /terraform/schema.yaml: -------------------------------------------------------------------------------- 1 | title: "Deploy a fully managed APEX instance" 2 | description: "Deploy the APEX low-code application development platform as a standalone OCI managed service" 3 | schemaVersion: 1.1.0 4 | version: "20190304" 5 | locale: "en" 6 | 7 | variableGroups: 8 | - title: General Configuration 9 | visible: false 10 | variables: 11 | - tenancy_ocid 12 | - region 13 | - compartment_ocid 14 | 15 | - title: Apex Configuration 16 | visible: true 17 | variables: 18 | - autonomous_database_admin_password 19 | outputs: 20 | apex_url: 21 | type: link 22 | title: Apex Login 23 | description: Open Apex 24 | primaryOutputButton: apex_url 25 | 26 | variables: 27 | autonomous_database_admin_password: 28 | type: password 29 | required: true 30 | title: "Apex password" 31 | description: "The password should be 12-30 characters and must include an uppercase, lowercase, numeral and a special character" 32 | #pattern: "^(?=[a-zA-Z0-9!@#%^*_+\-:?.,\[\]\{\}]{8,32}$)(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9]).*" 33 | pattern: "^(?=.*[!#$%&'()*+,\\-.\\/\\:;<=>?@\\[\\]^_`{|}~])(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{12,30}$" 34 | visible: true 35 | compartment_ocid: 36 | type: oci:identity:compartment:id 37 | title: "Compartment" 38 | description: "The compartment in which to create Apex instance" 39 | required: true 40 | 41 | 42 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_jetty_ca-ssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 1 argument 4 | # Arg1 : Compute FQDN (with customer's public domain) 5 | 6 | # Set Variables 7 | ComFQDN=$1 8 | 9 | ### Setup Jetty with using CA certifiate 10 | # Clean up self-signed Cert 11 | rm -rf ~/conf/ords/standalone/self-signed* 12 | 13 | # Update ORDS propaties 14 | openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in ~/.acme.sh/${ComFQDN}/${ComFQDN}.key -out ~/conf/ords/standalone/${ComFQDN}.pkcs8.key 15 | openssl pkcs8 -topk8 -inform PEM -outform DER -in ~/conf/ords/standalone/${ComFQDN}.pkcs8.key -out ~/conf/ords/standalone/${ComFQDN}.pkcs8.der -nocrypt 16 | rm ~/conf/ords/standalone/${ComFQDN}.pkcs8.key 17 | cp ~/.acme.sh/${ComFQDN}/${ComFQDN}.cer ~/conf/ords/standalone/ 18 | sed -i -e "s|ssl.cert=$|ssl.cert=$HOME/conf/ords/standalone/${ComFQDN}.cer|" ~/conf/ords/standalone/standalone.properties 19 | sed -i -e "s|ssl.cert.key=$|ssl.cert.key=$HOME/conf/ords/standalone/${ComFQDN}.pkcs8.der|" ~/conf/ords/standalone/standalone.properties 20 | 21 | # Restart ORDS as standalone 22 | cd ~ 23 | ./stop_ords.sh 24 | ./start_ords.sh 25 | 26 | # Update URL for *_add_db.sh 27 | for i in apex_add_db.sh 28 | do 29 | IP=`grep https $HOME/${i}|awk -F: '{print $2}'|sed -e 's|//||'` 30 | sed -i -e "s/${IP}/${ComFQDN}/g" $HOME/${i} 31 | done 32 | 33 | # Cleanup 34 | history -c 35 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/config_ords.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Creates directory 3 | file: path=/home/opc/ state=directory 4 | - name: copy setup scripts to hosts 5 | copy: 6 | src: ../files/jetty/ 7 | dest: /home/opc/ 8 | owner: opc 9 | group: opc 10 | 11 | - name: set execute to script files 12 | shell: 'chmod u+x *.sh' 13 | 14 | - name: fetch ords 15 | unarchive: 16 | src: "{{ demo_ords_par }}" 17 | dest: /home/opc/ 18 | remote_src: yes 19 | creates: /home/opc/ords.war 20 | 21 | - name: fetch apex 22 | unarchive: 23 | src: "{{ demo_apex_par }}" 24 | dest: /home/opc/ 25 | remote_src: yes 26 | creates: /home/opc/apex/ 27 | 28 | - name: set runtime 29 | blockinfile: 30 | dest: "~/.bashrc" 31 | block: | 32 | export ORACLE_HOME=/usr/lib/oracle/18.3/client64 33 | export LD_LIBRARY_PATH="$ORACLE_HOME/lib" 34 | export PATH="$ORACLE_HOME/bin:$PATH" 35 | marker: '# {mark} ANSIBLE MANAGED BLOCK - Oracle instant client' 36 | insertbefore: BOF 37 | create: yes 38 | 39 | - name: run jetty_ords script 40 | command: ./config_jetty_ords.sh {{ demo_db_password }} {{ demo_database_hostname }} {{ demo_database_service }} {{ ORDS_port}} 41 | register: ords_result 42 | 43 | - name: run install apex 44 | command: ./config_jetty_apex.sh {{ demo_db_password }} {{ demo_database_hostname }} {{ demo_database_service }} {{ ORDS_port}} 1 45 | register: apex_result 46 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/create_security_list.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Use a jinja2 template of the ingress and egress security rules to generate 4 | # a templated version of the final rules. 5 | - name: create ingress rules yaml body 6 | template: src=./templates/lb_ingress_security_rules.yaml.j2 dest=/tmp/lb_ingress_security_rules.yaml 7 | - name: create egress yaml body 8 | template: src=./templates/lb_egress_security_rules.yaml.j2 dest=/tmp/lb_egress_security_rules.yaml 9 | 10 | # Load the variables defined in the generated files 11 | - name: load the variables defined in the ingress rules yaml body 12 | include_vars: 13 | file: /tmp/lb_ingress_security_rules.yaml 14 | name: loaded_ingress 15 | 16 | - name: print loaded_ingress 17 | debug: 18 | msg: "loaded ingress is {{loaded_ingress}}" 19 | 20 | - name: load the variables defined in the egress rules yaml body 21 | include_vars: 22 | file: /tmp/lb_egress_security_rules.yaml 23 | name: loaded_egress 24 | 25 | - name: print loaded_egress 26 | debug: 27 | msg: "loaded egress is {{loaded_egress}}" 28 | 29 | - name: Create security list for bastion subnet 30 | oci_security_list: 31 | name: "{{ demo_lb_security_list_name }}" 32 | compartment_id: "{{ demo_compartment_ocid }}" 33 | vcn_id: '{{ demo_vcn_ocid }}' 34 | ingress_security_rules: "{{ loaded_ingress.lb_ingress_security_rules }}" 35 | egress_security_rules: "{{ loaded_egress.lb_egress_security_rules }}" 36 | register: result 37 | 38 | - set_fact: 39 | lb_security_list_ocid: "{{ result.security_list.id }}" 40 | -------------------------------------------------------------------------------- /ansible/roles/bastion/tasks/create_security_list.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Use a jinja2 template of the ingress and egress security rules to generate 4 | # a templated version of the final rules. 5 | - name: create ingress rules yaml body 6 | template: src=./templates/bastion_ingress_security_rules.yaml.j2 dest=/tmp/bastion_ingress_security_rules.yaml 7 | - name: create egress yaml body 8 | template: src=./templates/bastion_egress_security_rules.yaml.j2 dest=/tmp/bastion_egress_security_rules.yaml 9 | 10 | # Load the variables defined in the generated files 11 | - name: load the variables defined in the ingress rules yaml body 12 | include_vars: 13 | file: /tmp/bastion_ingress_security_rules.yaml 14 | name: loaded_ingress 15 | - name: print loaded_ingress 16 | debug: 17 | msg: "loaded ingress is {{loaded_ingress}}" 18 | - name: load the variables defined in the egress rules yaml body 19 | include_vars: 20 | file: /tmp/bastion_egress_security_rules.yaml 21 | name: loaded_egress 22 | - name: print loaded_egress 23 | debug: 24 | msg: "loaded egress is {{loaded_egress}}" 25 | 26 | - name: Create security list for bastion subnet 27 | oci_security_list: 28 | name: "{{ demo_bastion_subnet_security_list_name }}" 29 | compartment_id: "{{ demo_compartment_ocid }}" 30 | vcn_id: '{{ demo_vcn_ocid }}' 31 | ingress_security_rules: "{{ loaded_ingress.bastion_ingress_security_rules }}" 32 | egress_security_rules: "{{ loaded_egress.bastion_egress_security_rules }}" 33 | register: result 34 | 35 | - set_fact: 36 | bastion_security_list_ocid: "{{ result.security_list.id }}" 37 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/create_ords_subnet.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright (c) 2018, Oracle and/or its affiliates. 3 | # This software is made available to you under the terms of the GPL 3.0 license or the Apache 2.0 license. 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | # Apache License v2.0 6 | # See LICENSE.TXT for details. 7 | 8 | 9 | - name: Create ORDS AD1 subnet 10 | oci_subnet: 11 | availability_domain: "{{ demo_ordsserver_ad1}}" 12 | cidr_block: "{{ demo_ords_subnet_ad1_cidr }}" 13 | compartment_id: "{{ demo_compartment_ocid }}" 14 | display_name: "{{ demo_ords_subnet_ad1_name }}" 15 | prohibit_public_ip_on_vnic: true 16 | security_list_ids: [ "{{ ords_security_list_ocid }}" ] 17 | vcn_id: '{{ demo_vcn_ocid }}' 18 | dns_label: "{{ demo_ords_subnet_ad1_name }}" 19 | route_table_id: "{{ demo_core_rt_nat_ocid }}" 20 | register: result 21 | 22 | - set_fact: 23 | demo_ords_subnet_ad1_ocid: "{{ result.subnet.id }}" 24 | 25 | - name: Create ORDS AD2 subnet 26 | oci_subnet: 27 | availability_domain: "{{ demo_ordsserver_ad2 }}" 28 | cidr_block: "{{ demo_ords_subnet_ad2_cidr }}" 29 | compartment_id: "{{ demo_compartment_ocid }}" 30 | display_name: "{{ demo_ords_subnet_ad2_name }}" 31 | prohibit_public_ip_on_vnic: true 32 | security_list_ids: [ "{{ ords_security_list_ocid }}" ] 33 | vcn_id: '{{ demo_vcn_ocid }}' 34 | dns_label: "{{ demo_ords_subnet_ad2_name }}" 35 | route_table_id: "{{ demo_core_rt_nat_ocid }}" 36 | register: result 37 | 38 | - set_fact: 39 | demo_ords_subnet_ad2_ocid: "{{ result.subnet.id }}" 40 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/create_db_security_lists.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Use a jinja2 template of the ingress and egress security rules to generate 4 | # a templated version of the final rules. 5 | - name: create ingress rules yaml body 6 | template: src=templates/ingress_security_list_ad1.yaml.j2 dest=/tmp/ingress_security_list_ad1.yaml 7 | - name: create egress yaml body 8 | template: src=templates/egress_security_list_ad1.yaml.j2 dest=/tmp/egress_security_list_ad1.yaml 9 | 10 | # Load the variables defined in the generated files 11 | - name: load the variables defined in the ingress rules yaml body 12 | include_vars: 13 | file: /tmp/ingress_security_list_ad1.yaml 14 | name: loaded_ingress 15 | 16 | - name: print loaded_ingress 17 | debug: 18 | msg: "loaded ingress is {{loaded_ingress}}" 19 | 20 | - name: load the variables defined in the egress rules yaml body 21 | include_vars: 22 | file: /tmp/egress_security_list_ad1.yaml 23 | name: loaded_egress 24 | 25 | - name: print loaded_egress 26 | debug: 27 | msg: "loaded egress is {{loaded_egress}}" 28 | 29 | # Use the loaded variables as the ingress and egress security rules in our 30 | # sec list 31 | - name: Create a security list for dbsubnet in availability domain 1 32 | oci_security_list: 33 | name: "{{ db_subnet_sec_list_name }}" 34 | compartment_id: "{{ demo_compartment_ocid }}" 35 | vcn_id: "{{ demo_vcn_ocid }}" 36 | state: 'present' 37 | ingress_security_rules: "{{ loaded_ingress.ad1_ingress_security_rules }}" 38 | egress_security_rules: "{{ loaded_egress.ad1_egress_security_rules }}" 39 | register: result 40 | 41 | - set_fact: 42 | db_sec_list_id: "{{result.security_list.id}}" 43 | -------------------------------------------------------------------------------- /ansible/host_vars/localhost: -------------------------------------------------------------------------------- 1 | --- 2 | # Here we assign variables that are applicable to all groups 3 | # Define environment 4 | # 5 | # 6 | demo_ad1_name: "qasv:EU-FRANKFURT-1-AD-1" 7 | demo_ad2_name: "qasv:EU-FRANKFURT-1-AD-2" 8 | demo_compartment_ocid: "ocid1.compartment.oc1." 9 | demo_ol_image_ocid: "ocid1.image." 10 | 11 | # Location of SSH key, leave empty to generate key 12 | demo_ssh_private_key: "~/.ssh/auth_key" 13 | demo_ssh_public_key: "~/.ssh/auth_key.pub" 14 | # A random suffix to append to names so that we can run parallel demo environments. 15 | random_suffix: "{{ 250 | random(seed=ansible_nodename, step=10) }}" 16 | 17 | # Tag for the infrastructure 18 | infra_name: "apexdb-demo-setup-{{ random_suffix }}" 19 | 20 | # A prefix we add to all the display_names of demo artifacts that we 21 | # create in this demo 22 | demo_var_prefix: "apexdb-{{ random_suffix }}" 23 | 24 | # URLs to download required software 25 | demo_apex_par: "APEX URL" 26 | demo_ords_par: "ORDS URL" 27 | # Database variables 28 | demo_db_shape: "VM.Standard2.2" 29 | demo_db_cluster_name: "dbcluster" 30 | demo_db_password: "BEstr0ng_#1" 31 | demo_db_name: "oradb" 32 | demo_db_pdb_name: "pdbprod" 33 | 34 | demo_ordsserver_shape: "VM.Standard2.2" 35 | 36 | # networking common vars 37 | quad_zero_route: "0.0.0.0/0" 38 | TCP_protocol: "6" 39 | HTTP_port: "80" 40 | HTTPS_port: "443" 41 | ORDS_port: 8443 42 | DB_port: 1521 43 | SSH_port: 22 44 | 45 | # CIDR ranges for the various subnets in this demo 46 | demo_vcn_cidr_block: "10.0.0.0/26" 47 | demo_ords_subnet_ad1_cidr: "10.0.0.0/28" 48 | demo_ords_subnet_ad2_cidr: "10.0.0.16/28" 49 | demo_db_subnet_cidr: "10.0.0.32/28" 50 | demo_lb_subnet_ad1_cidr: "10.0.0.56/30" 51 | demo_lb_subnet_ad2_cidr: "10.0.0.60/30" 52 | bastion_subnet_cidr_block: "10.0.0.48/29" 53 | 54 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/create_certificate.yaml: -------------------------------------------------------------------------------- 1 | # A self-singed temporary certificate is used in this sample, so that the sample can be run without any dependencies, 2 | # and the certificate can be validated. In production environment, a valid certificate should be used. 3 | - name: create temporary directory for certificates 4 | tempfile: 5 | state: directory 6 | suffix: cert 7 | register: result 8 | 9 | - set_fact: 10 | cert_path: "{{ result.path }}" 11 | 12 | - name: Generate CA Cert Key 13 | openssl_privatekey: 14 | path: "{{cert_path}}/ca_key.pem" 15 | type: RSA 16 | size: 2048 17 | 18 | - name: Generate CA cert 19 | command: openssl req \ 20 | -x509 -new -days 365 \ 21 | -subj '/C=IN/ST=KA/L=mylocation/O=Ansible/CN=www.ansible.oracle.com' 22 | -key "{{cert_path}}/ca_key.pem" \ 23 | -out "{{cert_path}}/ca_cert.pem" 24 | args: 25 | creates: "{{cert_path}}/ca_cert.pem" 26 | 27 | - name: Generate Server Private Key Without Passphrase 28 | openssl_privatekey: 29 | path: "{{cert_path}}/private_key.pem" 30 | type: RSA 31 | size: 2048 32 | 33 | - name: Generate Certificate Signing Request With Normal Private Key 34 | openssl_csr: 35 | path: "{{cert_path}}/csr.pem" 36 | privatekey_path: "{{cert_path}}/private_key.pem" 37 | country_name: IN 38 | organization_name: Ansible 39 | state_or_province_name: KA 40 | locality_name: Bangalore 41 | common_name: www.ansible.oracle.com 42 | 43 | - name: Generate CA signed Certificate Without Passphrase 44 | command: openssl x509 -req \ 45 | -days 1825 -CA "{{cert_path}}/ca_cert.pem" -CAkey "{{cert_path}}/ca_key.pem" -CAcreateserial \ 46 | -in "{{cert_path}}/csr.pem" \ 47 | -out "{{cert_path}}/cert.pem" 48 | args: 49 | creates: "{{cert_path}}/cert.pem" 50 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/create_ords_security_list.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright (c) 2018, Oracle and/or its affiliates. 3 | # This software is made available to you under the terms of the GPL 3.0 license or the Apache 2.0 license. 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | # Apache License v2.0 6 | # See LICENSE.TXT for details. 7 | 8 | 9 | # Use a jinja2 template of the ingress and egress security rules to generate 10 | # a templated version of the final rules. 11 | - name: create ingress rules yaml body 12 | template: src=./templates/ingress_security_rules.yaml.j2 dest=/tmp/ingress_security_rules.yaml 13 | - name: create egress yaml body 14 | template: src=./templates/egress_security_rules.yaml.j2 dest=/tmp/egress_security_rules.yaml 15 | 16 | # Load the variables defined in the generated files 17 | - name: load the variables defined in the ingress rules yaml body 18 | include_vars: 19 | file: /tmp/ingress_security_rules.yaml 20 | name: loaded_ingress 21 | 22 | - name: print loaded_ingress 23 | debug: 24 | msg: "loaded ingress is {{loaded_ingress}}" 25 | 26 | - name: load the variables defined in the egress rules yaml body 27 | include_vars: 28 | file: /tmp/egress_security_rules.yaml 29 | name: loaded_egress 30 | 31 | - name: print loaded_egress 32 | debug: 33 | msg: "loaded egress is {{loaded_egress}}" 34 | 35 | - name: Create security list for ords subnet 36 | oci_security_list: 37 | name: "{{ demo_ords_subnet_security_list_name }}" 38 | compartment_id: "{{ demo_compartment_ocid }}" 39 | vcn_id: '{{ demo_vcn_ocid }}' 40 | ingress_security_rules: "{{ loaded_ingress.ingress_security_rules }}" 41 | egress_security_rules: "{{ loaded_egress.egress_security_rules }}" 42 | state: 'present' 43 | register: result 44 | 45 | - set_fact: 46 | ords_security_list_ocid: "{{ result.security_list.id }}" 47 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/create_ords_servers.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Copyright (c) 2018, Oracle and/or its affiliates. 3 | # This software is made available to you under the terms of the GPL 3.0 license or the Apache 2.0 license. 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | # Apache License v2.0 6 | # See LICENSE.TXT for details. 7 | 8 | - debug: 9 | msg: "Inside ordsserver role" 10 | 11 | - name: Template the ordsserver bootstrap to fill in ords and apex urls 12 | template: 13 | src: "./templates/ordsserver_bootstrap.j2" 14 | dest: "/tmp/ordsserver_bootstrap" 15 | backup: no 16 | 17 | - name: Slurp cloud-init content from the template-applied result for OS1 18 | slurp: 19 | src: "/tmp/ordsserver_bootstrap" 20 | register: demo_ordsserver_cloud_init 21 | 22 | - name: Launch OS1 in ords Subnet 23 | oci_instance: 24 | name: "{{ ords_name }} " 25 | image_id: "{{ demo_ol_image_ocid }}" 26 | shape: "{{ demo_ordsserver_shape }}" 27 | compartment_id: "{{ demo_compartment_ocid }}" 28 | availability_domain: "{{ ords_domain }}" 29 | metadata: 30 | ssh_authorized_keys: "{{ lookup('file', demo_ssh_public_key)}}" 31 | user_data: "{{ demo_ordsserver_cloud_init['content'] }}" 32 | vnic: 33 | hostname_label: "{{ ords_hostname }}" 34 | assign_pubic_ip: false 35 | subnet_id: "{{ subnet_id }}" 36 | freeform_tags: 37 | infra: "{{ infra_name }}" 38 | type: ordsserver 39 | state: 'present' 40 | wait: yes 41 | wait_until: "RUNNING" 42 | register: demoos1 43 | 44 | 45 | 46 | - name: Get details of the instance 47 | oci_instance_facts: 48 | id: "{{ demoos1.instance.id }}" 49 | register: result 50 | 51 | - name: set internalIP 52 | set_fact: 53 | ords_ip: "{{ result.instances[0].primary_private_ip }}" -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 6 arguments 4 | # Arg1 : Tenant OCID 5 | # Arg2 : Compartment OCID 6 | # Arg3 : User OCID 7 | # Arg4 : Fingerprint 8 | # Arg5 : Private Pem Key 9 | # Arg6 : Compute FQDN (with customer's public domain) 10 | 11 | ### Configure ORDS for the target database 12 | # Set Variables 13 | TenantID=$1 14 | CompartID=$2 15 | UserID=$3 16 | FP=$4 17 | PEM=$5 18 | ComFQDN=$6 19 | 20 | ### Setup oci_curl function to call REST API 21 | # Download bash script 22 | curl -L https://docs.cloud.oracle.com/iaas/Content/Resources/Assets/signing_sample_bash.txt > ~/oci_bash ; nkf --overwrite --oc=UTF-8 ~/oci_bash 23 | 24 | # Update environment variables 25 | mkdir ~/.oci 26 | 27 | reptgt_tenancyId=`grep "local tenancyId=" ~/oci_bash | awk -F\" '{print $2}'` 28 | reptgt_authUserId=`grep "local authUserId=" ~/oci_bash | awk -F\" '{print $2}'` 29 | reptgt_keyFingerprint=`grep "local keyFingerprint=" ~/oci_bash | awk -F\" '{print $2}'` 30 | reptgt_privateKeyPath=`grep "local privateKeyPath=" ~/oci_bash | awk -F\" '{print $2}'` 31 | 32 | sed -i -e "s/${reptgt_tenancyId}/${TenantID}/" ~/oci_bash 33 | sed -i -e "s/${reptgt_authUserId}/${UserID}/" ~/oci_bash 34 | sed -i -e "s/${reptgt_keyFingerprint}/${FP}/" ~/oci_bash 35 | sed -i -e "s|${reptgt_privateKeyPath}|$HOME/.oci/oci_api_key.pem|" ~/oci_bash 36 | 37 | echo "${PEM}" > ~/.oci/oci_api_key.pem 38 | chmod 600 ~/.oci/oci_api_key.pem 39 | 40 | # Source bash function oci_curl 41 | echo "source ~/oci_bash" >> ~/.bash_profile 42 | source ~/.bash_profile 43 | 44 | ### Install ACME Client acme.sh 45 | # Download acme.sh 46 | curl https://get.acme.sh | sh 47 | source ~/.bashrc 48 | 49 | # copy script for dns update to under ~/.acme.sh 50 | cp dns_ocidns.sh ~/.acme.sh/dnsapi/ 51 | 52 | ### Aquire a Certificate from Let's Encrypt 53 | export OCIDNS_C=${CompartID} 54 | ~/.acme.sh/acme.sh --issue --dnssleep 15 --dns dns_ocidns -d ${ComFQDN} 55 | # Debug mode 56 | # ~/.acme.sh/acme.sh --issue --debug 2 --dnssleep 15 --dns dns_ocidns -d ${ComFQDN} 57 | 58 | -------------------------------------------------------------------------------- /ansible/roles/oradb/tasks/launch_instance_oradb.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | #Task for launching an instance for Oracle db instance in ad1 4 | 5 | # check if db_home exists 6 | - name: check if db_home exist 7 | oci_db_system_facts: 8 | compartment_id: "{{ demo_compartment_ocid }}" 9 | display_name: "{{ cluster_name }}" 10 | register: dbhome 11 | 12 | - debug: 13 | msg: "{{ dbhome }}" 14 | 15 | - set_fact: 16 | demo_database_hostname: "{{ dbhome.db_systems[0].hostname }}.{{ dbhome.db_systems[0].domain }}" 17 | demo_database_service: "{{ db_pdb_name }}.{{ dbhome.db_systems[0].domain }}" 18 | when: dbhome.db_systems|length==1 19 | 20 | - name: Launch OraDB 21 | oci_db_system: 22 | compartment_id: "{{ demo_compartment_ocid }}" 23 | availability_domain: "{{ demo_ad1_name }}" 24 | cluster_name: "{{ cluster_name }}" 25 | database_edition: "{{db_edition}}" 26 | db_home: 27 | database: 28 | admin_password: "{{ password }}" 29 | character_set: 'AL32UTF8' 30 | db_backup_config: 31 | auto_backup_enabled: True 32 | db_name: "{{ db_name }}" 33 | db_workload: 'OLTP' 34 | ncharacter_set: 'AL16UTF16' 35 | pdb_name: "{{ db_pdb_name }}" 36 | db_version: "{{ db_version }}" 37 | display_name: "{{ demo_var_prefix }}db" 38 | disk_redundancy: "NORMAL" 39 | display_name: "{{ cluster_name }}" 40 | hostname: "{{ cluster_name }}" 41 | initial_data_storage_size_in_gb: 512 42 | license_model: "LICENSE_INCLUDED" 43 | node_count: 1 44 | shape: "{{ shape }}" 45 | ssh_public_keys: ["{{ demo_ssh_public_key}}"] 46 | subnet_id: "{{ db_subnet_id }}" 47 | wait: True 48 | #depending on the shape it takes a long time to provision the database service 49 | wait_timeout: 8000 50 | state: 'present' 51 | register: result 52 | ignore_errors: yes 53 | when: dbhome.db_systems|length==0 54 | 55 | - set_fact: 56 | demo_database_hostname: "{{ result.db_system.hostname }}.{{ result.db_system.domain }}" 57 | demo_database_service: "{{ db_pdb_name }}.{{ result.db_system.domain }}" 58 | 59 | when: dbhome.db_systems|length==0 60 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/tasks/check_ords_servers.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - debug: msg="Inside ordsserver role" 4 | 5 | - name: retrieve ORDS server in AD1 6 | oci_instance_facts: 7 | availability_domain: "{{ demo_ordsserver_ad1 }}" 8 | compartment_id: "{{ demo_compartment_ocid }}" 9 | display_name: "{{ demo_ordsserver_name_1 }}" 10 | lifecycle_state: 'RUNNING' 11 | register: ords_details 12 | 13 | - name: Include task list to create ords server 14 | include_tasks: "create_ords_servers.yaml" 15 | args: 16 | apply: 17 | vars: 18 | ords_domain: "{{ demo_ordsserver_ad1 }}" 19 | ords_name: "{{ demo_ordsserver_name_1 }}" 20 | ords_hostname: "{{ demo_ordsserver_host_name_1 }}" 21 | subnet_id: "{{ demo_ords_subnet_ad1_ocid }}" 22 | when: ords_details.instances|length==0 23 | 24 | - name: Add host to group 'ords_apex' with ssh 25 | add_host: 26 | name: "{{ ords_ip }}" 27 | groups: ords_apex 28 | ansible_ssh_common_args: "-i {{ demo_ssh_private_key }} -o StrictHostKeyChecking=no {{ ssh_extra_args }}" 29 | 30 | - name: retrieve ORDS server in AD2 31 | oci_instance_facts: 32 | availability_domain: "{{ demo_ordsserver_ad2 }}" 33 | compartment_id: "{{ demo_compartment_ocid }}" 34 | display_name: "{{ demo_ordsserver_name_2 }}" 35 | lifecycle_state: 'RUNNING' 36 | register: ords_details 37 | 38 | - name: Include task list to create ords server 39 | include_tasks: "create_ords_servers.yaml" 40 | args: 41 | apply: 42 | vars: 43 | ords_domain: "{{ demo_ordsserver_ad2 }}" 44 | ords_name: "{{ demo_ordsserver_name_2 }}" 45 | ords_hostname: "{{ demo_ordsserver_host_name_2 }}" 46 | subnet_id: "{{ demo_ords_subnet_ad2_ocid }}" 47 | when: ords_details.instances|length==0 48 | 49 | - name: Add host to group 'ords_apex' with ssh 50 | add_host: 51 | name: "{{ ords_ip }}" 52 | groups: ords_apex 53 | ansible_ssh_common_args: "-i {{ demo_ssh_private_key }} -o StrictHostKeyChecking=no {{ ssh_extra_args }}" 54 | 55 | 56 | - name: configure ords apex 57 | include_tasks: config_ords.yaml 58 | args: 59 | apply: 60 | delegate_to: "{{ item }}" 61 | remote_user: "opc" 62 | with_items: "{{ groups['ords_apex'] }}" -------------------------------------------------------------------------------- /ansible/roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ## Common tasks for the demo 4 | - debug: msg="Common infrastructure setup for this demo" 5 | 6 | - name: check if ssh key is defined if not create one 7 | include_tasks: "create_ssh_key.yaml" 8 | when: demo_ssh_private_key == "" 9 | 10 | - name: Create a VCN for the demo 11 | oci_vcn: 12 | compartment_id: "{{ demo_compartment_ocid }}" 13 | display_name: "{{ demo_vcn_name }}" 14 | cidr_block: "{{ demo_vcn_cidr_block }}" 15 | dns_label: "{{ demo_vcn_dns_label }}" 16 | register: demovcn 17 | 18 | - set_fact: 19 | demo_vcn_ocid: "{{ demovcn.vcn.id }}" 20 | demo_vcn_dns_label: "{{ demovcn.vcn.dns_label }}" 21 | 22 | - name: Create Internet Gateway 23 | oci_internet_gateway: 24 | compartment_id: "{{ demo_compartment_ocid }}" 25 | vcn_id: "{{ demo_vcn_ocid }}" 26 | name: "{{ demo_ig_display_name }}" 27 | enabled: 'yes' 28 | state: 'present' 29 | register: demoig 30 | - set_fact: 31 | demo_ig_ocid: "{{ demoig.internet_gateway.id }}" 32 | 33 | - name: Create a NAT gateway 34 | oci_nat_gateway: 35 | compartment_id: "{{ demo_compartment_ocid }}" 36 | vcn_id: "{{ demo_vcn_ocid }}" 37 | display_name: "{{ demo_nat_display_name }}" 38 | state: 'present' 39 | register: demonat 40 | 41 | - set_fact: 42 | demo_nat_ocid: "{{ demonat.nat_gateway.id }}" 43 | 44 | - name: Create route table to connect internet gateway to the demo VCN 45 | oci_route_table: 46 | compartment_id: "{{ demo_compartment_ocid }}" 47 | vcn_id: "{{ demo_vcn_ocid }}" 48 | name: "{{ demo_core_route_table_name }}ig" 49 | route_rules: "{{ demo_core_ig_route_table_rules }}" 50 | state: 'present' 51 | register: democoreroutetableig 52 | 53 | - set_fact: 54 | demo_core_rt_ig_ocid: "{{ democoreroutetableig.route_table.id }}" 55 | 56 | - name: Create NAT route table to connect to the demo VCN 57 | oci_route_table: 58 | compartment_id: "{{ demo_compartment_ocid }}" 59 | vcn_id: "{{ demo_vcn_ocid }}" 60 | name: "{{ demo_core_route_table_name }}nat" 61 | route_rules: "{{ demo_core_nat_route_table_rules }}" 62 | state: 'present' 63 | register: democoreroutetablenat 64 | 65 | - set_fact: 66 | demo_core_rt_nat_ocid: "{{ democoreroutetablenat.route_table.id }}" 67 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/apex_setup_base.exp: -------------------------------------------------------------------------------- 1 | #!/bin/expect 2 | 3 | set PW "ToBeUpdated_DBAdmPwd" 4 | set DBHOST "ToBeUpdated_DBSystemIP" 5 | set SRVNAME "ToBeUpdated_DBSrv" 6 | set DBNAME "ToBeUpdated_DBName" 7 | set Prompt "\[#$%>\]" 8 | set timeout 60 9 | 10 | spawn env LANG=C java -jar ords.war setup --database ${DBNAME} 11 | 12 | expect { 13 | -re "Enter the name of the database server \\\[.*\\\]:" { 14 | send -- "${DBHOST}\n" 15 | } 16 | } 17 | 18 | expect { 19 | -glob "Enter the database listen port \\\[1521\\\]:" { 20 | send -- "\n" 21 | exp_continue 22 | } 23 | -glob "Enter 1 to specify the database service name, or 2 to specify the database SID \\\[1\\\]:" { 24 | send -- "\n" 25 | } 26 | } 27 | 28 | expect { 29 | -re "Enter the database service name \\\[.*\\\]:" { 30 | send -- "${SRVNAME}\n" 31 | } 32 | "Enter the database service name:" { 33 | send -- "${SRVNAME}\n" 34 | } 35 | } 36 | 37 | expect { 38 | -glob "Enter 1 if you want to verify/install Oracle REST Data Services schema or 2 to skip this step \\\[1\\\]:" { 39 | send -- "2\n" 40 | exp_continue 41 | } 42 | -glob "If using Oracle Application Express or migrating from mod_plsql then you must enter 1 \\\[1\\\]:" { 43 | send -- "\n" 44 | exp_continue 45 | } 46 | -glob "Enter the PL/SQL Gateway database user name \\\[APEX_PUBLIC_USER\\\]:" { 47 | send -- "\n" 48 | exp_continue 49 | } 50 | -glob "Enter the database password for APEX_PUBLIC_USER:" { 51 | send -- "${PW}\n" 52 | exp_continue 53 | } 54 | -glob "Confirm password:" { 55 | send -- "${PW}\n" 56 | exp_continue 57 | } 58 | -glob "Enter 1 to specify passwords for Application Express RESTful Services database users (APEX_LISTENER, APEX_REST_PUBLIC_USER) or 2 to skip this step \\\[1\\\]:" { 59 | send -- "\n" 60 | exp_continue 61 | } 62 | -glob "Enter the database password for APEX_LISTENER:" { 63 | send -- "${PW}\n" 64 | exp_continue 65 | } 66 | -glob "Confirm password:" { 67 | send -- "${PW}\n" 68 | exp_continue 69 | } 70 | -glob "Enter the database password for APEX_REST_PUBLIC_USER:" { 71 | send -- "${PW}\n" 72 | exp_continue 73 | } 74 | -glob "Confirm password:" { 75 | send -- "${PW}\n" 76 | } 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /ansible/roles/load_balancer/tasks/create_loadbalancers.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Create Public Load Balancer 4 | oci_load_balancer: 5 | compartment_id: "{{ demo_compartment_ocid }}" 6 | name: "{{ lb_name }}" 7 | shape_name: "{{ sample_shape }}" 8 | subnet_ids: 9 | - "{{ sample_subnet_id_ad1 }}" 10 | - "{{ sample_subnet_id_ad2 }}" 11 | state: 'present' 12 | register: result 13 | 14 | - set_fact: 15 | public_load_balancer_id: "{{ result.load_balancer.id }}" 16 | public_load_balancer_ip_addresses: "{{ result.load_balancer.ip_addresses }}" 17 | 18 | - name: Create Certificate for Listener 19 | oci_load_balancer_certificate: 20 | load_balancer_id: "{{ public_load_balancer_id }}" 21 | name: '{{ sample_certificate_name }}' 22 | ca_certificate: '{{ sample_ca_certificate }}' 23 | private_key: '{{ sample_private_key }}' 24 | public_certificate: '{{ sample_public_certificate }}' 25 | state: 'present' 26 | 27 | - name: Create Backend Set 28 | oci_load_balancer_backend_set: 29 | load_balancer_id: "{{ public_load_balancer_id }}" 30 | name: '{{ sample_backend_set_name }}' 31 | policy: '{{ sample_backend_set_policy }}' 32 | health_checker: 33 | interval_in_millis: 30000 34 | port: '{{ ORDS_port }}' 35 | protocol: "TCP" 36 | retries: 3 37 | timeout_in_millis: 10000 38 | url_path: "/ords/{{ demo_db_pdb_name }}" 39 | ssl_configuration: 40 | certificate_name: '{{ sample_certificate_name }}' 41 | verify_peer_certificate: False 42 | state: 'present' 43 | 44 | - name: Create Listener for HTTPS traffic 45 | oci_load_balancer_listener: 46 | load_balancer_id: "{{ public_load_balancer_id }}" 47 | name: '{{ https_listener_name }}' 48 | default_backend_set_name: '{{ sample_backend_set_name }}' 49 | port: '{{ https_port }}' 50 | protocol: "HTTP" 51 | ssl_configuration: 52 | certificate_name: '{{ sample_certificate_name }}' 53 | verify_peer_certificate: False 54 | state: 'present' 55 | 56 | - name: Create Backend 57 | oci_load_balancer_backend: 58 | load_balancer_id: "{{ public_load_balancer_id }}" 59 | backend_set_name: "{{ sample_backend_set_name }}" 60 | ip_address: "{{ item }}" 61 | port: '{{ ORDS_port }}' 62 | backup: False 63 | drain: False 64 | offline: False 65 | weight: 1 66 | state: 'present' 67 | with_items: "{{ groups['ords_apex'] }}" 68 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_jetty_ords.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 6 arguments 4 | # Arg1 : Target db's admin pw 5 | # Arg2 : Target db's IP address, whether public or private is ok as long as it is reachable from compute isntance 6 | # Arg3 : Target db's service name to connect 7 | # Arg5 : Compute port for access for ORDS 8 | 9 | # Set Variables 10 | DBAdmPwd=$1 11 | DBSystemIP=$2 12 | DBSrv=$3 13 | DBName=`echo ${DBSrv} | awk -F. '{print $1}'` 14 | ComPort=$4 15 | 16 | ### Configure ORDS for the target database 17 | source ~/.bash_profile 18 | 19 | # Update password verify function - MOS 2408087.1 20 | CURRENT_PW_VERIFY_FUNC=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_prof_chk|sed '/^$/d'` 21 | cp pw_verify_base.sql pw_verify_back.sql 22 | sed -i -e "s/ToBeUpdated_PW_VERIFY_FUNC/$CURRENT_PW_VERIFY_FUNC/g" pw_verify_back.sql 23 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_null.sql 24 | 25 | # Setup ORDS for target DB 26 | cp ords_setup_base.exp ords_setup.exp 27 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" ords_setup.exp 28 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" ords_setup.exp 29 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" ords_setup.exp 30 | sed -i -e "s/ToBeUpdated_DBName/${DBName}/g" ords_setup.exp 31 | 32 | java -jar ords.war configdir ~/conf 33 | 34 | java -jar ords.war map-url --type base-path /${DBName} ${DBName} 35 | 36 | expect ords_setup.exp 37 | 38 | # Restore password verify function 39 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_back 40 | 41 | # Add entries to defaults.xml 42 | cp conf/ords/defaults.xml conf/ords/defaults.xml_orig 43 | sed -i -e '5i true' conf/ords/defaults.xml 44 | sed -i -e '6i 10000' conf/ords/defaults.xml 45 | 46 | # propaties for standalone mode 47 | mkdir -p ~/conf/ords/standalone 48 | cat <> ~/conf/ords/standalone/standalone.properties 49 | standalone.context.path=/ords 50 | standalone.doc.root=$HOME/conf/ords/standalone/doc_root 51 | standalone.scheme.do.not.prompt=true 52 | standalone.static.context.path=/i 53 | standalone.static.path=$HOME/conf/ords/standalone/doc_root 54 | jetty.secure.port=${ComPort} 55 | ssl.cert= 56 | ssl.cert.key= 57 | ssl.host= 58 | EOF 59 | 60 | # Start ORDS as standalone 61 | chmod +x *ords.sh 62 | ./start_ords.sh 63 | 64 | # Cleanup 65 | rm -rf ords_setup.exp pw_verify_back.sql 66 | history -c 67 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/ords_setup_base.exp: -------------------------------------------------------------------------------- 1 | #!/bin/expect 2 | 3 | set PW "ToBeUpdated_DBAdmPwd" 4 | set DBHOST "ToBeUpdated_DBSystemIP" 5 | set SRVNAME "ToBeUpdated_DBSrv" 6 | set DBNAME "ToBeUpdated_DBName" 7 | set Prompt "\[#$%>\]" 8 | set timeout 60 9 | 10 | spawn env LANG=C java -jar ords.war setup --database ${DBNAME} 11 | 12 | expect { 13 | -re "Enter the name of the database server \\\[.*\\\]:" { 14 | send -- "${DBHOST}\n" 15 | } 16 | } 17 | 18 | expect { 19 | -glob "Enter the database listen port \\\[1521\\\]:" { 20 | send -- "\n" 21 | exp_continue 22 | } 23 | -glob "Enter 1 to specify the database service name, or 2 to specify the database SID \\\[1\\\]:" { 24 | send -- "\n" 25 | } 26 | } 27 | 28 | expect { 29 | -re "Enter the database service name \\\[.*\\\]:" { 30 | send -- "${SRVNAME}\n" 31 | } 32 | "Enter the database service name:" { 33 | send -- "${SRVNAME}\n" 34 | } 35 | } 36 | 37 | expect { 38 | -glob "Enter 1 if you want to verify/install Oracle REST Data Services schema or 2 to skip this step \\\[1\\\]:" { 39 | send -- "\n" 40 | exp_continue 41 | } 42 | -glob "Enter the database password for ORDS_PUBLIC_USER:" { 43 | send -- "${PW}\n" 44 | exp_continue 45 | } 46 | -glob "Confirm password:" { 47 | send -- "${PW}\n" 48 | exp_continue 49 | } 50 | -glob "Enter the database password for SYS AS SYSDBA:" { 51 | send -- "${PW}\n" 52 | exp_continue 53 | } 54 | -glob "Confirm password:" { 55 | send -- "${PW}\n" 56 | exp_continue 57 | } 58 | -glob "Enter the default tablespace for ORDS_METADATA \\\[SYSAUX\\\]:" { 59 | send -- "\n" 60 | exp_continue 61 | } 62 | -glob "Enter the temporary tablespace for ORDS_METADATA \\\[TEMP\\\]:" { 63 | send -- "\n" 64 | exp_continue 65 | } 66 | -glob "Enter the default tablespace for ORDS_PUBLIC_USER \\\[SYSAUX\\\]:" { 67 | send -- "\n" 68 | exp_continue 69 | } 70 | -glob "Enter the temporary tablespace for ORDS_PUBLIC_USER \\\[TEMP\\\]:" { 71 | send -- "\n" 72 | exp_continue 73 | } 74 | -glob "If using Oracle Application Express or migrating from mod_plsql then you must enter 1 \\\[1\\\]:" { 75 | send "2\n" 76 | exp_continue 77 | } 78 | -glob "Enter 1 if you wish to start in standalone mode or 2 to exit \\\[1\\\]:" { 79 | send "2\n" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /ansible/README.md: -------------------------------------------------------------------------------- 1 | # oci-apex 2 | This is an ansible playbook sample that will deploy [APEX](https://apex.oracle.com) on [Oracle Cloud Infrastructure (OCI)](https://cloud.oracle.com/en_US/cloud-infrastructure). It is developed jointly by Oracle and Macty. 3 | 4 | ## About 5 | This playbook will configure a database and two ORDS servers load balanced with a self signed Certificate. 6 | 7 | ## Prerequisites 8 | 1. Ansible installed with [OCI-ansible](https://github.com/oracle/oci-ansible-modules). 9 | 2. Ensure that you have a valid OCI SDK configuration at the default config path ~/.oci/config 10 | 3. [Apex](https://www.oracle.com/tools/downloads/apex-downloads.html) and [ORDS](https://www.oracle.com/database/technologies/appdev/rest.html) installation files available through a weburl. 11 | You can upload it into OCI storage container and create a PAR for it. 12 | 13 | ## Configurations 14 | In host_vars/locahost configure the following: 15 | - Set the availabliltiy domains 16 | - Set the compartment OCID 17 | - Set the Oracle linux OCID 18 | - Define your ssh keys, set empty to create one 19 | - Set the urls where we can download the ORDS and APEX zipfiles 20 | - Verify the shapes to be used 21 | - Set a DB password this password will also be used for the apex users 22 | - Go over the other options and make sure they work for you 23 | 24 | ## What will be created 25 | - VCN 26 | - Public and Private Subnets 27 | - Database instance 28 | - ORDS servers 29 | - LoadBalancers with self signed Certificate 30 | - Bastion server 31 | 32 | 33 | ## How to run the sample 34 | - Run the demo playbook to create the sample infrastructure in OCI. The deployment of the 35 | Oracle database can take a long while depending on the shape used. 36 | > $ ansible-playbook sample.yaml 37 | - After a succesfull run it will show you the public ip of the loadbalancer to use 38 | - access the apex server with the last part is the pluggable database name 39 | > https:///ords/pdbprod 40 | 41 | ## Thanks and inspiration 42 | - Secure MongoDB Deployment in OCI Using Ansible 43 | - [WhitePaper terraform deployment](https://docs.cloud.oracle.com/iaas/Content/Resources/Assets/whitepapers/oracle-apex-on-oci-database.pdf) this provided the jetty-ords scripts for the configuration of ORDS 44 | - Oracle engineers for their support and expertise 45 | 46 | ## To Do 47 | - Alter the jetty configuration files to allow for different passwords used in ORDS-APEX configurations 48 | - Have option to use autonomous database deployment 49 | - Have option to use XE database deployment 50 | - use letsencrypt to create Certificate 51 | - ... 52 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/dns_ocidns.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" 4 | dns_ocidns_add() { 5 | fulldomain=$1 6 | txtvalue=$2 7 | reg=`curl -s http://169.254.169.254/opc/v1/instance/canonicalRegionName` 8 | 9 | OCIDNS_C="${OCIDNS_C:-$(_readaccountconf_mutable OCIDNS_C)}" 10 | if [ -z "$OCIDNS_C" ]; then 11 | OCIDNS_C="" 12 | _err "You don't specify credentials. Please set and try again." 13 | return 1 14 | fi 15 | 16 | source $HOME/oci_bash 17 | 18 | #save the api key and email to the account conf file. 19 | _saveaccountconf_mutable OCIDNS_C "$OCIDNS_C" 20 | 21 | zone_name=`echo ${fulldomain} | rev | cut -d '.' -f -2 | rev` 22 | 23 | cat < $HOME/request.json 24 | { 25 | "items": [ 26 | { 27 | "compartmentId" : "${OCIDNS_C}", 28 | "zone_name_or_id" : "${zone_name}", 29 | "domain" : "${fulldomain}", 30 | "rtype" : "TXT", 31 | "rdata" : "${txtvalue}", 32 | "ttl" : 120 33 | } 34 | ] 35 | } 36 | EOF 37 | 38 | if [ ! -e $HOME/request.json ]; then 39 | _err "json file couldn't be found at $HOME" 40 | return 1 41 | fi 42 | 43 | res_test=$(oci-curl) 44 | if [ ! "$res_test" = "invalid method" ]; then 45 | _err "oci-curl is not available." 46 | return 1 47 | fi 48 | 49 | _info "Adding record" 50 | if response=`oci-curl dns.${reg}.oraclecloud.com put $HOME/request.json "/20180115/zones/${zone_name}/records/${fulldomain}"`; then 51 | if printf -- "%s" "$response" | grep "$fulldomain" >/dev/null; then 52 | _info "Added, OK" 53 | return 0 54 | else 55 | _err "Add txt record error." 56 | return 1 57 | fi 58 | fi 59 | } 60 | 61 | #fulldomain txtvalue 62 | dns_ocidns_rm() { 63 | fulldomain=$1 64 | txtvalue=$2 65 | reg=`curl -s http://169.254.169.254/opc/v1/instance/canonicalRegionName` 66 | 67 | source $HOME/oci_bash 68 | 69 | OCIDNS_C="${OCIDNS_C:-$(_readaccountconf_mutable OCIDNS_C)}" 70 | if [ -z "$OCIDNS_C" ]; then 71 | OCIDNS_C="" 72 | _err "You didn't specify credentials. Please set and try again." 73 | return 1 74 | fi 75 | 76 | zone_name=`echo ${fulldomain} | rev | cut -d '.' -f -2 | rev` 77 | 78 | res_test=$(oci-curl) 79 | if [ ! "$res_test" = "invalid method" ]; then 80 | _err "oci-curl is not available." 81 | return 1 82 | fi 83 | 84 | _info "Deleting record" 85 | if response=`oci-curl dns.${reg}.oraclecloud.com delete "/20180115/zones/${zone_name}/records/${fulldomain}"?compartmentId=${OCIDNS_C}`; then 86 | _info "Deleted, OK" 87 | return 0 88 | else 89 | _err "Delete record error." 90 | return 1 91 | fi 92 | 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deploying Oracle Application Express on Oracle Cloud Infrastructure 2 | 3 | Oracle Application Express is a low-code development platform that enables you to build scalable, secure enterprise applications with world-class features that can be deployed anywhere. 4 | 5 | This repository provides multiple methods to automate the provisioning and management of Application Express on OCI. 6 | 7 | Application Express provides you with an easy-to-use browser-based environment to load data, manage database objects, develop REST interfaces, and build applications which look and run great on both desktop and mobile devices. You can use Application Express to develop a wide variety of solutions: import spreadsheets and develop a single source of truth in minutes, create compelling data visualizations against your existing data, deploy productivity applications to elegantly solve a business need, or build your next mission-critical data management application. 8 | 9 | Application Express embraces SQL. Anything you can express with SQL can be easily employed in an Application Express application. Application Express also enables low-code development, providing developers with powerful data management and data visualization components that deliver modern, responsive end-user experiences out of the box. Instead of writing code by hand, you are able to use intelligent wizards to guide you through the rapid creation of applications and components. 10 | 11 | ## Using Ansible 12 | 13 | Ansible is an open-source software provisioning, configuration management, and application-deployment tool enabling infrastructure as code. In the `/ansible` directory you will find the ansible configuration required to deploy the Oracle database and ORDS servers that enable the Application Express platform for low code application development. You can use this to deploy and self manage an APEX instance. 14 | 15 | ## Using Terraform 16 | 17 | Terraform is an open-source infrastructure as code software tool. You define data center infrastructure using a declarative configuration language known as HashiCorp Configuration Language (HCL) and Terraform calls the cloud APIs to create and manage the infrastructure. 18 | 19 | The terraform configuration provided in the `/terraform` directory provides a preconfigured, fully managed and secured Application Express environment to both build and deploy world-class data-centric applications. There are no limits on the number of developers or end users for your applications. 20 | 21 | Configuration, patching, monitoring, and upgrading of all Oracle Application Express components is fully managed by Oracle, leaving you free to focus on developing your solutions and solving your business problems. Oracle Application Express enables your organization to be more agile and develop solutions faster, for less cost, and with greater consistency. You can adapt to changing requirements with ease. And you can empower professional developers, citizen developers, and everyone else. 22 | 23 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/ords_add_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 3 arguments 4 | # -p : target db's admin pw 5 | # -i : target db's IP address, whether public or private is ok as long as it is reachable from compute isntance 6 | # -s : target db's service name to connect 7 | 8 | usage_exit() { 9 | echo "Usage: $CMDNAME -p VALUE -i VALUE -s VALUE" 1>&2 10 | echo " -p: Target DB/PDB's Admin (SYS) password " 1>&2 11 | echo " -i: Listener's IP address for Target DB/PDB " 1>&2 12 | echo " -s: Target DB/PDB's Service Name " 1>&2 13 | echo " -h: Showing this usage message" 1>&2 14 | exit 1 15 | } 16 | 17 | while getopts p:i:s:h OPT 18 | do 19 | case $OPT in 20 | "p" ) FLG_P="TRUE" ; VALUE_PW="$OPTARG" ;; 21 | "i" ) FLG_I="TRUE" ; VALUE_IP="$OPTARG" ;; 22 | "s" ) FLG_S="TRUE" ; VALUE_SN="$OPTARG" ;; 23 | "h" ) usage_exit ;; 24 | * ) usage_exit ;; 25 | esac 26 | done 27 | 28 | if [ "$FLG_P" = "TRUE" ] && [ "$FLG_I" = "TRUE" ] && [ "$FLG_S" = "TRUE" ]; then 29 | echo "Required options are specified." 30 | else 31 | echo "Required option is missing." 32 | usage_exit 33 | fi 34 | 35 | ### Configure ORDS for the target database 36 | # Set target DB's environment information 37 | DBAdmPwd=${VALUE_PW} 38 | DBSystemIP=${VALUE_IP} 39 | DBSrv=${VALUE_SN} 40 | DBName=`echo ${DBSrv} | awk -F. '{print $1}'` 41 | 42 | ### Debug 43 | #echo $DBSystemIP 44 | #echo $DBAdmPwd 45 | #echo $DBSrv 46 | #echo $DBName 47 | 48 | # Check if ORDS is already setup or not. 49 | ords_check=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @ords_pu_check | sed -e '/^$/d' -e 's/^[ \t]*//'` 50 | if [ "$ords_check" = "0" ]; then 51 | echo "ORDS has not configured for $DBName yet" 52 | elif [ "$ords_check" = "1" ]; then 53 | echo "Found ORDS has been already configured for $DBName" 54 | exit 55 | else 56 | echo "Found connection to $DBName or ORDS configuration for $DBName is something wrong. Exiting..." 57 | exit 1 58 | fi 59 | 60 | # Update password verify function - MOS 2408087.1 61 | CURRENT_PW_VERIFY_FUNC=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_prof_chk|sed '/^$/d'` 62 | cp pw_verify_base.sql pw_verify_back.sql 63 | sed -i -e "s/ToBeUpdated_PW_VERIFY_FUNC/$CURRENT_PW_VERIFY_FUNC/g" pw_verify_back.sql 64 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_null 65 | 66 | # Setup ORDS for target DB 67 | cp ords_setup_base.exp ords_setup.exp 68 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" ords_setup.exp 69 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" ords_setup.exp 70 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" ords_setup.exp 71 | sed -i -e "s/ToBeUpdated_DBName/${DBName}/g" ords_setup.exp 72 | 73 | java -jar ords.war map-url --type base-path /${DBName} ${DBName} 74 | 75 | expect ords_setup.exp 76 | 77 | # Restore password verify function 78 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_back 79 | 80 | # Cleanup 81 | rm -rf ords_setup.exp pw_verify_back.sql 82 | 83 | echo "ORDS for $DBName is configured." 84 | -------------------------------------------------------------------------------- /terraform/README.md: -------------------------------------------------------------------------------- 1 | # APEX Deployment 2 | 3 | This Terraform configuration helps you create a new fully managed APEX environment on Oracle Cloud Infrastructure. 4 | The APEX low-code development platform available as a managed cloud service that developers can use to build data-driven enterprise applications quickly and easily. 5 | While the original APEX platform was only available as part of the Oracle Database, APEX Application Development is available as a standalone service and works with a variety of applications. 6 | The service supports unlimited applications, and elastically scales as additional capacity is needed. 7 | 8 | ## Deploy Using Oracle Resource Manager 9 | 10 | 1. Click [![Deploy to Oracle Cloud](https://oci-resourcemanager-plugin.plugins.oci.oraclecloud.com/latest/deploy-to-oracle-cloud.svg)](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/oracle-quickstart/oci-apex/releases/download/v0.0.1/oci-quickstart-apex-v0.0.1.zip) 11 | 12 | If you aren't already signed in, when prompted, enter the tenancy name and user credentials. 13 | 14 | 2. Review and accept the terms and conditions. 15 | 16 | 3. Select the region where you want to deploy the stack. 17 | 18 | 4. Follow the on-screen prompts and instructions to create the stack. 19 | 20 | 5. After creating the stack, click **Terraform Actions**, and select **Plan**. 21 | 22 | 6. Wait for the job to be completed, and review the plan. 23 | 24 | To make any changes, return to the Stack Details page, click **Edit Stack**, and make the required changes. Then, run the **Plan** action again. 25 | 26 | 7. If no further changes are necessary, return to the Stack Details page, click **Terraform Actions**, and select **Apply**. 27 | 28 | ## Deploy Using the Terraform CLI 29 | 30 | ### Clone of the repo 31 | Now, you'll want a local copy of this repo. You can make that with the commands: 32 | 33 | ``` 34 | git clone https://github.com/oracle-quickstart/oci-apex 35 | cd oci-apex/terraform 36 | ls 37 | ``` 38 | 39 | ### Prerequisites 40 | 41 | To get stared, you need to setup terraform to be abel to connect to your OCI tenancy and execute actions against it. That's all detailed [here](https://github.com/cloud-partners/oci-prerequisites). 42 | 43 | Once you have terraform installed and configured, you can tell terraform how to connect to your OCI tenancy by creating a `terraform.tfvars` file and populating with the following information: 44 | 45 | ``` 46 | # Authentication 47 | tenancy_ocid = "" 48 | user_ocid = "" 49 | fingerprint = "" 50 | private_key_path = "" 51 | 52 | # Region 53 | region = "" 54 | 55 | # Compartment 56 | compartment_ocid = "" 57 | 58 | # Jenkins password 59 | autonomous_database_admin_password = "" 60 | ``` 61 | 62 | ### Create the Resources 63 | 64 | Run the following commands: 65 | 66 | ``` 67 | terraform init 68 | terraform plan 69 | terraform apply 70 | ``` 71 | 72 | ### Destroy the Deployment 73 | 74 | When you no longer need the deployment, you can run this command to destroy the resources: 75 | 76 | ``` 77 | terraform destroy 78 | ``` 79 | 80 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/config_jetty_apex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 7 arguments 4 | # Arg1 : Target db's admin pw 5 | # Arg2 : Target db's IP address, whether public or private is ok as long as it is reachable from compute isntance 6 | # Arg3 : Target db's service name to connect 7 | # Arg4 : Compute port for access for ORDS 8 | # Arg5 : Install mode: 0(full development) or 1(runtime) 9 | 10 | # Set Variables 11 | DBAdmPwd=$1 12 | DBSystemIP=$2 13 | DBSrv=$3 14 | DBName=`echo ${DBSrv} | awk -F. '{print $1}'` 15 | ComIP=$4 16 | ComPort=$5 17 | if [ $5 -eq 0 ]; then 18 | MODE=full 19 | elif [ $5 -eq 1 ]; then 20 | MODE=runtime 21 | else 22 | echo "Arg for Install Option is not set properly, 5h arg: $5" 23 | exit 1 24 | fi 25 | 26 | ### Configure APEX for the target database 27 | source $HOME/.bash_profile 28 | 29 | # Update password verify function - MOS 2408087.1 30 | CURRENT_PW_VERIFY_FUNC=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_prof_chk|sed '/^$/d'` 31 | cp pw_verify_base.sql pw_verify_back.sql 32 | sed -i -e "s/ToBeUpdated_PW_VERIFY_FUNC/$CURRENT_PW_VERIFY_FUNC/g" pw_verify_back.sql 33 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_null 34 | 35 | # APEX installation to target db 36 | cd apex 37 | if ! tail apexins.sql | grep exit > /dev/null ; then 38 | echo "exit" >> apexins.sql 39 | fi 40 | if ! tail apxrtins.sql | grep exit > /dev/null ; then 41 | echo "exit" >> apxrtins.sql 42 | fi 43 | 44 | if [ "$MODE" = "full" ]; then 45 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apexins SYSAUX SYSAUX TEMP /i/ 46 | elif [ "$MODE" = "runtime" ]; then 47 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apxrtins SYSAUX SYSAUX TEMP /i/ 48 | else 49 | echo "Install Option is not set properly, MODE: ${MODE}" 50 | exit 1 51 | fi 52 | 53 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @$HOME/config_apex1 ${DBAdmPwd} 54 | if ! tail apex_rest_config_core.sql | grep exit > /dev/null ; then 55 | echo "exit" >> apex_rest_config_core.sql 56 | fi 57 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apex_rest_config_core ./ ${DBAdmPwd} ${DBAdmPwd} 58 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @$HOME/config_apex2 59 | cd $HOME 60 | 61 | # Restore password verify function 62 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_back 63 | 64 | # Setup APEX for target DB 65 | cp apex_setup_base.exp apex_setup.exp 66 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" apex_setup.exp 67 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" apex_setup.exp 68 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" apex_setup.exp 69 | sed -i -e "s/ToBeUpdated_DBName/${DBName}/g" apex_setup.exp 70 | 71 | expect apex_setup.exp 72 | 73 | # Validate ORDS 74 | cp ords_validate_base.exp ords_validate.exp 75 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" ords_validate.exp 76 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" ords_validate.exp 77 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" ords_validate.exp 78 | 79 | expect ords_validate.exp 80 | 81 | # Wait for 10 sec 82 | sleep 10 83 | 84 | # Restart ORDS as standalone 85 | cd ~ 86 | ./stop_ords.sh 87 | ./start_ords.sh 88 | 89 | # Cleanup 90 | rm -rf apex_setup.exp ords_setup.exp ords_validate.exp pw_verify_back.sql 91 | history -c 92 | -------------------------------------------------------------------------------- /ansible/roles/ordsserver/files/jetty/apex_add_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script requires 3 arguments and 1 argument is optional 4 | # -p : target db's admin pw 5 | # -i : target db's IP address, whether public or private is ok as long as it is reachable from compute isntance 6 | # -s : target db's service name to connect 7 | # -m : APEX installation mode 8 | 9 | usage_exit() { 10 | echo "Usage: $CMDNAME -p VALUE -i VALUE -s VALUE" 1>&2 11 | echo " -p: Target DB/PDB's Admin (SYS) password [required] " 1>&2 12 | echo " -i: Listener's IP address for Target DB/PDB [required] " 1>&2 13 | echo " -s: Target DB/PDB's Service Name [required] " 1>&2 14 | echo " -m: Installation mode, full(default) or runtime " 1>&2 15 | echo " -h: Showing this usage message" 1>&2 16 | exit 1 17 | } 18 | 19 | while getopts p:i:s:m:h OPT 20 | do 21 | case $OPT in 22 | "p" ) FLG_P="TRUE" ; VALUE_PW="$OPTARG" ;; 23 | "i" ) FLG_I="TRUE" ; VALUE_IP="$OPTARG" ;; 24 | "s" ) FLG_S="TRUE" ; VALUE_SN="$OPTARG" ;; 25 | "m" ) FLG_M="TRUE" ; VALUE_IM="$OPTARG" ;; 26 | "h" ) usage_exit ;; 27 | * ) usage_exit ;; 28 | esac 29 | done 30 | 31 | if [ "$FLG_P" = "TRUE" ] && [ "$FLG_I" = "TRUE" ] && [ "$FLG_S" = "TRUE" ]; then 32 | echo "Required options are specified." 33 | else 34 | echo "Required option is missing." 35 | usage_exit 36 | fi 37 | 38 | ### Check if an APEX file exists in HOME directory 39 | if [ ! -d $HOME/apex ]; then 40 | echo "$HOME/apex directory is not found." 41 | exit 1 42 | fi 43 | 44 | ### Configure APEX for the target database 45 | # Set target DB's environment information 46 | DBAdmPwd=${VALUE_PW} 47 | DBSystemIP=${VALUE_IP} 48 | DBSrv=${VALUE_SN} 49 | DBName=`echo ${DBSrv} | awk -F. '{print $1}'` 50 | if [ "$FLG_M" = "TRUE" ]; then 51 | MODE=`echo ${VALUE_IM} | tr '[:upper:]' '[:lower:]'` 52 | else 53 | MODE=full 54 | fi 55 | if [ ! "$MODE" = "full" ] && [ ! "$MODE" = "runtime" ]; then 56 | echo "Install Option is not set properly." 57 | usage_exit 58 | fi 59 | 60 | ### Debug 61 | #echo $DBSystemIP 62 | #echo $DBAdmPwd 63 | #echo $DBSrv 64 | #echo $DBName 65 | #echo $MODE 66 | 67 | # Check if ORDS is already setup or not. 68 | ords_check=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @ords_pu_check | sed -e '/^$/d' -e 's/^[ \t]*//'` 69 | if [ "$ords_check" = "0" ]; then 70 | echo "ORDS has not configured for $DBName yet" 71 | ORDS_CONFIG=yet 72 | elif [ "$ords_check" = "1" ]; then 73 | echo "Found ORDS has been already configured for $DBName" 74 | else 75 | echo "Found connection to $DBName or ORDS configuration for $DBName is something wrong. Exiting..." 76 | exit 1 77 | fi 78 | 79 | # Check if APEX is already setup or not. 80 | apex_inst_check=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apex_inst_check | sed -e '/^$/d' -e 's/^[ \t]*//'` 81 | if [ ! "$apex_inst_check" = "no rows selected" ]; then 82 | echo "APEX has benn already configured for $DBName" 83 | exit 84 | fi 85 | 86 | # Update password verify function - MOS 2408087.1 87 | CURRENT_PW_VERIFY_FUNC=`sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_prof_chk|sed '/^$/d'` 88 | cp pw_verify_base.sql pw_verify_back.sql 89 | sed -i -e "s/ToBeUpdated_PW_VERIFY_FUNC/$CURRENT_PW_VERIFY_FUNC/g" pw_verify_back.sql 90 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_null 91 | 92 | # Setup ORDS for target DB 93 | if [ "$ORDS_CONFIG" = "yet" ]; then 94 | cp ords_setup_base.exp ords_setup.exp 95 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" ords_setup.exp 96 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" ords_setup.exp 97 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" ords_setup.exp 98 | sed -i -e "s/ToBeUpdated_DBName/${DBName}/g" ords_setup.exp 99 | 100 | java -jar ords.war map-url --type base-path /${DBName} ${DBName} 101 | 102 | expect ords_setup.exp 103 | fi 104 | 105 | # APEX installation to target db 106 | cd apex 107 | if [ ! -e apexins.sql ] || [ ! -e apxrtins.sql ]; then 108 | echo "APEX installation scripts were not found." 109 | exit 1 110 | fi 111 | if ! tail apexins.sql | grep exit > /dev/null ; then 112 | echo "exit" >> apexins.sql 113 | fi 114 | if ! tail apxrtins.sql | grep exit > /dev/null ; then 115 | echo "exit" >> apxrtins.sql 116 | fi 117 | 118 | if [ "$MODE" = "full" ]; then 119 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apexins SYSAUX SYSAUX TEMP /i/ 120 | elif [ "$MODE" = "runtime" ]; then 121 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apxrtins SYSAUX SYSAUX TEMP /i/ 122 | else 123 | echo "Install Option is not set properly, MODE: ${MODE}" 124 | exit 1 125 | fi 126 | 127 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @$HOME/config_apex1 ${DBAdmPwd} 128 | if ! tail apex_rest_config_core.sql | grep exit > /dev/null ; then 129 | echo "exit" >> apex_rest_config_core.sql 130 | fi 131 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @apex_rest_config_core ./ ${DBAdmPwd} ${DBAdmPwd} 132 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @$HOME/config_apex2 133 | cd $HOME 134 | 135 | # Restore password verify function 136 | sqlplus -s sys/"${DBAdmPwd}"@${DBSystemIP}/${DBSrv} as sysdba @pw_verify_back 137 | 138 | # Setup APEX for target DB 139 | cp apex_setup_base.exp apex_setup.exp 140 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" apex_setup.exp 141 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" apex_setup.exp 142 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" apex_setup.exp 143 | sed -i -e "s/ToBeUpdated_DBName/${DBName}/g" apex_setup.exp 144 | 145 | expect apex_setup.exp 146 | 147 | # Validate ORDS 148 | cp ords_validate_base.exp ords_validate.exp 149 | sed -i -e "s/ToBeUpdated_DBAdmPwd/${DBAdmPwd}/g" ords_validate.exp 150 | sed -i -e "s/ToBeUpdated_DBSystemIP/${DBSystemIP}/g" ords_validate.exp 151 | sed -i -e "s/ToBeUpdated_DBSrv/${DBSrv}/g" ords_validate.exp 152 | 153 | expect ords_validate.exp 154 | 155 | # Restart ORDS if ORDS is not running with apex mode 156 | if [ ! $chk_result -eq 0 ]; then 157 | # Wait for 10 sec 158 | sleep 10 159 | if ! ps -ef | grep ords.war | grep -v grep | grep apex-images > /dev/null ; then 160 | ./stop_ords.sh 161 | ./start_ords.sh 162 | fi 163 | fi 164 | 165 | # Cleanup 166 | rm -rf apex_setup.exp ords_setup.exp ords_validate.exp pw_verify_back.sql 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Macty 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------