X

Step Up to Modern Cloud Development

Provisioning your environment in Oracle Public Cloud

The scenario:

You are a Team Lead or a Developer; part of a developing organization who builds its products using primarily Java technologies and Oracle Database. You would like to create a fully automate provisioning process for one or all of the below as part of your Continuous Integration, Continuous Testing and Continuous Delivery Process:

  • Testing Environment = to test new implemented features within your own product(s)
  • Testing  + Benchmarking Environment = to take advantage of the latest features included in Oracle Database 12c, Weblogic 12c and Oracle Traffic Director , in a cluster environment 
  • Production Environment = to deploy your product(s)  in the production environment

You need to build a WebLogic cluster server. This means you will need your requests to be received by a Load Balancer (Oracle Traffic Director) that based on an algorithm (let's select "least connection count", you can read more about this here) will distribute the incoming requests to the WebLogic nodes, that will be configured to access Oracle Database Cloud Service. Both services Database and Java are Storage dependent. Moreover, for each instance of Database and Java you will need to create a Storage Container in the Oracle Storage Cloud Service.

Here is a typical workflow to fully automate the provisioning process for the scenario above. To build a fully automated provisioning process you can use any language of your choice. In this example Python was used.

OPC Provisioning workflow

Recommendations:

  • Read/explore the REST APIs for each used Oracle Service instance, original documentation links will be referred in the below.
  • Load your OPC (Oracle Public Cloud) credentials into an object opc_credentials, include: 
    • your identity domain name
    • your identity domain username
    • your identity domain password

  • Load various constant strings used inside OPC as per the REST API documentations into an object opc_properties
  • Load at least the following OPC instances names into an object opc_names
    • Database storage container name
    • Database instance name
    • Database SYS admin password 
    • Java storage container name
    • Java instance name
    • Java weblogic username
    • Java weblogic password
  • Two request body json files are needed (you can configure them as templates as you will see detailed farther on in this article) 
    • dbcs_create_request_body.json - for database 
    • jcs_create_request_body.json - for java
  • Import at least the requests and json python libs

The prerequisites are:

  •  Oracle Public Cloud credentials:
    • identity domain
    • username
    • password
  • Oracle Java Cloud Service service activated 
  • Python op your machine

In this demo, there are 3 python object types that will be used:

  • Storage (scs)
  • Database - constructor with storage as argument (dbcs
  • Java - constructor with storage and database as arguments (jcs)

The main() source code will look similar to:

 1
2
3
4
5
6
7
8
9
10
    # create Storage object
scs = Storage()# create Database object
dbcs = create_dbcs(scs)# create Java Object (LB + 1 node VM)
create_jcs(dbcs, scs)return 0 # success

Here are the 5 steps as per the workflow above:

1: Create the Database Storage Container 

Here you can read more about the Oracle Storage Service REST APIs.

1.1 First you must acquire a token: 

1
self.token = Storage.scs_get_token()

 1
2
3
4
5
6
7
8
9
10
11
12
    @staticmethoddef scs_get_token():"""
get authentication token for Oracle Storage Cloud Service
"""
req_headers = {"X-Storage-User": 'Storage-%s:%s' % (opc_credentials[OPC_IDENTITY_DOMAIN], opc_credentials[OPC_USERNAME]),"X-Storage-Pass": opc_credentials[OPC_PASSWORD]}
response = requests.get(opc_properties[OPC_STORAGE_URL_AUTH], auth=None, headers=req_headers)
print_response(response)return response.headers['X-Storage-Token']

In the above code snippet, storage_container_name is the name of the database storage container you have configured, loaded into opc_names object.

2: Create the Database Instance

Here you can read more about the Oracle Database Service REST APIs. 

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def create_dbcs(scs):
scs.storage_container_name = opc_names[OPC_DBCS_SC_NAME]
scs.scs_create_storage_container()# create Database object
my_dbcs_instance_name = opc_names[OPC_DBCS_NAME]
my_sys_password = opc_names[OPC_DBCS_SYS_PASSWORD]
dbcs = Database(my_dbcs_instance_name, my_sys_password, scs.storage_container_name)# create Database Instance
dbcs.odbcs_create_instance()# check Database Provisioning statuswhile True:
status_code, status, response = dbcs.odbcs_check_status()
if status == "Running":# get the DB public IP
db_ip = extract_ip("dbaasmonitor_url", response)
dbcs.odbcs_set_ip(db_ip)# send email with detailsbreak
n_min = 1
time.sleep(n_min*60)
logger.debug(" ************** %s min later ************** \n" % str(n_min))return dbcs

In the above snippet code, the function odbcs_create_instance() calls the REST API for creating the Database Cloud Service instance. As you can notice from the API documentation and from the snippet code below, all the configuration parameters of the database are inserted into a json file which is  named dbcs_create_request_body.json. Here is an example of request body. You can configure such a template file as per your needs and when creating the database, just invoke the template file and overwrite the parameters that you most likely need to change from one deployment to another, as in the below function:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    def odbcs_create_instance(self):
url = (opc_properties[OPC_DBCS_URL] + "/%s") % opc_credentials[OPC_IDENTITY_DOMAIN]
logger.debug("url = %s" % url)
req_auth = (opc_credentials[OPC_USERNAME], opc_credentials[OPC_PASSWORD])
req_headers = {"X-ID-TENANT-NAME": opc_credentials[OPC_IDENTITY_DOMAIN], "Content-Type": "application/json"}
req_json = json.loads(open("opc_dbcs/dbcs_create_request_body.json").read()) font-style: italic"># pprint.pprint(req_json)for key in req_json:if key == "serviceName":
req_json[key] = self.dbcs_instance_nameelif key == "parameters":
new_list = req_json[key]
new_dict = new_list[0]for param_key in new_dict:if param_key == "adminPassword":
new_dict[param_key] = self.dbcs_sys_passwordelif param_key == "cloudStorageContainer":
new_dict[param_key] = "%s-%s/%s" % ("Storage", opc_credentials[OPC_IDENTITY_DOMAIN], self.dbcs_storage_container_name)elif param_key == "cloudStorageUser":
new_dict[param_key] = opc_credentials[OPC_USERNAME]elif param_key == "cloudStoragePwd":
new_dict[param_key] = opc_credentials[OPC_PASSWORD]# pprint.pprint(req_json)
response = requests.post(url, json=req_json, auth=req_auth, headers=req_headers)
print_response(response)

In the above code snippet, odbcs_check_status() returns the status of the created instance:

 1
2
3
4
5
6
7
8
9
10
11
12
13
    def odbcs_check_status(self):
url = (opc_properties[OPC_DBCS_URL] + "/%s/%s") % (opc_credentials[OPC_IDENTITY_DOMAIN], self.dbcs_instance_name)
req_headers = {'X-ID-TENANT-NAME': opc_credentials[OPC_IDENTITY_DOMAIN]}
req_auth = (opc_credentials[OPC_USERNAME], opc_credentials[OPC_PASSWORD])
response = requests.get(url, auth=req_auth, headers=req_headers)
print_response(response)
status_code = response.status_code
status = response.json().get('status')return status_code, status, response

3: Create the Java Storage Container

Repeat the flow described in Step 1 to create a Storage Container for the Java cloud Service, making sure you set the storage_container_name with the java one that you loaded into opc_names object 

4: Create the Java Cloud Service Instance  

Here you can read more about the Oracle Java Cloud Service REST APIs.

Similar to the database creation process, we will create one for Java Cloud Service now. The only difference would be that Database Cloud Service instance is a prerequisite along with the Storage Cloud Service for the Java Service Instance:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def create_jcs(dbcs, scs):# set the JCS storage container
scs.storage_container_name = opc_names[OPC_JCS_SC_NAME]print "JCS SC = %s" % scs.storage_container_name# create the JCS storage container
scs.scs_create_storage_container()# create JCS object
jcs = Java(dbcs, opc_names[OPC_JCS_NAME], opc_names[OPC_JCS_WL_USERNAME], opc_names[OPC_JCS_WL_PASSWORD], scs.storage_container_name)# create JCS Instance
jcs.create_jcs_instance()# check Java Provisioning statuswhile True:
status_code, status, response = jcs.jcs_check_status()if status == "Running":
time_duration = curr_time - jcs.start_provision_time# get the JCS VM public IP
jcs_ip = extract_ip("wls_admin_url", response)
jcs.jcs_set_admin_ip(jcs_ip)# get the JCS LB public IP
jcs_ip = extract_ip("otd_admin_url", response)
jcs.jcs_set_lb_ip(jcs_ip)# send email with detailsbreak
n_min = 1
time.sleep(n_min*60)
logger.debug(" ************** %s min later ************** \n" % str(n_min))

In the above code snippet, the function create_jcs_instance() calls the REST API for creating the Java Cloud Service Instance. Just as for the Database Cloud Service Instance, for Java Cloud Service Instance, you should create a request body in json format jcs_create_request_body.json, see here (see the Examples tab) a few such examples of configurations. Just as previously described in the Database Service Instance, when loading the template we will overwrite the parameters with the configurations that are most likely to be changed from one deployment to another, loaded into opc_names object.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    def create_jcs_instance(self):
url = (opc_properties[OPC_JCS_URL] + "/%s") % opc_credentials[OPC_IDENTITY_DOMAIN]
logger.debug("url = %s" % url)
req_auth = (opc_credentials[OPC_USERNAME], opc_credentials[OPC_PASSWORD])
req_headers = {"X-ID-TENANT-NAME": opc_credentials[OPC_IDENTITY_DOMAIN],"Content-Type": "application/vnd.com.oracle.oracloud.provisioning.Service+json"}
req_json = json.loads(open("opc_jcs/jcs_create_request_body.json").read())for key in req_json:if key == "serviceName":
req_json[key] = self.jcs_instance_nameelif key == "cloudStorageContainer":
req_json[key] = "%s-%s/%s" % ("Storage", opc_credentials[OPC_IDENTITY_DOMAIN], self.jcs_storage_container_name)elif key == "cloudStorageUser":
req_json[key] = opc_credentials[OPC_USERNAME]elif key == "cloudStoragePassword":
req_json[key] = opc_credentials[OPC_PASSWORD]elif key == "parameters":
jcs_parameters_list = req_json[key]if len(jcs_parameters_list) != 2:raise StandardError("jcs JSON parameters are different than 2 ( node Admin + LB) !")
node_admin_dict = jcs_parameters_list[0]
lb__dict = jcs_parameters_list[1]for param_key in node_admin_dict:if param_key == "adminUserName":
node_admin_dict[param_key] = self.weblogic_username
lb__dict[param_key] = self.weblogic_usernameelif param_key == "adminPassword":
node_admin_dict[param_key] = self.weblogic_password
lb__dict[param_key] = self.weblogic_passwordelif param_key == "nodeManagerPassword":
node_admin_dict[param_key] = self.weblogic_passwordelif param_key == "dbaPassword":
node_admin_dict[param_key] = self.dbcs.dbcs_sys_passwordelif param_key == "dbServiceName":
node_admin_dict[param_key] = self.dbcs.dbcs_instance_name
pprint.pprint(req_json)
response = requests.post(url, json=req_json, auth=req_auth, headers=req_headers)
print_response(response)

 In the above code snippet, jcs_check_status() will return the status of the Java Cloud Service Instance:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def jcs_check_status(self):
url = (opc_properties[OPC_JCS_URL] + "/%s/%s") % (opc_credentials[OPC_IDENTITY_DOMAIN], self.jcs_instance_name)
logger.debug("url = %s" % url)
req_headers = {'X-ID-TENANT-NAME': opc_credentials[OPC_IDENTITY_DOMAIN]}
req_auth = (opc_credentials[OPC_USERNAME], opc_credentials[OPC_PASSWORD])
response = requests.get(url, auth=req_auth, headers=req_headers)
print_response(response)
status_code = response.status_code
status = response.json().get('status')return status_code, status, response

5: Submit notifications of provisioning status

Here are some sample notifications:

As an example you can :

  • send email notifications with the status of the process 
  • on DB instance successfully created, trigger loading Database data and/or loading minimum metadata relevant for your product(s)
  • trigger other developer actions related to the Continuous Integration, Continuous Testing and Continuous Delivery process:
    • for example if Java instance was loaded successfully and DB data was loaded successfully you can trigger Selenium Tests
    • and so on

In this article you saw how using Python you can build a simple demo fully automated provisioning process using the REST APIs that are defined for each Oracle Public Cloud Service. 

 More information on:

  •  Oracle PaaS: here
  • Learning shortcuts for Database & Java Cloud Services: here

"Happy Clouding !" 

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha

Recent Content