diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index d52e0314f1..25fd59873f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog `_.
+====================
+2.2.8 - 2019-05-07
+====================
+
+Added
+-----
+* Support for the Tokyo (NRT) region
+* A sample demonstrating how to find, stop and report on instances that have been improperly tagged is available on `GitHub `__.
+* A sample demonstrating adding and deleting an API key is available on `GitHub `__.
+* New services to showoci.py on `GitHub `__.
+
+Fixed
+-----
+* Updated example for Streaming service to address issue with encoding in Python 3 is available on `GitHub `__.
+
====================
2.2.7 - 2019-04-16
====================
diff --git a/README.rst b/README.rst
index eede868e6b..065ab0d50a 100644
--- a/README.rst
+++ b/README.rst
@@ -79,7 +79,7 @@ Full documentation, including prerequisites and installation and configuration i
API reference can be found `here`__.
__ https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/index.html
-__ https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/index.html
+__ https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/landing.html
A downloadable version of the documentation is include with in the release zip, which can be found `here`__.
diff --git a/docs/api/announcements_service/models/oci.announcements_service.models.NotificationFollowupDetails.rst b/docs/api/announcements_service/models/oci.announcements_service.models.NotificationFollowupDetails.rst
deleted file mode 100644
index 299c8d7b98..0000000000
--- a/docs/api/announcements_service/models/oci.announcements_service.models.NotificationFollowupDetails.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-NotificationFollowupDetails
-===========================
-
-.. currentmodule:: oci.announcements_service.models
-
-.. autoclass:: NotificationFollowupDetails
- :show-inheritance:
- :special-members: __init__
- :members:
- :undoc-members:
- :inherited-members:
\ No newline at end of file
diff --git a/docs/api/index.rst b/docs/api/index.rst
index 24316b1cfc..2f4c9c56e1 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -1,811 +1,7 @@
-.. _api-reference:
-
-.. raw:: html
-
-
-
Single Page Reference
~~~~~~~~~~~~~~~~~~~~~~
+This page has been deprecated.
-=====================
-Announcements Service
-=====================
-
---------
- Client
---------
-
-.. autoclass:: oci.announcements_service.announcement_client.AnnouncementClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.announcements_service.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-=====
-Audit
-=====
-
---------
- Client
---------
-
-.. autoclass:: oci.audit.audit_client.AuditClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.audit.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-===========
-Autoscaling
-===========
-
---------
- Client
---------
-
-.. autoclass:: oci.autoscaling.auto_scaling_client.AutoScalingClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.autoscaling.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-======
-Budget
-======
-
---------
- Client
---------
-
-.. autoclass:: oci.budget.budget_client.BudgetClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.budget.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-================
-Container Engine
-================
-
---------
- Client
---------
-
-.. autoclass:: oci.container_engine.container_engine_client.ContainerEngineClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.container_engine.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-=============
-Core Services
-=============
-
----------
- Clients
----------
-
-
-Block Storage
-=============
-
-.. autoclass:: oci.core.blockstorage_client.BlockstorageClient
- :members:
- :noindex:
-
-
-Compute
-=======
-
-.. autoclass:: oci.core.compute_client.ComputeClient
- :members:
- :noindex:
-
-
-Compute Management
-==================
-
-.. autoclass:: oci.core.compute_management_client.ComputeManagementClient
- :members:
- :noindex:
-
-
-Virtual Network
-===============
-
-.. autoclass:: oci.core.virtual_network_client.VirtualNetworkClient
- :members:
- :noindex:
-
-
---------
- Models
---------
-
-.. automodule:: oci.core.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-========
-Database
-========
-
---------
- Client
---------
-
-.. autoclass:: oci.database.database_client.DatabaseClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.database.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-===
-DNS
-===
-
---------
- Client
---------
-
-.. autoclass:: oci.dns.dns_client.DnsClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.dns.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-=====
-Email
-=====
-
---------
- Client
---------
-
-.. autoclass:: oci.email.email_client.EmailClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.email.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-============
-File Storage
-============
-
---------
- Client
---------
-
-.. autoclass:: oci.file_storage.file_storage_client.FileStorageClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.file_storage.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-============
-Healthchecks
-============
-
---------
- Client
---------
-
-.. autoclass:: oci.healthchecks.health_checks_client.HealthChecksClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.healthchecks.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-========
-Identity
-========
-
---------
- Client
---------
-
-.. autoclass:: oci.identity.identity_client.IdentityClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.identity.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-==============
-Key Management
-==============
-
----------
- Clients
----------
-
-
-Kms Crypto
-==========
-
-.. autoclass:: oci.key_management.kms_crypto_client.KmsCryptoClient
- :members:
- :noindex:
-
-
-Kms Management
-==============
-
-.. autoclass:: oci.key_management.kms_management_client.KmsManagementClient
- :members:
- :noindex:
-
-
-Kms Vault
-=========
-
-.. autoclass:: oci.key_management.kms_vault_client.KmsVaultClient
- :members:
- :noindex:
-
-
---------
- Models
---------
-
-.. automodule:: oci.key_management.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-=============
-Load Balancer
-=============
-
---------
- Client
---------
-
-.. autoclass:: oci.load_balancer.load_balancer_client.LoadBalancerClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.load_balancer.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-==========
-Monitoring
-==========
-
---------
- Client
---------
-
-.. autoclass:: oci.monitoring.monitoring_client.MonitoringClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.monitoring.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-==============
-Object Storage
-==============
-
---------
- Client
---------
-
-.. autoclass:: oci.object_storage.object_storage_client.ObjectStorageClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.object_storage.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-===
-Ons
-===
-
----------
- Clients
----------
-
-
-Notification Control Plane
-==========================
-
-.. autoclass:: oci.ons.notification_control_plane_client.NotificationControlPlaneClient
- :members:
- :noindex:
-
-
-Notification Data Plane
-=======================
-
-.. autoclass:: oci.ons.notification_data_plane_client.NotificationDataPlaneClient
- :members:
- :noindex:
-
-
---------
- Models
---------
-
-.. automodule:: oci.ons.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-================
-Resource Manager
-================
-
---------
- Client
---------
-
-.. autoclass:: oci.resource_manager.resource_manager_client.ResourceManagerClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.resource_manager.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-===============
-Resource Search
-===============
-
---------
- Client
---------
-
-.. autoclass:: oci.resource_search.resource_search_client.ResourceSearchClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.resource_search.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-=========
-Streaming
-=========
-
----------
- Clients
----------
-
-
-Stream Admin
-============
-
-.. autoclass:: oci.streaming.stream_admin_client.StreamAdminClient
- :members:
- :noindex:
-
-
-Stream
-======
-
-.. autoclass:: oci.streaming.stream_client.StreamClient
- :members:
- :noindex:
-
-
---------
- Models
---------
-
-.. automodule:: oci.streaming.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-====
-Waas
-====
-
---------
- Client
---------
-
-.. autoclass:: oci.waas.waas_client.WaasClient
- :members:
- :noindex:
-
---------
- Models
---------
-
-.. automodule:: oci.waas.models
- :special-members: __init__
- :members:
- :undoc-members:
- :imported-members:
- :inherited-members:
- :noindex:
-
-
-================
- Upload Manager
-================
-
-.. module:: oci.object_storage
- :noindex:
-
-.. autoclass:: UploadManager
- :special-members: __init__
- :members:
- :noindex:
-
-=============
- Base Client
-=============
-
-.. module:: oci.base_client
-
-.. autoclass:: BaseClient
- :members: call_api, request
-
-========
- Config
-========
-
-.. module:: oci.config
- :noindex:
-
-.. autofunction:: from_file
- :noindex:
-
-.. autofunction:: validate_config
- :noindex:
-
-.. module:: oci.regions
- :noindex:
-
-.. autofunction:: is_region
- :noindex:
-
-.. autofunction:: endpoint_for
- :noindex:
-
-
-============
- Exceptions
-============
-
-.. automodule:: oci.exceptions
- :members:
- :noindex:
-
-=========
- Signing
-=========
-
-.. module:: oci.signer
- :noindex:
-
-.. autofunction:: load_private_key_from_file
- :noindex:
-
-.. autofunction:: load_private_key
- :noindex:
-
-.. autoclass:: Signer
- :noindex:
-
-=====================
- Additional Signers
-=====================
-
-.. module:: oci.auth.signers
- :noindex:
-
-.. autoclass:: SecurityTokenSigner
- :special-members: __init__
- :members:
- :noindex:
-
-.. autoclass:: X509FederationClientBasedSecurityTokenSigner
- :special-members: __init__
- :members:
- :noindex:
-
-.. autoclass:: InstancePrincipalsSecurityTokenSigner
- :special-members: __init__
- :members:
- :noindex:
-
-============================
-X509 Certificate Retrievers
-============================
-
-.. module:: oci.auth.certificate_retriever
- :noindex:
-
-.. autoclass:: UrlBasedCertificateRetriever
- :special-members: __init__
- :members:
- :noindex:
-
-.. autoclass:: PEMStringCertificateRetriever
- :special-members: __init__
- :members:
- :noindex:
-
-.. autoclass:: FileBasedCertificateRetriever
- :special-members: __init__
- :members:
- :noindex:
-
-====================================
-X509 Certificate Federation Client
-====================================
-
-.. module:: oci.auth.federation_client
- :noindex:
-
-.. autoclass:: X509FederationClient
- :special-members: __init__
- :members:
- :noindex:
-
-.. module:: oci.auth.session_key_supplier
- :noindex:
-
-.. autoclass:: SessionKeySupplier
- :special-members: __init__
- :members:
- :noindex:
-
-===========
- Utilities
-===========
-
-.. module:: oci.util
- :noindex:
-
-.. autofunction:: to_dict
- :noindex:
-
-.. autoclass:: Sentinel
- :noindex:
-
-===========
- Waiters
-===========
-
-.. module:: oci
- :noindex:
-
-.. autofunction:: wait_until
- :noindex:
-
-===========
- Pagination
-===========
-
-.. module:: oci.pagination
- :noindex:
-
-.. autofunction:: list_call_get_all_results
- :noindex:
-
-.. autofunction:: list_call_get_up_to_limit
- :noindex:
-
-.. autofunction:: list_call_get_all_results_generator
- :noindex:
-
-.. autofunction:: list_call_get_up_to_limit_generator
- :noindex:
-
-=========
-Request
-=========
-.. module:: oci.request
- :noindex:
-
-.. autoclass:: Request
- :members:
- :undoc-members:
- :noindex:
-
-=========
-Response
-=========
-.. module:: oci.response
- :noindex:
-
-.. autoclass:: Response
- :members:
- :undoc-members:
- :noindex:
\ No newline at end of file
+* :doc:`Home <../index>`
+* :doc:`API Reference `
\ No newline at end of file
diff --git a/docs/api/landing.rst b/docs/api/landing.rst
index cf8d5db254..487ec5b4f7 100644
--- a/docs/api/landing.rst
+++ b/docs/api/landing.rst
@@ -44,9 +44,6 @@ API Reference
* :doc:`Utilities `
* :doc:`Waiters `
-.. rubric:: Single Page Reference
-
-* :doc:`Single Page Reference `
.. toctree::
:hidden:
@@ -82,4 +79,3 @@ API Reference
upload_manager
utilities
waiters
- index
\ No newline at end of file
diff --git a/examples/add_API_key.py b/examples/add_API_key.py
new file mode 100644
index 0000000000..325ab91ab6
--- /dev/null
+++ b/examples/add_API_key.py
@@ -0,0 +1,118 @@
+import oci
+import sys
+import os.path
+from hashlib import md5
+from codecs import decode
+from time import sleep
+
+
+# This script provides a basic example of how to upload and delete an API key
+# using the Python SDK.
+#
+# This script accepts one argument:
+#
+# * The path to the public API key to upload.
+#
+# The script relies on having a config file for the other variables.
+# More information on the config file can be found here:
+# https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm
+#
+# Note, you must already have an API key associated with your user to call the
+# APIs so this example shows you how to add a second key, or you could create
+# a new user and use the steps here to upload a key to that user.
+#
+# More information on Keys and API Signing can be found here:
+# https://docs.cloud.oracle.com/iaas/Content/API/Concepts/apisigningkey.htm
+#
+
+
+def get_fingerprint(key):
+
+ # There should be more error checking here, but to keep the example simple
+ # the error checking has been omitted.
+ m = md5()
+
+ # Strip out the parts of the key that are not used in the fingerprint
+ # computation.
+ key = key.replace(b'-----BEGIN PUBLIC KEY-----\n', b'')
+ key = key.replace(b'\n-----END PUBLIC KEY-----', b'')
+
+ # The key is base64 encoded and needs to be decoded before getting the md5
+ # hash
+ decoded_key = decode(key, "base64")
+ m.update(decoded_key)
+ hash = m.hexdigest()
+
+ # Break the hash into 2 character parts.
+ length = 2
+ parts = list(hash[0 + i:length + i] for i in range(0, len(hash), length))
+
+ # Join the parts with a colon seperator
+ fingerprint = ":".join(parts)
+
+ return fingerprint
+
+
+def is_key_already_uploaded(keys, fingerprint):
+ for key in keys:
+ if key.fingerprint == fingerprint:
+ return True
+
+ return False
+
+
+# Check there are enough arguments
+if len(sys.argv) != 2:
+ raise RuntimeError('This script expects an argument of a path to the public API key')
+
+# Verify the path to the public key exists
+public_key_path = sys.argv[1]
+if not os.path.exists(public_key_path):
+ raise RuntimeError('This argument must be a valid path to a public API key')
+
+# Open the key file and store the contents
+with open(public_key_path, 'rb') as f:
+ public_key = f.read().strip()
+
+# Get the fingerprint for the key
+fingerprint = get_fingerprint(public_key)
+print("Fingerprint of API key: {}".format(fingerprint))
+
+# Read the config file and initialize the identity client
+config = oci.config.from_file()
+identity = oci.identity.IdentityClient(config)
+
+# Check to see if this key is already associated with the user.
+if is_key_already_uploaded(identity.list_api_keys(config['user']).data, fingerprint):
+ print("Key with fingerprint {} has already been added to user".format(fingerprint))
+ sys.exit()
+
+# Initialize the CreateApiKeyDetails model
+key_details = oci.identity.models.CreateApiKeyDetails(key=public_key.decode())
+
+# Upload the key
+response = identity.upload_api_key(config['user'], key_details)
+
+# Results of uploading key
+print("Results of uploading key")
+print(response.data)
+
+# Check to see if the key is in the list of keys.
+# This is pretty crude and just checks that the fingerprint is in the list
+# of keys. If you want to do something similar you should also check that
+# the lifecycle_state is "ACTIVE"
+while True:
+ if is_key_already_uploaded(identity.list_api_keys(config['user']).data, fingerprint):
+ print("Sucessfully uploaded API key {}".format(public_key_path))
+ break
+ sleep(2)
+
+# Delete key and wait a bit.
+identity.delete_api_key(config['user'], fingerprint)
+sleep(2)
+
+# Verify the key has been deleted.
+if not is_key_already_uploaded(identity.list_api_keys(config['user']).data, fingerprint):
+ print("Deleted uploaded API key.")
+else:
+ print("Failed to delete uploaded API key.")
diff --git a/examples/showoci/CHANGELOG.rst b/examples/showoci/CHANGELOG.rst
index c725a34b9f..390f15fa7a 100644
--- a/examples/showoci/CHANGELOG.rst
+++ b/examples/showoci/CHANGELOG.rst
@@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog `_.
+====================
+19.4.23 - 2019-04-23
+====================
+
+Added
+-----
+* Added Autonomous Database Whitelist IPs
+* Added Identity - Cost Tracking Tags
+* Added Budgets
+* Added Compute Autoscaling
+* Add OS Version to the compute summary
+* Add Reboot migration alert
+
+Fixed / Changed
+---------------
+* Display Volume Backups with 1 line instead of 3 lines
+* Fix load balancer pathroute error when output to JSON
+
====================
19.4.14 - 2019-04-14
====================
diff --git a/examples/showoci/README.md b/examples/showoci/README.md
index 1db2aa0d30..1856206d72 100644
--- a/examples/showoci/README.md
+++ b/examples/showoci/README.md
@@ -15,7 +15,8 @@ Modules Included:
- oci.email.EmailClient
- oci.container_engine.ContainerEngineClient
- oci.streaming.StreamAdminClient
-
+- oci.budget.BudgetClient
+- oci.autoscaling.AutoScalingClient
## OCI User Requirement
Required OCI IAM user with read only privileges:
@@ -44,7 +45,8 @@ pip3 install oci oci-cli
### Installation on OCI VM with Oracle Cloud Developer Image
```
-All Installed, just run the config below
+Default is python 2.7 , please run as below:
+python showoci.py
```
### Installation on OCI VM with Oracle Linux 7
@@ -110,8 +112,8 @@ Execute
```
$ ./showoci.py
-usage: showoci [-h] [-a] [-ani] [-n] [-i] [-c] [-cn] [-o] [-l] [-d] [-f] [-e]
- [-s] [-rm] [-so] [-mc] [-nr] [-t PROFILE] [-p PROXY]
+usage: showoci [-h] [-a] [-ani] [-b] [-n] [-i] [-c] [-cn] [-o] [-l] [-d] [-f]
+ [-e] [-s] [-rm] [-so] [-mc] [-nr] [-t PROFILE] [-p PROXY]
[-rg REGION] [-cp COMPART] [-cf CONFIG] [-jf JOUTFILE] [-js]
[-cachef SERVICEFILE] [-caches] [--version]
@@ -119,6 +121,7 @@ optional arguments:
-h, --help show this help message and exit
-a Print All Resources
-ani Print All Resources but identity
+ -b Print Budgets
-n Print Network
-i Print Identity
-c Print Compute
@@ -144,7 +147,6 @@ optional arguments:
-caches Output Cache to screen (JSON format)
--version show program's version number and exit
-
```
## Below example of reports from few tenancies
@@ -333,6 +335,24 @@ Compartment gse00000000 (root):
Group Map :DemoUsers <-> demousers
Group Map :OCI_Administrators <-> Administrators
+##############################
+# Cost Tracking Tags #
+##############################
+--> Project.Billing
+ Desc :Billing Cost
+ Created :2019-04-03 12:38
+
+##############################
+# Budgets #
+##############################
+--> DemoBudget for Compartment: Demo (MONTHLY)
+ Costs : Spent: 0.0, Forcasted: 0.0 , Time Computed: 2019-04-17 17:45
+ Created : 2019-04-17 15:57, Total Alert Rules: 0
+
+--> BudgetForAdiCompartment for Compartment: Adi (MONTHLY)
+ Costs : Spent: 0.0, Forcasted: 0.0 , Time Computed: 2019-04-17 17:45
+ Created : 2019-04-17 13:29, Total Alert Rules: 2
+
##########################################################################################
# Region us-ashburn-1 #
##########################################################################################
@@ -488,6 +508,16 @@ Compartment gse00000000 (root):
ADs : fHBa:US-ASHBURN-AD-3, fHBa:US-ASHBURN-AD-2
Config: AdiInstanceConfig - VM.Standard2.1
+##############################
+# Compute Autoscaling #
+##############################
+--> AutoScallingConfig (ENABLED)
+ Resource : instancePool: Adi-Instance-Pool
+ Policy : auto-scaling-policy-20190417-1627 (threshold)
+ Capacity : Initial = 1, Min = 1, Max = 2
+ Rule : CHANGE_COUNT_BY -1 when CPU_UTILIZATION LT 20
+ Rule : CHANGE_COUNT_BY 1 when CPU_UTILIZATION GT 80
+
##############################
# Compute Custom Images #
##############################
@@ -502,22 +532,17 @@ Compartment gse00000000 (root):
##############################
# Boot Volume Backups #
##############################
---> demohost (Boot Volume), - Auto-backup for 2018-08-01 04:00:00 via policy: bronze
- Type : INCREMENTAL, SCHEDULED, 2018-08-01 16:27 -> 2019-08-01 23:07
- Size : 47gb , Stored 1gb
---> demohost (Boot Volume), - Auto-backup for 2018-09-01 04:00:00 via policy: bronze
- Type : INCREMENTAL, SCHEDULED, 2018-09-01 07:50 -> 2019-09-01 14:30
- Size : 47gb , Stored 1gb
+--> demohost (Boot Volume), 47gb , Stored 1gb, AUTO (bronze), INCR, SCHEDU, 2018-08-01 16:27 -> 2019-08-01 23:07
+--> demohost (Boot Volume), 47gb , Stored 1gb, AUTO (bronze), INCR, SCHEDU, 2018-09-01 07:50 -> 2019-09-01 14:30
+--> demohost (Boot Volume), 47gb , Stored 1gb, AUTO (bronze), INCR, SCHEDU, 2018-10-01 09:02 -> 2019-10-01 15:42
##############################
# Block Volume Backups #
##############################
---> Adi_50G ( Source TERMINATED ) - Adi_Backup_50G
- Type : FULL, MANUAL, 2018-10-22 02:52 -> Keep
- Size : 50gb , Stored 1gb
---> Adi_50G ( Source TERMINATED ) - Auto-backup for 2018-11-01 04:00:00 via policy: bronze
- Type : INCREMENTAL, SCHEDULED, 2018-11-01 04:40 -> 2019-11-01 11:20
- Size : 50gb , Stored 1gb
+--> Adi_50G (Source TERMINATED), 50gb , Stored 1gb, Adi_Backup_50G, FULL, MANUAL, 2018-10-22 02:52 -> Keep
+--> Adi_50G (Source TERMINATED), 50gb , Stored 1gb, AUTO (bronze), INCR, SCHEDU, 2018-11-01 04:40 -> 2019-11-01 11:20
+--> Adi_50G (Source TERMINATED), 50gb , Stored 1gb, AUTO (bronze), INCR, SCHEDU, 2018-12-01 05:53 -> 2019-12-01 12:33
+--> Adi_50G (Source TERMINATED), 50gb , Stored 1gb, AUTO (bronze), FULL, SCHEDU, 2019-01-01 06:23 -> 2023-12-31 06:23
##############################
# Databases #
@@ -678,53 +703,52 @@ Compartment gse00000000 (root):
###########################################################################
# Summary - Compartment generic #
###########################################################################
-Compute - Block Storage (gb) - 3547
-Compute - VM.Standard1.1 - 1
-Compute - VM.Standard2.1 - 7
-Compute - VM.Standard2.4 - 1
-Object Storage - BV Backups (gb) - 1276
-Object Storage - Buckets (gb) - 216
+Compute - Block Storage (gb) - 3547
+Compute - Oracle Linux - VM.Standard1.1 - 1
+Compute - Oracle Linux - VM.Standard2.1 - 7
+Compute - Oracle Linux - VM.Standard2.4 - 1
+Object Storage - BV Backups (gb) - 1276
+Object Storage - Buckets (gb) - 216
###########################################################################
# Summary - Compartment npdb #
###########################################################################
-Database - Exadata.Half2.184 - 1
-Object Storage - Buckets (gb) - 6152
+Database - Exadata.Half2.184 - 1
+Object Storage - Buckets (gb) - 6152
###########################################################################
# Summary - Compartment npebs #
###########################################################################
-Compute - Block Storage (gb) - 14121
-Compute - VM.Standard2.1 - 16
-Compute - VM.Standard2.2 - 28
-Compute - VM.Standard2.4 - 6
-Compute - VM.Standard2.8 - 5
-File Storage (gb) - 2617
-Load Balancer 100Mbps - 10
-Object Storage - BV Backups (gb) - 2806
-Object Storage - Images (gb) - 1862
+Compute - Block Storage (gb) - 14121
+Compute - Oracle Linux - VM.Standard2.1 - 16
+Compute - Oracle Linux - VM.Standard2.4 - 6
+Compute - Oracle Linux - VM.Standard2.8 - 5
+Compute - Windows - VM.Standard2.2 - 28
+File Storage (gb) - 2617
+Load Balancer 100Mbps - 10
+Object Storage - BV Backups (gb) - 2806
+Object Storage - Images (gb) - 1862
##########################################################################################
# Summary Total #
##########################################################################################
-Compute - Block Storage (gb) - 17668
-Compute - VM.Standard1.1 - 1
-Compute - VM.Standard2.1 - 23
-Compute - VM.Standard2.2 - 28
-Compute - VM.Standard2.4 - 7
-Compute - VM.Standard2.8 - 5
-Database - Exadata.Half2.184 - 1
-File Storage (gb) - 2617
-Load Balancer 100Mbps - 10
-Object Storage - BV Backups (gb) - 4082
-Object Storage - Buckets (gb) - 6368
-Object Storage - Images (gb) - 1862
+Compute - Block Storage (gb) - 17668
+Compute - Oracle Linux - VM.Standard1.1 - 1
+Compute - Oracle Linux - VM.Standard2.1 - 23
+Compute - Oracle Linux - VM.Standard2.4 - 7
+Compute - Oracle Linux - VM.Standard2.8 - 5
+Compute - Windows - VM.Standard2.2 - 28
+Database - Exadata.Half2.184 - 1
+File Storage (gb) - 2617
+Load Balancer 100Mbps - 10
+Object Storage - BV Backups (gb) - 4082
+Object Storage - Buckets (gb) - 6368
+Object Storage - Images (gb) - 1862
```
## Below example JSON report on us-ashburn-1 region, compartment Adi without identity
```
-
> showoci -t gse00015259 -ani -js -rg us-ashburn-1 -cp Adi
############################################################
@@ -1399,4 +1423,4 @@ Processing...
# Completed Successfully at 2019-04-05 08:15:16 #
##########################################################################################
-```
\ No newline at end of file
+```
diff --git a/examples/showoci/showoci.py b/examples/showoci/showoci.py
index 447b31aae3..68ddc73e2f 100644
--- a/examples/showoci/showoci.py
+++ b/examples/showoci/showoci.py
@@ -3,12 +3,10 @@
# Copyright(c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
# showoci.py
#
-# @Created On : Mar 17 2019
-# @Last Updated: Apr 14 2019
-# @author : Adi Zohar
-# @Version : 19.4.14
+# @author: Adi Zohar
#
# Supports Python 2.7 and above, Python 3 recommended
+# With Python 2, execute using - python showoci.py
#
# coding: utf-8
##########################################################################
@@ -30,19 +28,28 @@
##########################################################################
#
# Modules Included:
-# identity , virtual_network, compute , block_storage, file_storage
-# object_storage, database, load_balancer, email
-# resource_management, ContainerEngine, Streams
+# - oci.core.VirtualNetworkClient
+# - oci.core.ComputeClient
+# - oci.core.ComputeManagementClient
+# - oci.core.BlockstorageClient
+# - oci.file_storage.FileStorageClient
+# - oci.object_storage.ObjectStorageClient
+# - oci.database.DatabaseClient
+# - oci.identity.IdentityClient
+# - oci.load_balancer.LoadBalancerClient
+# - oci.email.EmailClient
+# - oci.container_engine.ContainerEngineClient
+# - oci.streaming.StreamAdminClient
+# - oci.budget.BudgetClient
+# - oci.autoscaling.AutoScalingClient
#
# Modules Not Yet Covered:
-# Monitoring
-# Notifications
-# WaasClient
-# HealthChecksClient
-# DnsClient
-# BudgetClient
-# AutoScalingClient
-# AnnouncementClient
+# - oci.ons.NotificationDataPlaneClient
+# - oci.waas.WaasClient
+# - oci.monitoring.MonitoringClient
+# - oci.healthchecks.HealthChecksClient
+# - oci.dns.DnsClient
+# - oci.announcements_service.AnnouncementClient
#
##########################################################################
from __future__ import print_function
@@ -54,7 +61,7 @@
import argparse
import datetime
-version = "19.4.14"
+version = "19.4.23"
##########################################################################
# execute_extract
@@ -150,6 +157,10 @@ def execute_extract():
############################################
complete_message = return_error_message(data.get_service_errors(), data.get_service_warnings(), data.error)
+ # if reboot migration
+ if data.get_service_reboot_migration() > 0:
+ output.print_header(str(data.get_service_reboot_migration()) + " Reboot Migration Alert for Compute", 0)
+
# print completion
output.print_header("Completed " + complete_message + " at " + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")), 0)
@@ -182,6 +193,7 @@ def set_parser_arguments():
parser = argparse.ArgumentParser()
parser.add_argument('-a', action='store_true', default=False, dest='all', help='Print All Resources')
parser.add_argument('-ani', action='store_true', default=False, dest='allnoiam', help='Print All Resources but identity')
+ parser.add_argument('-b', action='store_true', default=False, dest='budgets', help='Print Budgets')
parser.add_argument('-n', action='store_true', default=False, dest='network', help='Print Network')
parser.add_argument('-i', action='store_true', default=False, dest='identity', help='Print Identity')
parser.add_argument('-c', action='store_true', default=False, dest='compute', help='Print Compute')
@@ -216,7 +228,7 @@ def set_parser_arguments():
if not (result.all or result.allnoiam or result.network or result.identity or
result.compute or result.object or
result.load or result.database or result.file or result.email or result.orm or result.container or
- result.streams):
+ result.streams or result.budgets):
parser.print_help()
@@ -276,6 +288,9 @@ def set_service_extract_flags(cmd):
if cmd.all or cmd.allnoiam or cmd.streams:
prm.read_streams = True
+ if cmd.all or cmd.allnoiam or cmd.budgets:
+ prm.read_budgets = True
+
if cmd.noroot:
prm.read_root_compartment = False
diff --git a/examples/showoci/showoci_data.py b/examples/showoci/showoci_data.py
index 145c0dc007..c9146d4efd 100755
--- a/examples/showoci/showoci_data.py
+++ b/examples/showoci/showoci_data.py
@@ -1,11 +1,8 @@
##########################################################################
# Copyright(c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
-# showocy_data.py
+# showoci_data.py
#
-# @Created On : Mar 17 2019
-# @Last Updated: Apr 14 2019
-# @author : Adi Zohar
-# @Version : 19.4.14
+# @author: Adi Zohar
#
# Supports Python 2.7 and above, Python 3 recommended
#
@@ -67,6 +64,12 @@ def process_oci_data(self):
identity_data = {'type': "identity", 'data': self.service.get_identity()}
self.data.append(identity_data)
+ # run on budgets module
+ if self.service.flags.read_budgets:
+ budgets_data = {'type': "budgets", 'data': self.service.get_budgets()}
+ self.data.append(budgets_data)
+
+ # run on compartments
if self.service.flags.is_loop_on_compartments:
# pointer to Tenancy in cache
@@ -128,6 +131,13 @@ def get_service_warnings(self):
return self.service.warning
+ ##########################################################################
+ # get service reboot migration
+ ##########################################################################
+ def get_service_reboot_migration(self):
+
+ return self.service.reboot_migration_counter
+
##########################################################################
# print print error
##########################################################################
@@ -983,28 +993,29 @@ def __get_core_block_volume(self, volume_id, compartment_name):
self.__print_error("__get_core_block_volume", e)
##########################################################################
- # get compute boot volume
+ # get compute boot volume or volume
##########################################################################
- def __get_core_block_volume_boot_backup(self, region_name, compartment):
+ def __get_core_block_volume_boot_backup(self, region_name, compartment, volume_name, service_name):
data = []
try:
- backups = self.service.search_multi_items(self.service.C_BLOCK, self.service.C_BLOCK_BOOTBACK, 'region_name', region_name, 'compartment_id', compartment['id'])
+ backups = self.service.search_multi_items(self.service.C_BLOCK, service_name, 'region_name', region_name, 'compartment_id', compartment['id'])
for backup in backups:
value = {}
if backup['backup_lifecycle_state'] != "AVAILABLE":
- value['name'] = backup['backup_name'] + " ( Source " + backup['backup_lifecycle_state'] + " )"
+ value['name'] = backup['backup_name'] + " (Source " + backup['backup_lifecycle_state'] + ")"
else:
- value['name'] = backup['backup_name'] + ", "
+ value['name'] = backup['backup_name']
value['desc'] = backup['display_name']
- value['type'] = backup['type'] + ", " + backup['source_type'] + ", " + backup['time_created'][0:16] + " -> " + backup['expiration_time'][0:16]
- value['size'] = (str(backup['size_in_gbs']) + "gb " + ", Stored " + str(backup['unique_size_in_gbs']) + "gb")
+ value['type'] = backup['type'][0:4] + ", " + backup['source_type'][0:6] + ", " + backup['time_created'][0:16] + " -> " + backup['expiration_time'][0:16]
+ value['size'] = (str(backup['size_in_gbs']).rjust(3) + "gb " + ", Stored " + str(backup['unique_size_in_gbs']).rjust(3) + "gb")
value['sum_info'] = 'Object Storage - BV Backups (gb)'
value['sum_size_gb'] = (str(backup['unique_size_in_gbs']))
- value['boot_volume_id'] = str(backup['boot_volume_id'])
+ value[volume_name] = str(backup[volume_name])
+ value['id'] = str(backup[volume_name])
data.append(value)
@@ -1013,7 +1024,7 @@ def __get_core_block_volume_boot_backup(self, region_name, compartment):
return data
except Exception as e:
- self.__print_error("__get_core_compute_images", e)
+ self.__print_error("__get_core_block_volume_boot_backup", e)
return data
##########################################################################
@@ -1137,39 +1148,6 @@ def __get_core_block_volume_groups(self, region_name, compartment):
self.__print_error("__get_core_block_volume_groups", e)
return data
- ##########################################################################
- # get compute boot volume
- ##########################################################################
- def __get_core_block_volume_backup(self, region_name, compartment):
-
- data = []
- try:
- backups = self.service.search_multi_items(self.service.C_BLOCK, self.service.C_BLOCK_VOLBACK, 'region_name', region_name, 'compartment_id', compartment['id'])
-
- for backup in backups:
- value = {}
-
- if backup['backup_lifecycle_state'] != "AVAILABLE":
- value['name'] = backup['backup_name'] + " ( Source " + backup['backup_lifecycle_state'] + " )"
- else:
- value['name'] = backup['backup_name']
- value['desc'] = backup['display_name']
- value['type'] = backup['type'] + ", " + backup['source_type'] + ", " + backup['time_created'][0:16] + " -> " + backup['expiration_time'][0:16]
- value['size'] = (str(backup['size_in_gbs']) + "gb " + ", Stored " + str(backup['unique_size_in_gbs']) + "gb")
- value['sum_info'] = 'Object Storage - BV Backups (gb)'
- value['sum_size_gb'] = (str(backup['unique_size_in_gbs']))
- value['volume_id'] = str(backup['volume_id'])
-
- data.append(value)
-
- if len(data) > 0:
- return sorted(data, key=lambda k: k['name'])
- return data
-
- except Exception as e:
- self.__print_error("__get_core_block_volume_block_backup", e)
- return data
-
##########################################################################
# print compute instances
##########################################################################
@@ -1181,11 +1159,12 @@ def __get_core_compute_instances(self, region_name, compartment):
for instance in instances:
inst = {'id': instance['id'], 'name': instance['shape'] + " - " + instance['display_name'] + " - " + instance['lifecycle_state'],
- 'sum_info': 'Compute', 'sum_shape': instance['shape'],
+ 'sum_info': 'Compute', 'sum_shape': instance['image_os'][0:14] + " - " + instance['shape'],
'availability_domain': instance['availability_domain'],
'fault_domain': instance['fault_domain'],
'time_maintenance_reboot_due': str(instance['time_maintenance_reboot_due']),
'image': instance['image'], 'image_id': instance['image_id'],
+ 'image_os': instance['image_os'],
'console_id': instance['console_id'], 'console': instance['console'],
'time_created': instance['time_created'],
'defined_tags': instance['defined_tags'], 'freeform_tags': instance['freeform_tags']}
@@ -1250,8 +1229,8 @@ def __get_core_compute_images(self, region_name, compartment):
for image in images:
value = {'id': image['id'],
- 'desc': image['display_name'] + " - " + image['operating_system'] + " - " + image[
- 'size_in_gbs'] + "gb - Base: " + image['base_image_name'],
+ 'desc': image['display_name'].ljust(24) + " - " + image['operating_system'] + " - " + image[
+ 'size_in_gbs'].rjust(3) + "gb - Base: " + image['base_image_name'],
'sum_info': 'Object Storage - Images (gb)', 'sum_size_gb': image['size_in_gbs'],
'time_created': image['time_created'],
'defined_tags': image['defined_tags'], 'freeform_tags': image['freeform_tags']}
@@ -1317,6 +1296,35 @@ def __get_core_compute_instance_pool(self, region_name, compartment):
self.__print_error("__get_core_compute_instance_pool", e)
return data
+ ##########################################################################
+ # get compute autoscaling
+ ##########################################################################
+ def __get_core_compute_autoscaling(self, region_name, compartment):
+
+ data = []
+ try:
+
+ autos = self.service.search_multi_items(self.service.C_COMPUTE, self.service.C_COMPUTE_AUTOSCALING, 'region_name', region_name, 'compartment_id', compartment['id'])
+
+ for auto in autos:
+ value = {'id': auto['id'],
+ 'name': str(auto['display_name']) + " (" + ("ENABLED" if auto['is_enabled'] else "DISABLED") + ")",
+ 'time_created': auto['time_created'],
+ 'compartment_name': auto['compartment_name'],
+ 'compartment_id': auto['compartment_id'],
+ 'resource_id': auto['resource_id'],
+ 'resource_name': auto['resource_name'],
+ 'resource_type': auto['resource_type'],
+ 'policies': auto['policies']
+ }
+ data.append(value)
+
+ return data
+
+ except Exception as e:
+ self.__print_error("__get_core_compute_autoscaling", e)
+ return data
+
##########################################################################
# Compute
##########################################################################
@@ -1345,6 +1353,10 @@ def __get_core_compute_main(self, region_name, compartment):
if len(data) > 0:
return_data['instance_pool'] = data
+ data = self.__get_core_compute_autoscaling(region_name, compartment)
+ if len(data) > 0:
+ return_data['autoscaling'] = data
+
data = self.__get_core_block_volume_groups(region_name, compartment)
if len(data) > 0:
return_data['volume_groups'] = data
@@ -1357,11 +1369,11 @@ def __get_core_compute_main(self, region_name, compartment):
if len(data) > 0:
return_data['volume_not_attached'] = data
- data = self.__get_core_block_volume_boot_backup(region_name, compartment)
+ data = self.__get_core_block_volume_boot_backup(region_name, compartment, 'boot_volume_id', self.service.C_BLOCK_BOOTBACK)
if len(data) > 0:
return_data['boot_volume_backup'] = data
- data = self.__get_core_block_volume_backup(region_name, compartment)
+ data = self.__get_core_block_volume_boot_backup(region_name, compartment, 'volume_id', self.service.C_BLOCK_VOLBACK)
if len(data) > 0:
return_data['volume_backup'] = data
@@ -1606,6 +1618,7 @@ def __get_database_autonomous_databases(self, region_name, compartment):
'connection_strings': str(dbs['connection_strings']), 'sum_info': "Autonomous Database (OCPUs) - " + dbs['license_model'],
'sum_count': str(dbs['sum_count']), 'sum_info_storage': "Autonomous Database (tb)",
'sum_size_tb': str(dbs['data_storage_size_in_tbs']), 'backups': self.__get_database_autonomous_backups(dbs['backups']),
+ 'whitelisted_ips': dbs['whitelisted_ips'],
'defined_tags': dbs['defined_tags'], 'freeform_tags': dbs['freeform_tags']}
data.append(value)
diff --git a/examples/showoci/showoci_output.py b/examples/showoci/showoci_output.py
index 20239e130e..23d85ebc7c 100755
--- a/examples/showoci/showoci_output.py
+++ b/examples/showoci/showoci_output.py
@@ -1,11 +1,8 @@
##########################################################################
# Copyright(c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
-# showocy_output.py
+# showoci_output.py
#
-# @Created On : Mar 17 2019
-# @Last Updated: Apr 14 2019
-# @author : Adi Zohar
-# @Version : 19.4.14
+# @author: Adi Zohar
#
# Supports Python 2.7 and above, Python 3 recommended
#
@@ -60,6 +57,10 @@ def print_data(self, data, print_version=False):
self.__print_identity_main(d['data'])
has_data = True
+ elif d['type'] == "budgets":
+ self.__print_budgets_main(d['data'])
+ has_data = True
+
elif d['type'] == "region":
self.__print_region_data(d['region'], d['data'])
has_data = True
@@ -225,6 +226,24 @@ def __print_identity_dynamic_groups(self, dynamic_groups):
except Exception as e:
self.__print_error("__print_identity_dynamic_groups", e)
+ ##########################################################################
+ # Print Cost Tracking Tags
+ ##########################################################################
+ def __print_identity_cost_tracking_tags(self, tags):
+ try:
+ if not tags:
+ return
+ self.print_header("Cost Tracking Tags", 2)
+
+ for tag in tags:
+ print(self.taba + tag['tag_namespace_name'] + "." + tag['name'])
+ print(self.tabs + "Desc :" + tag['description'])
+ print(self.tabs + "Created :" + tag['time_created'][0:16])
+ print("")
+
+ except Exception as e:
+ self.__print_error("__print_identity_cost_tracking_tags", e)
+
##########################################################################
# Identity Module
##########################################################################
@@ -243,6 +262,8 @@ def __print_identity_main(self, data):
self.__print_identity_policies(data['policies'])
if 'providers' in data:
self.__print_identity_providers(data['providers'])
+ if 'cost_tracking_tags' in data:
+ self.__print_identity_cost_tracking_tags(data['cost_tracking_tags'])
except Exception as e:
self.__print_error("__print_identity_data", e)
@@ -583,7 +604,7 @@ def __print_load_balancer_details(self, load_balance_obj):
print(self.tabs + "Path Route : " + prs['name'])
if 'path_routes' in prs:
for p in prs['path_routes']:
- print(self.tabs + " : Backend: " + str(p.backend_set_name) + ', Path: ' + p.path)
+ print(self.tabs + " : Backend: " + str(p['backend_set_name']) + ', Path: ' + p['path'])
# Hostnames
if 'hostnames' in lb:
@@ -789,13 +810,15 @@ def __print_database_db_autonomous(self, dbs):
for db in dbs:
print(self.taba + db['name'])
if 'cpu_core_count' in db:
- print(self.tabs + "Cores : " + str(db['cpu_core_count']))
+ print(self.tabs + "Cores : " + str(db['cpu_core_count']))
if 'data_storage_size_in_tbs' in db:
- print(self.tabs + "Size TB : " + str(db['data_storage_size_in_tbs']))
+ print(self.tabs + "Size TB : " + str(db['data_storage_size_in_tbs']))
if 'db_name' in db:
- print(self.tabs + "DB Name : " + db['db_name'])
+ print(self.tabs + "DB Name : " + db['db_name'])
if 'time_created' in db:
- print(self.tabs + "Created : " + db['time_created'])
+ print(self.tabs + "Created : " + db['time_created'])
+ if 'whitelisted_ips' in db:
+ print(self.tabs + "Allowed IPs : " + db['whitelisted_ips'])
# print backups
if db['backups']:
@@ -890,6 +913,26 @@ def __print_streams_main(self, streams):
except Exception as e:
self.__print_error("__print_streams_main", e)
+ ##########################################################################
+ # Budgets
+ ##########################################################################
+ def __print_budgets_main(self, budgets):
+
+ try:
+ if not budgets:
+ return
+
+ self.print_header("Budgets", 2)
+
+ for budget in budgets:
+ print(self.taba + budget['display_name'] + " for Compartment: " + budget['compartment_name'] + " (" + budget['reset_period'] + ")")
+ print(self.tabs + "Costs : Spent: " + budget['actual_spend'] + ", Forcasted: " + budget['forecasted_spend'], ", Time Computed: " + budget['time_spend_computed'][0:16])
+ print(self.tabs + "Created : " + budget['time_created'][0:16] + ", Total Alert Rules: " + budget['alert_rule_count'])
+ print("")
+
+ except Exception as e:
+ self.__print_error("__print_budgets_main", e)
+
##########################################################################
# Container
##########################################################################
@@ -980,8 +1023,10 @@ def __print_core_compute_instances(self, instances):
print(self.tabs2 + "VNIC: " + vnic['desc'])
if 'console' in instance:
- print(self.tabs2 + instance['console'])
- print("")
+ if instance['console']:
+ print(self.tabs2 + instance['console'])
+
+ print("")
except Exception as e:
self.__print_error("__print_core_compute_instances", e)
@@ -1003,7 +1048,7 @@ def __print_core_compute_images(self, images):
self.__print_error("__print_core_compute_images", e)
##########################################################################
- # print compute images
+ # print compute pool
##########################################################################
def __print_core_compute_instance_pool(self, pools):
@@ -1021,6 +1066,34 @@ def __print_core_compute_instance_pool(self, pools):
except Exception as e:
self.__print_error("__print_core_compute_instance_pool", e)
+ ##########################################################################
+ # print compute autoscaling
+ ##########################################################################
+ def __print_core_compute_autoscaling(self, autos):
+
+ try:
+ if len(autos) == 0:
+ return
+
+ self.print_header("Compute Autoscaling", 2)
+ for auto in autos:
+ print(self.taba + auto['name'])
+ print(self.tabs + "Resource : " + auto['resource_type'] + ": " + auto['resource_name'])
+
+ # Policies
+ for pol in auto['policies']:
+ print(self.tabs + "Policy : " + pol['display_name'] + " (" + pol['policy_type'] + ")")
+ print(self.tabs + " Capacity : Initial = " + pol['capacity_initial'] + ", Min = " + pol['capacity_min'] + ", Max = " + pol['capacity_max'])
+
+ # Rules
+ for rule in pol['rules']:
+ print(self.tabs + " Rule : " + rule)
+
+ print("")
+
+ except Exception as e:
+ self.__print_error("__print_core_compute_autoscaling", e)
+
##########################################################################
# print compute images
##########################################################################
@@ -1041,48 +1114,33 @@ def __print_core_compute_instance_configuration(self, configs):
self.__print_error("__print_core_compute_instance_configuration", e)
##########################################################################
- # print compute boot volume
+ # print compute boot volume or volumes
##########################################################################
- def __print_core_compute_boot_volume_backup(self, backups):
+ def __print_core_compute_boot_volume_backup(self, backups, header):
try:
if len(backups) == 0:
return
- self.print_header("Boot Volume Backups", 2)
+ self.print_header(header, 2)
prev_id = ""
for backup in backups:
- if prev_id and prev_id != backup['boot_volume_id']:
+ if prev_id and prev_id != backup['id']:
print("")
- print(self.taba + backup['name'] + " - " + backup['desc'])
- print(self.tabs + self.tabs + "Type : " + backup['type'])
- print(self.tabs + self.tabs + "Size : " + backup['size'])
- prev_id = backup['boot_volume_id']
- except Exception as e:
- self.__print_error("__print_core_compute_boot_volume_backup", e)
+ # if auto backup, print only the policy name
+ desc_name = backup['desc']
+ if 'via policy' in backup['desc']:
+ start = backup['desc'].find('via policy') + 12
+ desc_name = "AUTO (" + backup['desc'][start:] + ")"
- ##########################################################################
- # print compute block volume
- ##########################################################################
- def __print_core_compute_volume_backup(self, backups):
+ # print the line
+ print(self.taba + backup['name'] + ", " + backup['size'] + ", " + desc_name + ", " + backup['type'])
- try:
- if len(backups) == 0:
- return
-
- self.print_header("Block Volume Backups", 2)
- prev_id = ""
- for backup in backups:
- if prev_id and prev_id != backup['volume_id']:
- print("")
- print(self.taba + backup['name'] + " - " + backup['desc'])
- print(self.tabs + self.tabs + "Type : " + backup['type'])
- print(self.tabs + self.tabs + "Size : " + backup['size'])
- prev_id = backup['volume_id']
+ prev_id = backup['id']
except Exception as e:
- self.__print_error("__print_core_compute_volume_backup", e)
+ self.__print_error("__print_core_compute_boot_volume_backup", e)
##########################################################################
# print compute block volume Groups
@@ -1152,6 +1210,9 @@ def __print_core_compute_main(self, data):
if 'instance_pool' in data:
self.__print_core_compute_instance_pool(data['instance_pool'])
+ if 'autoscaling' in data:
+ self.__print_core_compute_autoscaling(data['autoscaling'])
+
if 'images' in data:
self.__print_core_compute_images(data['images'])
@@ -1165,10 +1226,10 @@ def __print_core_compute_main(self, data):
self.__print_core_compute_volume_groups(data['volume_group'])
if 'boot_volume_backup' in data:
- self.__print_core_compute_boot_volume_backup(data['boot_volume_backup'])
+ self.__print_core_compute_boot_volume_backup(data['boot_volume_backup'], "Boot Volume Backups")
if 'volume_backup' in data:
- self.__print_core_compute_volume_backup(data['volume_backup'])
+ self.__print_core_compute_boot_volume_backup(data['volume_backup'], "Block Volume Backups")
except Exception as e:
self.__print_error("__print_core_compute_main", e)
@@ -1493,7 +1554,7 @@ def __summary_print_results(self, data, header, header_size):
# sort and print
for d in sorted(grouped_data, key=lambda i: i['type']):
- print(d['type'].ljust(43)[0:42] + " - " + str(round(d['size'])).rjust(10))
+ print(d['type'].ljust(46)[0:45] + " - " + str(round(d['size'])).rjust(10))
except Exception as e:
self.__print_error("__summary_print_results", e)
diff --git a/examples/showoci/showoci_service.py b/examples/showoci/showoci_service.py
index 3ad64185e8..fdf31e5ff3 100755
--- a/examples/showoci/showoci_service.py
+++ b/examples/showoci/showoci_service.py
@@ -1,12 +1,8 @@
-
##########################################################################
# Copyright(c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
-# showocy_service.py
+# showoci_service.py
#
-# @Created On : Mar 17 2019
-# @Last Updated: Apr 14 2019
-# @author : Adi Zohar
-# @Version : 19.4.14
+# @author: Adi Zohar
#
# Supports Python 2.7 and above, Python 3 recommended
#
@@ -41,6 +37,7 @@ class ShowOCIFlags(object):
read_resource_management = False
read_containers = False
read_streams = False
+ read_budgets = False
read_ManagedCompartmentForPaaS = True
read_root_compartment = True
@@ -76,7 +73,8 @@ def is_loop_on_compartments(self):
self.read_email_distribution or
self.read_resource_management or
self.read_containers or
- self.read_streams)
+ self.read_streams or
+ self.read_budgets)
############################################
# check if to load basic network (vcn+subnets)
@@ -94,7 +92,7 @@ def is_load_basic_network(self):
# class ShowOCIService
##########################################################################
class ShowOCIService(object):
- oci_compatible_version = "2.2.5"
+ oci_compatible_version = "2.2.7"
##########################################################################
# Global Constants
@@ -133,6 +131,7 @@ class ShowOCIService(object):
C_IDENTITY_PROVIDERS = 'providers'
C_IDENTITY_DYNAMIC_GROUPS = 'dynamic_groups'
C_IDENTITY_USERS_GROUPS_MEMBERSHIP = 'users_groups_membership'
+ C_IDENTITY_COST_TRACKING_TAGS = 'cost_tracking_tags'
# Compute Identifiers
C_COMPUTE = 'compute'
@@ -143,6 +142,7 @@ class ShowOCIService(object):
C_COMPUTE_BOOT_VOL_ATTACH = 'instance_boot_vol_attach'
C_COMPUTE_VOLUME_ATTACH = 'instance_volume_attach'
C_COMPUTE_VNIC_ATTACH = 'instance_vnic_attach'
+ C_COMPUTE_AUTOSCALING = 'auto_scaling'
# Block Storage Identifiers
C_BLOCK = 'blockstorage'
@@ -190,9 +190,14 @@ class ShowOCIService(object):
C_STREAMS = "streams"
C_STREAMS_STREAMS = "streams"
- # Error flag
+ # budgets
+ C_BUDGETS = "budgets"
+ C_BUDGETS_BUDGETS = "budgets"
+
+ # Error flag and reboot migration
error = 0
warning = 0
+ reboot_migration_counter = 0
##########################################################################
# Local Variables
@@ -262,6 +267,15 @@ def get_availability_domains(self, region_name):
ads = self.data[self.C_IDENTITY][self.C_IDENTITY_ADS]
return [e for e in ads if e['region_name'] == region_name]
+ ##########################################################################
+ # return budget data
+ ##########################################################################
+ def get_budgets(self):
+ if self.C_BUDGETS in self.data:
+ if self.C_BUDGETS_BUDGETS in self.data[self.C_BUDGETS]:
+ return self.data[self.C_BUDGETS][self.C_BUDGETS_BUDGETS]
+ return []
+
##########################################################################
# return subnet
##########################################################################
@@ -424,8 +438,9 @@ def __load_print_cnt(self, cnt, start_time):
##########################################################################
# print auth warning
##########################################################################
- def __load_print_auth_warning(self, special_char="a"):
- self.warning += 1
+ def __load_print_auth_warning(self, special_char="a", increase_warning=True):
+ if increase_warning:
+ self.warning += 1
print(special_char, end="")
##########################################################################
@@ -506,10 +521,25 @@ def __load_oci_region_data(self, region_name):
if self.flags.read_object_storage:
self.__load_object_storage_main()
- # file storage - not exist in toronto yet
- if region_name != "ca-toronto-1":
- if self.flags.read_file_storage:
- self.__load_file_storage_main()
+ # file storage
+ if self.flags.read_file_storage:
+ self.__load_file_storage_main()
+
+ # containers
+ if self.flags.read_containers:
+ self.__load_container_main()
+
+ # resource management
+ if self.flags.read_resource_management:
+ self.__load_resource_management_main()
+
+ # if streams
+ if self.flags.read_streams:
+ self.__load_streams_main()
+
+ # if budgets
+ if self.flags.read_budgets:
+ self.__load_budgets_main()
# only available in US Regions
if region_name == "us-ashburn-1" or region_name == "us-phoenix-1":
@@ -518,19 +548,6 @@ def __load_oci_region_data(self, region_name):
if self.flags.read_email_distribution:
self.__load_email_main()
- # resource management - only at us for now
- if self.flags.read_resource_management:
- self.__load_resource_management_main()
-
- # if streams
- if self.flags.read_streams:
- self.__load_streams_main()
-
- # containers - not exist in toronto yet
- if region_name != "ca-toronto-1":
- if self.flags.read_containers:
- self.__load_container_main()
-
##########################################################################
# Identity Module
##########################################################################
@@ -557,6 +574,7 @@ def __load_identity_main(self):
self.__load_identity_dynamic_groups(identity, tenancy_id)
self.__load_identity_policies(identity)
self.__load_identity_providers(identity, tenancy_id)
+ self.__load_identity_cost_tracking_tags(identity, tenancy_id)
print("")
except oci.exceptions.RequestException:
@@ -911,6 +929,46 @@ def __load_identity_dynamic_groups(self, identity, tenancy_id):
except Exception as e:
self.__print_error("__load_identity_dynamic_groups", e)
+ ##########################################################################
+ # load cost tracking tags
+ ##########################################################################
+ def __load_identity_cost_tracking_tags(self, identity, tenancy_id):
+
+ data = []
+ self.__load_print_status("Cost Tracking Tags")
+ start_time = time.time()
+
+ try:
+ try:
+ tags = oci.pagination.list_call_get_all_results(identity.list_cost_tracking_tags, tenancy_id).data
+ except oci.exceptions.ServiceError as e:
+ if self.__check_service_error(e.code):
+ self.__load_print_auth_warning()
+ else:
+ raise
+
+ # tag = oci.identity.models.Tag
+ for tag in tags:
+ dataval = {'tag_namespace_id': str(tag.tag_namespace_id),
+ 'tag_namespace_name': str(tag.tag_namespace_name),
+ 'id': str(tag.id),
+ 'name': str(tag.name),
+ 'description': str(tag.description),
+ 'is_retired': str(tag.is_retired),
+ 'time_created': str(tag.time_created),
+ 'is_cost_tracking': str(tag.is_cost_tracking)
+ }
+ data.append(dataval)
+
+ # add to data
+ self.data[self.C_IDENTITY][self.C_IDENTITY_COST_TRACKING_TAGS] = data
+ self.__load_print_cnt(len(data), start_time)
+
+ except oci.exceptions.RequestException:
+ raise
+ except Exception as e:
+ self.__print_error("__load_identity_cost_tracking_tags", e)
+
##########################################################################
# Load Identity Availability Domains
##########################################################################
@@ -2154,6 +2212,11 @@ def __load_core_compute_main(self):
if self.flags.proxy:
virtual_network.base_client.session.proxies = {'https': self.flags.proxy}
+ # auto scaling
+ auto_scaling = oci.autoscaling.AutoScalingClient(self.config)
+ if self.flags.proxy:
+ auto_scaling.base_client.session.proxies = {'https': self.flags.proxy}
+
# reference to compartments
compartments = self.get_compartment()
@@ -2166,6 +2229,7 @@ def __load_core_compute_main(self):
self.__initialize_data_key(self.C_COMPUTE, self.C_COMPUTE_INST_CONFIG)
self.__initialize_data_key(self.C_COMPUTE, self.C_COMPUTE_INST_POOL)
+ self.__initialize_data_key(self.C_COMPUTE, self.C_COMPUTE_AUTOSCALING)
self.__initialize_data_key(self.C_BLOCK, self.C_BLOCK_VOLGRP)
self.__initialize_data_key(self.C_BLOCK, self.C_BLOCK_BOOT)
@@ -2185,6 +2249,7 @@ def __load_core_compute_main(self):
compute[self.C_COMPUTE_VNIC_ATTACH] += self.__load_core_compute_vnic_attach(compute_client, virtual_network, compartments)
compute[self.C_COMPUTE_INST_CONFIG] += self.__load_core_compute_inst_config(compute_client, compute_manage, block_storage, compartments)
compute[self.C_COMPUTE_INST_POOL] += self.__load_core_compute_inst_pool(compute_manage, compartments)
+ compute[self.C_COMPUTE_AUTOSCALING] += self.__load_core_compute_autoscaling(auto_scaling, compute_manage, compartments)
print("")
print("Block Storage...")
@@ -2246,7 +2311,7 @@ def __load_core_compute_instances(self, compute, compartments):
print(".", end="")
# loop on array
- # arr = oci.core.models.Instance()
+ # arr = oci.core.models.Instance
for arr in arrs:
if (arr.lifecycle_state == oci.core.models.Instance.LIFECYCLE_STATE_TERMINATED or
arr.lifecycle_state == oci.core.models.Instance.LIFECYCLE_STATE_PROVISIONING or
@@ -2264,11 +2329,24 @@ def __load_core_compute_instances(self, compute, compartments):
'console_id': "", 'console': "", 'console_connection_string': "",
'defined_tags': [] if arr.defined_tags is None else arr.defined_tags,
'freeform_tags': [] if arr.freeform_tags is None else arr.freeform_tags,
- 'console_vnc_connection_string': "", 'image': "Not Found"}
+ 'console_vnc_connection_string': "", 'image': "Not Found", 'image_os': "Oracle Linux"}
+
+ # if PaaS compartment assign Paas Image
+ if self.__if_managed_paas_compartment(compartment['name']):
+ val['image_os'] = "PaaS Image"
+ val['image'] = "PaaS Image"
- # check image name
+ # mark reboot migration flag
+ if arr.time_maintenance_reboot_due is not None:
+ self.reboot_migration_counter += 1
+
+ # get image info
try:
- val['image'] = str(compute.get_image(arr.image_id).data.display_name)
+ # image = oci.core.models.Image
+ image = compute.get_image(arr.image_id).data
+ if image:
+ val['image'] = str(image.display_name)
+ val['image_os'] = str(image.operating_system)
except Exception:
pass
@@ -2355,7 +2433,131 @@ def __load_core_compute_images(self, compute, compartments):
return data
##########################################################################
- # data compute read images
+ # compute auto scaling
+ ##########################################################################
+ def __load_core_compute_autoscaling(self, autoscaling, compute_manage, compartments):
+
+ data = []
+ cnt = 0
+ start_time = time.time()
+
+ try:
+
+ self.__load_print_status("Autoscaling")
+
+ # loop on all compartments
+ for compartment in compartments:
+
+ if self.__if_managed_paas_compartment(compartment['name']):
+ print(".", end="")
+ continue
+
+ autos = []
+ try:
+ # pagination didn't work on auto scaling code
+ autos = oci.pagination.list_call_get_all_results(autoscaling.list_auto_scaling_configurations, compartment['id']).data
+
+ except oci.exceptions.ServiceError as e:
+ if self.__check_service_error(e.code):
+ self.__load_print_auth_warning()
+ continue
+ raise
+
+ print(".", end="")
+
+ # loop on array
+ # arr = oci.autoscaling.models.AutoScalingConfigurationSummary
+ for auto in autos:
+ val = {'id': str(auto.id), 'display_name': str(auto.display_name),
+ 'cool_down_in_seconds': str(auto.cool_down_in_seconds),
+ 'is_enabled': auto.is_enabled,
+ 'time_created': str(auto.time_created),
+ 'compartment_name': str(compartment['name']), 'compartment_id': str(compartment['id']),
+ 'region_name': str(self.config['region']),
+ 'resource_id': "",
+ 'resource_type': "",
+ 'resource_name': "",
+ 'policies': []
+ }
+
+ ###########################
+ # get the resources
+ # if resource is oci.autoscaling.models.InstancePoolResource
+ ###########################
+ if auto.resource:
+ if isinstance(auto.resource, oci.autoscaling.models.InstancePoolResource):
+ val['resource_id'] = str(auto.resource.id)
+ val['resource_type'] = str(auto.resource.type)
+
+ # get instance pool name
+ try:
+ pool_name = compute_manage.get_instance_pool(auto.resource.id).data.display_name
+ val['resource_name'] = str(pool_name)
+ except oci.exceptions.ServiceError as e:
+ if self.__check_service_error(e.code):
+ self.__load_print_auth_warning("p")
+ else:
+ raise
+
+ ##################
+ # get the policy
+ ##################
+ try:
+ policies = autoscaling.list_auto_scaling_policies(auto.id).data
+
+ # policy = oci.autoscaling.models.AutoScalingPolicySummary
+ for policy in policies:
+
+ # read the proper policy which has the capacity and rules
+ # pol = oci.autoscaling.models.AutoScalingPolicy
+ # didn't add the rules for now.
+ pol = autoscaling.get_auto_scaling_policy(auto.id, policy.id).data
+ if pol:
+ valpol = {'id': str(pol.id),
+ 'display_name': str(pol.display_name),
+ 'policy_type': str(pol.policy_type),
+ 'time_created': str(pol.time_created),
+ 'capacity_min': str(pol.capacity.min),
+ 'capacity_max': str(pol.capacity.max),
+ 'capacity_initial': str(pol.capacity.initial),
+ 'rules': []
+ }
+
+ ##############################
+ # if policy is ThresholdPolicy
+ ##############################
+ if pol.policy_type == "threshold":
+ for rule in pol.rules:
+ valpol['rules'].append(
+ str(rule.action.type) + " " +
+ str(rule.action.value).ljust(3) + " when " +
+ str(rule.metric.metric_type) + " " +
+ str(rule.metric.threshold.operator) + " " +
+ str(rule.metric.threshold.value))
+
+ # add policy
+ val['policies'].append(valpol)
+
+ except oci.exceptions.ServiceError as e:
+ if self.__check_service_error(e.code):
+ self.__load_print_auth_warning("l")
+ else:
+ raise
+
+ data.append(val)
+ cnt += 1
+
+ self.__load_print_cnt(cnt, start_time)
+ return data
+
+ except oci.exceptions.RequestException:
+ raise
+ except Exception as e:
+ self.__print_error("__load_core_compute_autoscaling", e)
+ return data
+
+ ##########################################################################
+ # __load_core_compute_inst_config
##########################################################################
def __load_core_compute_inst_config(self, compute, compute_manage, block_storage, compartments):
@@ -2382,9 +2584,11 @@ def __load_core_compute_inst_config(self, compute, compute_manage, block_storage
compartment['id']
).data
+ # inst pool and inst config service often goes down, not marking warning
+ # for inst pool and inst config
except oci.exceptions.ServiceError as e:
if self.__check_service_error(e.code):
- self.__load_print_auth_warning()
+ self.__load_print_auth_warning("a", False)
continue
raise
@@ -2459,7 +2663,7 @@ def __load_core_compute_inst_config(self, compute, compute_manage, block_storage
return data
##########################################################################
- # data compute read images
+ # __load_core_compute_inst_pool
##########################################################################
def __load_core_compute_inst_pool(self, compute_manage, compartments):
@@ -2486,9 +2690,11 @@ def __load_core_compute_inst_pool(self, compute_manage, compartments):
compartment['id']
).data
+ # inst pool and inst config service often goes down, not marking warning
+ # for inst pool and inst config
except oci.exceptions.ServiceError as e:
if self.__check_service_error(e.code):
- self.__load_print_auth_warning()
+ self.__load_print_auth_warning("a", False)
continue
raise
@@ -3214,7 +3420,16 @@ def __load_load_balancers(self, load_balancer, compartments):
datapath = []
for prs in arr.path_route_sets:
pro = arr.path_route_sets[prs]
- datapath.append({'name': pro.name, 'path_routes': pro.path_routes})
+
+ # get the path routes
+ array_path = []
+ if pro.path_routes is not None:
+ for path_route in pro.path_routes:
+ array_path.append({'path': path_route.path, 'backend_set_name': path_route.backend_set_name})
+
+ # add the paths
+ datapath.append({'name': pro.name, 'path_routes': array_path})
+
val['path_route'] = datapath
# Hostnames
@@ -4533,6 +4748,7 @@ def __load_database_autonomouns(self, database_client, compartments):
'defined_tags': [] if dbs.defined_tags is None else dbs.defined_tags,
'freeform_tags': [] if dbs.freeform_tags is None else dbs.freeform_tags,
'region_name': str(self.config['region']),
+ 'whitelisted_ips': "" if dbs.whitelisted_ips is None else str(', '.join(x for x in dbs.whitelisted_ips)),
'backups': self.__load_database_autonomouns_backups(database_client, dbs.id)}
# license model
@@ -4846,3 +5062,108 @@ def __load_streams_streams(self, stream_client, compartments):
except Exception as e:
self.__print_error("__load_streams_streams", e)
return data
+
+ ##########################################################################
+ # __load_budget_main
+ ##########################################################################
+ #
+ # OCI Classes used:
+ #
+ # class oci.budget.BudgetClient(config, **kwargs)
+ #
+ ##########################################################################
+ def __load_budgets_main(self):
+
+ try:
+ print("Budgets...")
+
+ # BudgetClient
+ budget_client = oci.budget.BudgetClient(self.config)
+ if self.flags.proxy:
+ budget_client.base_client.session.proxies = {'https': self.flags.proxy}
+
+ # reference to tenancy
+ tenancy = self.get_tenancy()
+
+ # add the key if not exists
+ self.__initialize_data_key(self.C_BUDGETS, self.C_BUDGETS_BUDGETS)
+
+ # reference to stream
+ budget = self.data[self.C_BUDGETS]
+
+ # append the data
+ budget[self.C_BUDGETS_BUDGETS] += self.__load_budgets_budgets(budget_client, tenancy['id'])
+ print("")
+
+ except oci.exceptions.RequestException:
+ raise
+ except oci.exceptions.ServiceError:
+ raise
+ except Exception as e:
+ self.__print_error("__load_budgets_main", e)
+
+ ##########################################################################
+ # __load_budgets_budgets
+ ##########################################################################
+ def __load_budgets_budgets(self, budget_client, tenancy_id):
+
+ data = []
+ cnt = 0
+ start_time = time.time()
+
+ try:
+ self.__load_print_status("Budgets")
+
+ budgets = []
+ try:
+ budgets = oci.pagination.list_call_get_all_results(
+ budget_client.list_budgets,
+ tenancy_id,
+ lifecycle_state=oci.budget.models.BudgetSummary.LIFECYCLE_STATE_ACTIVE
+ ).data
+
+ except oci.exceptions.ServiceError as e:
+ if self.__check_service_error(e.code):
+ self.__load_print_auth_warning()
+ else:
+ raise
+
+ print(".", end="")
+
+ # budget = oci.budget.models.BudgetSummary
+ for budget in budgets:
+ val = {'id': str(budget.id),
+ 'target_compartment_id': str(budget.target_compartment_id),
+ 'compartment_name': "",
+ 'display_name': str(budget.display_name),
+ 'description': str(budget.description),
+ 'amount': str(budget.amount),
+ 'reset_period': str(budget.reset_period),
+ 'alert_rule_count': str(budget.alert_rule_count),
+ 'version': str(budget.version),
+ 'actual_spend': str(budget.actual_spend),
+ 'forecasted_spend': str(budget.forecasted_spend),
+ 'time_spend_computed': str(budget.time_spend_computed),
+ 'time_created': str(budget.time_created),
+ 'time_updated': str(budget.time_updated),
+ 'defined_tags': [] if budget.defined_tags is None else budget.defined_tags,
+ 'freeform_tags': [] if budget.freeform_tags is None else budget.freeform_tags,
+ 'region_name': str(self.config['region'])}
+
+ # fill the comaprtment name
+ compartment = self.search_unique_item(self.C_IDENTITY, self.C_IDENTITY_COMPARTMENTS, 'id', str(budget.target_compartment_id))
+ if compartment:
+ val['compartment_name'] = compartment['path']
+
+ # add the data
+ cnt += 1
+ data.append(val)
+
+ self.__load_print_cnt(cnt, start_time)
+ return data
+
+ except oci.exceptions.RequestException:
+ raise
+ except Exception as e:
+ self.__print_error("__load_budgets_budgets", e)
+ return data
diff --git a/examples/stop_untagged_instances.py b/examples/stop_untagged_instances.py
new file mode 100644
index 0000000000..fd91f74c12
--- /dev/null
+++ b/examples/stop_untagged_instances.py
@@ -0,0 +1,205 @@
+# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+
+# This example demonstrates how to find, stop and report on instances that have
+# been improperly tagged.
+#
+# I recommend that you run this every 30 minutes and set the audit hours to 1.
+# Example usage 'stop_untagged_instances.py --hours_to_audit 2 --tag_string CostCenter'
+# This searches for any instance without the CostCenter tag applied, stops them, finds who started it and logs
+# the results.
+
+import oci
+import datetime
+import argparse
+
+
+# After determining all the events associated with th stopped instances, merge those event records (OCID and Email)
+# with the existing list of instances_to_stop to add the email to the existing list, then write it to disk.
+def join_lists(instance_list, events_list, filename):
+ for item in instance_list:
+ for item2 in events_list:
+ # when you find a match between the event_list & instances to stop, add the email to the creator column
+ if item['instance_ocid'] == item2['instance_ocid']:
+ item['creator'] = item2['principal_name']
+
+ # Write out this joined list to disk
+ try:
+ with open(filename, 'w') as f:
+ for item in instance_list:
+ f.write('{0},{1},{2},{3},{4},{5},{6},{7},{8}\n'
+ .format(item['stop_datetime'], item['region'], item['compartment_name'], item['instance_name'],
+ item['instance_shape'], item['time_created'], item['instance_ocid'],
+ item['compartment_ocid'], item['creator']))
+ except Exception as e:
+ print('An unexpected Error Occured writing the file: {0}' .format(e))
+
+
+# This function stops the instance sent in as a parameter
+def stop_resource(instance_id, region):
+ base_compute = oci.core.compute_client.ComputeClient(config)
+ base_compute.base_client.set_region(region)
+
+ # Stop a running instance, but it is possible for it to fail so putting it in a try catch for common errors.
+ try:
+ if base_compute.get_instance(instance_id).data.lifecycle_state in 'RUNNING':
+ try:
+ print('\t\tStopping instance. Stop response code: {1}'
+ .format(instance_id, str(base_compute.instance_action(instance_id, 'STOP').status)))
+ except oci.exceptions.ServiceError as e:
+ print('\t\tStopping instance failed. {0}' .format(e))
+ else:
+ print('\t\tThe instance was in the incorrect state to stop' .format(instance_id))
+ except oci.exceptions.ServiceError as e:
+ print('\t\tStopping instance failed. {0}'.format(e))
+
+
+# determines the list of subscribed regions for the tenancy
+def list_of_regions():
+ identity = oci.identity.IdentityClient(config)
+ list_of_regions = []
+ list_regions_response = identity.list_regions()
+ for r in list_regions_response.data:
+ list_of_regions.append(r.name)
+ return list_of_regions
+
+
+# This function finds LaunchInstance audit events based on the instance OCID and compartment passed into it
+# from the find_resources_wo_tags function. The LaunchInstance events give it the principal (usually email) of the
+# 'person' who started the resource and joins it to the exisitng instances_to_stop so it now contains the email of who
+# started it.
+def find_audit_events(instances_to_stop, instance_stop_list, compartment_id_stop_list):
+ end_time = datetime.datetime.utcnow()
+ start_time = end_time + datetime.timedelta(hours=-int(audit_hours))
+ list_of_audit_events = []
+ events_list = [{'principal_name': '', 'instance_ocid': ''}]
+ audit = oci.audit.audit_client.AuditClient(config)
+ print('\nGetting list of audit events for the last {0} hour(s).' .format(audit_hours))
+
+ # Finding all Resources in a region
+ region_list = list_of_regions()
+ for region in region_list:
+ audit.base_client.set_region(region)
+
+ for c in compartment_id_stop_list:
+ # clear out the audit events from a compartment
+ del list_of_audit_events[:]
+ list_events_response = oci.pagination.list_call_get_all_results(audit.list_events, compartment_id=c,
+ start_time=start_time,
+ end_time=end_time).data
+ list_of_audit_events.extend(list_events_response)
+ print('\t\tNumber of audit events in {0}\\{1}: {2}' .format(region, identity_client.get_compartment(c).data.name, len(list_of_audit_events)))
+
+ for ae in list_of_audit_events:
+ if ae.event_name == 'LaunchInstance':
+ if ae.response_payload['id'] in instance_stop_list:
+ if len(ae.user_name) == 0:
+ principal_name = ae.principal_id.rsplit('/', 1)[-1]
+ else:
+ principal_name = ae.user_name
+
+ events_line = {'principal_name': principal_name,
+ 'instance_ocid': ae.response_payload['id']}
+
+ events_list.append(events_line)
+ print('\t\t\tFound a launch instance: {0}'.format(ae.response_payload['id']))
+ join_lists(instances_to_stop, events_list, 'stop_untagged_instances_result.csv')
+
+
+# This function looks for all compute instances using the RQS (search) service, then it filters that list by looking
+# For any resources that are in the correct state and that are either missing tags entirely or not tag correctly.
+# It records those which are going to be stopped and calls stop_resource with a list of all compute instances to be
+# stopped.
+def find_resources_wo_tags(instances_to_stop_list, search_string):
+ instances_stop_list = []
+ compartment_id_stop_list = []
+ search_client = oci.resource_search.ResourceSearchClient(config)
+ compute_client = oci.core.ComputeClient(config)
+
+ # Finding all Resources in a region
+ region_list = list_of_regions()
+ for region in region_list:
+ print('Searching RQS to find mis-tagged resources in Region:{0}' .format(region))
+ try:
+ search_client.base_client.set_region(region)
+ structured_search = oci.resource_search.models.StructuredSearchDetails(
+ query="query instance resources",
+ type='Structured',
+ matching_context_type=oci.resource_search.models.SearchDetails.MATCHING_CONTEXT_TYPE_NONE)
+ results = search_client.search_resources(structured_search)
+ except oci.exceptions.ServiceError as e:
+ print('\t\tRQS Search failed with Service Error: {0}' .format(e))
+ except oci.exceptions.RequestException as e:
+ print('\t\tRQS Search failed w/ a Request exception. {0}' .format(e))
+
+ # Filtering from everything to just those not tagged.
+ # This method is needed to also find resources with no tags at all
+ filter_key = search_string
+ for result in results.data.items:
+ if (filter_key not in str(result.defined_tags)) or len(result.defined_tags) == 0:
+ if result.lifecycle_state in ('Provisioning', 'Starting', 'Running'):
+ compute_client.base_client.set_region(region)
+ try:
+ stopped_instances_line = {'stop_datetime': datetime.datetime.utcnow().replace(microsecond=0).isoformat(),
+ 'region': region,
+ 'compartment_name': identity_client.get_compartment(result.compartment_id).data.name,
+ 'instance_name': result.display_name,
+ 'instance_shape': compute_client.get_instance(result.identifier).data.shape,
+ 'time_created': result.time_created.replace(microsecond=0).isoformat(),
+ 'instance_ocid': result.identifier,
+ 'compartment_ocid': result.compartment_id,
+ 'creator': 'Not Found'}
+ instances_to_stop_list.append(stopped_instances_line)
+ instances_stop_list.append(result.identifier)
+ if result.compartment_id not in compartment_id_stop_list:
+ compartment_id_stop_list.append(result.compartment_id)
+ print('\t\t*Found an resource ({0}) without a tag. Stopping it.*' .format(result.display_name))
+ stop_resource(result.identifier, region)
+
+ except oci.exceptions.ServiceError as e:
+ print('\t\tThe instance ({0}) could not be retrieved. It may be a ghost Search entry.'
+ .format(result.display_name, e))
+
+ # Only find audit events for those compartments with a stopped instance
+ if len(instances_to_stop_list) != 0:
+ find_audit_events(instances_to_stop_list, instances_stop_list, compartment_id_stop_list)
+
+
+# A helper function that processes the two arguments for this program. Tag_string is the string that is searched for.
+# Hours to audit is the number of hours before now to search the audit log for.
+def prep_arguments():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--tag_string', default='', help='The string in all tags that will be searched for.')
+ parser.add_argument('--hours_to_audit', default=1, help='The number of hours to search the audit logs for.')
+ args = parser.parse_args()
+ return args
+
+
+if __name__ == "__main__":
+ # Starts a timer for the execution time.
+ print('Stop the Untagged v0.6')
+ start_time = datetime.datetime.now()
+ print('Start Time: {0}'.format(start_time.replace(microsecond=0).isoformat()))
+
+ config = oci.config.from_file()
+ identity_client = oci.identity.IdentityClient(config)
+
+ # Set the search_string and audit_hours from arguments
+ args = prep_arguments()
+ search_string = args.tag_string
+ audit_hours = args.hours_to_audit
+
+ # Create a list of dictionaries that represents the final csv file that records all stopped records.
+ instances_to_stop = []
+ instance_line = {'stop_datetime': 'stop_datetime', 'region': 'region', 'compartment_name': 'compartment_name',
+ 'instance_name': 'instance_name', 'instance_shape': 'instance_shape',
+ 'time_created': 'time_created', 'instance_ocid': 'instance_ocid ',
+ 'compartment_ocid': 'compartment_ocid', 'creator': 'creator'}
+ instances_to_stop.append(instance_line)
+
+ # This is the main function that finds any instance that's not tagged with the search_string
+ find_resources_wo_tags(instances_to_stop, search_string)
+
+ # Completes the program and shows the duration of the run
+ end_time = datetime.datetime.now()
+ print('\nEnd Time: {0}' .format(end_time.replace(microsecond=0).isoformat()))
+ print('Duration: {0}' .format((end_time - start_time)))
diff --git a/examples/stream_example.py b/examples/stream_example.py
index 623d891642..ce3e31209f 100644
--- a/examples/stream_example.py
+++ b/examples/stream_example.py
@@ -3,8 +3,8 @@
import oci
import sys
-import base64
import time
+from codecs import encode, decode
# ==========================================================
# This file provides an example of basic streaming usage
@@ -29,8 +29,8 @@ def publish_example_messages(client, stream_id):
for i in range(100):
key = "key" + str(i)
value = "value" + str(i)
- encoded_key = base64.b64encode(key)
- encoded_value = base64.b64encode(value)
+ encoded_key = encode(key.encode(), "base-64").decode().strip()
+ encoded_value = encode(value.encode(), "base-64").decode().strip()
message_list.append(oci.streaming.models.PutMessagesDetailsEntry(key=encoded_key, value=encoded_value))
print("Publishing {} messages to the stream {} ".format(len(message_list), stream_id))
@@ -74,8 +74,8 @@ def get_stream(admin_client, stream_id):
def delete_stream(client, stream_id):
print(" Deleting Stream {}".format(stream_id))
- # Stream deletion is an asynchronous operation, give it some time to complete.
- client.delete_stream_and_wait_for_state(stream_id, oci.streaming.models.StreamSummary.LIFECYCLE_STATE_DELETED)
+ print(" Stream deletion is an asynchronous operation, give it some time to complete.")
+ client.delete_stream_and_wait_for_state(stream_id, wait_for_states=[oci.streaming.models.StreamSummary.LIFECYCLE_STATE_DELETED])
def get_cursor_by_partition(client, stream_id, partition):
@@ -99,7 +99,8 @@ def simple_message_loop(client, stream_id, initial_cursor):
# Process the messages
print(" Read {} messages".format(len(get_response.data)))
for message in get_response.data:
- print("{}: {}".format(base64.b64decode(message.key), base64.b64decode(message.value)))
+ print("{}: {}".format(decode(message.key.encode(), "base64").decode(),
+ decode(message.value.encode(), "base64").decode()))
# get_messages is a throttled method; clients should retrieve sufficiently large message
# batches, as to avoid too many http requests.
diff --git a/examples/tagging.py b/examples/tagging.py
index 6b4eea8441..8ac791abbe 100644
--- a/examples/tagging.py
+++ b/examples/tagging.py
@@ -84,7 +84,7 @@
# correspond to the name of a tag within the specified namespace (and the namespace must exist).
#
# Resources where we can create/update tags will have the freeform_tags and defined_tags attributes. Consult the API
-# documentation to see what these are (https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/index.html)
+# documentation to see what these are (https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/landing.html)
num_tries = 0
while True:
# You may get a 404 if you create/reactivate a tag and try and use it straight away. If you have a delay/sleep between
@@ -118,7 +118,7 @@
# We can also update tags on a resource. Note that this is a total replacement for any previously set freeform or defined tags.
#
# Resources where we can create/update tags will have the freeform_tags and defined_tags attributes. Consult the API
-# documentation to see what these are (https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/index.html)
+# documentation to see what these are (https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/api/landing.html)
update_vcn_response = virtual_network.update_vcn(
vcn_id,
oci.core.models.UpdateVcnDetails(
diff --git a/src/oci/load_balancer/load_balancer_client.py b/src/oci/load_balancer/load_balancer_client.py
index 9f5a0c71b0..897802b0f9 100644
--- a/src/oci/load_balancer/load_balancer_client.py
+++ b/src/oci/load_balancer/load_balancer_client.py
@@ -740,7 +740,10 @@ def create_path_route_set(self, create_path_route_set_details, load_balancer_id,
def create_rule_set(self, load_balancer_id, create_rule_set_details, **kwargs):
"""
CreateRuleSet
- Creates a new rule set associated with the specified load balancer.
+ Creates a new rule set associated with the specified load balancer. For more information, see
+ `Managing Rule Sets`__.
+
+ __ https://docs.cloud.oracle.com/Content/Balance/Tasks/managingrulesets.htm
:param str load_balancer_id: (required)
diff --git a/src/oci/load_balancer/models/add_http_request_header_rule.py b/src/oci/load_balancer/models/add_http_request_header_rule.py
index 374d2943fe..aea9921dfe 100644
--- a/src/oci/load_balancer/models/add_http_request_header_rule.py
+++ b/src/oci/load_balancer/models/add_http_request_header_rule.py
@@ -10,7 +10,7 @@
class AddHttpRequestHeaderRule(Rule):
"""
An object that represents the action of adding a header to a request.
- This rule applies only to HTTP or HTTP2 listeners.
+ This rule applies only to HTTP listeners.
**NOTES:**
diff --git a/src/oci/load_balancer/models/add_http_response_header_rule.py b/src/oci/load_balancer/models/add_http_response_header_rule.py
index 434dd91b80..6e3fde9c7f 100644
--- a/src/oci/load_balancer/models/add_http_response_header_rule.py
+++ b/src/oci/load_balancer/models/add_http_response_header_rule.py
@@ -10,7 +10,7 @@
class AddHttpResponseHeaderRule(Rule):
"""
An object that represents the action of adding a header to a response.
- This rule applies only to HTTP or HTTP2 listeners.
+ This rule applies only to HTTP listeners.
**NOTES:**
diff --git a/src/oci/load_balancer/models/extend_http_request_header_value_rule.py b/src/oci/load_balancer/models/extend_http_request_header_value_rule.py
index 7bd3ecaa92..53bf09d75b 100644
--- a/src/oci/load_balancer/models/extend_http_request_header_value_rule.py
+++ b/src/oci/load_balancer/models/extend_http_request_header_value_rule.py
@@ -9,7 +9,7 @@
@init_model_state_from_kwargs
class ExtendHttpRequestHeaderValueRule(Rule):
"""
- An object that represents the action of modifying a request header value. This rule applies only to HTTP or HTTP2 listeners.
+ An object that represents the action of modifying a request header value. This rule applies only to HTTP listeners.
This rule adds a prefix, a suffix, or both to the header value.
diff --git a/src/oci/load_balancer/models/extend_http_response_header_value_rule.py b/src/oci/load_balancer/models/extend_http_response_header_value_rule.py
index f3622aa33d..cc517ece0d 100644
--- a/src/oci/load_balancer/models/extend_http_response_header_value_rule.py
+++ b/src/oci/load_balancer/models/extend_http_response_header_value_rule.py
@@ -9,7 +9,7 @@
@init_model_state_from_kwargs
class ExtendHttpResponseHeaderValueRule(Rule):
"""
- An object that represents the action of modifying a response header value. This rule applies only to HTTP or HTTP2 listeners.
+ An object that represents the action of modifying a response header value. This rule applies only to HTTP listeners.
This rule adds a prefix, a suffix, or both to the header value.
diff --git a/src/oci/load_balancer/models/health_check_result.py b/src/oci/load_balancer/models/health_check_result.py
index bd33f16a95..8a7d782b63 100644
--- a/src/oci/load_balancer/models/health_check_result.py
+++ b/src/oci/load_balancer/models/health_check_result.py
@@ -120,7 +120,7 @@ def source_ip_address(self):
"""
**[Required]** Gets the source_ip_address of this HealthCheckResult.
The IP address of the health check status report provider. This identifier helps you differentiate same-subnet
- (private) load balancers that report health check status.
+ load balancers that report health check status.
Example: `10.0.0.7`
@@ -135,7 +135,7 @@ def source_ip_address(self, source_ip_address):
"""
Sets the source_ip_address of this HealthCheckResult.
The IP address of the health check status report provider. This identifier helps you differentiate same-subnet
- (private) load balancers that report health check status.
+ load balancers that report health check status.
Example: `10.0.0.7`
diff --git a/src/oci/load_balancer/models/remove_http_request_header_rule.py b/src/oci/load_balancer/models/remove_http_request_header_rule.py
index ccc81d160a..4ef3d87ffa 100644
--- a/src/oci/load_balancer/models/remove_http_request_header_rule.py
+++ b/src/oci/load_balancer/models/remove_http_request_header_rule.py
@@ -9,7 +9,7 @@
@init_model_state_from_kwargs
class RemoveHttpRequestHeaderRule(Rule):
"""
- An object that represents the action of removing a header from a request. This rule applies only to HTTP or HTTP2 listeners.
+ An object that represents the action of removing a header from a request. This rule applies only to HTTP listeners.
If the same header appears more than once in the request, the load balancer removes all occurances of the specified header.
diff --git a/src/oci/load_balancer/models/remove_http_response_header_rule.py b/src/oci/load_balancer/models/remove_http_response_header_rule.py
index 9171bcd868..0db62e2551 100644
--- a/src/oci/load_balancer/models/remove_http_response_header_rule.py
+++ b/src/oci/load_balancer/models/remove_http_response_header_rule.py
@@ -9,7 +9,7 @@
@init_model_state_from_kwargs
class RemoveHttpResponseHeaderRule(Rule):
"""
- An object that represents the action of removing a header from a response. This rule applies only to HTTP or HTTP2 listeners.
+ An object that represents the action of removing a header from a response. This rule applies only to HTTP listeners.
If the same header appears more than once in the response, the load balancer removes all occurances of the specified header.
diff --git a/src/oci/load_balancer/models/rule_set.py b/src/oci/load_balancer/models/rule_set.py
index 7858b621e3..58862ab955 100644
--- a/src/oci/load_balancer/models/rule_set.py
+++ b/src/oci/load_balancer/models/rule_set.py
@@ -10,7 +10,10 @@
class RuleSet(object):
"""
A named set of rules associated with a load balancer. Rules are objects that represent actions to apply to a listener,
- such as adding, altering, or removing HTTP headers.
+ such as adding, altering, or removing HTTP headers. For more information, see
+ `Managing Rule Sets`__.
+
+ __ https://docs.cloud.oracle.com/Content/Balance/Tasks/managingrulesets.htm
"""
def __init__(self, **kwargs):
diff --git a/src/oci/regions.py b/src/oci/regions.py
index 021c114836..591d1d8cdb 100644
--- a/src/oci/regions.py
+++ b/src/oci/regions.py
@@ -11,6 +11,7 @@
'yyz': 'ca-toronto-1'
}
REGION_REALMS = {
+ 'ap-tokyo-1': 'oc1',
'us-phoenix-1': 'oc1',
'us-ashburn-1': 'oc1',
'eu-frankfurt-1': 'oc1',
@@ -30,6 +31,7 @@
'oc3': 'oraclegovcloud.com'
}
REGIONS = [
+ "ap-tokyo-1",
"us-phoenix-1",
"us-ashburn-1",
"eu-frankfurt-1",
diff --git a/src/oci/version.py b/src/oci/version.py
index fccd104160..dbfc4d7e14 100644
--- a/src/oci/version.py
+++ b/src/oci/version.py
@@ -1,4 +1,4 @@
# coding: utf-8
# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
-__version__ = "2.2.7"
+__version__ = "2.2.8"
diff --git a/tests/testing_service_client.py b/tests/testing_service_client.py
index 43f698fb45..62a64adfdd 100644
--- a/tests/testing_service_client.py
+++ b/tests/testing_service_client.py
@@ -1,6 +1,7 @@
# coding: utf-8
# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+import base64
import json
import requests
import uuid
@@ -157,7 +158,7 @@ def validate_result(self, service_name, api_name, container_id, request, oci_res
if api_name.lower().startswith('list'):
data_field_name = 'items'
response_dict = self.get_response_dictionary(oci_response, is_delete_operation, data_field_name)
- response_json = util.make_dict_keys_camel_case(response_dict)
+ response_json = util.make_dict_keys_camel_case(response_dict, ['freeformTags', 'definedTags', 'metadata'])
data['responseJson'] = json.dumps(response_json)
data['responseClass'] = response_class
@@ -185,7 +186,14 @@ def get_response_dictionary(self, oci_response, is_delete_operation, data_field_
if is_delete_operation:
oci_response.data = {}
- response_dict = oci_util.to_dict({data_field_name: oci_response.data})
+ if data_field_name == 'stream':
+ # for binary data, decode them first then put into inputStream
+ response_dict = {"inputStream": str(base64.b64encode(oci_response.data.content).decode('utf-8')),
+ "contentLength": len(oci_response.data.content)}
+ else:
+ response_dict = oci_util.to_dict({data_field_name: oci_response.data})
+
+ # response_dict = oci_util.to_dict({data_field_name: oci_response.data})
response_dict['opcRequestId'] = self.build_request_id()
response_dict['opcNextPage'] = oci_response.next_page
@@ -273,3 +281,20 @@ def is_api_enabled(self, service_name, api_name):
assert api_enabled_response is True or api_enabled_response is False, 'Received invalid response from testing service, should be true or false. Response: {}'.format(api_enabled_response)
return api_enabled_response
+
+ def get_endpoint(self, service_name, client_name, api_name):
+ # standardize service name to convention for Java SDK model namespaces (all lower case one word)
+ service_name = service_name.replace('_', '').lower()
+
+ url = '{service_root_url}/endpoint'.format(service_root_url=SERVICE_ROOT_URL)
+ params = {
+ 'sessionId': self.session_id,
+ 'serviceName': service_name,
+ 'clientName': client_name,
+ 'lang': SERVICE_LANGUAGE,
+ 'apiName': api_name
+ }
+
+ response = requests.get(url, params=params)
+ assert response.status_code == 200, response.content
+ return response.content.decode('UTF-8')
diff --git a/tests/util.py b/tests/util.py
index 4c0d4d5683..e929d257ad 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -160,6 +160,20 @@ def camel_to_snake_keys(dictionary):
def camelize(to_camelize, uppercase_first_letter=False):
+ # some cases are not be able to handle by this method such as: ip will be changed to Ip
+ # here is a hard coded list for that cases. As of right now, haven't figured out a good way to handle it
+ # as the list need to be updated in the future with new spec changes
+ camelized_dict = {
+ 'create_ip_sec_connection_details': 'CreateIPSecConnectionDetails',
+ 'update_ip_sec_connection_details': 'UpdateIPSecConnectionDetails'
+ }
+
+ if to_camelize in camelized_dict:
+ if uppercase_first_letter:
+ return camelized_dict[to_camelize]
+ else:
+ return camelized_dict[to_camelize][0].lower() + camelized_dict[to_camelize][1:]
+
if not to_camelize:
return ''
@@ -169,7 +183,9 @@ def camelize(to_camelize, uppercase_first_letter=False):
return to_camelize[0].lower() + camelize(to_camelize, uppercase_first_letter=True)[1:]
-def make_dict_keys_camel_case(original_obj):
+# ignore_for_parent_keys will not convert the sub-nodes of that key in dictionary
+# such as for defineTag the key is defined by user, we don't want to covert it to camel case
+def make_dict_keys_camel_case(original_obj, ignore_for_parent_keys=None):
if isinstance(original_obj, six.string_types):
return original_obj
@@ -182,14 +198,18 @@ def make_dict_keys_camel_case(original_obj):
new_dict = {}
for key, value in six.iteritems(original_obj):
camelized_key = camelize(key)
- new_dict[camelized_key] = make_dict_keys_camel_case(value)
+
+ if ignore_for_parent_keys is not None and camelized_key in ignore_for_parent_keys:
+ new_dict[camelized_key] = value
+ else:
+ new_dict[camelized_key] = make_dict_keys_camel_case(value, ignore_for_parent_keys)
return new_dict
if isinstance(original_obj, abc.Iterable):
new_list = []
for obj in original_obj:
- new_list.append(make_dict_keys_camel_case(obj))
+ new_list.append(make_dict_keys_camel_case(obj, ignore_for_parent_keys))
return new_list