How to Architect and Implement Devops on ExaCS TIP4120 Jeffrey T. Wright Sr. Principal Product Manager Database Cloud Services, Exadata October 25, 2018
Agenda Architecture block diagram System credentials OCI Terraform to deploy ExaCS, scale ExaCS OCPUs OCI Python SDK for user and group administration Database creation and patching via Python Demo 2
OCI Architecture Block Diagram Tenancy Region e.g., Frankfurt Region e.g., Phoenix Availability Domain 1 Availability Domain 2 Availability Domain 3 Availability Domain 1 Availability Domain 2 Availability Domain 3 ExaCS ExaCS ExaCS ExaCS ExaCS ExaCS Compute Compute Compute Compute Compute Compute VCN VCN Compartment Compartment 3
OCI Architecture Block Diagram Tenancy Region e.g., Frankfurt Region e.g., Phoenix Availability Domain 1 Availability Domain 2 Availability Domain 3 Availability Domain 1 Availability Domain 2 Availability Domain 3 ExaCS ExaCS ExaCS ExaCS ExaCS ExaCS Compute Compute Compute Compute Compute Compute VCN Compartment 4
Exadata Cloud Service Example DB System Tenancy Region e.g., Frankfurt Availability Domain 2 ExaCS VCN Security Lists Client Subnet Backup Subnet Routing Rules Internet Gateway Service Gateway Compartment 5
System Credentials How to log in Cloud credentials Give you access to cloud automation to deploy cloud resources welcome email Virtual Machine credentials Give you access to the virtual machines you create with your cloud credentials Token based ssh installed via cloud automation Database Service credentials Give you access to databases you create with your cloud credentials Passwords specified when you create the database service 6
Welcome Email 7
OCI Console 8
Setting up your Credentials Keys and OCIDs https://docs.cloud.oracle.com/iaas/content/api/concepts/apisigningkey.htm Make an RSA public/private key pair in PEM format Get the fingerprint of your RSA key Get your tenancy OCID and user OCID Set up your local environment variables to run terraform https://www.terraform.io/docs/providers/oci/ 9
Make the Keys # make the private key openssl genrsa -out ~/.oci/oci_api_key.pem 2048 chmod go-rwx ~/.oci/oci_api_key.pem # make the public key from the private key openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem # copy the public key to the clipboard cat ~/.oci/oci_api_key_public.pem pbcopy # get the key's fingerprint openssl rsa -pubout -outform DER -in ~/.oci/oci_api_key.pem openssl md5 -c 10
Get the Tenancy OCID 11
Get the Tenancy OCID 12
Get the User OCID 13
Get the User OCID 14
Add Your Public Key 15
Get Your Compartment OCID 16
Get Your Compartment OCID 17
Environment Variables export OCI_GO_SDK_DEBUG=1 export TF_LOG=DEBUG export TF_VAR_tenancy_ocid=ocid1.tenancy.oc1..aaaaaaaambnyexdtahy6ug7dy2ngnfnthvvbpfgmgmg3slb73f52wkbudvwq export TF_VAR_region=eu-frankfurt-1 export TF_VAR_compartment_ocid=ocid1.compartment.oc1..aaaaaaaarimctbi7gbn45dj4zdpvuny75aa6lajw2vbvzepgioydyv2i57pq export TF_VAR_user_ocid=ocid1.user.oc1..aaaaaaaagzwawhkatr2yd74nnox4hpylpllvbau7t3wzehqk7nynpmkhbbcq export TF_VAR_private_key_path=/Users/jtwright/.oci/oci_api_key.pem export TF_VAR_fingerprint=a0:fc:3c:2c:e1:9c:4c:3b:7b:37:b7:4a:12:42:ef:56 export TF_VAR_vcn=ocid1.vcn.oc1.eu-frankfurt-1.aaaaaaaaleafo2w7glqy4sarriqlaj7utqz2o4oeyxpmryjw7kg65dxgjnfq 18
Get Terraform and the OCI Provider (Plugin) Formal doc https://www.terraform.io/docs/providers/oci/ Terraform download https://github.com/hashicorp/terraform https://github.com/hashicorp/terraform/archive/master.zip OCI Provider download https://github.com/terraform-providers/terraform-provider-oci https://github.com/terraform-providers/terraform-provider-oci/archive/master.zip 19
Non-Database System Variable Setup variable "tenancy_ocid" { variable "user_ocid" { variable "fingerprint" { variable "private_key_path" { variable "compartment_ocid" { variable "region" { provider "oci" { tenancy_ocid = "${var.tenancy_ocid" user_ocid = "${var.user_ocid" fingerprint = "${var.fingerprint" private_key_path = "${var.private_key_path" region = "${var.region" variable "CLIENT-CIDR" { default = "10.10.3.0/24" variable "BACKUP-CIDR" { default = "10.10.4.0/24" variable "VPC-CIDR" { default = "10.10.0.0/16" variable "availability_domain" { default = "2" data "oci_identity_availability_domains" "ADs" { compartment_id = "${var.tenancy_ocid" data "oci_core_services" "test_services" { filter { name = "name" values = [".*Object.*Storage"] regex = true 20
Database System Variable Setup variable "db_disk_redundancy" { default = "HIGH" variable "hostname" { default = "exanode" variable "db_edition" { default = "ENTERPRISE_EDITION_EXTREME_PERFORMANCE" variable "db_admin_password" { default = "WelcoMe-OCI#123" variable "db_name" { default = "TESTDB" variable "character_set" { default = "AL32UTF8" variable "n_character_set" { default = "AL16UTF16" variable "db_workload" { default = "DSS" variable "pdb_name" { default = "TESTPDB" variable "db_version" { default = "12.2.0.1" variable "db_home_display_name" { default = "TESTDBHOME" variable "db_system_shape" { default = "Exadata.Quarter1.84" variable "cpu_core_count" { default = "22" variable "data_storage_percentage" { default = "80" variable "db_system_display_name" { default = "TESTDB" variable "license_model" { default = "LICENSE_INCLUDED" variable "ssh_public_key" { default = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCaqkoNWcD3QDPH4H6LvUizCwcO1Gnk8Xke2b8VToK8U9PjwGDYdH6afdkF2fq0u+kpbiW15AJoJgSvUKIORn+L+htY F9aWRJ3DcAjm9xaSpb+aFPxeh0b5WbYyL5kISD/uBDJvauubIHe9P1ccHv82Tl1EOVrwL0S3N6wFIOCza4ZGXvpyOM9eKyuxy3qnmQDGJ+SKDzT/Yql4NthI himcu4ixuqixwpuf5q8puzzqdbkmaeihdkixh08y1yfou60ypilwavbegpc1pj3hqne4zbzy4bhkushuhiovjp+qodmjagstljtvaabgjomxooekzfhnq26q LUW9G2eIcrct jtwright@jtwright-mac" 21
Create and ExaCS in OCI in 8 Steps https://cloud.oracle.com/iaas/whitepapers/deploying_exadata_on_oci.pdf 1. Get your userid and compartment from your administrator 2. Create a VCN 3. Create Gateways 4. Create Route Tables 5. Create Security Lists 6. Create DHCP Options 7. Create Subnets 8. Launch an Exadata DB System 22
VCN and Gateways resource "oci_core_vcn" "ExaVCN" { cidr_block = "${var.vpc-cidr" compartment_id = "${var.compartment_ocid" dns_label = "frankfurt" display_name = "frankfurt" resource "oci_core_internet_gateway" "ExaIG" { compartment_id = "${var.compartment_ocid" display_name = "ExaIG" vcn_id = "${oci_core_vcn.exavcn.id" resource "oci_core_service_gateway" "ExaSG" { compartment_id = "${var.compartment_ocid" services { service_id = "${lookup(data.oci_core_services.test_services.services[0], "id")" display_name = "ExaSG" vcn_id = "${oci_core_vcn.exavcn.id" 23
Route Tables resource "oci_core_route_table" "Client_RT" { compartment_id = "${var.compartment_ocid" vcn_id = "${oci_core_vcn.exavcn.id" display_name = "Client_RT" route_rules { cidr_block = "0.0.0.0/0" network_entity_id = "${oci_core_internet_gateway.exaig.id" resource "oci_core_route_table" "Backup_RT" { compartment_id = "${var.compartment_ocid" vcn_id = "${oci_core_vcn.exavcn.id" display_name = "Backup_RT" route_rules { destination = "${lookup(data.oci_core_services.test_services.services[0], "cidr_block")" destination_type = "SERVICE_CIDR_BLOCK" network_entity_id = "${oci_core_service_gateway.exasg.id" 24
Node Traffic Security List resource "oci_core_security_list" "NodeTraffic" { compartment_id = "${var.compartment_ocid" display_name = "NodeTraffic" vcn_id = "${oci_core_vcn.exavcn.id" egress_security_rules = [{ destination = "${var.client-cidr" protocol = "6", { destination = "${var.backup-cidr" protocol = 6, { destination = "${var.client-cidr" protocol = 1, { destination = "${var.backup-cidr" protocol = 1 ] ingress_security_rules = [{ source = "${var.client-cidr" protocol = "6", { source = "${var.backup-cidr" protocol = 6, { source = "${var.client-cidr" protocol = 1, { source = "${var.backup-cidr" protocol = 1 ] 25
SSH Traffic Security List resource "oci_core_security_list" "SSHTraffic" { compartment_id = "${var.compartment_ocid" display_name = "SSHTraffic" vcn_id = "${oci_core_vcn.exavcn.id" ingress_security_rules { protocol = "6" source = "0.0.0.0/0" stateless = false tcp_options = { "min" = 22 "max" = 22 // tcp 26
SQLNet Traffic Security List resource "oci_core_security_list" "SQLNet" { compartment_id = "${var.compartment_ocid" display_name = "SQLNet" vcn_id = "${oci_core_vcn.exavcn.id" ingress_security_rules = [{ protocol = "6" source = "${var.client-cidr" tcp_options = { "min" = 1521 "max" = 1521, { protocol = "6" source = "${var.backup-cidr" tcp_options = { "min" = 1521 "max" = 1521 ] 27
Client Traffic Security List resource "oci_core_security_list" "Client" { compartment_id = "${var.compartment_ocid" display_name = "Client" vcn_id = "${oci_core_vcn.exavcn.id" egress_security_rules = [{ destination = "${var.client-cidr" protocol = "6", { destination = "${var.backup-cidr" protocol = 6, { destination = "${var.client-cidr" protocol = 1, { destination = "${var.backup-cidr" protocol = 1, ] ingress_security_rules = [{ source = "${var.client-cidr" protocol = "6", { source = "${var.backup-cidr" protocol = 6, { source = "${var.client-cidr" protocol = 1, { source = "${var.backup-cidr" protocol = 1, ] 28
Backup Traffic Security List resource "oci_core_security_list" "DB_Backup" { compartment_id = "${var.compartment_ocid" display_name = "DB_Backup" vcn_id = "${oci_core_vcn.exavcn.id" egress_security_rules = [{ destination = "${var.client-cidr" protocol = "6", { destination = "${var.backup-cidr" protocol = 6 ] ingress_security_rules = [{ protocol = "6" source = "${var.client-cidr", { protocol = "6" source = "${var.backup-cidr" ] 29
Empty Security Lists for Future Use resource "oci_core_security_list" "Flex1" { compartment_id = "${var.compartment_ocid" display_name = "Flex1" vcn_id = "${oci_core_vcn.exavcn.id" # empty rule set resource "oci_core_security_list" "Flex2" { compartment_id = "${var.compartment_ocid" display_name = "Flex2" vcn_id = "${oci_core_vcn.exavcn.id" # empty rule set 30
DHCP Options resource "oci_core_dhcp_options" "ExaDHCP" { compartment_id = "${var.compartment_ocid" vcn_id = "${oci_core_vcn.exavcn.id" display_name = "ExaDHCP" options { type server_type = "DomainNameServer" = "VcnLocalPlusInternet" 31
Client Subnet resource "oci_core_subnet" "Client_Subnet_AD2" { availability_domain = "${lookup(data.oci_identity_availability_domains.ads.availability_domains[var.availability_ domain - 1],"name")" cidr_block = "${var.client-cidr" display_name = "Client_Subnet_AD2" compartment_id = "${var.compartment_ocid" vcn_id = "${oci_core_vcn.exavcn.id" route_table_id security_list_ids dns_label dhcp_options_id = "${oci_core_route_table.client_rt.id" = ["${oci_core_security_list.client.id", "${oci_core_security_list.sqlnet.id", "${oci_core_security_list.flex1.id", "${oci_core_security_list.nodetraffic.id", "${oci_core_security_list.sshtraffic.id" ] = "clientad2" = "${oci_core_dhcp_options.exadhcp.id" 32
Backup Subnet resource "oci_core_subnet" "Backup_Subnet_AD2" { availability_domain = "${lookup(data.oci_identity_availability_domains.ads.availability_domains[var.availability_ domain - 1],"name")" cidr_block = "${var.backup-cidr" display_name = "Backup_Subnet_AD2" compartment_id = "${var.compartment_ocid" vcn_id = "${oci_core_vcn.exavcn.id" route_table_id = "${oci_core_route_table.backup_rt.id" dns_label security_list_ids dhcp_options_id = "backupad1" = ["${oci_core_security_list.nodetraffic.id", "${oci_core_security_list.db_backup.id", "${oci_core_security_list.sshtraffic.id", "${oci_core_security_list.flex2.id" ] = "${oci_core_dhcp_options.exadhcp.id" 33
Create the Exadata DB System resource "oci_database_db_system" "DemoExaCS" { availability_domain = "${lookup(data.oci_identity_availability_domains.ads.availability_domains[var.availability_domain - 1],"name")" compartment_id = "${var.compartment_ocid" database_edition = "${var.db_edition" cpu_core_count = "${var.cpu_core_count" db_home { database { admin_password = "${var.db_admin_password" db_name = "${var.db_name" character_set = "${var.character_set" ncharacter_set = "${var.n_character_set" db_workload = "${var.db_workload" pdb_name = "${var.pdb_name" db_backup_config { auto_backup_enabled = true db_version = "${var.db_version" display_name = "${var.db_home_display_name" shape = "${var.db_system_shape" subnet_id = "${oci_core_subnet.client_subnet_ad2.id" backup_subnet_id = "${oci_core_subnet.backup_subnet_ad2.id" ssh_public_keys = ["${var.ssh_public_key"] display_name = "${var.db_system_display_name" hostname = "${var.hostname" data_storage_percentage = "${var.data_storage_percentage" license_model = "${var.license_model" 34
Plan and Apply! jtwright-mac:jtw jtwright$ pwd /Users/jtwright/.terraform.d/plugins/terraform-provider-oci-master/docs/examples/jtw jtwright-mac:jtw jtwright$ terraform plan... Plan: 16 to add, 0 to change, 1 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run. jtwright-mac:jtw... jtwright$ terraform apply Plan: 16 to add, 0 to change, 1 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes... Apply complete! Resources: 16 added, 0 changed, 1 destroyed. 35
How to Scale OCPUs Simply change the DB System variable for OCPU count, plan, and apply variable "cpu_core_count" { default = 44"... Terraform will perform the following actions: ~ oci_core_dhcp_options.exadhcp 2018/10/19 13:43:52 [DEBUG] plugin: waiting for all plugin processes to complete... options.#: "2" => "1" options.1.search_domain_names.#: "1" => "0" options.1.search_domain_names.0: "frankfurt.oraclevcn.com" => "" options.1.type: "SearchDomain" => "" ~ oci_database_db_system.demoexacs cpu_core_count: "22" => "44" Plan: 0 to add, 2 to change, 0 to destroy.... Apply complete! Resources: 0 added, 2 changed, 0 destroyed. jtwright-mac:jtw jtwright$ 36
Demo Exadata DB System in OCI via Terraform 37
Python API SDK https://docs.cloud.oracle.com/iaas/content/api/sdkdocs/pythonsdk.htm #!/usr/bin/python import oci, pprint, os from oci.identity.models import AddUserToGroupDetails from oci.config import from_file # config = from_file() config = { "compartment" : ocid1.compartment.oc1..aaaaaaaarimctbi7gbn45dj4zdpvuny75aa6lajw2vbvzepgioydyv2i57pq, "region": eu-frankfurt-1, "tenancy" : ocid1.tenancy.oc1..aaaaaaaambnyexdtahy6ug7dy2ngnfnthvvbpfgmgmg3slb73f52wkbudvwq, "user" : ocid1.user.oc1..aaaaaaaagzwawhkatr2yd74nnox4hpylpllvbau7t3wzehqk7nynpmkhbbcq, "fingerprint": a0:fc:3c:2c:e1:9c:4c:3b:7b:37:b7:4a:12:42:ef:56, "key_file": /Users/jtwright/.oci/oci_api_key.pem, "vcn" : ocid1.vcn.oc1.eu-frankfurt-1.aaaaaaaaleafo2w7glqy4sarriqlaj7utqz2o4oeyxpmryjw7kg65dxgjnfq pprint.pprint( config ) identity = oci.identity.identityclient(config) compartment_id = config["tenancy"] 38
Create a Group and a User from oci.identity.models import CreateGroupDetails request = CreateGroupDetails() request.compartment_id = compartment_id request.name = "exa-pm-group" request.description = "Exadata PM group" group = identity.create_group(request) pprint.pprint( group.data ) request = CreateUserDetails() request.compartment_id = compartment_id request.name = "exadata-pm" request.description = "Created with the Python SDK" user = identity.create_user(request) pprint.pprint(user.data) request = AddUserToGroupDetails() request.group_id = group.data.id request.user_id = user.data.id response = identity.add_user_to_group(request) pprint.pprint(response.data) 39
Create a Database Exadata Cloud at Customer, Oracle Cloud Infrastructure Classic x_id_tenant_name = 'a516946' user = 'jeff.wright@oracle.com' password = 'Welc0me!' baseurl='https://dbaas.oraclecloud.com/ servicesurl='paas/service/dbcs/api/v1.1/instances/' url = baseurl + servicesurl + x_id_tenant_name headers = {'X-ID-TENANT-NAME':x_id_tenant_name, 'content-type': 'application/json' payload = { "servicename" : "JTWTEST", "description" : "Test database for JTW", "edition" : "EE_EP", "exadatasystemname": "oow2017exa", "level" : "PAAS_EXADATA", "subscriptiontype": "MONTHLY", "version": "12.1.0.2", "vmpublickeytext": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCaqkoNWcD3QDPH4H6LvUizCwcO1Gnk8Xke2b8VToK8U9PjwGDYdH6afdkF2fq0u+kpbiW15AJoJgSvUKIORn+L+htYF9aWRJ3DcAjm9xaSpb+aFPxeh0 b5wbyyl5kisd/ubdjvauubihe9p1cchv82tl1eovrwl0s3n6wfiocza4zgxvpyom9ekyuxy3qnmqdgj+skdzt/yql4nthihimcu4ixuqixwpuf5q8puzzqdbkmaeihdkixh08y1yfou60ypilw avbegpc1pj3hqne4zbzy4bhkushuhiovjp+qodmjagstljtvaabgjomxooekzfhnq26qluw9g2eicrct jtwright@jtwright-mac", "parameters": [ { "adminpassword": "Welc0me#1", "backupdestination": "none", "israc": "yes", "pdbname": "JTWTESTPDB", "sid": "JTWTEST", "type": "db" ] response = requests.post( url, headers = headers, auth = (user, password), data=json.dumps( payload ) ) 40
Patch a Database Exadata Cloud at Customer, Oracle Cloud Infrastructure Classic servicesurl="/paas/api/v.1/instancemgmt/" url = baseurl + servicesurl + x_id_tenant_name + "/services/dbaas/instances/" + "JTWTEST" + "/patches/available" headers = {'X-ID-TENANT-NAME':x_id_tenant_name response = requests.get( url, headers = headers, auth = (user, password) ) newestpatchid = 0 for data in response.json(): if data["servicetype"] == "DBaaS": print data["releasedate"] + " " + data["patchnumber"] + " " + data["patchid"] if data["patchid"] > newestpatchid: newestpatchid = data["patchid"] servicesurl="/paas/api/v1.1/instancemgmt/" url = baseurl + servicesurl + x_id_tenant_name + "/services/dbaas/instances/" + "JTWTEST" + "/patches/checks/" + newestpatchid headers = {'X-ID-TENANT-NAME':x_id_tenant_name, 'content-type': 'application/json' payload = { "additionalnote" : "Patch precheck using REST API" response = requests.put( url, headers = headers, auth = (user, password), data=json.dumps( payload ) ) jobid=response.json()["details"]["jobid"] servicesurl="/paas/api/v1.1/instancemgmt/" url = baseurl + servicesurl + x_id_tenant_name + "/services/dbaas/instances/" + "JTWTEST" + "/patches/checks/job/" + jobid headers = {'X-ID-TENANT-NAME':x_id_tenant_name while True: response = requests.get( url, headers = headers, auth = (user, password) ) status=response.json()["status"] print status if status!= "IN_PROGRESS": break time.sleep( 10 ) 41
Patch a Database Exadata Cloud at Customer, Oracle Cloud Infrastructure Classic servicesurl="/paas/api/v1.1/instancemgmt/" url = baseurl + servicesurl + x_id_tenant_name + "/services/dbaas/instances/" + "JTWTEST" + "/patches/checks/" + newestpatchid headers = {'X-ID-TENANT-NAME':x_id_tenant_name, 'content-type': 'application/json' payload = { "additionalnote" : "Patch precheck using REST API" response = requests.put( url, headers = headers, auth = (user, password), data=json.dumps( payload ) ) jobid=response.json()["details"]["jobid"] servicesurl="/paas/api/v1.1/instancemgmt/" url = baseurl + servicesurl + x_id_tenant_name + "/services/dbaas/instances/" + "JTWTEST" + "/patches/checks/job/" + jobid headers = {'X-ID-TENANT-NAME':x_id_tenant_name while True: response = requests.get( url, headers = headers, auth = (user, password) ) status=response.json()["status"] print status if status!= "IN_PROGRESS": break time.sleep( 10 ) 42
43