├── CHANGELOG.rst ├── CONTRIBUTING.md ├── LICENSE.txt ├── NOTICE.txt ├── README.md ├── SECURITY.md ├── THIRD_PARTY_LICENSES.txt ├── img ├── Image_01.png ├── Image_02.png ├── Image_03.png ├── Image_04.png ├── Image_05.png ├── Image_06.png ├── Image_07.png ├── Image_08.png ├── Image_09.png ├── Image_10.png ├── Image_11.png ├── Image_12.png ├── Image_13.png ├── Image_14.png ├── Image_15.png ├── Image_16.png ├── Image_17.png ├── Image_18.png ├── Image_19.png ├── Image_20.png ├── Image_21.png ├── Image_22.png ├── Image_23.png ├── Image_24.png ├── Image_25.png ├── Image_26.png ├── Image_27.png ├── Image_28.png ├── Image_29.png ├── Image_30.png ├── Image_31.png ├── Image_32.png ├── Image_33.png ├── Image_34.png ├── Image_35.png ├── Image_36.png ├── pe1.png ├── pe2.png ├── pe3.png ├── report_01.png ├── report_02.png ├── report_03.png ├── report_04.png ├── report_05.png ├── screen_1.png ├── screen_2.png ├── screen_3.png ├── screen_4.png ├── screen_5.png ├── screen_6.png ├── screen_7.png ├── screen_8.png ├── stack_1.png ├── stack_10.png ├── stack_11.png ├── stack_12.png ├── stack_13.png ├── stack_14.png ├── stack_15.png ├── stack_16.png ├── stack_17.png ├── stack_18.png ├── stack_19.png ├── stack_2.png ├── stack_20.png ├── stack_3.png ├── stack_4.png ├── stack_5.png ├── stack_6.png ├── stack_7.png ├── stack_8.png └── stack_9.png ├── shell_scripts ├── run_daily_report.sh ├── run_gather_stats.sh ├── run_load_showoci_csv_to_adw.sh ├── run_multi_daily_usage2adw.sh ├── run_report_compart_service_daily_to_csv.sh ├── run_report_compart_service_sku_daily_to_csv.sh ├── run_sqlplus_usage.sh ├── run_table_size_info.sh └── run_tenant_usage_report.sh ├── step_by_step_howto.md ├── step_by_step_installation.md ├── step_by_step_manual_installation.md ├── step_by_step_terraform.md ├── terraform ├── main.tf ├── modules │ ├── adb │ │ └── main.tf │ ├── compute │ │ ├── bootstrap.tpl │ │ └── main.tf │ ├── iam │ │ └── main.tf │ ├── network │ │ └── main.tf │ └── oac │ │ └── main.tf ├── schema.yaml └── variables.tf ├── usage2adw.py ├── usage2adw_check_connectivity.py ├── usage2adw_demo_apex_app.sql ├── usage2adw_download_adb_wallet.py ├── usage2adw_retrieve_secret.py ├── usage2adw_setup.sh └── usage2adw_showoci_csv2adw.py /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Change Log 2 | ~~~~~~~~~~ 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on `Keep a Changelog `_. 6 | 7 | ===================== 8 | 25.05.01 - 2025.05.01 9 | ===================== 10 | * Removed handling usage files which deprecated it includes all relevant tables OCI_USAGE,.. 11 | * Removed OCI_INTERNAL_COST which based on OCI_USAGE 12 | * Redesigned the APEX app Usage area fetching data from OCI_COST 13 | * Added Tag Special Key 3 and Tag Special Key 4 14 | 15 | ===================== 16 | 25.01.01 - 2025.01.01 17 | ===================== 18 | * Added attributedCost (COST_ATTRIBUTED_COST) and attributedUsage (USG_ATTRIBUTED_USAGE) 19 | 20 | ===================== 21 | 24.11.01 - 2024.11.01 22 | ===================== 23 | * Added database_pdbs csv 24 | 25 | ===================== 26 | 24.10.01 - 2024.10.01 27 | ===================== 28 | * Fixed bugs and updated dependencies 29 | 30 | ===================== 31 | 24.07.02 - 2024.07.02 32 | ===================== 33 | * Added Identity Policies and Identity Domain csv to adw 34 | 35 | ===================== 36 | 24.06.03 - 2024.06.03 37 | ===================== 38 | * Update instantclient to version 19.23 39 | 40 | ===================== 41 | 24.06.01 - 2024.06.01 42 | ===================== 43 | * Update Requests to 2.32.1 44 | 45 | ===================== 46 | 24.03.01 - 2024.03.01 47 | ===================== 48 | * Update instantclient to version 19.22 49 | 50 | ===================== 51 | 23.12.20 - 2023.12.20 52 | ===================== 53 | * Added new flags -nm for override namespace and -bn for override bucketname 54 | 55 | ===================== 56 | 23.10.15 - 2023.10.15 57 | ===================== 58 | * Added OCI_TENANT table for child tenant display name 59 | 60 | ===================== 61 | 23.09.10 - 2023.09.10 62 | ===================== 63 | * Terraform deployed on ECPUs 64 | * Added support for ECPUs 65 | 66 | ===================== 67 | 23.08.01 - 2023.08.01 68 | ===================== 69 | * ADB Password moved to KMS Secret 70 | 71 | ===================== 72 | 23.04.18 - 2023.04.18 73 | ===================== 74 | * Added showoci_csv2adw.py to load showoci csv files to adw if showoci enabled 75 | * Simplified the setup script 76 | 77 | ===================== 78 | 23.04.11 - 2023.04.11 79 | ===================== 80 | * Point to OCI Python SDK Repo 81 | 82 | ===================== 83 | 23.03.22 - 2023.03.22 84 | ===================== 85 | * Added OCI_RESOURCES Table populated from showoci 86 | 87 | ===================== 88 | 23.03.15 - 2023.03.15 89 | ===================== 90 | * Fix OCI_LOAD_STATUS Constraint bug 91 | 92 | ===================== 93 | 23.03.14 - 2023.03.14 94 | ===================== 95 | * Added 51 ShowOCI tables to the APEX Page 96 | 97 | ===================== 98 | 23.03.07 - 2023.03.07 99 | ===================== 100 | * Added ShowOCI Section if ShowOCI data enabled 101 | 102 | ===================== 103 | 23.03.01 - 2023.03.01 104 | ===================== 105 | * Added Load statistics to Apex main page 106 | * Added Service Grouping in cost over time report 107 | 108 | ===================== 109 | 23.02.22 - 2023.02.22 110 | ===================== 111 | * Added Load Status Page and OCI_LOAD_STATUS table 112 | * Added Public Load Balancer to the Private End Point Image 113 | 114 | ===================== 115 | 23.02.16 - 2023.02.16 116 | ===================== 117 | * Change Image to Oracle Linux 8 118 | * Added showoci code to the image 119 | 120 | ===================== 121 | 23.02.07 - 2023.02.07 122 | ===================== 123 | * Migrated cx_oracle to oracledb libraries 124 | 125 | ===================== 126 | 22.11.22 - 2022.11.22 127 | ===================== 128 | * Update the list price API 129 | 130 | ===================== 131 | 22.10.15 - 2022.10.15 132 | ===================== 133 | * Added additional output information 134 | * Added Option to Tag resources 135 | 136 | ===================== 137 | 22.10.04 - 2022.10.04 138 | ===================== 139 | * Added new report to Cost Analysis 140 | * Fix few report to include billing amendment rows 141 | 142 | ===================== 143 | 22.09.02 - 2022.09.02 144 | ===================== 145 | * Fix error with script run_single_daily_usage2adw.sh 146 | 147 | ===================== 148 | 22.08.12 - 2022.08.12 149 | ===================== 150 | * Added second special tag key and corresponding reports and charts 151 | * Added Report for Cost Analysis 152 | 153 | ===================== 154 | 22.08.08 - 2022.08.08 155 | ===================== 156 | * Fix few bugs 157 | * Added OCPU report by service to daily_report and Data Statistics page 158 | 159 | ===================== 160 | 22.02.22 - 2022.02.22 161 | ===================== 162 | * New Marketplace Version 163 | 164 | ===================== 165 | 21.12.12 - 2021-12-12 166 | ===================== 167 | * Added option to run report on all Tenants when multi tenants loaded 168 | 169 | ===================== 170 | 21.11.02 - 2021-11-02 171 | ===================== 172 | * Amended APEX application for version 21.1 173 | * Amended the APEX Theme 174 | * Added instructions to the installation guide how to change the Autonomous database to private endpoint. 175 | 176 | ===================== 177 | 21.07.13 - 2021-07-13 178 | ===================== 179 | * Added Parallel queries for better performance for both APEX and usage2adw.py 180 | 181 | ===================== 182 | 21.05.25 - 2021-05-25 183 | ===================== 184 | * Added table view in APEX Application for current usage 185 | * Redesign the usage over time on APEX Application 186 | 187 | ===================== 188 | 21.05.18 - 2021-05-18 189 | ===================== 190 | * Remove Oracle IDCS prefix from the tag special if exist 191 | * Added OCI_INTERNAL_COST for internal usage 192 | 193 | ===================== 194 | 21.05.04 - 2021-05-04 195 | ===================== 196 | * Added OCPU and Storage report to the daily shell script 197 | 198 | ===================== 199 | 21.04.27 - 2021-04-27 200 | ===================== 201 | * Added gather stats crontab weekly with script run_gather_stats.sh 202 | * Fixed bug calling reference update 203 | 204 | ===================== 205 | 21.04.04 - 2021-04-04 206 | ===================== 207 | * Added option to specify one Tag Key to extract the data to TAG_SPECIAL column , use -ts 208 | * Added the Tag Special to filter and reports. 209 | * Fixed filter by Tag Data Bug 210 | 211 | ===================== 212 | 20.12.03 - 2020-12-03 213 | ===================== 214 | * Added Pagination call to the list_objects 215 | 216 | ===================== 217 | 20.11.10 - 2020-11-10 218 | ===================== 219 | * Added tenant aggregation for cost report 220 | * Added sub tenants in daily report 221 | 222 | ===================== 223 | 20.11.03 - 2020-11-03 224 | ===================== 225 | * Added functionality for faster deployment (Step by Step installation amended) 226 | * Added functionality to support Market Place Image with automatic deployment 227 | * Changed shell scripts to support credential at file config.user 228 | 229 | ===================== 230 | 20.10.27 - 2020-10.27 231 | ===================== 232 | * Added flag -sr to skip public rate 233 | * Fix Public Rate new SKUs 234 | * Added TENANT_ID with 6 last digits to support organization 235 | 236 | ===================== 237 | 20.08.04 - 2020-08-04 238 | ===================== 239 | * Aligned to APEX Version 20.1 240 | * Aligned to one cost instead of Paygo/Monthly 241 | * Added monthly consumption in the Data Statistics tab 242 | 243 | ===================== 244 | 20.07.28 - 2020-07-28 245 | ===================== 246 | * Added sleep 0.5 to the public API call to avoid too many requests error 247 | * Change Public Rate API to use one value only after OCI change costs 248 | 249 | ===================== 250 | 20.07.21 - 2020-07-21 251 | ===================== 252 | * Added Full + Parallel scan when retrieving max cost and usage file 253 | 254 | ===================== 255 | 20.07.14 - 2020-07-14 256 | ===================== 257 | * Support for Cost column changed - OCI amend the column billingUnitReadable to skuUnitDescription 258 | * Added daily report script with step by step configuration - requires OCI Email setup 259 | * Fixed bug on Apex related to the column change for Cost Report 260 | 261 | ===================== 262 | 20.07.07 - 2020-07-07 263 | ===================== 264 | * Added flags to skip usage or skip cost with -sc and -su 265 | * Added buffer size and array size for database multi insert to avoid large transaction failing 266 | 267 | ===================== 268 | 20.06.02 - 2020-06-02 269 | ===================== 270 | * Added Hourly cost over time 271 | 272 | ===================== 273 | 20.06.02 - 2020-06-02 274 | ===================== 275 | * Added Summary cost per day to the Data Statistics - if you manage many tenants, it is a great view to see them all 276 | * Added Cost by SKU to the Cost Over Time - Daily/Weekly and Monthly 277 | 278 | ===================== 279 | 20.05.18 - 2020-05-18 280 | ===================== 281 | * Added Rate Card with OCI_PRICE_LIST and using API to obtain info, Thanks to Fabio for the Idea and the API 282 | * Added discount and public rate to the cost report 283 | 284 | ===================== 285 | 20.05.11 - 2020-05-11 286 | ===================== 287 | * Added performance improvements to Cost by adding index OCI_COST_1IX and reference table OCI_COST_REFERENCE 288 | * Added Graph Report Selector to the Cost pages 289 | * Added accumulative Chart to Cost 290 | * Added Manual Descriptions for products that don't have. 291 | * Added More Charts to Cost Over Time 292 | * Added More Charts to Cost Analysis 293 | 294 | ===================== 295 | 20.05.04 - 2020-05-04 296 | ===================== 297 | * Added connectivity to the home region where bling bucket exist 298 | * Added performance improvements by adding stats tables OCI_USAGE_STATS and OCI_COST_STATS and indexes OCI_USAGE_1IX, OCI_COST_1IX, 299 | Please run the load script before importing the APEX app in order to create those tables and index 300 | 301 | ===================== 302 | 20.04.27 - 2020-04-27 303 | ===================== 304 | * Added limit, prefix and start to the list_object call 305 | * Added support for special chars 306 | * Added Currency Code to the pages 307 | * Added checks if columns exist in the file to avoid failure 308 | * Added Support for null overage 309 | * Align code to use functions properly 310 | 311 | ===================== 312 | 20.04.20 - 2020-04-20 313 | ===================== 314 | * Added table OCI_USAGE_TAG_KEYS for tags 315 | * Added table OCI_COST and OCI_COST_TAG_KEYS for cost usage 316 | * Added support for cost files 317 | * Added Cost Analysis and Cost Overview to the APEX App 318 | 319 | ===================== 320 | 20.04.13 - 2020-04-13 321 | ===================== 322 | * Added support for tags - TAGS_DATA columns to the table OCI_USAGE 323 | * Added step by step installation guide for instant principles 324 | * Added APEX Application to query the data 325 | 326 | ===================== 327 | 20.02.01 - 2020-02-01 328 | ===================== 329 | * Initial Release 330 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this repository 2 | 3 | We welcome your contributions! There are multiple ways to contribute. 4 | 5 | ## Opening issues 6 | 7 | For bugs or enhancement requests, please file a GitHub issue unless it's 8 | security related. When filing a bug remember that the better written the bug is, 9 | the more likely it is to be fixed. 10 | 11 | ## Contributing code 12 | 13 | We welcome your code contributions. Before submitting code via a pull request, 14 | you will need to have signed the [Oracle Contributor Agreement][OCA] (OCA) and 15 | your commits need to include the following line using the name and e-mail 16 | address you used to sign the OCA: 17 | 18 | ```text 19 | Signed-off-by: Your Name 20 | ``` 21 | 22 | This can be automatically added to pull requests by committing with `--sign-off` 23 | or `-s`, e.g. 24 | 25 | ```text 26 | git commit --signoff 27 | ``` 28 | 29 | Only pull requests from committers that can be verified as having signed the OCA 30 | can be accepted. 31 | 32 | ## Pull request process 33 | 34 | 1. Ensure there is an issue created to track and discuss the fix or enhancement 35 | you intend to submit. 36 | 1. Fork this repository. 37 | 1. Create a branch in your fork to implement the changes. We recommend using 38 | the issue number as part of your branch name, e.g. `1234-fixes`. 39 | 1. Ensure that any documentation is updated with the changes that are required 40 | by your change. 41 | 1. Ensure that any samples are updated if the base image has been changed. 42 | 1. Submit the pull request. *Do not leave the pull request blank*. Explain exactly 43 | what your changes are meant to do and provide simple steps on how to validate. 44 | your changes. Ensure that you reference the issue you created as well. 45 | 1. We will assign the pull request to 2-3 people for review before it is merged. 46 | 47 | ## Code of conduct 48 | 49 | Follow the [Golden Rule](https://en.wikipedia.org/wiki/Golden_Rule). If you'd 50 | like more specific guidelines, see the [Contributor Covenant Code of Conduct][COC]. 51 | 52 | [OCA]: https://oca.opensource.oracle.com 53 | [COC]: https://www.contributor-covenant.org/version/1/4/code-of-conduct/ -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Usage Report to ADW 25.05.01. 2 | 3 | Copyright (c) 2025, Oracle and/or its affiliates. 4 | 5 | The Universal Permissive License (UPL), Version 1.0 6 | 7 | Subject to the condition set forth below, permission is hereby granted to any 8 | person obtaining a copy of this software, associated documentation and/or data 9 | (collectively the "Software"), free of charge and under any and all copyright 10 | rights in the Software, and any and all patent rights owned or freely 11 | licensable by each licensor hereunder covering either (i) the unmodified 12 | Software as contributed to or provided by such licensor, or (ii) the Larger 13 | Works (as defined below), to deal in both 14 | 15 | (a) the Software, and 16 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if 17 | one is included with the Software (each a "Larger Work" to which the Software 18 | is contributed by such licensors), 19 | 20 | without restriction, including without limitation the rights to copy, create 21 | derivative works of, display, perform, and distribute the Software and make, 22 | use, sell, offer for sale, import, export, have made, and have sold the 23 | Software and the Larger Work(s), and to sublicense the foregoing rights on 24 | either these or other terms. 25 | 26 | This license is subject to the following condition: 27 | The above copyright notice and either this complete permission notice or at 28 | a minimum a reference to the UPL must be included in all copies or 29 | substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | This software is licensed under the Universal Permissive License (UPL) 1.0 2 | 3 | The Universal Permissive License (UPL), Version 1.0 4 | Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Usage2ADW - Oracle Cloud Infrastructure Usage and Cost Reports to Autonomous Database Tool 2 | 3 | ## Getting Started 4 | 5 | Usage2adw is a tool which uses the Python SDK to extract the cost reports from your tenant and load it to Oracle Autonomous Database. (DbaaS can be used as well) 6 | Authentication to OCI by User or instance principals. 7 | 8 | It uses APEX for Visualization and generates Daily e-mail report. 9 | 10 | **DISCLAIMER - This is not an official Oracle application, It does not supported by Oracle Support, It should NOT be used for utilization calculation purposes, and rather OCI's official 11 | [cost analysis](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/costanalysisoverview.htm) 12 | and [usage reports](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) features should be used instead.** 13 | 14 | For application issues, please open ticket at [github issues](https://github.com/oracle-samples/usage-reports-to-adw/issues) 15 | 16 | 17 | **Developed by Adi Zohar, 2020-2025** 18 | 19 | ## Documentation 20 | 21 | - Current State - Report the current state of a tenant. 22 | - CPU and Storage Over Time - Report usage over time for OCPUs and Storage. 23 | - Cost Analysis - Report Cost analysis for a chosen time period. 24 | - Cost Over Time - Report Cost over time by house, day, week, month. 25 | - Rate Card for Used Product - Report the rate card from the cost files. 26 | - ShowOCI Data (If Enabled) - Report ShowOCI data if ShowOCI enabled and data loaded to ADW. 27 | 28 | ## Cost Reports 29 | 30 | ![](img/screen_4.png) 31 | ![](img/screen_5.png) 32 | ![](img/screen_6.png) 33 | ![](img/screen_7.png) 34 | 35 | ## Rate Card 36 | 37 | ![](img/screen_8.png) 38 | 39 | ## Cost Reports 40 | 41 | ![](img/screen_1.png) 42 | ![](img/screen_2.png) 43 | ![](img/screen_3.png) 44 | 45 | ## Daily E-Mail Report 46 | 47 | ![](img/report_05.png) 48 | 49 | ## Cost Reports Overview 50 | 51 | A usage report is a comma-separated value (CSV) file that can be used to get a detailed breakdown of resources in Oracle Cloud Infrastructure for audit or invoice reconciliation. 52 | 53 | ## How Cost Reports Work 54 | 55 | The cost report is automatically generated daily, and is stored in an Oracle-owned Object Storage bucket. It contains one row per each Oracle Cloud Infrastructure resource (such as instance, Object Storage bucket, VNIC) per hour along with consumption information, metadata, and tags. Cost reports generally contain 24 hours of usage and cost data, although occasionally a cost report may contain late-arriving data that is older than 24 hours. 56 | 57 | More information can be found at [usagereportsoverview.htm](https://docs.cloud.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) 58 | 59 | ## Installation 60 | 61 | 1. [Step by Step using Resource Management (Terraform)](step_by_step_terraform.md) 62 | 63 | 2. [Step by Step Installation](step_by_step_installation.md) 64 | 65 | 3. [Step by Step Manual Installation](step_by_step_manual_installation.md) 66 | 67 | 4. [Step by Step How to File](step_by_step_howto.md) 68 | 69 | ## OCI SDK Modules and API used 70 | 71 | - IdentityClient.list_compartments - Policy COMPARTMENT_INSPECT 72 | - IdentityClient.get_tenancy - Policy TENANCY_INSPECT 73 | - ObjectStorageClient.list_objects - Policy OBJECT_INSPECT 74 | - ObjectStorageClient.get_object - Policy OBJECT_READ 75 | - SecretsClient.get_secret_bundle - Policy SECRET_BUNDLE_READ 76 | 77 | - Rest API Used - [Accessing List Pricing](https://docs.oracle.com/en-us/iaas/Content/GSG/Tasks/signingup_topic-Estimating_Costs.htm#accessing_list_pricing) 78 | 79 | ## Database Tables 80 | 81 | - OCI_COST - Raw data of the cost reports 82 | - OCI_COST_STATS - Summary Stats of the Cost Report for quick query if only filtered by tenant and date 83 | - OCI_COST_TAG_KEYS - Tag keys of the cost reports 84 | - OCI_COST_REFERENCE - Reference table of the cost filter keys - SERVICE, REGION, COMPARTMENT, PRODUCT, SUBSCRIPTION 85 | - OCI_PRICE_LIST - Has the price list and the cost per product 86 | - OCI_LOAD_STATUS - Has the load file statistics 87 | - OCI_TENANT - Has the display name of the child tenants (Manual Update) 88 | 89 | ## 3rd Party Dependencies including tested versions 90 | 91 | - Python 3.9.19 92 | - oracledb 3.0.0 93 | - requests 2.32.1 94 | - OCI Python SDK 2.144.1 95 | 96 | ## Contributing 97 | 98 | Usage2ADW utility is an open source project. 99 | Oracle gratefully acknowledges the contributions to Usage2ADW utility that have been made by the community. 100 | Before submitting a pull request, please [review our contribution guide](./CONTRIBUTING.md) 101 | 102 | ## Security 103 | 104 | Please consult the [security guide](./SECURITY.md) for our responsible security vulnerability disclosure process 105 | 106 | ## My Other Projects 107 | 108 | - [ShowOCI](https://github.com/oracle/oci-python-sdk/tree/master/examples/showoci) 109 | 110 | - [ShowUsage](https://github.com/oracle/oci-python-sdk/tree/master/examples/showusage) 111 | 112 | - [ShowSubscription](https://github.com/oracle/oci-python-sdk/tree/master/examples/showsubscription) 113 | 114 | - [ShowRewards](https://github.com/oracle/oci-python-sdk/tree/master/examples/showrewards) 115 | 116 | - [List Resources in Tenancy](https://github.com/oracle/oci-python-sdk/tree/master/examples/list_resources_in_tenancy) 117 | 118 | - [Object Storage Tools](https://github.com/oracle/oci-python-sdk/tree/master/examples/object_storage) 119 | 120 | - [Tag Resources in Tenancy](https://github.com/oracle/oci-python-sdk/tree/master/examples/tag_resources_in_tenancy) 121 | 122 | ## License 123 | 124 | Copyright (c) 2025, Oracle and/or its affiliates. 125 | Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 126 | 127 | See [LICENSE](./LICENSE.txt) for details. 128 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting security vulnerabilities 2 | 3 | Oracle values the independent security research community and believes that 4 | responsible disclosure of security vulnerabilities helps us ensure the security 5 | and privacy of all our users. 6 | 7 | Please do NOT raise a GitHub Issue to report a security vulnerability. If you 8 | believe you have found a security vulnerability, please submit a report to 9 | [secalert_us@oracle.com][1] preferably with a proof of concept. Please review 10 | some additional information on [how to report security vulnerabilities to Oracle][2]. 11 | We encourage people who contact Oracle Security to use email encryption using 12 | [our encryption key][3]. 13 | 14 | We ask that you do not use other channels or contact the project maintainers 15 | directly. 16 | 17 | Non-vulnerability related security issues including ideas for new or improved 18 | security features are welcome on GitHub Issues. 19 | 20 | ## Security updates, alerts and bulletins 21 | 22 | Security updates will be released on a regular cadence. Many of our projects 23 | will typically release security fixes in conjunction with the 24 | Oracle Critical Patch Update program. Additional 25 | information, including past advisories, is available on our [security alerts][4] 26 | page. 27 | 28 | ## Security-related information 29 | 30 | We will provide security related information such as a threat model, considerations 31 | for secure use, or any known security issues in our documentation. Please note 32 | that labs and sample code are intended to demonstrate a concept and may not be 33 | sufficiently hardened for production use. 34 | 35 | [1]: mailto:secalert_us@oracle.com 36 | [2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html 37 | [3]: https://www.oracle.com/security-alerts/encryptionkey.html 38 | [4]: https://www.oracle.com/security-alerts/ 39 | -------------------------------------------------------------------------------- /img/Image_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_01.png -------------------------------------------------------------------------------- /img/Image_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_02.png -------------------------------------------------------------------------------- /img/Image_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_03.png -------------------------------------------------------------------------------- /img/Image_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_04.png -------------------------------------------------------------------------------- /img/Image_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_05.png -------------------------------------------------------------------------------- /img/Image_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_06.png -------------------------------------------------------------------------------- /img/Image_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_07.png -------------------------------------------------------------------------------- /img/Image_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_08.png -------------------------------------------------------------------------------- /img/Image_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_09.png -------------------------------------------------------------------------------- /img/Image_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_10.png -------------------------------------------------------------------------------- /img/Image_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_11.png -------------------------------------------------------------------------------- /img/Image_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_12.png -------------------------------------------------------------------------------- /img/Image_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_13.png -------------------------------------------------------------------------------- /img/Image_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_14.png -------------------------------------------------------------------------------- /img/Image_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_15.png -------------------------------------------------------------------------------- /img/Image_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_16.png -------------------------------------------------------------------------------- /img/Image_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_17.png -------------------------------------------------------------------------------- /img/Image_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_18.png -------------------------------------------------------------------------------- /img/Image_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_19.png -------------------------------------------------------------------------------- /img/Image_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_20.png -------------------------------------------------------------------------------- /img/Image_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_21.png -------------------------------------------------------------------------------- /img/Image_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_22.png -------------------------------------------------------------------------------- /img/Image_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_23.png -------------------------------------------------------------------------------- /img/Image_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_24.png -------------------------------------------------------------------------------- /img/Image_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_25.png -------------------------------------------------------------------------------- /img/Image_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_26.png -------------------------------------------------------------------------------- /img/Image_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_27.png -------------------------------------------------------------------------------- /img/Image_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_28.png -------------------------------------------------------------------------------- /img/Image_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_29.png -------------------------------------------------------------------------------- /img/Image_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_30.png -------------------------------------------------------------------------------- /img/Image_31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_31.png -------------------------------------------------------------------------------- /img/Image_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_32.png -------------------------------------------------------------------------------- /img/Image_33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_33.png -------------------------------------------------------------------------------- /img/Image_34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_34.png -------------------------------------------------------------------------------- /img/Image_35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_35.png -------------------------------------------------------------------------------- /img/Image_36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/Image_36.png -------------------------------------------------------------------------------- /img/pe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/pe1.png -------------------------------------------------------------------------------- /img/pe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/pe2.png -------------------------------------------------------------------------------- /img/pe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/pe3.png -------------------------------------------------------------------------------- /img/report_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/report_01.png -------------------------------------------------------------------------------- /img/report_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/report_02.png -------------------------------------------------------------------------------- /img/report_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/report_03.png -------------------------------------------------------------------------------- /img/report_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/report_04.png -------------------------------------------------------------------------------- /img/report_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/report_05.png -------------------------------------------------------------------------------- /img/screen_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_1.png -------------------------------------------------------------------------------- /img/screen_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_2.png -------------------------------------------------------------------------------- /img/screen_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_3.png -------------------------------------------------------------------------------- /img/screen_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_4.png -------------------------------------------------------------------------------- /img/screen_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_5.png -------------------------------------------------------------------------------- /img/screen_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_6.png -------------------------------------------------------------------------------- /img/screen_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_7.png -------------------------------------------------------------------------------- /img/screen_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/screen_8.png -------------------------------------------------------------------------------- /img/stack_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_1.png -------------------------------------------------------------------------------- /img/stack_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_10.png -------------------------------------------------------------------------------- /img/stack_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_11.png -------------------------------------------------------------------------------- /img/stack_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_12.png -------------------------------------------------------------------------------- /img/stack_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_13.png -------------------------------------------------------------------------------- /img/stack_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_14.png -------------------------------------------------------------------------------- /img/stack_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_15.png -------------------------------------------------------------------------------- /img/stack_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_16.png -------------------------------------------------------------------------------- /img/stack_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_17.png -------------------------------------------------------------------------------- /img/stack_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_18.png -------------------------------------------------------------------------------- /img/stack_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_19.png -------------------------------------------------------------------------------- /img/stack_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_2.png -------------------------------------------------------------------------------- /img/stack_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_20.png -------------------------------------------------------------------------------- /img/stack_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_3.png -------------------------------------------------------------------------------- /img/stack_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_4.png -------------------------------------------------------------------------------- /img/stack_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_5.png -------------------------------------------------------------------------------- /img/stack_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_6.png -------------------------------------------------------------------------------- /img/stack_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_7.png -------------------------------------------------------------------------------- /img/stack_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_8.png -------------------------------------------------------------------------------- /img/stack_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/45a959c64797e91b075202a90785afda4ed68e63/img/stack_9.png -------------------------------------------------------------------------------- /shell_scripts/run_gather_stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, Jul 7th 2020 7 | # 8 | # run_gather_stats for crontab use weekly run 9 | # 10 | # Amend variables below and database connectivity 11 | # 12 | # Crontab set: 13 | # 30 0 * * 0 timeout 6h /home/opc/usage_reports_to_adw/shell_scripts/run_gather_stats.sh > /home/opc/usage_reports_to_adw/run_gather_stats_run.txt 2>&1 14 | ############################################################################################################################# 15 | # Env Variables based on yum instant client 16 | export CLIENT_HOME=/usr/lib/oracle/current/client64 17 | export PATH=$PATH:$CLIENT_HOME/bin:$CLIENT_HOME 18 | 19 | # App dir 20 | export TNS_ADMIN=$HOME/ADWCUSG 21 | export APPDIR=$HOME/usage_reports_to_adw 22 | export CREDFILE=$APPDIR/config.user 23 | cd $APPDIR 24 | 25 | # Mail Info 26 | export DATE_PRINT="`date '+%d-%b-%Y'`" 27 | 28 | # database info 29 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 30 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 31 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 32 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 33 | 34 | #################################################### 35 | # Retrieve Database Password 36 | # From KMS Vault using Secret 37 | #################################################### 38 | if [ -z "${DATABASE_SECRET_ID}" ] 39 | then 40 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 41 | exit 1 42 | fi 43 | 44 | if [ -z "${DATABASE_SECRET_TENANT}" ] 45 | then 46 | export DATABASE_SECRET_TENANT=local 47 | fi 48 | 49 | # Retrieve Secret from KMS Vault 50 | log=/tmp/check_secret_$$.log 51 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 52 | 53 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 54 | echo "Error retrieving Secret, Abort" 55 | rm -f $log 56 | exit 1 57 | fi 58 | rm -f $log 59 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 60 | 61 | # Fixed variables 62 | export DATE=`date '+%Y%m%d_%H%M'` 63 | export REPORT_DIR=${APPDIR}/report/daily 64 | export OUTPUT_FILE=${REPORT_DIR}/gather_stats_${DATE}.txt 65 | mkdir -p ${REPORT_DIR} 66 | 67 | ################################## 68 | # run stats 69 | ################################## 70 | echo "Running Gather Stats, Log = $OUTPUT_FILE" 71 | echo " 72 | connect ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 73 | set pages 0 head on feed on lines 799 trimsp on echo on time on timing on 74 | prompt exec dbms_stats.gather_schema_stats(ownname=>'USAGE',DEGREE=>8,estimate_percent=>10,block_sample=>TRUE,stattype=>'DATA',force=>TRUE, method_opt=>'FOR ALL COLUMNS SIZE 1',cascade=>TRUE); 75 | exec dbms_stats.gather_schema_stats(ownname=>'USAGE',DEGREE=>8,estimate_percent=>10,block_sample=>TRUE,stattype=>'DATA',force=>TRUE, method_opt=>'FOR ALL COLUMNS SIZE 1',cascade=>TRUE); 76 | " | sqlplus -s /nolog | tee -a $OUTPUT_FILE 77 | 78 | # Check for errors 79 | if (( `grep ORA- $OUTPUT_FILE | wc -l` > 0 )) 80 | then 81 | echo "" 82 | echo "!!! Error running gather stats, check logfile $OUTPUT_FILE" 83 | echo "" 84 | grep ORA- $OUTPUT_FILE 85 | exit 1 86 | fi 87 | 88 | -------------------------------------------------------------------------------- /shell_scripts/run_load_showoci_csv_to_adw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################################################################# 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, Feb 8th 2023, Amended May 1st 2025 7 | # 8 | # Run load_showoci_csv_to_adw 9 | # 10 | # Crontab set: 11 | # 0 0 * * * timeout 6h /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh > /home/opc/usage_reports_to_adw/run_multi_tenants_crontab_run.txt 2>&1 12 | ############################################################################################################################# 13 | 14 | # Env Variables based on yum instant client 15 | export CLIENT_HOME=/usr/lib/oracle/current/client64 16 | export LD_LIBRARY_PATH=${CLIENT_HOME}/lib 17 | export PATH=$PATH:$CLIENT_HOME/bin:$CLIENT_HOME 18 | export EXTRA_VARIABLE=$1 19 | 20 | # App dir 21 | export TNS_ADMIN=$HOME/ADWCUSG 22 | export APPDIR=$HOME/usage_reports_to_adw 23 | export SHOWOCI_DIR=$HOME/showoci 24 | export CREDFILE=$APPDIR/config.user 25 | cd $APPDIR 26 | 27 | # database info 28 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 29 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 30 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 31 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 32 | 33 | #################################################### 34 | # Check Secret Exist 35 | #################################################### 36 | if [ -z "${DATABASE_SECRET_ID}" ] 37 | then 38 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 39 | exit 1 40 | fi 41 | 42 | if [ -z "${DATABASE_SECRET_TENANT}" ] 43 | then 44 | export DATABASE_SECRET_TENANT=local 45 | fi 46 | 47 | # Fixed variables 48 | export DATE=`date '+%Y%m%d_%H%M'` 49 | export REPORT_DIR=${APPDIR}/report 50 | mkdir -p ${REPORT_DIR} 51 | 52 | # Check if showoci_csv2adw.py already running 53 | if (( `ps -ef |grep python |grep showoci_csv2adw.py |wc -l` > 0 )) 54 | then 55 | echo "showoci_csv2adw.py is already running, abort.." 56 | ps -ef |grep python |grep showoci_csv2adw.py 57 | exit 1 58 | fi 59 | 60 | ################################## 61 | # Report Function 62 | ################################## 63 | run_report() 64 | { 65 | NAME=$1 66 | CSV=$2 67 | export tenant="-t $NAME" 68 | if [ -z "$NAME" ] 69 | then 70 | exit 1 71 | fi 72 | 73 | if [ -z "${CSV}" ] 74 | then 75 | exit 1 76 | fi 77 | 78 | DIR=${REPORT_DIR}/CSV_$NAME 79 | OUTPUT_FILE=${DIR}/${DATE}_${NAME}.txt 80 | mkdir -p $DIR 81 | echo "Running $NAME... to $OUTPUT_FILE " 82 | python3 $APPDIR/usage2adw_showoci_csv2adw.py -du $DATABASE_USER -t $DATABASE_SECRET_TENANT -ds $DATABASE_SECRET_ID -dn $DATABASE_NAME -csv $CSV -usethick $EXTRA_VARIABLE |tee -a $OUTPUT_FILE 83 | grep -i "Error" $OUTPUT_FILE 84 | 85 | ERROR="" 86 | 87 | if (( `grep -i Error $OUTPUT_FILE | wc -l` > 0 )) 88 | then 89 | ERROR=" with **** Errors ****" 90 | fi 91 | 92 | echo "Finish `date` - $NAME $ERROR " 93 | } 94 | 95 | ########################################################### 96 | # Main 97 | ########################################################### 98 | echo "Start running at `date`..." 99 | 100 | run_report local $SHOWOCI_DIR/report/local/csv/local 101 | 102 | echo "Completed at `date`.." 103 | -------------------------------------------------------------------------------- /shell_scripts/run_multi_daily_usage2adw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################################################################# 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, Feb 28th 2020, Amended May 1st 2025 7 | # 8 | # Run Multi daily usage load for crontab use 9 | # 10 | # Amend variables below and database connectivity 11 | # Use .oci/config profiles with user authentications 12 | # 13 | # Crontab set: 14 | # 0 0 * * * timeout 6h /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh > /home/opc/usage_reports_to_adw/cron_run_multi_tenants_crontab_run.txt 2>&1 15 | ############################################################################################################################# 16 | 17 | # Env Variables based on yum instant client 18 | export CLIENT_HOME=/usr/lib/oracle/current/client64 19 | export PATH=$PATH:$CLIENT_HOME/bin:$CLIENT_HOME 20 | 21 | # App dir 22 | export TNS_ADMIN=$HOME/ADWCUSG 23 | export APPDIR=$HOME/usage_reports_to_adw 24 | export CREDFILE=$APPDIR/config.user 25 | cd $APPDIR 26 | 27 | # database info 28 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 29 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 30 | export TAG1_SPECIAL=`grep "^TAG_SPECIAL" $CREDFILE| sed -s 's/TAG_SPECIAL=//'` 31 | export TAG2_SPECIAL=`grep "^TAG2_SPECIAL" $CREDFILE| sed -s 's/TAG2_SPECIAL=//'` 32 | export TAG3_SPECIAL=`grep "^TAG3_SPECIAL" $CREDFILE| sed -s 's/TAG3_SPECIAL=//'` 33 | export TAG4_SPECIAL=`grep "^TAG4_SPECIAL" $CREDFILE| sed -s 's/TAG4_SPECIAL=//'` 34 | export EXTRACT_DATE=`grep "^EXTRACT_DATE" $CREDFILE| sed -s 's/EXTRACT_DATE=//'` 35 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 36 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 37 | 38 | #################################################### 39 | # Check Secret Exist 40 | #################################################### 41 | if [ -z "${DATABASE_SECRET_ID}" ] 42 | then 43 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 44 | exit 1 45 | fi 46 | 47 | if [ -z "${DATABASE_SECRET_TENANT}" ] 48 | then 49 | export DATABASE_SECRET_TENANT=local 50 | fi 51 | 52 | # Fixed variables 53 | export DATE=`date '+%Y%m%d_%H%M'` 54 | export REPORT_DIR=${APPDIR}/report 55 | mkdir -p ${REPORT_DIR} 56 | 57 | # Check if usage2adw.py already running 58 | if (( `ps -ef |grep python |grep usage2adw.py |wc -l` > 0 )) 59 | then 60 | echo "usage2adw.py is already running, abort.." 61 | ps -ef |grep python |grep usage2adw.py 62 | exit 1 63 | fi 64 | 65 | ################################## 66 | # Report Function 67 | ################################## 68 | run_report() 69 | { 70 | NAME=$1 71 | export tenant="-t $NAME" 72 | if [ -z "$NAME" ] 73 | then 74 | exit 1 75 | fi 76 | 77 | if [ "${1}" = "local" ]; then 78 | export tenant="-ip" 79 | fi 80 | 81 | if [ -z "${2}" ] 82 | then 83 | TAG1=$TAG1_SPECIAL 84 | else 85 | TAG1=$2 86 | fi 87 | 88 | if [ -z "${3}" ] 89 | then 90 | TAG2=$TAG2_SPECIAL 91 | else 92 | TAG2=$3 93 | fi 94 | 95 | if [ -z "${4}" ] 96 | then 97 | TAG3=$TAG3_SPECIAL 98 | else 99 | TAG3=$4 100 | fi 101 | 102 | if [ -z "${5}" ] 103 | then 104 | TAG4=$TAG4_SPECIAL 105 | else 106 | TAG4=$5 107 | fi 108 | 109 | DIR=${REPORT_DIR}/$NAME 110 | OUTPUT_FILE=${DIR}/${DATE}_${NAME}.txt 111 | mkdir -p $DIR 112 | echo "Running $NAME... to $OUTPUT_FILE " 113 | python3 $APPDIR/usage2adw.py $tenant -du $DATABASE_USER -ds $DATABASE_SECRET_ID -dst $DATABASE_SECRET_TENANT -dn $DATABASE_NAME -d $EXTRACT_DATE -ts "${TAG1}" -ts2 "${TAG2}" -ts3 "${TAG3}" -ts4 "${TAG4}" $6 |tee -a $OUTPUT_FILE 114 | grep -i "Error" $OUTPUT_FILE 115 | 116 | ERROR="" 117 | 118 | if (( `grep -i Error $OUTPUT_FILE | wc -l` > 0 )) 119 | then 120 | ERROR=" with **** Errors ****" 121 | fi 122 | 123 | echo "Finish `date` - $NAME $ERROR " 124 | } 125 | 126 | ########################################################### 127 | # Main 128 | ########################################################### 129 | # local - authentication by instant principle 130 | # add oci config tenant profile to add more tenants to load 131 | ################################## 132 | echo "Start running at `date`..." 133 | 134 | run_report local 135 | #run_report tenant2 tagspecial1 tagspecial2 tagspecial3 tagspecial4 136 | #run_report tenant3 tagspecial1 tagspecial2 tagspecial3 tagspecial4 137 | 138 | echo "Completed at `date`.." 139 | -------------------------------------------------------------------------------- /shell_scripts/run_report_compart_service_daily_to_csv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, OCt 18 202 7 | # 8 | # run_report_compart_service_daily_to_csv.sh 9 | # 10 | # Extract Tenant, Compartment, Service and Cost to CSV 11 | # 12 | ############################################################################################################################# 13 | # Env Variables based on yum instant client 14 | export CLIENT_HOME=/usr/lib/oracle/current/client64 15 | export PATH=$PATH:$CLIENT_HOME/bin 16 | 17 | # App dir 18 | export TNS_ADMIN=$HOME/ADWCUSG 19 | export APPDIR=$HOME/usage_reports_to_adw 20 | export CREDFILE=$APPDIR/config.user 21 | cd $APPDIR 22 | 23 | # database info 24 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 25 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 26 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 27 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 28 | 29 | #################################################### 30 | # Retrieve Database Password 31 | # From KMS Vault using Secret 32 | #################################################### 33 | if [ -z "${DATABASE_SECRET_ID}" ] 34 | then 35 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 36 | exit 1 37 | fi 38 | 39 | if [ -z "${DATABASE_SECRET_TENANT}" ] 40 | then 41 | export DATABASE_SECRET_TENANT=local 42 | fi 43 | 44 | # Retrieve Secret from KMS Vault 45 | log=/tmp/check_secret_$$.log 46 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 47 | 48 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 49 | echo "Error retrieving Secret, Abort" 50 | rm -f $log 51 | exit 1 52 | fi 53 | rm -f $log 54 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 55 | 56 | 57 | # Fixed variables 58 | export DATE=`date '+%Y%m%d'` 59 | export REPORT_DIR=${APPDIR}/report/daily 60 | export OUTPUT_FILE=${REPORT_DIR}/daily_compartment_service_${DATE}.csv 61 | mkdir -p ${REPORT_DIR} 62 | 63 | echo "Running Report to $OUTPUT_FILE ..." 64 | 65 | ################################## 66 | # run report 67 | ################################## 68 | echo " 69 | connect ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 70 | set pages 0 head off feed off lines 799 trimsp on echo off verify off 71 | set define @ 72 | col line for a1000 73 | 74 | ALTER SESSION SET OPTIMIZER_IGNORE_HINTS=FALSE; 75 | ALTER SESSION SET OPTIMIZER_IGNORE_PARALLEL_HINTS=FALSE; 76 | 77 | prompt tenant,date,compartment,service,total 78 | 79 | select tenant_name||','||usage_day||','||prd_compartment_name||','||prd_service||','||TOTAL line 80 | from 81 | ( 82 | select /*+ parallel(oci_cost,8) full(oci_cost) */ 83 | TENANT_NAME, 84 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD') as USAGE_DAY, 85 | prd_compartment_name, 86 | replace(nvl(prd_service,COST_PRODUCT_SKU),'_',' ') prd_service, 87 | sum(COST_MY_COST) as TOTAL 88 | from oci_cost 89 | group by 90 | TENANT_NAME, 91 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD'), 92 | prd_compartment_name, 93 | replace(nvl(prd_service,COST_PRODUCT_SKU),'_',' ') 94 | order by 1,2,3 95 | ); 96 | 97 | " | sqlplus -s /nolog > $OUTPUT_FILE 98 | 99 | # Check for errors 100 | if (( `grep ORA- $OUTPUT_FILE | wc -l` > 0 )) 101 | then 102 | echo "" 103 | echo "!!! Error running daily report, check logfile $OUTPUT_FILE" 104 | echo "" 105 | grep ORA- $OUTPUT_FILE 106 | exit 1 107 | fi 108 | 109 | echo "File Exctracted to $OUTPUT_FILE" 110 | 111 | -------------------------------------------------------------------------------- /shell_scripts/run_report_compart_service_sku_daily_to_csv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, OCt 18 202 7 | # 8 | # run_report_compart_service_sku_daily_to_csv.sh 9 | # 10 | # Extract Tenant, Compartment, Service and Cost to CSV 11 | # 12 | ############################################################################################################################# 13 | # Env Variables based on yum instant client 14 | export CLIENT_HOME=/usr/lib/oracle/current/client64 15 | export PATH=$PATH:$CLIENT_HOME/bin 16 | 17 | # App dir 18 | export TNS_ADMIN=$HOME/ADWCUSG 19 | export APPDIR=$HOME/usage_reports_to_adw 20 | export CREDFILE=$APPDIR/config.user 21 | cd $APPDIR 22 | 23 | # database info 24 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 25 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 26 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 27 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 28 | 29 | #################################################### 30 | # Retrieve Database Password 31 | # From KMS Vault using Secret 32 | #################################################### 33 | if [ -z "${DATABASE_SECRET_ID}" ] 34 | then 35 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 36 | exit 1 37 | fi 38 | 39 | if [ -z "${DATABASE_SECRET_TENANT}" ] 40 | then 41 | export DATABASE_SECRET_TENANT=local 42 | fi 43 | 44 | # Retrieve Secret from KMS Vault 45 | log=/tmp/check_secret_$$.log 46 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 47 | 48 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 49 | echo "Error retrieving Secret, Abort" 50 | rm -f $log 51 | exit 1 52 | fi 53 | rm -f $log 54 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 55 | 56 | 57 | # Fixed variables 58 | export DATE=`date '+%Y%m%d'` 59 | export REPORT_DIR=${APPDIR}/report/daily 60 | export OUTPUT_FILE=${REPORT_DIR}/daily_compartment_service_sku_${DATE}.csv 61 | mkdir -p ${REPORT_DIR} 62 | 63 | echo "Running Report to $OUTPUT_FILE ..." 64 | 65 | ################################## 66 | # run report 67 | ################################## 68 | echo " 69 | connect ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 70 | set pages 0 head off feed off lines 799 trimsp on echo off verify off 71 | set define @ 72 | col line for a1000 73 | 74 | ALTER SESSION SET OPTIMIZER_IGNORE_HINTS=FALSE; 75 | ALTER SESSION SET OPTIMIZER_IGNORE_PARALLEL_HINTS=FALSE; 76 | 77 | prompt tenant,date,compartment,service,sku,desc,total 78 | 79 | select tenant_name||','||usage_day||','||prd_compartment_name||','||prd_service||','||prd_sku||','||prd_desc||','||TOTAL line 80 | from 81 | ( 82 | select /*+ parallel(oci_cost,8) full(oci_cost) */ 83 | TENANT_NAME, 84 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD') as USAGE_DAY, 85 | prd_compartment_name, 86 | replace(nvl(prd_service,COST_PRODUCT_SKU),'_',' ') prd_service, 87 | COST_PRODUCT_SKU prd_sku, 88 | min(PRD_DESCRIPTION) prd_desc, 89 | sum(COST_MY_COST) as TOTAL 90 | from oci_cost 91 | group by 92 | TENANT_NAME, 93 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD'), 94 | prd_compartment_name, 95 | replace(nvl(prd_service,COST_PRODUCT_SKU),'_',' '), 96 | cost_product_sku 97 | order by 1,2,3 98 | ); 99 | 100 | " | sqlplus -s /nolog > $OUTPUT_FILE 101 | 102 | # Check for errors 103 | if (( `grep ORA- $OUTPUT_FILE | wc -l` > 0 )) 104 | then 105 | echo "" 106 | echo "!!! Error running daily report, check logfile $OUTPUT_FILE" 107 | echo "" 108 | grep ORA- $OUTPUT_FILE 109 | exit 1 110 | fi 111 | 112 | echo "File Exctracted to $OUTPUT_FILE" 113 | 114 | -------------------------------------------------------------------------------- /shell_scripts/run_sqlplus_usage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, Aug 1st 2023 7 | # 8 | # run_sqlplus_usage.sh 9 | # 10 | ############################################################################################################################# 11 | # Env Variables based on yum instant client 12 | export CLIENT_HOME=/usr/lib/oracle/current/client64 13 | export PATH=$PATH:$CLIENT_HOME/bin 14 | 15 | # App dir 16 | export TNS_ADMIN=$HOME/ADWCUSG 17 | export APPDIR=$HOME/usage_reports_to_adw 18 | export CREDFILE=$APPDIR/config.user 19 | cd $APPDIR 20 | 21 | # database info 22 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 23 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 24 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 25 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 26 | 27 | #################################################### 28 | # Retrieve Database Password 29 | # From KMS Vault using Secret 30 | #################################################### 31 | if [ -z "${DATABASE_SECRET_ID}" ] 32 | then 33 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 34 | exit 1 35 | fi 36 | 37 | if [ -z "${DATABASE_SECRET_TENANT}" ] 38 | then 39 | export DATABASE_SECRET_TENANT=local 40 | fi 41 | 42 | # Retrieve Secret from KMS Vault 43 | log=/tmp/check_secret_$$.log 44 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 45 | 46 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 47 | echo "Error retrieving Secret, Abort" 48 | rm -f $log 49 | exit 1 50 | fi 51 | rm -f $log 52 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 53 | 54 | ################################## 55 | # run sqlplus 56 | ################################## 57 | sqlplus ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 58 | -------------------------------------------------------------------------------- /shell_scripts/run_table_size_info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, OCt 18 2022 7 | # 8 | # run_table_size_info.sh 9 | # 10 | # Extract Tenant, Compartment, Service and Cost to CSV 11 | # 12 | ############################################################################################################################# 13 | # Env Variables based on yum instant client 14 | export CLIENT_HOME=/usr/lib/oracle/current/client64 15 | export PATH=$PATH:$CLIENT_HOME/bin 16 | 17 | # App dir 18 | export TNS_ADMIN=$HOME/ADWCUSG 19 | export APPDIR=$HOME/usage_reports_to_adw 20 | export CREDFILE=$APPDIR/config.user 21 | cd $APPDIR 22 | 23 | # database info 24 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 25 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 26 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 27 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 28 | 29 | #################################################### 30 | # Retrieve Database Password 31 | # From KMS Vault using Secret 32 | #################################################### 33 | if [ -z "${DATABASE_SECRET_ID}" ] 34 | then 35 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 36 | exit 1 37 | fi 38 | 39 | if [ -z "${DATABASE_SECRET_TENANT}" ] 40 | then 41 | export DATABASE_SECRET_TENANT=local 42 | fi 43 | 44 | # Retrieve Secret from KMS Vault 45 | log=/tmp/check_secret_$$.log 46 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 47 | 48 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 49 | echo "Error retrieving Secret, Abort" 50 | rm -f $log 51 | exit 1 52 | fi 53 | rm -f $log 54 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 55 | 56 | 57 | ################################## 58 | # run report 59 | ################################## 60 | echo " 61 | connect ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 62 | set pages 1000 lines 700 trimsp on 63 | col segment_name for a36 64 | col gb for 999,999.99 65 | select segment_name, sum(bytes/1024/1024/1024) GB 66 | from user_segments 67 | group by segment_name 68 | having sum(bytes/1024/1024/1024) > 0.01 69 | order by 2 desc; 70 | " | sqlplus -s /nolog 71 | 72 | -------------------------------------------------------------------------------- /shell_scripts/run_tenant_usage_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ############################################################################################################################# 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # Author - Adi Zohar, Apr 28 2023 7 | # 8 | # run_tenant_usage_report.sh 9 | # 10 | # Amend variables below and database connectivity 11 | # 12 | # Crontab set: 13 | # 7 0 * * 1 timeout 6h /home/opc/usage_reports_to_adw/shell_scripts/run_tenant_usage_report.sh > /home/opc/usage_reports_to_adw/log/run_tenant_usage_report_run.txt 2>&1 14 | # 15 | ############################################################################################################################# 16 | # Env Variables based on yum instant client 17 | export CLIENT_HOME=/usr/lib/oracle/current/client64 18 | export PATH=$PATH:$CLIENT_HOME/bin:$CLIENT_HOME 19 | 20 | # App dir 21 | export TNS_ADMIN=$HOME/ADWCUSG 22 | export APPDIR=$HOME/usage_reports_to_adw 23 | export CREDFILE=$APPDIR/config.user 24 | cd $APPDIR 25 | 26 | # Mail Info 27 | export DATE_PRINT="`date '+%d-%b-%Y'`" 28 | export MAIL_FROM_NAME="Tenant.Usage.Report" 29 | export MAIL_FROM_EMAIL="report@oracleemaildelivery.com" 30 | export MAIL_SUBJECT="Cost Usage Report $DATE_PRINT" 31 | 32 | # database info 33 | export DATABASE_USER=`grep "^DATABASE_USER" $CREDFILE | sed -s 's/DATABASE_USER=//'` 34 | export DATABASE_NAME=`grep "^DATABASE_NAME" $CREDFILE | sed -s 's/DATABASE_NAME=//'` 35 | export DATABASE_SECRET_ID=`grep "^DATABASE_SECRET_ID" $CREDFILE | sed -s 's/DATABASE_SECRET_ID=//'` 36 | export DATABASE_SECRET_TENANT=`grep "^DATABASE_SECRET_TENANT" $CREDFILE | sed -s 's/DATABASE_SECRET_TENANT=//'` 37 | 38 | #################################################### 39 | # Retrieve Database Password 40 | # From KMS Vault using Secret 41 | #################################################### 42 | if [ -z "${DATABASE_SECRET_ID}" ] 43 | then 44 | echo "Usage2ADW moved to Secret and DATABASE_SECRET_ID does not exist, abort ..." 45 | exit 1 46 | fi 47 | 48 | if [ -z "${DATABASE_SECRET_TENANT}" ] 49 | then 50 | export DATABASE_SECRET_TENANT=local 51 | fi 52 | 53 | # Retrieve Secret from KMS Vault 54 | log=/tmp/check_secret_$$.log 55 | python3 ${APPDIR}/usage2adw_retrieve_secret.py -t $DATABASE_SECRET_TENANT -secret $DATABASE_SECRET_ID -check | tee -a $log 56 | 57 | if (( `grep "Secret Okay" $log | wc -l` < 1 )); then 58 | echo "Error retrieving Secret, Abort" 59 | rm -f $log 60 | exit 1 61 | fi 62 | rm -f $log 63 | export DATABASE_PASS=`python3 usage2adw_retrieve_secret.py -ip -secret $DATABASE_SECRET_ID | grep "^Value=" | sed -s 's/Value=//'` 64 | 65 | ############################################ 66 | # Main 67 | ############################################ 68 | run_report() 69 | { 70 | # Fixed variables 71 | export TENANT_NAME=$1 72 | export TENANT_ID=$2 73 | export USER_EMAIL=$3 74 | export DATE=`date '+%Y%m%d_%H%M'` 75 | export REPORT_DIR=${APPDIR}/report/daily 76 | export OUTPUT_FILE=${REPORT_DIR}/usage_report_${TENANT_NAME}_${TENANT_ID}_${DATE}.txt 77 | export LOG_FILE=${REPORT_DIR}/usage_report_log_${TENANT_NAME}_${TENANT_ID}_${DATE}.txt 78 | mkdir -p ${REPORT_DIR} 79 | 80 | echo "" | tee -a $LOG_FILE 81 | echo "Running on $TENANT_NAME : $TENANT_ID ..." | tee -a $LOG_FILE 82 | 83 | ################################## 84 | # run report per tenant_id 85 | ################################## 86 | echo " 87 | connect ${DATABASE_USER}/${DATABASE_PASS}@${DATABASE_NAME} 88 | set pages 0 head off feed off lines 799 trimsp on echo off verify off 89 | set define off 90 | col line for a1000 91 | 92 | prompt 104 | 105 | prompt 106 | prompt Below Tenant Usage Report for Tenant $TENANT_NAME : $TENANT_ID.

107 | prompt Please review this list and continue to look for ways to optimize your usage.

108 | prompt
109 | 110 | prompt 111 | prompt 112 | with last_date as 113 | ( 114 | select distinct USAGE_INTERVAL_START as DATE_FILTER 115 | from 116 | ( 117 | select 118 | USAGE_INTERVAL_START, 119 | dense_rank() over (partition by null order by USAGE_INTERVAL_START desc) rn 120 | from oci_cost_stats 121 | where tenant_name='${TENANT_NAME}' 122 | ) where rn=48 123 | ), 124 | data as 125 | ( 126 | select /*+ use_nl(l,d) leading(l) */ 127 | USAGE_INTERVAL_START, 128 | COST_PRODUCT_SKU || ' ' || min(replace(PRD_DESCRIPTION,COST_PRODUCT_SKU||' - ','')) product, 129 | min(COST_BILLING_UNIT) COST_BILLING_UNIT, 130 | sum(USG_BILLED_QUANTITY) USG_BILLED_QUANTITY, 131 | sum(COST_MY_COST) as COST_PER_HOUR, 132 | sum(COST_MY_COST)*365 as COST_PER_YEAR 133 | from 134 | last_date l, 135 | oci_cost d 136 | where 137 | tenant_name='${TENANT_NAME}' and 138 | tenant_id='${TENANT_ID}' and 139 | USAGE_INTERVAL_START = l.DATE_FILTER and 140 | USG_BILLED_QUANTITY>0 and 141 | COST_MY_COST<>0 142 | group by USAGE_INTERVAL_START,COST_PRODUCT_SKU 143 | order by COST_PER_HOUR desc 144 | ) 145 | select 146 | ''|| 147 | ''|| 148 | ''|| 149 | ''|| 150 | ''|| 151 | ''|| 152 | ''|| 153 | '' 154 | as line 155 | from dual 156 | union all 157 | select ''|| 158 | ''|| 159 | ''|| 160 | ''|| 161 | ''|| 162 | ''|| 163 | ''|| 164 | '' as line 165 | from 166 | data 167 | ; 168 | 169 | prompt
Summary report for $USER_NAME - $TENANT_NAME : $TENANT_ID
Usage TimeProductUnitsUsageCost Per HourCost Per Year
'||to_char(USAGE_INTERVAL_START,'MM/DD/YYYY HH24:MI')||''||product||''||COST_BILLING_UNIT||''||to_char(USG_BILLED_QUANTITY,'999,999,999,999')||''||to_char(COST_PER_HOUR,'999,999,999,999')||''||to_char(COST_PER_YEAR,'999,999,999,999')||'
170 | 171 | prompt
172 | prompt Thank you

173 | prompt
174 | 175 | " | sqlplus -s /nolog > $OUTPUT_FILE 176 | 177 | # Check for errors 178 | if (( `grep ORA- $OUTPUT_FILE | wc -l` > 0 )) 179 | then 180 | echo "" 181 | echo "!!! Error running daily report, check logfile $OUTPUT_FILE" 182 | echo "" 183 | grep ORA- $OUTPUT_FILE 184 | else 185 | #################### 186 | # Sending e-mail 187 | #################### 188 | cat <<-eomail | /usr/sbin/sendmail -f "$MAIL_FROM_EMAIL" -F "$MAIL_FROM_NAME" -t 189 | To: $USER_EMAIL 190 | Subject: $MAIL_SUBJECT 191 | Content-Type: text/html 192 | `cat $OUTPUT_FILE` 193 | eomail 194 | rm -f $OUTPUT_FILE 195 | echo "Report sent to $USER_EMAIL ..." | tee -a $LOG_FILE 196 | fi 197 | 198 | } 199 | 200 | ############################################ 201 | # Main 202 | ############################################ 203 | 204 | run_report orasenatdpltdevopsnetw02 w4s3bq "adi.zohar@oracle.com" -------------------------------------------------------------------------------- /step_by_step_howto.md: -------------------------------------------------------------------------------- 1 | # Usage2ADW - Oracle Cloud Infrastructure Usage and Cost Reports to Autonomous Database with APEX Reporting 2 | 3 | ## How To Manual 4 | 5 | **DISCLAIMER - This is not an official Oracle application, It does not supported by Oracle Support, It should NOT be used for utilization calculation purposes, and rather OCI's official 6 | [cost analysis](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/costanalysisoverview.htm) 7 | and [usage reports](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) features should be used instead.** 8 | 9 | **Developed by Adi Zohar, 2020-2024** 10 | 11 | ## Content 12 | [1. How to create additional APEX End User Accounts](#1-how-to-create-additional-apex-end-user-accounts) 13 | 14 | [2. How to change Autonomous Database to Private End Point](#2-how-to-change-autonomous-database-to-private-end-point) 15 | 16 | [3a. How to install Usage2ADW on child tenant fetching cost and usage reports from parent tenant](#3a-how-to-install-usage2adw-on-child-tenant-fetching-cost-and-usage-reports-from-parent-tenant) 17 | 18 | [3b. How to add multiple tenants](#3b-how-to-add-multiple-tenants) 19 | 20 | [4. How to upgrade the usage2adw application and APEX](#4-how-to-upgrade-the-usage2adw-application-and-apex) 21 | 22 | [5. How to Refresh the Autonomous Database Wallet for the usage2adw application](#5-how-to-refresh-the-autonomous-database-wallet-for-the-usage2adw-application) 23 | 24 | [6. How to upgrade Oracle Instant Client to Version 19.18](#6-how-to-upgrade-oracle-instant-client-to-version-1918) 25 | 26 | [7. How to Schedule Daily Report](#7-how-to-schedule-daily-report) 27 | 28 | [8. How to Setup e-mail subscription](#8-how-to-setup-e-mail-subscription) 29 | 30 | [9. How to Enable showoci extract on usage2adw vm](#9-how-to-enable-showoci-extract-on-usage2adw-vm) 31 | 32 | [10. How to unlock user USAGE and change password](#10-how-to-unlock-user-usage-and-change-password) 33 | 34 | [11. How to truncate the Usage2ADW tables in order to reload](#11-how-to-truncate-the-usage2adw-tables-in-order-to-reload) 35 | 36 | [12. Application Flags and Sample Execution](#12-application-flags-and-sample-execution) 37 | 38 | [13. Sample of database queries](#13-sample-of-database-queries) 39 | 40 | 41 | ## 1. How to create additional APEX End User Accounts 42 | 43 | ``` 44 | Login to Workspace Managament 45 | Top 3rd Right Menu -> Manage Users and Groups 46 | --> Create User 47 | 48 | Fill: 49 | --> Username 50 | --> Email 51 | --> Password 52 | --> Confirm Password 53 | --> Optional - Require to change passqword = No 54 | --> Apply Changes 55 | ``` 56 | 57 | ![](img/Image_19.png) 58 | 59 | ![](img/Image_20.png) 60 | 61 | ![](img/Image_21.png) 62 | 63 | ![](img/Image_22.png) 64 | 65 | 66 | ## 2. How to change Autonomous Database to Private End Point 67 | 68 | Login to OCI Console -> Menu -> Oracle Database -> Autonomous Database 69 | 70 | Choose The Autonomous database for Usage2ADW 71 | 72 | More Actions Menu -> Update Network Access 73 | 74 | ![](img/pe1.png) 75 | 76 | #### Update Network Access 77 | 78 | Choose Network Access -> Private endpoint access Only 79 | 80 | Choose Network security group that will assigned to the Autonomous database 81 | 82 | If you don't have Network Security Group, Go to the Virtual Cloud Network and Create one. 83 | 84 | Make sure you allow port 1522/TCP inbound traffic. 85 | 86 | ![](img/pe2.png) 87 | 88 | #### Update VM tnsnames to the private endpoint 89 | 90 | Find the Private Endpoint URL: 91 | 92 | ![](img/pe3.png) 93 | 94 | Login to the usage2adw virtual machine using ssh tool with opc user 95 | 96 | cd ADWCUSG 97 | 98 | Edit tnsnames.ora file and change the tnsnames *_low entry host to the private end point specify in the ADW page 99 | 100 | ## 3a. How to install Usage2ADW on child tenant fetching cost and usage reports from parent tenant 101 | 102 | ``` 103 | Install Usage2ADW on the child tenant following the installation guide. 104 | Create User authentication on parent tenant as described in the following section (3.1) 105 | update run_multi_daily_usage2adw.sh file as described in section (3.2) and remove the "run_report local" 106 | ``` 107 | 108 | ## 3b. How to add multiple tenants 109 | 110 | 111 | ### 3.1 Create group and user for authentication at additional tenancy 112 | 113 | ``` 114 | Policy -> 115 | --> Name = UsageDownloadPolicy 116 | --> Desc = Allow Group UsageDownloadGroup to Extract Usage report script 117 | --> Statement 1 = define tenancy usage-report as ocid1.tenancy.oc1..aaaaaaaaned4fkpkisbwjlr56u7cj63lf3wffbilvqknstgtvzub7vhqkggq 118 | --> Statement 2 = endorse group UsageDownloadGroup to read objects in tenancy usage-report 119 | --> Statement 3 = Allow group UsageDownloadGroup to inspect compartments in tenancy 120 | --> Statement 4 = Allow group UsageDownloadGroup to inspect tenancies in tenancy 121 | ``` 122 | 123 | ### 3.2 Add the authentication to the VM 124 | 125 | Login to Usage2adw VM 126 | 127 | ``` 128 | # setup oci tenant configuration 129 | oci setup config 130 | Enter a location for your config [/home/opc/.oci/config]: ( Press Enter) 131 | Do you want add a profile here - Press Y 132 | Name of the profile - Enter the tenant name 133 | Complete the rest of the questions based on the user authentication 134 | 135 | # update run_multi_daily_usage2adw.sh 136 | cd /home/opc/usage_reports_to_adw/shell_scripts 137 | vi run_multi_daily_usage2adw.sh 138 | 139 | # scroll to the bottom and add lines per tenant profile, you can specify different tagspecial1 and tagspecial2 if different then the main tenant 140 | run_report tenant2 tagspecial1 tagspecial2 141 | run_report tenant3 tagspecial1 tagspecial2 142 | ``` 143 | 144 | ## 4. How to upgrade the usage2adw application and APEX 145 | 146 | Recommend only from version 23.8.1 or above. 147 | 148 | ``` 149 | bash -c "export usage2adw_param=-upgrade_app; $(curl -L https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/usage2adw_setup.sh)" 150 | ``` 151 | 152 | ## 5. How to Refresh the Autonomous Database Wallet for the usage2adw application 153 | 154 | ### 5a. If provisioned after July 2023 155 | 156 | ``` 157 | # On the Usage2ADW VM: 158 | cd usage_reports_to_adw 159 | ./usage2adw_setup.sh -download_wallet 160 | ``` 161 | 162 | ### 5b. Download Autonomus Database Wallet - If you provisioned before July 2023: 163 | 164 | ``` 165 | # On OCI -> MENU -> Autonomous Data Warehouse -> ADWCUSG 166 | --> Database Connection 167 | --> Wallet Type = Instance Wallet 168 | --> Download Client Credential 169 | --> Specify the Password 170 | --> Download the wallet to wallet.zip 171 | --> Copy the Wallet to the Linux folder /home/opc with the name wallet.zip 172 | ``` 173 | 174 | ### Replace existing wallet folder 175 | ``` 176 | ---> Rename existing wallet folder to old (if old folder exist, delete it using rm -rf ADWCUSG.old ) 177 | mv ADWCUSG ADWCUSG.old 178 | 179 | ---> Extract the new wallet 180 | unzip -o wallet.zip -d /home/opc/ADWCUSG 181 | 182 | ---> Fix sqlnet.ora params 183 | sed -i "s#?/network/admin#$HOME/ADWCUSG#" ~/ADWCUSG/sqlnet.ora 184 | 185 | ---> Run the script to check 186 | $HOME/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 187 | ``` 188 | 189 | If you deployed usage2adw before Jan 2022 you may need to download new Oracle Instant Client - check next section 190 | 191 | ## 6. How to upgrade Oracle Instant Client to Version 19.19 (Apr 2023) 192 | 193 | ``` 194 | # If Oracle Linux 8 please run the below to install glibc: 195 | sudo dnf install -y libnsl 196 | 197 | # Install 19.19: 198 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1922000/oracle-instantclient19.22-basic-19.22.0.0.0-1.x86_64.rpm 199 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1922000/oracle-instantclient19.22-sqlplus-19.22.0.0.0-1.x86_64.rpm 200 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1922000/oracle-instantclient19.22-tools-19.22.0.0.0-1.x86_64.rpm 201 | sudo rm -f /usr/lib/oracle/current 202 | sudo ln -s /usr/lib/oracle/19.22 /usr/lib/oracle/current 203 | 204 | # Check by running the application 205 | $HOME/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 206 | ``` 207 | 208 | ## 7. How to schedule daily report 209 | 210 | ### 7.1. Create approved sender 211 | ``` 212 | OCI -> Menu -> Solutions and Platform -> Email Delivery -> Email Approved Sender 213 | --> Create approved sender 214 | --> email address to be used, your domain must allow to send e-mail from it, if not use report@oracleemaildelivery.com, 215 | ``` 216 | 217 | ![](img/report_01.png) 218 | 219 | ![](img/report_02.png) 220 | 221 | ### 7.2. Create user smtp password 222 | ``` 223 | OCI -> Menu -> Identity -> Users 224 | 225 | Find the user that will send e-mail 226 | Bottom left -> SMTP Credentials 227 | 228 | Generate SMTP Credentials 229 | --> Description = cost_usage_email_credentials 230 | --> Copy the username and password to notepad, they won't appear again 231 | ``` 232 | 233 | 234 | ![](img/report_03.png) 235 | 236 | ![](img/report_04.png) 237 | 238 | ### 7.3. Find connection end point for current region 239 | 240 | Find your SMTP endpoint from the documentation - 241 | 242 | https://docs.cloud.oracle.com/en-us/iaas/Content/Email/Tasks/configuresmtpconnection.htm 243 | 244 | Example For Ashburn - smtp.us-ashburn-1.oraclecloud.com 245 | 246 | ### 7.4. Install Postfix 247 | 248 | Following the documentation - https://docs.oracle.com/en/learn/oracle-linux-postfix 249 | 250 | Tested on Oracle Linux 8. 251 | 252 | ``` 253 | sudo dnf install -y postfix 254 | sudo firewall-cmd --zone=public --add-service=smtp --permanent 255 | sudo firewall-cmd --reload 256 | sudo dnf remove -y sendmail 257 | sudo alternatives --set mta /usr/sbin/sendmail.postfix 258 | sudo systemctl enable --now postfix 259 | sudo dnf install -y mailx 260 | ``` 261 | 262 | ### 7.5. Setup postfix e-mail - part #1 - main.cf 263 | 264 | Following the documentation - https://docs.cloud.oracle.com/en-us/iaas/Content/Email/Reference/postfix.htm 265 | 266 | ``` 267 | Login to the unix machine 268 | 269 | sudo vi /etc/postfix/main.cf 270 | 271 | # Add the following information to the end of the file: 272 | smtp_tls_security_level = may 273 | smtp_sasl_auth_enable = yes 274 | smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd 275 | smtp_sasl_security_options = 276 | 277 | # Update the Postfix main.cf file - If the following line is present, either remove the line or turn it off: 278 | smtpd_use_tls = yes 279 | 280 | # Update relayhost to include your SMTP connection endpoint and port. take it from item #3 281 | relayhost = smtp.us-ashburn-1.oraclecloud.com:587 282 | ``` 283 | 284 | ### 7.6. Setup postfix e-mail - part #2 - sasl_passwd 285 | 286 | ``` 287 | sudo vi /etc/postfix/sasl_passwd 288 | 289 | # Add your relay host and port by entering: 290 | # server:port user:pass 291 | 292 | smtp.us-ashburn-1.oraclecloud.com:587 ocid1.user.oc1..aaaaaaa....@ocid1.tenancy.oc1..aaaaaaa.....:password 293 | 294 | # run 295 | sudo chown root:root /etc/postfix/sasl_passwd && sudo chmod 600 /etc/postfix/sasl_passwd 296 | sudo postmap hash:/etc/postfix/sasl_passwd 297 | ``` 298 | 299 | ### 7.7. Setup postfix e-mail - part #3 - Reload Postfix 300 | 301 | ``` 302 | # if postfix running - run start else reload 303 | sudo systemctl enable postfix 304 | sudo postfix start 305 | sudo postfix reload 306 | ``` 307 | 308 | ### 7.8. Setup postfix e-mail - part #4 - Test Mail 309 | 310 | ``` 311 | # Test e-mail 312 | echo "This is a test message" | mail -s "Test" -r "approved@sendermail" youremail@yourdomain.com 313 | ``` 314 | 315 | ### 7.9. Clone the OCI Python SDK Repo from Git Hub 316 | 317 | ``` 318 | # Required if previous clone not includes run_daily_report.sh 319 | cd $HOME 320 | sudo yum install -y git 321 | git clone https://github.com/oracle-samples/usage-reports-to-adw usage_reports_to_adw 322 | cd usage_reports_to_adw/shell_scripts 323 | chmod +x run_daily_report.sh 324 | ``` 325 | 326 | ### 7.10. Update script parameters 327 | 328 | ``` 329 | # update run_daily_report.sh for the database connection and mail info details 330 | export DATABASE_USER=usage 331 | export DATABASE_NAME=adwcusg_low 332 | 333 | export MAIL_FROM_NAME="Cost.Report" 334 | export MAIL_FROM_EMAIL="report@oracleemaildelivery.com" 335 | export MAIL_TO="oci.user@oracle.com" 336 | ``` 337 | 338 | ### 7.11. Execute the script 339 | 340 | ``` 341 | ./run_daily_report.sh 342 | ``` 343 | 344 | ### 7.12. Add crontab to run daily at 7am 345 | 346 | ``` 347 | # add the line to the crontab using - crontab -e 348 | 0 7 * * * timeout 6h /home/opc/oci-python-sdk/examples/usage_reports_to_adw/shell_scripts > /home/opc/oci-python-sdk/examples/usage_reports_to_adw/shell_scripts/run_daily_report_crontab_run.txt 2>&1 349 | ``` 350 | 351 | ## 8. How to setup e-mail subscription 352 | 353 | ### 8.1. Create approved sender 354 | ``` 355 | OCI -> Menu -> Solutions and Platform -> Email Delivery -> Email Approved Sender 356 | --> Create approved sender 357 | --> email address to be used, your domain must allow to send e-mail from it 358 | ``` 359 | 360 | ![](img/report_01.png) 361 | 362 | ![](img/report_02.png) 363 | 364 | ### 8.2. Create user smtp password 365 | ``` 366 | OCI -> Menu -> Identity -> Users 367 | 368 | Find the user that will send e-mail 369 | Bottom left -> SMTP Credentials 370 | 371 | Generate SMTP Credentials 372 | --> Description = cost_usage_email_credentials 373 | --> Copy the username and password to notepad, they won't appear again 374 | ``` 375 | 376 | 377 | ![](img/report_03.png) 378 | 379 | ![](img/report_04.png) 380 | 381 | ### 8.3. Find connection end point for current region 382 | 383 | Find your SMTP endpoint from the documentation - 384 | 385 | https://docs.cloud.oracle.com/en-us/iaas/Content/Email/Tasks/configuresmtpconnection.htm 386 | 387 | Example For Ashburn - smtp.us-ashburn-1.oraclecloud.com 388 | 389 | ### 8.4. Integrating Oracle Application Express with Email Delivery 390 | 391 | Based on the documentation - https://docs.oracle.com/en-us/iaas/Content/Email/Reference/apex.htm 392 | 393 | ``` 394 | Login to the unix machine 395 | 396 | connect to the ADW Database using sqlplus 397 | > sqlplus admin@usage2adw_low 398 | 399 | Execute: 400 | 401 | BEGIN 402 | APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_HOST_ADDRESS', 'smtp.region.oraclecloud.com'); 403 | APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_USERNAME', 'ocid1.user.oc1.username'); 404 | APEX_INSTANCE_ADMIN.SET_PARAMETER('SMTP_PASSWORD', 'paste your password'); 405 | COMMIT; 406 | END; 407 | / 408 | 409 | # Test 410 | BEGIN 411 | APEX_MAIL.SEND(p_from => 'oci_user@domain.com', 412 | p_to => 'john@example.com', 413 | p_subj => 'Email from Oracle Autonomous Database', 414 | p_body => 'Sent using APEX_MAIL'); 415 | END; 416 | / 417 | 418 | ``` 419 | 420 | ### 8.5. Configure APEX application to use the approved sender 421 | 422 | #### 8.5.1. Open Autonomous Database APEX Workspace 423 | 424 | ``` 425 | OCI Console -> Autonomous Databases -> ADWCUSG -> Service Console 426 | Development Menu -> Oracle APEX 427 | Choose Workspace Login. 428 | 429 | Workspace = Usage 430 | User = Usage 431 | Password = Password you defined for the application 432 | 433 | 434 | ``` 435 | ![](img/Image_16.png) 436 | 437 | #### 8.5.2. Choose the OCI Usage and Cost Report application 438 | 439 | ![](img/Image_33.png) 440 | 441 | #### 8.5.3. Press on Edit Application Definition - Top Right 442 | 443 | ![](img/Image_34.png) 444 | 445 | #### 8.5.4. Update "Application Email From Address" with approved sender 446 | 447 | ![](img/Image_35.png) 448 | 449 | ### 8.6. Send report via download to e-mail or Subscription 450 | 451 | ![](img/Image_36.png) 452 | 453 | ``` 454 | Please bear in mind: 455 | 1. OCI e-mail delivery is limited to 2mb 456 | 2. If Subscribed to report, please use future date filter 457 | 458 | ``` 459 | 460 | ## 9. How to enable showoci extract on usage2adw vm 461 | 462 | ### 9.1 Upgrade showoci and oci sdk packages 463 | 464 | Run on oci vm 465 | 466 | ``` 467 | bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-python-sdk/master/examples/showoci/showoci_upgrade.sh)" 468 | chmod +x /home/opc/showoci/run_daily_report.sh 469 | ``` 470 | 471 | ``` 472 | mkdir -p ${HOME}/usage_reports_to_adw/cron 473 | ``` 474 | 475 | ### 9.2 Add read all-resources policy to allow showoci to extract data 476 | 477 | Update the policy for the dynamic group of the host as below (inspect can be used instead but some information won't be exported) 478 | 479 | ``` 480 | Allow dynamic-group UsageDownloadGroup to read all-resources in tenancy 481 | ``` 482 | 483 | ### 9.3 Add/Enable crontab to extract showoci every night 484 | 485 | Edit crontab using crontab -e and add/update the below: (If exist remove the # before the command) 486 | 487 | ``` 488 | ############################################################################### 489 | # Crontab to run showoci every night 490 | ############################################################################### 491 | 0 0 * * * timeout 23h /home/opc/showoci/run_daily_report.sh > /home/opc/showoci/run_daily_report_crontab_run.txt 2>&1 492 | ``` 493 | 494 | ### 9.4 Add-Update crontab to load showoci-csv to Autonomous database 495 | 496 | Download run_load_showoci_csv_to_adw.sh if not exist 497 | 498 | ``` 499 | wget https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/shell_scripts/run_load_showoci_csv_to_adw.sh -O /home/opc/usage_reports_to_adw/shell_scripts/run_load_showoci_csv_to_adw.sh 500 | chmod +x /home/opc/usage_reports_to_adw/shell_scripts/run_load_showoci_csv_to_adw.sh 501 | ``` 502 | 503 | Edit crontab using crontab -e and add/update the below (If exist remove the # before the command) 504 | 505 | ``` 506 | ############################################################################### 507 | # Crontab to run showoci_csv to ADB 508 | ############################################################################### 509 | 00 8 * * * timeout 2h /home/opc/usage_reports_to_adw/shell_scripts/run_load_showoci_csv_to_adw.sh > /home/opc/usage_reports_to_adw/cron/run_load_showoci_csv_to_adw.sh_run.txt 2>&1 510 | ``` 511 | 512 | ### 9.5 showoci outputs 513 | 514 | ShowOCI output locations: 515 | 516 | ``` 517 | /home/opc/showoci/report/local and /home/opc/showoci/report/local/csv 518 | Autonomous tables - OCI_SHOWOCI_* 519 | ``` 520 | 521 | ## 10. How to unlock user USAGE and change password 522 | 523 | ### 10.1. Login to the VM host 524 | 525 | ### 10.2. Obtain the database connect string 526 | 527 | ``` 528 | grep low $HOME/usage_reports_to_adw/config.user | awk -F= '{ print $2 }' 529 | ``` 530 | Example: adi19c_low 531 | 532 | ### 10.3. Connect to the database using Admin, Please replace the connect_string from item above. 533 | (if you don't know the admin password, please update the admin password at the OCI Console [here](https://docs.oracle.com/en-us/iaas/autonomous-database/doc/unlock-or-change-admin-database-user-password.html) 534 | 535 | ``` 536 | sqlplus admin@connect_string 537 | ``` 538 | 539 | ### 10.4. Unlock the USAGE account if locked 540 | 541 | ``` 542 | ALTER USER USAGE ACCOUNT UNLOCK; 543 | ``` 544 | 545 | ### 10.4. Change USAGE user password (), New Password must contain at least 12 chars, upper case, lower case and special symbol # or _ 546 | 547 | ``` 548 | ALTER USER USAGE IDENTIFIED BY NEW_PASSWORD; 549 | ``` 550 | 551 | ### 10.5. Update application credential 552 | 553 | ``` 554 | # Browse the config file /home/opc/usage_reports_to_adw/config.user find the secret parameter DATABASE_SECRET_ID 555 | # Login to OCI console, Navigate to Security - Vault - Secrets 556 | 557 | # Update the secret to the new password 558 | # Check the password by running on the VM: 559 | 560 | /home/opc/usage_reports_to_adw/shell_scripts/run_table_size_info.sh 561 | ``` 562 | 563 | ### 10.6. Test the application 564 | 565 | ``` 566 | /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 567 | ``` 568 | 569 | ## 11. How to truncate the Usage2ADW tables in order to reload 570 | 571 | Login to VM 572 | ``` 573 | /home/opc/usage_reports_to_adw/usage2adw_setup.sh -truncate_tables 574 | ``` 575 | 576 | ## 12. Application Flags and Sample Execution 577 | 578 | ``` 579 | python3 usage2adw.py 580 | usage: usage2adw.py [-h] [-c CONFIG] [-t PROFILE] [-f FILEID] [-ts TAGSPECIAL] [-ts2 TAGSPECIAL2] [-d FILEDATE] [-p PROXY] [-su] [-sc] [-sr] [-ip] [-du DUSER] [-dn DNAME] 581 | [-ds DSECRET_ID] [-dst DSECRET_PROFILE] [--force] [--version] 582 | 583 | optional arguments: 584 | -h, --help show this help message and exit 585 | -c CONFIG Config File 586 | -t PROFILE Config file section to use (tenancy profile) 587 | -f FILEID File Id to load 588 | -ts TAGSPECIAL tag special key 1 to load the data to TAG_SPECIAL column 589 | -ts2 TAGSPECIAL2 tag special key 2 to load the data to TAG_SPECIAL2 column 590 | -ts3 TAGSPECIAL2 tag special key 3 to load the data to TAG_SPECIAL3 column 591 | -ts4 TAGSPECIAL2 tag special key 4 to load the data to TAG_SPECIAL4 column 592 | -d FILEDATE Minimum File Date to load (i.e. yyyy-mm-dd) 593 | -p PROXY Set Proxy (i.e. www-proxy-server.com:80) 594 | -sc Skip Load Cost Files 595 | -sr Skip Public Rate API 596 | -ip Use Instance Principals for Authentication 597 | -du DUSER ADB User 598 | -dn DNAME ADB Name 599 | -ds DSECRET_ID ADB Secret Id 600 | -dst DSECRET_PROFILE ADB Secret tenancy profile (local or blank = instant principle) 601 | --force Force Update without updated file 602 | --version show program's version number and exit 603 | 604 | ``` 605 | 606 | ### Below example of execution 607 | 608 | ``` 609 | ./usage2adw.py -t temp_tenant -du db_user -ds xxxsecret_idxxx -dst local -dn dbname -d 2020-02-15 610 | 611 | ########################################################################################## 612 | # Running Usage and Cost Load to ADW # 613 | ########################################################################################## 614 | Starts at 2020-04-21 12:05:45 615 | Command Line : -t temp_tenant -du db_user -ds xxxsecret_idxxx -dst local -dn dbname -d 2020-04-15 616 | 617 | Connecting to Identity Service... 618 | Tenant Name : temp_tenant 619 | Tenant Id : ocid1.tenancy.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 620 | App Version : 20.4.27 621 | 622 | Loading Compartments... 623 | Total 108 compartments loaded. 624 | 625 | Connecting to database adirep_low 626 | Connected 627 | 628 | Checking Database Structure... 629 | Table OCI_COST exist 630 | Table OCI_COST_TAG_KEYS exist 631 | 632 | Checking Last Loaded File... 633 | Max Cost File Id Processed = 0001000000007463 634 | 635 | Connecting to Object Storage Service... 636 | Connected 637 | 638 | Handling Cost Report... 639 | Processing file reports/cost-csv/0001000000007464.csv.gz - 123150, 2020-04-16 01:44 640 | Completed file reports/cost-csv/0001000000007464.csv.gz - 1844 Rows Inserted 641 | Total 15 Tags Merged. 642 | Processing file reports/cost-csv/0001000000008343.csv.gz - 743467, 2020-04-16 11:14 643 | Completed file reports/cost-csv/0001000000008343.csv.gz - 11278 Rows Inserted 644 | Total 14 Tags Merged. 645 | 646 | Total 2 Cost Files Loaded 647 | 648 | Completed at 2020-04-21 12:05:46 649 | ``` 650 | 651 | ## 13. Sample of database queries 652 | 653 | ``` 654 | ------------------------------------------------------------------------ 655 | -- Cost per specific hour 656 | ------------------------------------------------------------------------ 657 | set lines 199 trimsp on pages 1000 tab off 658 | col PRODUCT for a60 trunc 659 | col COST_BILLING_UNIT for a20 trunc 660 | col USG_BILLED_QUANTITY for 999,999,999 661 | col COST_PER_HOUR for 999,999,999.00 662 | col COST_PER_YEAR for 999,999,999 663 | 664 | select 665 | COST_PRODUCT_SKU || ' ' || min(replace(PRD_DESCRIPTION,COST_PRODUCT_SKU||' - ','')) PRODUCT, 666 | min(COST_BILLING_UNIT) as COST_BILLING_UNIT, 667 | sum(USG_BILLED_QUANTITY) as USG_BILLED_QUANTITY, 668 | sum(COST_MY_COST) as COST_PER_HOUR, 669 | sum(COST_MY_COST)*365 as COST_PER_YEAR 670 | from oci_cost 671 | where 672 | USAGE_INTERVAL_START = to_date('2025-03-01 10:00','YYYY-MM-DD HH24:MI') and 673 | USG_BILLED_QUANTITY>0 and 674 | COST_MY_COST<>0 675 | group by 676 | COST_PRODUCT_SKU 677 | order by COST_PER_HOUR desc; 678 | 679 | ------------------------------------------------------------------------ 680 | -- Cost per day for last 30 days 681 | ------------------------------------------------------------------------ 682 | set lines 199 trimsp on pages 1000 tab off 683 | col tenant_name for a30 trunc 684 | col USAGE_DAY for a20 trunc 685 | col COST_MY_COST for 999,999,999.99 686 | 687 | select 688 | tenant_name, 689 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD DY') as USAGE_DAY, 690 | sum(COST_MY_COST) as COST_MY_COST 691 | from oci_cost_stats 692 | where 693 | USAGE_INTERVAL_START >= trunc(sysdate-30) 694 | and COST_MY_COST > 0 695 | group by 696 | tenant_name, 697 | to_char(USAGE_INTERVAL_START,'YYYY-MM-DD DY') 698 | order by 1,2; 699 | 700 | ``` 701 | 702 | ## License 703 | 704 | Copyright (c) 2025, Oracle and/or its affiliates. 705 | Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -------------------------------------------------------------------------------- /step_by_step_installation.md: -------------------------------------------------------------------------------- 1 | # Usage2ADW - Oracle Cloud Infrastructure Usage and Cost Reports to Autonomous Database with APEX Reporting 2 | 3 | ## Step by Step Manual installation Guide on OCI VM and Autonomous Data Warehouse Database 4 | Usage2adw is a tool which uses the Python SDK to extract the usage reports from your tenant and load it to Oracle Autonomous Database. 5 | 6 | Oracle Application Express (APEX) will be used for reporting. 7 | 8 | **DISCLAIMER – This is not an official Oracle application, It does not supported by Oracle Support, It should NOT be used for utilization calculation purposes, and rather OCI's official 9 | [cost analysis](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/costanalysisoverview.htm) 10 | and [usage reports](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) features should be used instead.** 11 | 12 | **Developed by Adi Zohar, 2020-2024** 13 | 14 | ## 1. Deploy VM Compute instance to run the python script 15 | ``` 16 | OCI -> Menu -> Compute -> Instances 17 | Create Instance 18 | --> Name = UsageVM 19 | --> Image = Oracle Linux 8 20 | --> Shape = VM.Flex.E4 or Higher 21 | --> Choose your network VCN and Subnet (any type of VCN and Subnet) 22 | --> Assign public IP - Optional if on public subnet 23 | --> Add your public SSH key 24 | --> Press Create 25 | ``` 26 | 27 | ``` 28 | Copy Instance Info: 29 | --> Compute OCID to be used for Dynamic Group Permission 30 | --> Compute IP 31 | ``` 32 | 33 | ## 2. Create Dynamic Group for Instance Principles 34 | 35 | ``` 36 | OCI -> Menu -> Identity -> Default Domain -> Dynamic Groups -> Create Dynamic Group 37 | --> Name = UsageDownloadGroup 38 | --> Desc = Dynamic Group for the Usage Report VM 39 | --> Rule 1 = ANY { instance.id = 'OCID_Of_Step_1_Instance' } 40 | ``` 41 | 42 | ## 3. Create Policy to allow the Dynamic Group to extract usage report and read Compartments 43 | 44 | ``` 45 | OCI -> Menu -> Identity -> Policies 46 | Choose Root Compartment 47 | Create Policy 48 | --> Name = UsageDownloadPolicy 49 | --> Desc = Allow Dynamic Group UsageDownloadGroup to Extract Usage report script 50 | Statements: 51 | define tenancy usage-report as ocid1.tenancy.oc1..aaaaaaaaned4fkpkisbwjlr56u7cj63lf3wffbilvqknstgtvzub7vhqkggq 52 | endorse dynamic-group UsageDownloadGroup to read objects in tenancy usage-report 53 | Allow dynamic-group UsageDownloadGroup to inspect compartments in tenancy 54 | Allow dynamic-group UsageDownloadGroup to inspect tenancies in tenancy 55 | Allow dynamic-group UsageDownloadGroup to read autonomous-databases in compartment {APPCOMP} 56 | Allow dynamic-group UsageDownloadGroup to read secret-bundles in compartment {APPCOMP} 57 | 58 | *** Please don't change the usage report tenant OCID, it is fixed for oc1, if you are running on oc2..oc9 please obtain the proper ocid. 59 | ``` 60 | 61 | ## 4. Deploy Autonomous Data Warehouse Database 62 | 63 | ``` 64 | OCI -> Menu -> Autonomous Data Warehouse 65 | Create Autonomous Database 66 | --> Compartment = Please Choose 67 | --> Display Name = ADWCUSG 68 | --> Database Name ADWCUSG 69 | --> Workload = Data Warehouse 70 | --> Deployment = Shared 71 | --> Always Free = Optional (20GB is limited) 72 | --> ECPU = 2 or OCPU = 1 73 | --> Storage = 1 74 | --> Auto Scale = No 75 | --> Password = $passwprd (Please choose your own password, 12 chars, one upper, one lower, one number and one # ) 76 | --> Choose Network Access = Allow secure Access from Everywhere (you can use VCN as well which requires NSG) 77 | --> Choose License Type 78 | ``` 79 | 80 | ***Please ensure that your password meets the following criteria:** 81 | 82 | - Length: Between 12 and 30 characters. 83 | - The password cannot contain the username. 84 | - Character types: Must include at least one uppercase letter, one lowercase letter, and one numeric character (e.g. 0-9). 85 | - No dictionary words: Avoid using common words found in the dictionary. 86 | - Symbols: If you wish to use symbols, you may only use the "#" symbol. 87 | 88 | 89 | ## 5. Add the Autonomous App Password into Vault Secret 90 | 91 | ``` 92 | OCI -> Menu -> Indeitty and Security -> Vault 93 | Use Existing Vault or Create new Vault 94 | Use Existing Master Key or Create new Encryption Master Key 95 | --> Bottom Left -> Secrets 96 | --> Create new Secret with the database App Password 97 | --> Write down the secret OCID 98 | ``` 99 | 100 | ## 6. Login to Linux Machine 101 | 102 | ``` 103 | Using the SSH key you provided, SSH to the linux machine from step #1 104 | ssh opc@UsageVM 105 | ``` 106 | 107 | ## 7. Run Install Packages Script from Github 108 | 109 | The script will install Python3, Git and python packages - oci, oracledb and requests 110 | Install Oracle Database Instance Client, Update .bashrc and Clone the Python SDK 111 | 112 | ``` 113 | bash -c "export usage2adw_param=-setup_ol8_packages; $(curl -L https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/usage2adw_setup.sh)" 114 | ``` 115 | 116 | ## 8. Setup Credentials 117 | 118 | ``` 119 | /home/opc/usage_reports_to_adw/usage2adw_setup -setup_credential 120 | ``` 121 | 122 | This script will ask for: 123 | 124 | 1. Database Name - the database connect string. 125 | 2. Database Id (OCID) - the database ocid. 126 | 3. Application Secret Id from KMS Vault. 127 | 4. Application Secret Tenant Profile - The Tenancy profile (from oci config) in which the Secret Vault resides (For instance principle use 'local') 128 | 5. Extract Start Date 129 | 6. Tag Special Key 1 - Convert extract key to column #1 130 | 7. Tag Special Key 2 - Convert extract key to column #2 131 | 132 | 133 | ## 9. Setup the application 134 | 135 | ``` 136 | # Execute: 137 | /home/opc/usage_reports_to_adw/usage2adw_setup -setup_app 138 | 139 | ``` 140 | 141 | ## 10. Open Autonomous Database APEX Workspace Admin 142 | 143 | ``` 144 | OCI Console -> Autonomous Databases -> ADWCUSG -> Service Console 145 | Development Menu -> Oracle APEX 146 | Choose Workspace Login. 147 | 148 | Workspace = Usage 149 | User = Usage 150 | Password = Password you defined for the application 151 | ``` 152 | 153 | ![](img/Image_16.png) 154 | 155 | ## 11. Login to Apex Application 156 | 157 | ``` 158 | Press on App Builder on the Left side 159 | Press on the application "Usage and Cost Report" 160 | Execute the application 161 | Bookmark this page for future use 162 | 163 | User = Usage 164 | Password = Password you defined for the application 165 | 166 | ``` 167 | 168 | ![](img/Image_30.png) 169 | 170 | 171 | ## Additional Contents 172 | Please Visit [How To File](step_by_step_howto.md) 173 | 174 | 175 | ## License 176 | 177 | Copyright (c) 2025, Oracle and/or its affiliates. 178 | Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -------------------------------------------------------------------------------- /step_by_step_manual_installation.md: -------------------------------------------------------------------------------- 1 | # Usage2ADW - Oracle Cloud Infrastructure Usage and Cost Reports to Autonomous Database with APEX Reporting 2 | 3 | ## Step by Step Manual installation Guide on OCI VM and Autonomous Data Warehouse Database 4 | Usage2adw is a tool which uses the Python SDK to extract the usage reports from your tenant and load it to Oracle Autonomous Database. 5 | 6 | Oracle Application Express (APEX) will be used for reporting. 7 | 8 | **DISCLAIMER – This is not an official Oracle application, It does not supported by Oracle Support, It should NOT be used for utilization calculation purposes, and rather OCI's official 9 | [cost analysis](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/costanalysisoverview.htm) 10 | and [usage reports](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) features should be used instead.** 11 | 12 | **Developed by Adi Zohar, 2020-2024** 13 | 14 | ## 1. Deploy VM Compute instance to run the python script 15 | 16 | ``` 17 | OCI -> Menu -> Compute -> Instances 18 | Create Instance 19 | --> Name = UsageVM 20 | --> Image = Oracle Linux 8 21 | --> Shape = VM.Flex.E4 or Higher 22 | --> Choose your network VCN and Subnet (any type of VCN and Subnet) 23 | --> Assign public IP - Optional if on public subnet 24 | --> Add your public SSH key 25 | --> Press Create 26 | 27 | Copy Instance Info: 28 | --> Compute OCID to be used for Dynamic Group Permission 29 | --> Compute IP 30 | 31 | ``` 32 | 33 | ## 2. Create Dynamic Group for Instance Principles 34 | 35 | ``` 36 | OCI -> Menu -> Identity -> Default Domain -> Dynamic Groups -> Create Dynamic Group 37 | --> Name = UsageDownloadGroup 38 | --> Desc = Dynamic Group for the Usage Report VM 39 | --> Rule 1 = ANY { instance.id = 'OCID_Of_Step_1_Instance' } 40 | ``` 41 | 42 | ## 3. Create Policy to allow the Dynamic Group to extract usage report and read Compartments 43 | 44 | ``` 45 | OCI -> Menu -> Identity -> Policies 46 | Choose Root Compartment 47 | Create Policy 48 | --> Name = UsageDownloadPolicy 49 | --> Desc = Allow Dynamic Group UsageDownloadGroup to Extract Usage report script 50 | --> Statement 1 = define tenancy usage-report as ocid1.tenancy.oc1..aaaaaaaaned4fkpkisbwjlr56u7cj63lf3wffbilvqknstgtvzub7vhqkggq 51 | --> Statement 2 = endorse dynamic-group UsageDownloadGroup to read objects in tenancy usage-report 52 | --> Statement 3 = Allow dynamic-group UsageDownloadGroup to inspect compartments in tenancy 53 | --> Statement 4 = Allow dynamic-group UsageDownloadGroup to inspect tenancies in tenancy 54 | --> Statement 5 = Allow dynamic-group UsageDownloadGroup to read autonomous-databases in compartment {APPCOMP} 55 | --> Statement 6 = Allow dynamic-group UsageDownloadGroup to read secret-bundles in compartment {APPCOMP} 56 | 57 | *** Please don't change the usage report tenant OCID, it is fixed for oc1, if you are running on oc2..oc9 please obtain the proper ocid. 58 | ``` 59 | 60 | ## 4. Deploy Autonomous Data Warehouse Database 61 | 62 | ``` 63 | OCI -> Menu -> Autonomous Data Warehouse 64 | Create Autonomous Database 65 | --> Compartment = Please Choose 66 | --> Display Name = ADWCUSG 67 | --> Database Name ADWCUSG 68 | --> Workload = Data Warehouse 69 | --> Deployment = Shared 70 | --> Always Free = Optional (20GB storage is limited) 71 | --> ECPU = 2 or OCPU = 1 72 | --> Storage = 1 73 | --> Auto Scale = No 74 | --> (Please choose your own credentials) 75 | --> Choose Network Access = Allow secure Access from Everywhere (you can use VCN as well which requires NSG) 76 | --> Choose License Type 77 | ``` 78 | 79 | ## 5. Login to Linux Machine 80 | 81 | ``` 82 | Using the SSH key you provided, SSH to the linux machine from step #1 83 | ssh opc@UsageVM 84 | ``` 85 | 86 | ## 6. Install Python 3.9 OCI packages 87 | 88 | ``` 89 | sudo dnf module install python39 90 | sudo alternatives --set python3 /usr/bin/python3.9 91 | 92 | # Install Python required packages 93 | python3 -m pip install --upgrade pip 94 | python3 -m pip install --upgrade oci oracledb requests 95 | ``` 96 | 97 | ## 7. Install Oracle instant client 98 | 99 | ``` 100 | # Please refer to the download site for Manual installation = https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html 101 | 102 | 4. install oracle instant client 19 103 | sudo dnf install -y libnsl 104 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1923000/oracle-instantclient19.23-basic-19.23.0.0.0-1.x86_64.rpm 105 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1923000/oracle-instantclient19.23-sqlplus-19.23.0.0.0-1.x86_64.rpm 106 | sudo rpm -i --force --nodeps https://download.oracle.com/otn_software/linux/instantclient/1923000/oracle-instantclient19.23-tools-19.23.0.0.0-1.x86_64.rpm 107 | sudo rm -f /usr/lib/oracle/current 108 | sudo ln -s /usr/lib/oracle/19.23 /usr/lib/oracle/current 109 | 110 | # setup oracle home variables 111 | # Add the below to $HOME/.bashrc: 112 | export CLIENT_HOME=/usr/lib/oracle/current/client64 113 | export PATH=$PATH:$CLIENT_HOME/bin 114 | export TNS_ADMIN=$HOME/ADWCUSG 115 | 116 | # Load the variables 117 | source $HOME/.bashrc 118 | ``` 119 | 120 | ## 8. Clone the GitHub Repo 121 | 122 | ``` 123 | cd $HOME 124 | sudo yum install -y git 125 | git clone https://github.com/oracle-samples/usage-reports-to-adw usage_reports_to_adw 126 | cd usage_reports_to_adw 127 | ``` 128 | 129 | ## 9. Add the Autonomous App Password into Vault Secret 130 | 131 | ``` 132 | OCI -> Menu -> Indeitty and Security -> Vault 133 | Use Existing Vault or Create new Vault 134 | Use Existing Master Key or Create new Encryption Master Key 135 | --> Bottom Left -> Secrets 136 | --> Create new Secret with the database App Password 137 | --> Write down the secret OCID 138 | ``` 139 | 140 | **Please ensure that your password meets the following criteria:** 141 | 142 | - Length: Between 12 and 30 characters. 143 | - The password cannot contain the username. 144 | - Character types: Must include at least one uppercase letter, one lowercase letter, and one numeric character (e.g. 0-9). 145 | - No dictionary words: Avoid using common words found in the dictionary. 146 | - Symbols: If you wish to use symbols, you may only use the "#" symbol. 147 | 148 | 149 | ## 10. Download Autonomous database Wallet 150 | 151 | 2 options to download the Autonomous Wallet: 152 | 153 | Python Script 154 | 155 | ``` 156 | cd usage_reports_to_adw 157 | python3 usage2adw_download_adb_wallet.py -dbid $database_ocid -secret secret_ocid -folder $HOME/ADWCUSG -zipfile $HOME/wallet.zip 158 | ``` 159 | 160 | OCI console 161 | 162 | ``` 163 | # On OCI -> MENU -> Autonomous Data Warehouse -> ADWCUSG 164 | --> Service Console 165 | --> Administration 166 | --> Download Client Credential 167 | --> Specify the Admin Password 168 | --> Copy the Wallet wallet.zip to the Linux folder $HOME/ADWCUSG 169 | 170 | # on Linux -> Unzip Wallet 171 | cd $HOME/ADWCUSG 172 | unzip wallet.zip 173 | 174 | # Change directory of sqlnet.ora to $HOME/ADWCUSG 175 | sed -i "s#?/network/admin#$HOME/ADWCUSG#" sqlnet.ora 176 | ``` 177 | 178 | ## 11. Create Database User for the Usage repository 179 | 180 | ``` 181 | sqlplus admin/@adwcusg_low 182 | 183 | # Choose your own password 184 | SQL> create user usage identified by ; 185 | SQL> grant connect, resource, dwrole, unlimited tablespace to usage; 186 | SQL> exit 187 | ``` 188 | 189 | ## 12. Setup Credentials 190 | 191 | This script will ask for Database Name, Secret Id for Application Password and Extract Start Date 192 | 193 | ``` 194 | /home/opc/usage_reports_to_adw/usage2adw_setup.sh -setup_credential 195 | ``` 196 | 197 | This script will ask for: 198 | 199 | 1. Database Name - the database connect string. 200 | 2. Database Id (OCID) - the database ocid. 201 | 3. Application Secret Id from KMS Vault. 202 | 4. Application Secret Tenant Profile - The Tenancy profile (from oci config) in which the Secret Vault resides (For instance principle use 'local') 203 | 5. Extract Start Date 204 | 6. Tag Special Key 1 - Convert extract key to column #1 205 | 7. Tag Special Key 2 - Convert extract key to column #2 206 | 207 | 208 | ## 13. Execute the python script - usage2adw.py or setup_usage2adw.sh 209 | 210 | ``` 211 | # if you want to skip 14 to 18, execute the script /home/opc/usage_reports_to_adw/usage2adw_setup.sh -setup_app 212 | 213 | # Load the data: 214 | /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 215 | ``` 216 | 217 | ## 14. Open Autonomous Database APEX Application 218 | 219 | ``` 220 | OCI Console -> Autonomous Databases -> ADWCUSG -> Service Console 221 | Development Menu -> Oracle APEX 222 | ``` 223 | 224 | ![](img/Image_11.png) 225 | 226 | ``` 227 | Enter Admin Password - for first time setup 228 | ``` 229 | 230 | ![](img/Image_12.png) 231 | 232 | 233 | ## 15. Create APEX workspace 234 | 235 | ![](img/Image_13.png) 236 | 237 | ``` 238 | Database User = USAGE 239 | Workspace Name = USAGE 240 | ``` 241 | 242 | ![](img/Image_14.png) 243 | 244 | ``` 245 | Sign Out - Top Right Menu -> Sign Out 246 | ``` 247 | 248 | ![](img/Image_15.png) 249 | 250 | ## 16. Setup APEX Administrator User Application 251 | 252 | ``` 253 | Login under USAGE Workspace 254 | --> Workspace = USAGE 255 | --> Username = USAGE 256 | --> "USAGE Schema Password" 257 | --> Press Continue 258 | 259 | Specify your e-mail and name. 260 | --> Apply Changes 261 | ``` 262 | 263 | ![](img/Image_16.png) 264 | 265 | ![](img/Image_17.png) 266 | 267 | ![](img/Image_18.png) 268 | 269 | ## 17. Create End User Account 270 | 271 | ``` 272 | Top 3rd Right Menu -> Manage Users and Groups 273 | --> Create User 274 | 275 | Fill: 276 | --> Username 277 | --> Email 278 | --> Password 279 | --> Confirm Password 280 | --> Optional - Require to change passqword = No 281 | --> Apply Changes 282 | ``` 283 | 284 | ![](img/Image_19.png) 285 | 286 | ![](img/Image_20.png) 287 | 288 | ![](img/Image_21.png) 289 | 290 | ![](img/Image_22.png) 291 | 292 | ## 18. Import APEX application 293 | 294 | Right Click and Download [usage2adw_demo_apex_app](https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/usage2adw_demo_apex_app.sql) from github. 295 | 296 | ``` 297 | APEX Top Menu -> App Builder -> Import 298 | --> Choose File = usage.demo.apex.sql (Download from github apex folder) 299 | --> Press Next 300 | --> Press Next 301 | --> Press Install Application 302 | --> Press Next 303 | --> Press Install 304 | ``` 305 | 306 | ![](img/Image_23.png) 307 | 308 | ![](img/Image_24.png) 309 | 310 | ![](img/Image_25.png) 311 | 312 | ![](img/Image_26.png) 313 | 314 | ![](img/Image_27.png) 315 | 316 | ![](img/Image_28.png) 317 | 318 | ## 19. Execute Application 319 | 320 | ``` 321 | Press Run application 322 | Bookmark the page for future use. 323 | Login = your end user username and password 324 | ``` 325 | 326 | ![](img/Image.png) 327 | 328 | ![](img/Image_30.png) 329 | 330 | ![](img/Image_31.png) 331 | 332 | ![](img/Image_32.png) 333 | 334 | ![](img/screen_1.png) 335 | ![](img/screen_2.png) 336 | ![](img/screen_3.png) 337 | 338 | 339 | ## 20. Schedule a crontab job to execute the load daily 340 | ``` 341 | # Amend the oracle instance client path run_multi_daily_usage2adw.sh according to your environment. i.e. 18.3 or later 342 | $HOME/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 343 | 344 | # change execution permission 345 | chmod +x $HOME/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 346 | 347 | # Test the execution 348 | $HOME/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh 349 | 350 | # add crontab that execute every night 351 | 0 0 * * * timeout 6h /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw.sh > /home/opc/usage_reports_to_adw/shell_scripts/run_multi_daily_usage2adw_crontab_run.txt 2>&1 352 | ``` 353 | 354 | ## Additional Contents 355 | Please Visit [How To File](step_by_step_howto.md) 356 | 357 | 358 | ## License 359 | 360 | Copyright (c) 2025, Oracle and/or its affiliates. 361 | Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -------------------------------------------------------------------------------- /step_by_step_terraform.md: -------------------------------------------------------------------------------- 1 | # Usage2ADW - Oracle Cloud Infrastructure Usage and Cost Reports to Autonomous Database with APEX Reporting 2 | 3 | ## Step by Step installation using Oracle Cloud Resource Management and Terraform 4 | usage2adw is a tool which uses the Python SDK to extract the usage reports from your tenant and load it to Oracle Autonomous Database. 5 | 6 | Oracle Application Express (APEX) will be used for reporting. 7 | 8 | **Developed by Adi Zohar** 9 | 10 | ## Must be deployed at Home Region and VCN must have access to the internet using Internet Gateway or NAT Gateway and utilize Vault Secret for database password. 11 | 12 | **DISCLAIMER - This is not an official Oracle application, It does not supported by Oracle Support, It should NOT be used for utilization calculation purposes, and rather OCI's official 13 | [cost analysis](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/costanalysisoverview.htm) 14 | and [usage reports](https://docs.oracle.com/en-us/iaas/Content/Billing/Concepts/usagereportsoverview.htm) features should be used instead.** 15 | 16 | 17 | ## 1. Create KMS Vault Secret for Autonomous database password 18 | 19 | OCI -> Menu -> Identity & Security -> Vault 20 | 21 | Choose Vault or create new Vault, Please follow [Vault Documentation](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/home.htm) 22 | 23 | Make sure you have an existing Master Encryption Key, [Master Key Documentation](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/managingkeys_topic-To_create_a_new_key.htm#createnewkey) 24 | 25 | Create Secret for the Autonomous Database Password, [Secret Documentation](https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/managingsecrets_topic-To_create_a_new_secret.htm#createnewsecret) 26 | 27 | The password must meet the strong password complexity criteria based on Oracle Cloud security standards, [doc](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/manage-users-create.html#GUID-72DFAF2A-C4C3-4FAC-A75B-846CC6EDBA3F) 28 | 29 | **Please ensure that your password meets the following criteria:** 30 | 31 | - Length: Between 12 and 30 characters. 32 | - The password cannot contain the username. 33 | - Character types: Must include at least one uppercase letter, one lowercase letter, and one numeric character (e.g. 0-9). 34 | - No dictionary words: Avoid using common words found in the dictionary. 35 | - Symbols: If you wish to use symbols, you may only use the "#" symbol. 36 | 37 | 38 | ## 2. Generate Terraform stack from Usage Reports to ADW Github 39 | 40 | 41 | Navigate to Usage Reports to ADW GitHub - [https://github.com/oracle-samples/usage-reports-to-adw](https://github.com/oracle-samples/usage-reports-to-adw) 42 | 43 | 44 | ``` 45 | --> Choose Code drop down 46 | --> Download Zip 47 | ``` 48 | 49 | ## 3. Launch Oracle Resource Management Stack 50 | 51 | ``` 52 | 53 | OCI -> Menu -> Developer Services -> Resource Management -> Stacks 54 | 55 | --> Create Stack 56 | --> My Configuration 57 | --> Choose Zip File 58 | --> Browse to the Zip file downloaded from GitHub. 59 | 60 | --> Name = Usage2ADW Usage and Cost Reports to Autonomous Database with APEX Reporting 61 | --> Press Next 62 | 63 | ``` 64 | 65 | ![](img/stack_11.png) 66 | 67 | ![](img/stack_12.png) 68 | 69 | 70 | ### 3a. Compartment 71 | 72 | ``` 73 | 74 | Stack Compartment - Specifies the Compartment where the resources will be created 75 | It is generally the location that you have access to build the compute node and autonomous database. 76 | 77 | ``` 78 | 79 | ![](img/stack_13.png) 80 | 81 | 82 | ### 3b. Resource Tags 83 | 84 | Option to tag the resources 85 | 86 | 87 | ![](img/stack_14.png) 88 | 89 | 90 | ### 3c. Identity Configuration 91 | 92 | ``` 93 | 94 | - New IAM Dynamic Group and Policy will be created - 95 | New Dynamic Group and Policy will be created - This option required Admin access 96 | - I have already created Dynamic Group and Policy per the documentation - 97 | Choose this option if you already created Dynamic group and policies according to the documentation. 98 | Below is the requirement: 99 | - APPCOMP is the compartment where the usage2adw will be installed 100 | 101 | Dynamic Group: 102 | OCI -> Menu -> Identity -> Default Domain -> Dynamic Groups -> Create Dynamic Group 103 | --> Name = UsageDownloadGroup 104 | --> Desc = Dynamic Group for the Usage Report Compartment 105 | --> Rule 1 = ANY { instance.compartment.id = 'OCID_Of_Compartment' } 106 | 107 | Policy: 108 | OCI -> Menu -> Identity -> Policies 109 | Choose Root Compartment 110 | Create Policy 111 | --> Name = UsageDownloadPolicy 112 | --> Desc = Allow Dynamic Group UsageDownloadGroup to Extract Usage report script 113 | Statements: 114 | define tenancy usage-report as ocid1.tenancy.oc1..aaaaaaaaned4fkpkisbwjlr56u7cj63lf3wffbilvqknstgtvzub7vhqkggq 115 | endorse dynamic-group UsageDownloadGroup to read objects in tenancy usage-report 116 | Allow dynamic-group UsageDownloadGroup to inspect compartments in tenancy 117 | Allow dynamic-group UsageDownloadGroup to inspect tenancies in tenancy 118 | Allow dynamic-group UsageDownloadGroup to read autonomous-database in compartment {APPCOMP} 119 | Allow dynamic-group UsageDownloadGroup to read secret-bundles in compartment {APPCOMP} 120 | *** Please don't change the usage report tenant OCID, it is fixed. 121 | 122 | ``` 123 | 124 | ![](img/stack_20.png) 125 | 126 | 127 | ### 3d. Network Configuration - 128 | 129 | ``` 130 | - Select the VCN compartment and the VCN 131 | - Select the Subnet compartment and the Subnet 132 | 133 | ``` 134 | 135 | ![](img/stack_15.png) 136 | 137 | 138 | ### 3e. Autonomous Database Configuration 139 | 140 | ``` 141 | 142 | - Autonomous Database Deployment Option - Public or Private Endpoint 143 | - Autonomous database name - the name to be assigned to the Autonomous database 144 | - Database Secret - Choose the Secret Compartment and Secret you created 145 | - Database License - License Included or Bring your own license if you have 146 | - Network Security Group - For Privatendpoint - choose network security group name 147 | - Private End Point Label - the host name for the private end point 148 | 149 | ``` 150 | 151 | ![](img/stack_16.png) 152 | ![](img/stack_17.png) 153 | 154 | 155 | ### 3f. Load Balancer Configuration - If private end point created 156 | 157 | ``` 158 | 159 | - Load Balancer Options - Provision or Not 160 | - Load Balancer Name 161 | - Load Balancer Public Subnet Compartment 162 | - Load Balancer Public Subnet 163 | 164 | ``` 165 | 166 | ![](img/stack_18.png) 167 | 168 | ### 3g. Instance Configuration 169 | 170 | ``` 171 | - Availability Domain to deploy the instance 172 | - Instance Name - the name of the compute instance 173 | - Compute Shape - Compute Shape to deploy the instance 174 | - SSH Public Key - The public key you generated at the prerequisite stage 175 | - Extract Usage From Date - Load Data since which date with format of YYYY-MM (i.e. 2020-08) 176 | - Extract Tag Key 1 to special tag column 1 - use this tag to load to special column 1 for better filter and report 177 | - Extract Tag Key 2 to special tag column 2 - use this tag to load to special column 2 for better filter and report 178 | 179 | ``` 180 | 181 | ![](img/stack_19.png) 182 | 183 | 184 | ### 3h. Oracle Analytics (OAC) 185 | 186 | 187 | Option to deploy Oracle Analytics Cloud (OAC) 188 | 189 | Advance Feature 190 | 191 | It will deploy only, connection to ADW database should be done manually using the documentation 192 | 193 | 194 | ### 3i. Applying the Stack 195 | 196 | 197 | ``` 198 | 199 | Click Next. 200 | 201 | On the Review page, review the information you provided and then click Create. 202 | 203 | Press Apply. 204 | 205 | When you get a message Provisioning Completed/Successful from the OCI console, the instance is created. 206 | However please note the rest of the Usage2ADW configuration happens in the background 207 | including extract of the usage which takes approximately 10 minutes to complete. 208 | 209 | After approximately 10 minutes log into the compute node and examine the setup.log file 210 | 211 | ``` 212 | 213 | ## 4. Login to Apex Application 214 | 215 | 216 | ``` 217 | Check the Resource Manager Log and find APEX_Application_Login_URL 218 | Should be similar to: https://xxxxxx.adb.us-ashburn-1.oraclecloudapps.com/ords/f?p=100:LOGIN_DESKTOP:::::: 219 | Bookmark this page for future use 220 | 221 | First time may take up to a minute to load 222 | 223 | User = Usage 224 | Password = Password you defined for the application 225 | 226 | ``` 227 | ![](img/Image_30.png) 228 | 229 | 230 | ## 5. Open Autonomous Database APEX Workspace Admin if required 231 | 232 | ``` 233 | OCI Console -> Autonomous Databases -> ADWCUSG -> Service Console 234 | Development Menu -> Oracle APEX 235 | Choose Workspace Login. 236 | 237 | Workspace = Usage 238 | User = Usage 239 | Password = Password you defined for the application 240 | 241 | 242 | ``` 243 | ![](img/Image_16.png) 244 | 245 | 246 | ## Additional Contents 247 | Please Visit [How To File](step_by_step_howto.md) 248 | 249 | 250 | ## License 251 | 252 | Copyright (c) 2025, Oracle and/or its affiliates. 253 | Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ -------------------------------------------------------------------------------- /terraform/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2024, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | module "network" { 7 | source = "./modules/network" 8 | compartment_id = var.compartment_ocid 9 | network_nsg_name = var.db_network_nsg_name 10 | existing_vcn_id = var.network_vcn_id 11 | service_tags = var.service_tags 12 | load_balancer_display_name = var.loadbalancer_name 13 | load_balancer_subnet_id = var.loadbalancer_subnet_id 14 | adw_pe_ip_address = module.adb.adwc_pe_ip 15 | load_balancer_enabled = var.option_loadbalancer == "Provision Public Load Balancer" ? true : false 16 | autonomous_pe_enabled = var.option_autonomous_database == "Private Endpoint" ? true : false 17 | } 18 | 19 | module "compute" { 20 | source = "./modules/compute" 21 | region = var.region 22 | compartment_id = var.compartment_ocid 23 | availability_domain = var.instance_availability_domain 24 | instance_name = var.instance_name 25 | ssh_authorized_keys = var.ssh_public_key 26 | shape = var.instance_shape 27 | subnet_id = var.network_subnet_id 28 | db_db_name = var.db_db_name 29 | db_db_id = module.adb.adwc_id 30 | 31 | db_secret_id = var.db_secret_id 32 | tenancy_ocid = var.tenancy_ocid 33 | extract_from_date = var.extract_from_date 34 | extract_tag1_special_key = var.extract_tag1_special_key 35 | extract_tag2_special_key = var.extract_tag2_special_key 36 | extract_tag3_special_key = var.extract_tag3_special_key 37 | extract_tag4_special_key = var.extract_tag4_special_key 38 | service_tags = var.service_tags 39 | 40 | admin_url = module.adb.apex_url 41 | application_url = replace(module.adb.apex_url,"apex","f?p=100:LOGIN_DESKTOP::::::") 42 | lb_application_url = module.network.load_balancer_ip_address != null ? "https://${module.network.load_balancer_ip_address}/ords/f?p=100:LOGIN_DESKTOP::::::" : "NA" 43 | lb_admin_url = module.network.load_balancer_ip_address != null ? "https://${module.network.load_balancer_ip_address}/ords/f?p=4550:1::::::" : "NA" 44 | } 45 | 46 | module "adb" { 47 | source = "./modules/adb" 48 | compartment_id = var.compartment_ocid 49 | db_secret_id = var.db_secret_id 50 | db_name = var.db_db_name 51 | license_model = var.db_license_model 52 | nsg_id = module.network.nsg_id 53 | subnet_id = var.network_subnet_id 54 | private_end_point_label = var.db_private_end_point_label 55 | service_tags = var.service_tags 56 | autonomous_pe_enabled = var.option_autonomous_database == "Private Endpoint" ? true : false 57 | } 58 | 59 | module "iam" { 60 | source = "./modules/iam" 61 | iam_enabled = var.option_iam == "New IAM Dynamic Group and Policy will be created" 62 | tenancy_ocid = var.tenancy_ocid 63 | compartment_id = var.compartment_ocid 64 | db_secret_compartment_id = var.db_secret_compartment_id 65 | policy_name = var.new_policy_name 66 | dynamic_group_name = var.new_dynamic_group_name 67 | dynamic_group_matching_rule = "ALL {instance.id = '${module.compute.compute_id}'}" 68 | service_tags = var.service_tags 69 | } 70 | 71 | module "oac" { 72 | source = "./modules/oac" 73 | oac_enabled = var.option_oac == "Deploy Oracle Analytics Cloud" 74 | compartment_id = var.compartment_ocid 75 | analytics_instance_name = var.analytics_instance_name 76 | analytics_instance_capacity_value = var.analytics_instance_capacity_value 77 | analytics_instance_feature_set = var.analytics_instance_feature_set 78 | analytics_instance_license_type = var.analytics_instance_license_type 79 | analytics_instance_idcs_access_token = var.analytics_instance_idcs_access_token 80 | service_tags = var.service_tags 81 | } 82 | 83 | #******************************************************************************************** 84 | # Outputs 85 | #******************************************************************************************** 86 | 87 | output "APEX_Admin_Workspace_URL" { 88 | value = module.adb.apex_url 89 | } 90 | 91 | output "DB_Secret_Id" { 92 | value = var.db_secret_id 93 | } 94 | 95 | output "APEX_Application_Login_URL" { 96 | value = replace(module.adb.apex_url,"apex","f?p=100:LOGIN_DESKTOP::::::") 97 | } 98 | 99 | output "Load_Balancer_Apex_Admin_Workspace" { 100 | value = module.network.load_balancer_ip_address != null ? "https://${module.network.load_balancer_ip_address}/ords/f?p=4550:1::::::" : null 101 | } 102 | 103 | output "Load_Balancer_Apex_App_Login_URL" { 104 | value = module.network.load_balancer_ip_address != null ? "https://${module.network.load_balancer_ip_address}/ords/f?p=100:LOGIN_DESKTOP::::::" : null 105 | } 106 | 107 | output "ADWC_Service_Console_URL" { 108 | value = module.adb.adwc_console 109 | } 110 | 111 | output "VM_Private_IP" { 112 | value = module.compute.private_ip 113 | } 114 | 115 | output "VM_Public_IP" { 116 | value = module.compute.public_ip != null ? module.compute.public_ip : null 117 | } 118 | 119 | output "VM_OS_Image" { 120 | value = module.compute.usage_image 121 | } 122 | 123 | output "Analytics_URL" { 124 | value = module.oac.Analytics_URL != null ? module.oac.Analytics_URL : null 125 | } 126 | 127 | output "ZZZ_Instructions" { 128 | value = "Please login to the VM under opc user and check the file boot.log for any errors and continue login to APEX Application URL" 129 | } 130 | -------------------------------------------------------------------------------- /terraform/modules/adb/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | ############################################ 7 | # Variables 8 | ############################################ 9 | variable "compartment_id" {} 10 | variable "db_secret_id" {} 11 | variable "db_name" {} 12 | variable "license_model" {} 13 | variable "nsg_id" {} 14 | variable "subnet_id" {} 15 | variable "private_end_point_label" {} 16 | variable "service_tags" {} 17 | variable "autonomous_pe_enabled" {} 18 | 19 | ############################################ 20 | # Secret Id Bundle 21 | ############################################ 22 | data "oci_secrets_secretbundle" "bundle" { 23 | secret_id = var.db_secret_id 24 | } 25 | 26 | ############################################ 27 | # ADWC 28 | ############################################ 29 | resource "oci_database_autonomous_database" "adwc" { 30 | compartment_id = var.compartment_id 31 | admin_password = base64decode(data.oci_secrets_secretbundle.bundle.secret_bundle_content.0.content) 32 | compute_count = "2" 33 | compute_model = "ECPU" 34 | data_storage_size_in_tbs = "1" 35 | db_name = var.db_name 36 | display_name = var.db_name 37 | license_model = var.license_model 38 | db_version = "19c" 39 | db_workload = "DW" 40 | is_auto_scaling_enabled = "false" 41 | is_free_tier = "false" 42 | is_preview_version_with_service_terms_accepted = "false" 43 | defined_tags = var.service_tags.definedTags 44 | freeform_tags = var.service_tags.freeformTags 45 | 46 | nsg_ids = var.autonomous_pe_enabled ? [ var.nsg_id ] : null 47 | private_endpoint_label = var.autonomous_pe_enabled ? var.private_end_point_label : null 48 | subnet_id = var.autonomous_pe_enabled ? var.subnet_id : null 49 | } 50 | 51 | ############################################ 52 | # Outputs 53 | ############################################ 54 | 55 | output "apex_url" { 56 | value = oci_database_autonomous_database.adwc.connection_urls.0.apex_url 57 | } 58 | 59 | output "adwc_id" { 60 | value = oci_database_autonomous_database.adwc.id 61 | } 62 | 63 | output "adwc_pe_ip" { 64 | value = var.autonomous_pe_enabled ? oci_database_autonomous_database.adwc.private_endpoint_ip : null 65 | } 66 | 67 | output "adwc_console" { 68 | value = oci_database_autonomous_database.adwc.service_console_url 69 | } 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /terraform/modules/compute/bootstrap.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | #******************************************************************************************** 3 | # Copyright (c) 2023, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | #******************************************************************************************** 6 | 7 | runcmd: 8 | - su opc 9 | - cd /home/opc/ 10 | - export LOG=/home/opc/boot.log 11 | - export APPDIR=/home/opc/usage_reports_to_adw 12 | - export CRED=$APPDIR/config.user 13 | - echo "Start process at `date`" > $LOG 14 | - chown opc:opc $LOG 15 | - mkdir -p $APPDIR 16 | - chown opc:opc $APPDIR 17 | 18 | # Create the properties file for app_url 19 | - export APP_URL=/home/opc/app_url.txt 20 | - echo "Post application url into $APP_URL" >> $LOG 21 | - echo "APP_URL=${application_url}" > $APP_URL 22 | - echo "ADMIN_URL==${admin_url}" >> $APP_URL 23 | - echo "LB_APP_URL=${lb_application_url}" >> $APP_URL 24 | - echo "LB_ADMIN_URL==${lb_admin_url}" >> $APP_URL 25 | - chown opc:opc $APP_URL 26 | 27 | # Create the properties file 28 | - echo "Post variables into config.user file." >> $LOG 29 | - echo "DATABASE_USER=USAGE" > $CRED 30 | - echo "DATABASE_ID=${db_db_id}" >> $CRED 31 | - echo "DATABASE_NAME=${db_db_name}_low" >> $CRED 32 | - echo "DATABASE_SECRET_ID=${db_secret_id}" >> $CRED 33 | - echo "DATABASE_SECRET_TENANT=local" >> $CRED 34 | - echo "EXTRACT_DATE=${extract_from_date}" >> $CRED 35 | - echo "TAG_SPECIAL=${extract_tag1_special_key}" >> $CRED 36 | - echo "TAG2_SPECIAL=${extract_tag2_special_key}" >> $CRED 37 | - echo "TAG3_SPECIAL=${extract_tag3_special_key}" >> $CRED 38 | - echo "TAG4_SPECIAL=${extract_tag4_special_key}" >> $CRED 39 | - chown opc:opc $CRED 40 | 41 | # Sleep 80 seconds to wait for the policy and services to be created and synched 42 | - echo "Waiting 80 seconds..." >> $LOG 43 | - sleep 20 44 | - echo "Waiting 60 seconds..." >> $LOG 45 | - sleep 20 46 | - echo "Waiting 40 seconds..." >> $LOG 47 | - sleep 20 48 | - echo "Waiting 20 seconds..." >> $LOG 49 | - sleep 20 50 | 51 | # Continue Setup using initial_setup.sh and post info into initial_setup.txt 52 | - echo "https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/usage2adw_setup.sh -O $APPDIR/initial_setup.sh" > $APPDIR/initial_setup.txt 53 | - echo "/home/opc/usage_reports_to_adw/initial_setup.sh -setup_full" >> $APPDIR/initial_setup.txt 54 | 55 | - wget https://raw.githubusercontent.com/oracle-samples/usage-reports-to-adw/main/usage2adw_setup.sh -O $APPDIR/initial_setup.sh >>$LOG 56 | - chown opc:opc $APPDIR/initial_setup.sh 57 | - chmod +x $APPDIR/initial_setup.sh 58 | - su - opc -c '/home/opc/usage_reports_to_adw/initial_setup.sh -setup_full' >>$LOG 59 | 60 | final_message: "The system is finally up, after $UPTIME seconds" 61 | -------------------------------------------------------------------------------- /terraform/modules/compute/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | #***************************** 7 | # Variables 8 | #***************************** 9 | 10 | variable "compartment_id" {} 11 | variable "region" {} 12 | variable "availability_domain" {} 13 | variable "instance_name" {} 14 | variable "ssh_authorized_keys" {} 15 | variable "shape" {} 16 | variable "subnet_id" {} 17 | variable "db_db_id" {} 18 | variable "db_db_name" {} 19 | variable "db_secret_id" {} 20 | variable "extract_from_date" {} 21 | variable "extract_tag1_special_key" {} 22 | variable "extract_tag2_special_key" {} 23 | variable "extract_tag3_special_key" {} 24 | variable "extract_tag4_special_key" {} 25 | variable "tenancy_ocid" {} 26 | 27 | variable "service_tags" {} 28 | variable "application_url" {} 29 | variable "admin_url" {} 30 | variable "lb_application_url" {} 31 | variable "lb_admin_url" {} 32 | 33 | #***************************** 34 | # Subnet Query 35 | #***************************** 36 | data "oci_core_subnet" "subnet" { 37 | subnet_id = var.subnet_id 38 | } 39 | 40 | #***************************** 41 | # Images 42 | #***************************** 43 | data "oci_core_images" "usage_image" { 44 | compartment_id = var.compartment_id 45 | operating_system = "Oracle Linux" 46 | operating_system_version = "8" 47 | filter { 48 | name = "display_name" 49 | values = ["^([a-zA-z]+)-([a-zA-z]+)-([\\.0-9]+)-([\\.0-9-]+)$"] 50 | regex = true 51 | } 52 | } 53 | 54 | #***************************** 55 | # Instance 56 | #***************************** 57 | resource "oci_core_instance" "usagevm" { 58 | availability_domain = var.availability_domain 59 | compartment_id = var.compartment_id 60 | display_name = var.instance_name 61 | shape = var.shape 62 | 63 | create_vnic_details { 64 | subnet_id = data.oci_core_subnet.subnet.subnet_id 65 | assign_public_ip = !data.oci_core_subnet.subnet.prohibit_public_ip_on_vnic 66 | } 67 | 68 | shape_config { 69 | ocpus = 1 70 | memory_in_gbs = 15 71 | } 72 | 73 | source_details { 74 | source_type = "image" 75 | source_id = data.oci_core_images.usage_image.images.0.id 76 | } 77 | 78 | metadata = { 79 | ssh_authorized_keys = var.ssh_authorized_keys 80 | user_data = base64encode(templatefile("${path.module}/bootstrap.tpl", { 81 | db_db_name = var.db_db_name, 82 | db_db_id = var.db_db_id, 83 | db_secret_id = var.db_secret_id, 84 | extract_from_date = var.extract_from_date, 85 | extract_tag1_special_key = var.extract_tag1_special_key, 86 | extract_tag2_special_key = var.extract_tag2_special_key, 87 | extract_tag3_special_key = var.extract_tag3_special_key, 88 | extract_tag4_special_key = var.extract_tag4_special_key, 89 | admin_url = var.admin_url 90 | application_url = var.application_url 91 | lb_admin_url = var.lb_admin_url 92 | lb_application_url = var.lb_application_url 93 | })) 94 | } 95 | 96 | timeouts { 97 | create = "30m" 98 | } 99 | 100 | preserve_boot_volume = false 101 | 102 | defined_tags = var.service_tags.definedTags 103 | freeform_tags = var.service_tags.freeformTags 104 | } 105 | 106 | ############################################### 107 | # Output 108 | ############################################### 109 | output "public_ip" { 110 | value = oci_core_instance.usagevm.public_ip 111 | } 112 | 113 | output "private_ip" { 114 | value = oci_core_instance.usagevm.private_ip 115 | } 116 | 117 | output "compute_id" { 118 | value = oci_core_instance.usagevm.id 119 | } 120 | 121 | output "usage_image" { 122 | value = data.oci_core_images.usage_image.images.0.display_name 123 | } -------------------------------------------------------------------------------- /terraform/modules/iam/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | ############################################ 7 | # Variables 8 | ############################################ 9 | variable "iam_enabled" {} 10 | variable "tenancy_ocid" {} 11 | variable "compartment_id" {} 12 | variable "db_secret_compartment_id" {} 13 | variable "policy_name" {} 14 | variable "dynamic_group_name" {} 15 | variable "dynamic_group_matching_rule" {} 16 | variable "service_tags" {} 17 | 18 | ############################################ 19 | # Dynamic Group 20 | ############################################ 21 | resource "oci_identity_dynamic_group" "dynamic_group" { 22 | count = var.iam_enabled ? 1 : 0 23 | compartment_id = var.tenancy_ocid 24 | description = "Usage2ADW_Dynamic_Group to define the Usage2ADW Compute VM" 25 | matching_rule = var.dynamic_group_matching_rule 26 | name = var.dynamic_group_name 27 | 28 | defined_tags = var.service_tags.definedTags 29 | freeform_tags = var.service_tags.freeformTags 30 | } 31 | 32 | ############################################ 33 | # Policy 34 | ############################################ 35 | resource "oci_identity_policy" "policy" { 36 | count = var.iam_enabled ? 1 : 0 37 | compartment_id = var.tenancy_ocid 38 | description = "Usage2ADW Policy to allow the VM to extract Usage and Cost Report and list compartments" 39 | name = var.policy_name 40 | statements = [ 41 | "define tenancy usage-report as ocid1.tenancy.oc1..aaaaaaaaned4fkpkisbwjlr56u7cj63lf3wffbilvqknstgtvzub7vhqkggq", 42 | "endorse dynamic-group ${var.dynamic_group_name} to read objects in tenancy usage-report", 43 | "Allow dynamic-group ${var.dynamic_group_name} to inspect compartments in tenancy", 44 | "Allow dynamic-group ${var.dynamic_group_name} to inspect tenancies in tenancy", 45 | "Allow dynamic-group ${var.dynamic_group_name} to read autonomous-databases in compartment id ${var.compartment_id}", 46 | "Allow dynamic-group ${var.dynamic_group_name} to read secret-bundles in compartment id ${var.db_secret_compartment_id}" 47 | ] 48 | depends_on = [ 49 | oci_identity_dynamic_group.dynamic_group 50 | ] 51 | 52 | defined_tags = var.service_tags.definedTags 53 | freeform_tags = var.service_tags.freeformTags 54 | } 55 | -------------------------------------------------------------------------------- /terraform/modules/network/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2025, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | ############################################ 7 | # Variables 8 | ############################################ 9 | locals { 10 | all_cidr = "0.0.0.0/0" 11 | } 12 | 13 | variable "compartment_id" {} 14 | variable "network_nsg_name" {} 15 | variable "existing_vcn_id" {} 16 | variable "service_tags" {} 17 | 18 | variable "load_balancer_display_name" {} 19 | variable "load_balancer_subnet_id" {} 20 | variable "adw_pe_ip_address" {} 21 | variable "load_balancer_enabled" {} 22 | 23 | variable "autonomous_pe_enabled" {} 24 | 25 | ############################################ 26 | # Network Security Group 27 | ############################################ 28 | resource oci_core_network_security_group vcn_nsg { 29 | count = var.autonomous_pe_enabled ? 1 : 0 30 | compartment_id = var.compartment_id 31 | display_name = var.network_nsg_name 32 | vcn_id = var.existing_vcn_id 33 | defined_tags = var.service_tags.definedTags 34 | freeform_tags = var.service_tags.freeformTags 35 | } 36 | 37 | resource oci_core_network_security_group_security_rule nsg_rule_1 { 38 | count = var.autonomous_pe_enabled ? 1 : 0 39 | description = "Network Security Group for Usage2ADW Ingress port 1522" 40 | destination_type = "" 41 | direction = "INGRESS" 42 | network_security_group_id = oci_core_network_security_group.vcn_nsg[count.index].id 43 | protocol = "6" 44 | source = local.all_cidr 45 | source_type = "CIDR_BLOCK" 46 | stateless = "false" 47 | tcp_options { 48 | destination_port_range { 49 | max = "1522" 50 | min = "1522" 51 | } 52 | } 53 | } 54 | 55 | resource oci_core_network_security_group_security_rule nsg_rule_2 { 56 | count = var.autonomous_pe_enabled ? 1 : 0 57 | description = "Network Security Group for Usage2ADW Ingress port 443" 58 | destination_type = "" 59 | direction = "INGRESS" 60 | network_security_group_id = oci_core_network_security_group.vcn_nsg[count.index].id 61 | protocol = "6" 62 | source = local.all_cidr 63 | source_type = "CIDR_BLOCK" 64 | stateless = "false" 65 | tcp_options { 66 | destination_port_range { 67 | max = "443" 68 | min = "443" 69 | } 70 | } 71 | } 72 | 73 | resource oci_core_network_security_group_security_rule nsg_rule_3 { 74 | count = var.autonomous_pe_enabled ? 1 : 0 75 | description = "Network Security Group for Usage2ADW Egress" 76 | destination = local.all_cidr 77 | destination_type = "CIDR_BLOCK" 78 | direction = "EGRESS" 79 | network_security_group_id = oci_core_network_security_group.vcn_nsg[count.index].id 80 | protocol = "all" 81 | stateless = "false" 82 | } 83 | 84 | ############################################ 85 | # Load Balancer 86 | ############################################ 87 | 88 | resource "oci_load_balancer_backend" "usage2adw_backend" { 89 | count = var.load_balancer_enabled ? 1 : 0 90 | backendset_name = oci_load_balancer_backend_set.usage2adw_backendset[count.index].name 91 | ip_address = var.adw_pe_ip_address 92 | load_balancer_id = oci_load_balancer_load_balancer.usage2adw_loadbalancer[count.index].id 93 | port = 443 94 | } 95 | 96 | resource "oci_load_balancer_backend_set" "usage2adw_backendset" { 97 | count = var.load_balancer_enabled ? 1 : 0 98 | load_balancer_id = oci_load_balancer_load_balancer.usage2adw_loadbalancer[count.index].id 99 | name = "usage2adw_backendset" 100 | policy = "ROUND_ROBIN" 101 | health_checker { 102 | protocol = "TCP" 103 | interval_ms = 10000 104 | port = 443 105 | retries = 3 106 | return_code = 200 107 | timeout_in_millis = 3000 108 | } 109 | } 110 | 111 | resource "oci_load_balancer_listener" "usage2adw_listener" { 112 | count = var.load_balancer_enabled ? 1 : 0 113 | load_balancer_id = oci_load_balancer_load_balancer.usage2adw_loadbalancer[count.index].id 114 | name = "usage2adw_listener" 115 | port = 443 116 | protocol = "TCP" 117 | default_backend_set_name = oci_load_balancer_backend_set.usage2adw_backendset[count.index].name 118 | connection_configuration { 119 | idle_timeout_in_seconds = "300" 120 | backend_tcp_proxy_protocol_version = 0 121 | } 122 | } 123 | 124 | resource "oci_load_balancer_load_balancer" "usage2adw_loadbalancer" { 125 | count = var.load_balancer_enabled ? 1 : 0 126 | compartment_id = var.compartment_id 127 | display_name = var.load_balancer_display_name 128 | subnet_ids = [ var.load_balancer_subnet_id ] 129 | defined_tags = var.service_tags.definedTags 130 | freeform_tags = var.service_tags.freeformTags 131 | shape = "flexible" 132 | ip_mode = "IPV4" 133 | is_private = false 134 | network_security_group_ids = [ oci_core_network_security_group.vcn_nsg[count.index].id ] 135 | shape_details { 136 | maximum_bandwidth_in_mbps = 10 137 | minimum_bandwidth_in_mbps = 10 138 | } 139 | } 140 | 141 | ############################################ 142 | # Output 143 | ############################################ 144 | output "nsg_id" { 145 | value = var.autonomous_pe_enabled && length(oci_core_network_security_group.vcn_nsg) > 0 ? oci_core_network_security_group.vcn_nsg[0].id : null 146 | } 147 | 148 | output "load_balancer_ip_address" { 149 | value = var.load_balancer_enabled && length(oci_load_balancer_load_balancer.usage2adw_loadbalancer) > 0 ? oci_load_balancer_load_balancer.usage2adw_loadbalancer[0].ip_address_details[0].ip_address : null 150 | } 151 | -------------------------------------------------------------------------------- /terraform/modules/oac/main.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2023, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | ############################################ 7 | # Variables 8 | ############################################ 9 | variable "oac_enabled" {} 10 | variable "compartment_id" {} 11 | variable "analytics_instance_name" {} 12 | variable "analytics_instance_capacity_value" {} 13 | variable "analytics_instance_feature_set" {} 14 | variable "analytics_instance_license_type" {} 15 | variable "analytics_instance_idcs_access_token" {} 16 | variable "service_tags" {} 17 | 18 | ############################################ 19 | # OAC 20 | ############################################ 21 | resource "oci_analytics_analytics_instance" "analytics_instance" { 22 | count = var.oac_enabled ? 1 : 0 23 | compartment_id = var.compartment_id 24 | feature_set = var.analytics_instance_feature_set == "OAC Standard Edition" ? "SELF_SERVICE_ANALYTICS" : "ENTERPRISE_ANALYTICS" 25 | license_type = var.analytics_instance_license_type 26 | name = var.analytics_instance_name 27 | description = var.analytics_instance_name 28 | idcs_access_token = var.analytics_instance_idcs_access_token 29 | defined_tags = var.service_tags.definedTags 30 | freeform_tags = var.service_tags.freeformTags 31 | 32 | capacity { 33 | capacity_type = "OLPU_COUNT" 34 | capacity_value = var.analytics_instance_capacity_value 35 | } 36 | } 37 | 38 | ############################################ 39 | # Outputs 40 | ############################################ 41 | output "Analytics_URL" { 42 | value = oci_analytics_analytics_instance.analytics_instance.*.service_url 43 | } -------------------------------------------------------------------------------- /terraform/schema.yaml: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2025, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | title: Usage2ADW 7 | description: OCI Usage and Cost Reports to Autonomous Database Version 25.05.01 8 | schemaVersion: 1.0.0 9 | version: "20250501" 10 | locale: "en" 11 | 12 | groupings: 13 | 14 | - title: "Compartment" 15 | variables: 16 | - ${compartment_ocid} 17 | 18 | - title: "Resource Tags" 19 | variables: 20 | - ${service_tags} 21 | 22 | - title: "Identity Configuration" 23 | visible: true 24 | variables: 25 | - ${option_iam} 26 | - ${new_policy_name} 27 | - ${new_dynamic_group_name} 28 | 29 | - title: "Network Configuration" 30 | visible: true 31 | variables: 32 | - ${network_vcn_compartment_id} 33 | - ${network_vcn_id} 34 | - ${network_subnet_compartment_id} 35 | - ${network_subnet_id} 36 | 37 | - title: "Autonomous Database Configuration" 38 | visible: true 39 | variables: 40 | - ${option_autonomous_database} 41 | - ${db_db_name} 42 | - ${db_secret_compartment_id} 43 | - ${db_secret_id} 44 | - ${db_license_model} 45 | - ${db_network_nsg_name} 46 | - ${db_private_end_point_label} 47 | 48 | - title: "Load Balancer Configuration" 49 | visible: true 50 | variables: 51 | - ${option_loadbalancer} 52 | - ${loadbalancer_name} 53 | - ${loadbalancer_subnet_compartment_id} 54 | - ${loadbalancer_subnet_id} 55 | 56 | - title: "Instance Configuration" 57 | variables: 58 | - ${instance_availability_domain} 59 | - ${instance_name} 60 | - ${instance_shape} 61 | - ${ssh_public_key} 62 | - ${extract_from_date} 63 | - ${extract_tag1_special_key} 64 | - ${extract_tag2_special_key} 65 | - ${extract_tag3_special_key} 66 | - ${extract_tag4_special_key} 67 | 68 | - title: "Oracle Analytics (OAC) Configuration" 69 | variables: 70 | - ${option_oac} 71 | - ${analytics_instance_name} 72 | - ${analytics_instance_capacity_value} 73 | - ${analytics_instance_feature_set} 74 | - ${analytics_instance_license_type} 75 | - ${analytics_instance_idcs_access_token} 76 | 77 | variables: 78 | 79 | ################################################### 80 | # Main Menu 81 | ################################################### 82 | compartment_ocid: 83 | title: Stack Compartment 84 | description: Choose the compartment where all the provisioned resources will be deployed *** Deployment must be at Home Region *** 85 | type: oci:identity:compartment:id 86 | required: true 87 | 88 | service_tags: 89 | title: Add Tags 90 | type: oci:identity:tag:value 91 | required: false 92 | 93 | ################################################### 94 | # Identity Configuration 95 | ################################################### 96 | option_iam: 97 | title: Identity Options 98 | description: IAM Dynamic Group and Policies can be created for you under the root compartment, it required Admin access. 99 | visible: true 100 | type: enum 101 | enum: 102 | - New IAM Dynamic Group and Policy will be created 103 | - I have already created Dynamic Group and Policy per the documentation 104 | default: I have already created Dynamic Group and Policy per the documentation 105 | required: true 106 | 107 | new_dynamic_group_name: 108 | title: Dynamic Group Name 109 | required: true 110 | pattern: ^[A-Za-z][A-Za-z0-9-_]+$ 111 | type: string 112 | maxLength: 30 113 | default: Usage2ADW_DynamicGroup 114 | visible: 115 | eq: 116 | - ${option_iam} 117 | - New IAM Dynamic Group and Policy will be created 118 | 119 | new_policy_name: 120 | title: Policy Name 121 | required: true 122 | pattern: ^[A-Za-z][A-Za-z0-9-_]+$ 123 | type: string 124 | maxLength: 30 125 | default: Usage2ADW_Policy 126 | visible: 127 | eq: 128 | - ${option_iam} 129 | - New IAM Dynamic Group and Policy will be created 130 | 131 | ################################################### 132 | # Network Configuration 133 | ################################################### 134 | network_vcn_compartment_id: 135 | title: VCN Compartment 136 | type: oci:identity:compartment:id 137 | default: ${compartment_ocid} 138 | required: true 139 | visible: true 140 | 141 | network_vcn_id: 142 | title: VCN 143 | type: oci:core:vcn:id 144 | dependsOn: 145 | compartmentId: ${network_vcn_compartment_id} 146 | required: true 147 | visible: true 148 | 149 | network_subnet_compartment_id: 150 | title: Subnet Compartment 151 | type: oci:identity:compartment:id 152 | default: ${compartment_ocid} 153 | required: true 154 | visible: true 155 | 156 | network_subnet_id: 157 | title: Subnet 158 | type: oci:core:subnet:id 159 | dependsOn: 160 | compartmentId: ${network_subnet_compartment_id} 161 | vcnId: ${network_vcn_id} 162 | required: true 163 | visible: true 164 | 165 | 166 | ################################################### 167 | # Database Configuration 168 | ################################################### 169 | option_autonomous_database: 170 | title: Autonomous Database Deployment Option 171 | description: Deployed Autonomous Database in Public or Private Endpoint. 172 | visible: true 173 | type: enum 174 | enum: 175 | - Public 176 | - Private Endpoint 177 | default: Public 178 | required: true 179 | 180 | db_db_name: 181 | title: Autonomous Database Name 182 | description: Choose an Autonomous Database Name 183 | required: true 184 | pattern: ^[A-Za-z][A-Za-z0-9]+$ 185 | type: string 186 | maxLength: 14 187 | visible: true 188 | 189 | db_secret_compartment_id: 190 | title: Secret Compartment 191 | type: oci:identity:compartment:id 192 | default: ${compartment_ocid} 193 | required: true 194 | visible: true 195 | 196 | db_secret_id: 197 | title: Secret Id 198 | description: Provide database password secret id should be created under KMS Vault. 199 | type: oci:kms:secret:id 200 | dependsOn: 201 | compartmentId: ${db_secret_compartment_id} 202 | required: true 203 | visible: true 204 | 205 | db_license_model: 206 | title: Database License 207 | description: Choose your database license type. 208 | type: enum 209 | enum: 210 | - LICENSE_INCLUDED 211 | - BRING_YOUR_OWN_LICENSE 212 | default: BRING_YOUR_OWN_LICENSE 213 | required: true 214 | visible: true 215 | 216 | db_network_nsg_name: 217 | title: Network Security Group 218 | description: Choose your Network Security Group Name. 219 | type: string 220 | maxLength: 30 221 | required: true 222 | pattern: ^[A-Za-z][A-Za-z0-9-_]+$ 223 | default: Usage2ADW_NSG 224 | visible: 225 | eq: 226 | - ${option_autonomous_database} 227 | - Private Endpoint 228 | 229 | db_private_end_point_label: 230 | title: Private End Point Label 231 | description: Choose your Private End Point Label for the ADB 232 | type: string 233 | required: true 234 | pattern: ^[A-Za-z][A-Za-z_]+$ 235 | maxLength: 12 236 | default: usageadb 237 | visible: 238 | eq: 239 | - ${option_autonomous_database} 240 | - Private Endpoint 241 | 242 | 243 | ################################################### 244 | # Load Balancer Configuration 245 | ################################################### 246 | option_loadbalancer: 247 | title: Load Balancer Options 248 | description: Public Load Balancer can be provisioned to access the Private End-Point. 249 | type: enum 250 | enum: 251 | - Provision Public Load Balancer 252 | - No Public Load Balancer 253 | default: No Public Load Balancer 254 | required: true 255 | visible: 256 | eq: 257 | - ${option_autonomous_database} 258 | - Private Endpoint 259 | 260 | loadbalancer_name: 261 | title: Load Balancer Name 262 | description: Choose your Load Balancer Name. 263 | type: string 264 | maxLength: 30 265 | required: true 266 | pattern: ^[A-Za-z][A-Za-z0-9-_]+$ 267 | default: Usage2ADW_LB 268 | visible: 269 | eq: 270 | - ${option_loadbalancer} 271 | - Provision Public Load Balancer 272 | 273 | loadbalancer_subnet_compartment_id: 274 | title: Load Balancer Public Subnet Compartment 275 | type: oci:identity:compartment:id 276 | default: ${compartment_ocid} 277 | required: true 278 | visible: 279 | eq: 280 | - ${option_loadbalancer} 281 | - Provision Public Load Balancer 282 | 283 | loadbalancer_subnet_id: 284 | title: Load Balancer Public Subnet 285 | type: oci:core:subnet:id 286 | dependsOn: 287 | compartmentId: ${loadbalancer_subnet_compartment_id} 288 | vcnId: ${network_vcn_id} 289 | hidePrivateSubnet: true 290 | required: true 291 | visible: 292 | eq: 293 | - ${option_loadbalancer} 294 | - Provision Public Load Balancer 295 | 296 | 297 | ########################### 298 | # instance 299 | ########################### 300 | instance_name: 301 | title: Instance Name 302 | description: Provide the instance name 303 | type: string 304 | minLength: 1 305 | maxLength: 12 306 | pattern: ^[A-Za-z][A-Za-z0-9]+$ 307 | default: Usage2AdwVM 308 | required: true 309 | 310 | ssh_public_key: 311 | type: oci:core:ssh:publickey 312 | title: SSH Public Key 313 | description: Use public key to secure your VM, Private key pair will be needed later. 314 | required: true 315 | 316 | instance_shape: 317 | title: Compute Shape 318 | description: The shape for the usage2adw compute instances 319 | type: enum 320 | enum: 321 | - VM.Standard.E3.Flex 322 | - VM.Standard.E4.Flex 323 | - VM.Standard.E5.Flex 324 | - VM.Optimized3.Flex 325 | - VM.Standard3.Flex 326 | default: VM.Standard3.Flex 327 | required: true 328 | visible: true 329 | 330 | instance_availability_domain: 331 | title: Availability Domain 332 | description: The name of the availability domain in which to create compute instances, must be at home region 333 | type: oci:identity:availabilitydomain:name 334 | required: true 335 | dependsOn: 336 | compartmentId: ${compartment_ocid} 337 | 338 | extract_from_date: 339 | title: Extract usage from date 340 | description: Please specify the date to extract from, in format (YYYY-MM) 341 | type: string 342 | default: "2025-01" 343 | pattern: "^(2019|202[0-9])-(0[0-9]|1[0-2])$" 344 | required: true 345 | visible: true 346 | 347 | extract_tag1_special_key: 348 | title: Extract Tag Key 1 to special tag column 349 | description: Please specify the tag key 1 to load to Tag Special 1 column 350 | type: string 351 | default: "Oracle-Tags.CreatedBy" 352 | required: true 353 | visible: true 354 | 355 | extract_tag2_special_key: 356 | title: Extract Tag Key 2 to special tag column 357 | description: Please specify the tag key 2 to load to Tag Special 2 column 358 | type: string 359 | default: "Oracle-Tags.Project" 360 | required: true 361 | visible: true 362 | 363 | extract_tag3_special_key: 364 | title: Extract Tag Key 3 to special tag column 365 | description: Please specify the tag key 3 to load to Tag Special 3 column 366 | type: string 367 | default: "Core.Project" 368 | required: true 369 | visible: true 370 | 371 | extract_tag4_special_key: 372 | title: Extract Tag Key 4 to special tag column 373 | description: Please specify the tag key 4 to load to Tag Special 4 column 374 | type: string 375 | default: "Core.Budget" 376 | required: true 377 | visible: true 378 | 379 | 380 | ################################################### 381 | # Analytics Configuration 382 | ################################################### 383 | option_oac: 384 | title: Oracle Analytics (OAC) Options 385 | description: Advance Analytics using Oracle Analytics (OAC) - Required experience with Oracle Analytics 386 | visible: true 387 | type: enum 388 | enum: 389 | - Deploy Oracle Analytics Cloud 390 | - Do Not Deploy Oracle Analytics Cloud 391 | default: Do Not Deploy Oracle Analytics Cloud 392 | required: true 393 | 394 | analytics_instance_name: 395 | title: Oracle Analytics Name 396 | description: Provide the Oracle Analytics name 397 | type: string 398 | minLength: 1 399 | maxLength: 18 400 | pattern: ^[A-Za-z][A-Za-z0-9]+$ 401 | default: Usage2AdwOAC 402 | required: true 403 | visible: 404 | eq: 405 | - ${option_oac} 406 | - Deploy Oracle Analytics Cloud 407 | 408 | analytics_instance_capacity_value: 409 | title: Analytics Instance Capacity 410 | description: Provide the number of OCPUs for the Analytics Instance. 411 | type: enum 412 | enum: 413 | - 1 414 | - 2 415 | - 4 416 | - 6 417 | - 8 418 | - 10 419 | - 12 420 | - 16 421 | - 24 422 | - 36 423 | - 52 424 | required: true 425 | visible: 426 | eq: 427 | - ${option_oac} 428 | - Deploy Oracle Analytics Cloud 429 | 430 | analytics_instance_feature_set: 431 | title: Analytics Instance Type 432 | description: Choose the Analytics Product Type. 433 | type: enum 434 | enum: 435 | - OAC Standard Edition 436 | - OAC Enterprise Edition 437 | default: SELF_SERVICE_ANALYTICS 438 | required: true 439 | visible: 440 | eq: 441 | - ${option_oac} 442 | - Deploy Oracle Analytics Cloud 443 | 444 | analytics_instance_license_type: 445 | title: Analytics License 446 | description: Choose your Oracle Analytics Cloud License Type. 447 | type: enum 448 | enum: 449 | - LICENSE_INCLUDED 450 | - BRING_YOUR_OWN_LICENSE 451 | default: BRING_YOUR_OWN_LICENSE 452 | required: true 453 | visible: 454 | eq: 455 | - ${option_oac} 456 | - Deploy Oracle Analytics Cloud 457 | 458 | analytics_instance_idcs_access_token: 459 | title: IDCS access token identifying a stripe and service administrator user 460 | description: Provide IDCS Access token. See Pre-req section in the Installation Document. 461 | type: string 462 | required: true 463 | visible: 464 | eq: 465 | - ${option_oac} 466 | - Deploy Oracle Analytics Cloud 467 | 468 | 469 | ########################### 470 | # Connections Variables 471 | ########################### 472 | tenancy_ocid: 473 | title: Tenancy ID 474 | description: The Oracle Cloud Identifier (OCID) for your tenancy. 475 | type: string 476 | required: true 477 | visible: false 478 | 479 | region: 480 | title: Region 481 | description: The region in which to create all resources. 482 | type: oci:identity:region:name 483 | required: true 484 | visible: false 485 | 486 | user_ocid: 487 | title: User ID 488 | description: The Oracle Cloud Identifier (OCID) for the user 489 | type: string 490 | visible: false 491 | 492 | fingerprint: 493 | title: Private Key Fingerprint 494 | type: string 495 | visible: false 496 | 497 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | #******************************************************************************************** 2 | # Copyright (c) 2025, Oracle and/or its affiliates. 3 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 4 | #******************************************************************************************** 5 | 6 | ########################## 7 | # Version 8 | ########################## 9 | terraform { 10 | required_version = ">= 0.12.0" 11 | } 12 | 13 | ########################## 14 | # Provider 15 | ########################## 16 | provider "oci" { 17 | region = var.region 18 | } 19 | 20 | variable "tenancy_ocid" {} 21 | variable "region" {} 22 | variable "compartment_ocid" {} 23 | 24 | ########################## 25 | # Service Tag 26 | ########################## 27 | variable "service_tags" { 28 | type = object({ 29 | freeformTags = map(string) 30 | definedTags = map(string) 31 | }) 32 | description = "Tags to be applied to all resources that support tag created by the Usage2ADW for OCI stack" 33 | default = { freeformTags = {}, definedTags = {} } 34 | } 35 | 36 | ########################## 37 | # IAM 38 | ########################## 39 | variable "option_iam" {} 40 | variable "new_policy_name" { default = "" } 41 | variable "new_dynamic_group_name" { default = "" } 42 | 43 | ########################## 44 | # Network 45 | ########################## 46 | variable "network_vcn_compartment_id" { default = "" } 47 | variable "network_vcn_id" { default = "" } 48 | variable "network_subnet_compartment_id" { default = "" } 49 | variable "network_subnet_id" { default = "" } 50 | 51 | variable "option_loadbalancer" { default = "" } 52 | variable "loadbalancer_name" { default = "" } 53 | variable "loadbalancer_subnet_compartment_id" { default = "" } 54 | variable "loadbalancer_subnet_id" { default = "" } 55 | 56 | ########################## 57 | # Database 58 | ########################## 59 | 60 | variable "option_autonomous_database" { default = "" } 61 | variable "db_db_name" { default = "" } 62 | variable "db_secret_compartment_id" { default = "" } 63 | variable "db_secret_id" { default = "" } 64 | variable "db_license_model" { default = "" } 65 | variable "db_network_nsg_name" { default = "" } 66 | variable "db_private_end_point_label" { default = "" } 67 | 68 | ########################## 69 | # Compute 70 | ########################## 71 | variable "ssh_public_key" { default = "" } 72 | variable "instance_shape" { default = "" } 73 | variable "instance_name" { default = "" } 74 | variable "instance_availability_domain" { default = "" } 75 | variable "extract_from_date" { default = "" } 76 | variable "extract_tag1_special_key" { default = "" } 77 | variable "extract_tag2_special_key" { default = "" } 78 | variable "extract_tag3_special_key" { default = "" } 79 | variable "extract_tag4_special_key" { default = "" } 80 | 81 | ########################## 82 | # OAC 83 | ########################## 84 | variable "option_oac" { default = "" } 85 | variable "analytics_instance_name" { default = "" } 86 | variable "analytics_instance_capacity_value" { default = "" } 87 | variable "analytics_instance_feature_set" { default = "" } 88 | variable "analytics_instance_license_type" { default = "" } 89 | variable "analytics_instance_idcs_access_token" { default = "" } 90 | -------------------------------------------------------------------------------- /usage2adw_check_connectivity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ########################################################################## 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # check_connectivity.py - to check if policies granted the proper roles 7 | # @author: Adi Zohar 8 | # 9 | # Supports Python 3 and above 10 | # 11 | # coding: utf-8 12 | ########################################################################## 13 | import oci 14 | import requests 15 | 16 | # Get Instance Principles Signer 17 | signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() 18 | config = {'region': signer.region, 'tenancy': signer.tenancy_id} 19 | tenancy_id = signer.tenancy_id 20 | curr_region = signer.region 21 | 22 | try: 23 | print("\n Connecting to Identity Service...") 24 | identity = oci.identity.IdentityClient(config, signer=signer) 25 | print(" Okay.") 26 | 27 | print("\n Check Tenancy Details Access...") 28 | tenancy = identity.get_tenancy(tenancy_id).data 29 | print(" Okay.") 30 | 31 | print("\n Get List of Regions...") 32 | regions = identity.list_regions() 33 | print(" Okay.") 34 | 35 | print("\n Check running in home region...") 36 | home_region_array = next(item for item in regions.data if str(item.key) == str(tenancy.home_region_key)) 37 | home_region = str(home_region_array.name) 38 | print(" Home Region = " + home_region) 39 | print(" Current Region = " + curr_region) 40 | if home_region == curr_region: 41 | print(" Okay.") 42 | else: 43 | print(" Okay. But recommend to install it at Home Region, home region " + home_region + ".") 44 | 45 | print("\n Check Compartment List Access...") 46 | all_compartments = identity.list_compartments(tenancy_id, compartment_id_in_subtree=True).data 47 | print(" Okay...") 48 | 49 | print("\n Check Access to Cost and Usage Object Storage...") 50 | signer.region = home_region 51 | config['region'] = home_region 52 | 53 | object_storage = oci.object_storage.ObjectStorageClient(config, signer=signer) 54 | objects = object_storage.list_objects("bling", tenancy_id, fields="timeCreated,size").data 55 | print(" Okay.") 56 | 57 | try: 58 | print("\n Check Access to OCI Public Rates URL (Required Internet Access)...") 59 | api_url = "https://apexapps.oracle.com/pls/apex/cetools/api/v1/products/?currencyCode=USD" 60 | resp = requests.get(api_url) 61 | print(" Okay.") 62 | except Exception: 63 | print(" Issue with Internet, List Price will no be extracted") 64 | 65 | print("\n Check Completed Successfully.") 66 | print(" Tenant Name : " + str(tenancy.name)) 67 | print(" Tenant Id : " + tenancy.id) 68 | print("") 69 | 70 | except oci.exceptions.ServiceError as e: 71 | print("Error oci.exceptions.ServiceError") 72 | print(e) 73 | except oci.exceptions.RequestException as e: 74 | print("Error oci.exceptions.RequestException") 75 | print(e) 76 | except Exception as e: 77 | print("Error Exception") 78 | print(e) 79 | -------------------------------------------------------------------------------- /usage2adw_download_adb_wallet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ########################################################################## 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # DISCLAIMER This is not an official Oracle application, It does not supported by Oracle Support, 7 | # 8 | # usage2adw_download_adb_wallet.py 9 | # 10 | # @author: Adi Zohar 11 | # 12 | # Supports Python 3 and above 13 | # 14 | # coding: utf-8 15 | ########################################################################## 16 | # This script required policy to allow to generate ADB Wallet 17 | # Allow group UsageDownloadGroup to read autonomous-database in compartment {APPCOMP} 18 | # Allow group UsageDownloadGroup to read secret-bundles in compartment {APPCOMP} 19 | # 20 | ########################################################################## 21 | # 22 | # Modules Included: 23 | # - oci.database.DatabaseClient 24 | # 25 | # APIs Used: 26 | # - DatabaseClient.generate_autonomous_database_wallet - Policy read autonomous-database 27 | # - SecretsClient.get_secret_bundle - Policy SECRET_BUNDLE_READ 28 | # 29 | ########################################################################## 30 | 31 | import os 32 | import argparse 33 | import datetime 34 | import oci 35 | import sys 36 | import shutil 37 | import base64 38 | 39 | version = "24.10.01" 40 | 41 | 42 | ########################################################################## 43 | # Print header centered 44 | ########################################################################## 45 | def print_header(name, category): 46 | options = {0: 90, 1: 60, 2: 30} 47 | chars = int(options[category]) 48 | print("") 49 | print('#' * chars) 50 | print("#" + name.center(chars - 2, " ") + "#") 51 | print('#' * chars) 52 | 53 | 54 | ########################################################################## 55 | # get command line and mask password 56 | ########################################################################## 57 | def get_command_line(): 58 | 59 | str = "" 60 | was_password = False 61 | 62 | for var in sys.argv[1:]: 63 | str += " " if str else "" 64 | str += "xxxxxxx" if was_password else var 65 | was_password = (var == "-password") 66 | 67 | return str 68 | 69 | 70 | ########################################################################## 71 | # Get Currnet Date Time 72 | ########################################################################## 73 | def get_current_date_time(): 74 | return str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) 75 | 76 | 77 | ########################################################################## 78 | # Create signer 79 | ########################################################################## 80 | def create_signer(cmd): 81 | 82 | # assign default values 83 | config_file = oci.config.DEFAULT_LOCATION 84 | config_section = oci.config.DEFAULT_PROFILE 85 | 86 | if cmd.config: 87 | if cmd.config.name: 88 | config_file = cmd.config.name 89 | 90 | if cmd.profile: 91 | config_section = cmd.profile 92 | 93 | if cmd.instance_principals: 94 | try: 95 | signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() 96 | config = {'region': signer.region, 'tenancy': signer.tenancy_id} 97 | return config, signer 98 | except Exception: 99 | print_header("Error obtaining instance principals certificate, aborting", 0) 100 | raise SystemExit 101 | else: 102 | config = oci.config.from_file(config_file, config_section) 103 | signer = oci.signer.Signer( 104 | tenancy=config["tenancy"], 105 | user=config["user"], 106 | fingerprint=config["fingerprint"], 107 | private_key_file_location=config.get("key_file"), 108 | pass_phrase=oci.config.get_config_value_or_default(config, "pass_phrase"), 109 | private_key_content=config.get("key_content") 110 | ) 111 | return config, signer 112 | 113 | 114 | ########################################################################## 115 | # get_secret_password 116 | ########################################################################## 117 | def get_secret_password(config, signer, proxy, secret_id): 118 | 119 | try: 120 | print("\nConnecting to Secret Client Service...") 121 | secret_client = oci.secrets.SecretsClient(config, signer=signer) 122 | if proxy: 123 | secret_client.base_client.session.proxies = {'https': proxy} 124 | print("Connected.") 125 | 126 | secret_data = secret_client.get_secret_bundle(secret_id).data 127 | 128 | print("Secret Retrieved.") 129 | secret_bundle_content = secret_data.secret_bundle_content 130 | secret_base64 = secret_bundle_content.content 131 | secret_text_bytes = base64.b64decode(secret_base64) 132 | secret_text = secret_text_bytes.decode('ASCII') 133 | return secret_text 134 | 135 | except oci.exceptions.ServiceError as e: 136 | print("\nServiceError retrieving secret at get_secret_password !") 137 | print("\n" + str(e) + "\n") 138 | raise SystemExit 139 | 140 | except Exception as e: 141 | print("\nException retrieving secret at get_secret_password !") 142 | print("\n" + str(e) + "\n") 143 | raise SystemExit 144 | 145 | 146 | ########################################################################## 147 | # set parser 148 | ########################################################################## 149 | def set_parser_arguments(): 150 | parser = argparse.ArgumentParser() 151 | 152 | parser.add_argument('-c', type=argparse.FileType('r'), dest='config', help="Config File") 153 | parser.add_argument('-t', default="", dest='profile', help='Config file section to use (tenancy profile)') 154 | parser.add_argument('-p', default="", dest='proxy', help='Set Proxy (i.e. www-proxy-server.com:80) ') 155 | parser.add_argument('-ip', action='store_true', default=False, dest='instance_principals', help='Use Instance Principals for Authentication') 156 | 157 | parser.add_argument('-dbid', default="", dest='dbid', help='Database OCID') 158 | parser.add_argument('-folder', default="", dest='folder', help='Folder to extract the Wallet') 159 | parser.add_argument('-zipfile', default="~/wallet.zip", dest='zipfile', help='Zip file for wallet, default wallet.zip') 160 | parser.add_argument('-secret', default="", dest='secret', help='Wallet Secret for Password') 161 | 162 | parser.add_argument('--version', action='version', version='%(prog)s ' + version) 163 | 164 | result = parser.parse_args() 165 | 166 | if not (result.dbid and result.folder and result.secret): 167 | parser.print_help() 168 | print_header("You must specify dbid, folder and secret in order to generate wallet!", 0) 169 | return None 170 | 171 | return result 172 | 173 | 174 | ########################################################################## 175 | # Main 176 | ########################################################################## 177 | def main_process(): 178 | cmd = set_parser_arguments() 179 | if cmd is None: 180 | exit() 181 | config, signer = create_signer(cmd) 182 | 183 | wallet_zipfile = cmd.zipfile 184 | wallet_folder = cmd.folder 185 | wallet_folder_abs_path = os.path.abspath(wallet_folder) 186 | database_id = cmd.dbid 187 | section = "" 188 | 189 | ############################################ 190 | # Start 191 | ############################################ 192 | print_header("Running Autonomous Database Generate Wallet", 0) 193 | print("Starts at " + get_current_date_time()) 194 | print("Command Line : " + get_command_line()) 195 | 196 | wallet_password = get_secret_password(config, signer, cmd.proxy, cmd.secret) 197 | 198 | ############################################ 199 | # Download Wallet 200 | ############################################ 201 | try: 202 | print("\nConnecting to Database Client Service...") 203 | section = "Connecting to Database Client Service" 204 | database_client = oci.database.DatabaseClient(config, signer=signer) 205 | if cmd.proxy: 206 | database_client.base_client.session.proxies = {'https': cmd.proxy} 207 | print("Connected.") 208 | 209 | try: 210 | section = "Generating Wallet" 211 | print("\nGenerating Wallet to " + wallet_zipfile) 212 | generateAutonomousDatabaseWalletDetails = oci.database.models.GenerateAutonomousDatabaseWalletDetails( 213 | password=wallet_password, 214 | generate_type='SINGLE' 215 | ) 216 | 217 | response_data = database_client.generate_autonomous_database_wallet( 218 | database_id, 219 | generateAutonomousDatabaseWalletDetails 220 | ).data 221 | 222 | section = f'Store Wallet to {wallet_zipfile}' 223 | # Store Wallet 224 | with open(wallet_zipfile, 'wb') as file: 225 | for chunk in response_data.raw.stream(1024 * 1024, decode_content=False): 226 | file.write(chunk) 227 | 228 | print("Wallet Downloaded.") 229 | 230 | # Creating Wallet Folder if not exist 231 | section = f'Creating Folder {wallet_folder}' 232 | print(f'\nCreating Folder {wallet_folder}') 233 | os.makedirs(wallet_folder, exist_ok=True) 234 | print("Folder Created") 235 | 236 | # unzip Wallet 237 | print(f'\nUnzip Wallet to {wallet_folder}') 238 | section = f'unzip wallet to {wallet_folder}' 239 | shutil.unpack_archive(wallet_zipfile, wallet_folder) 240 | print(f'Wallet unzipped to {wallet_folder}') 241 | 242 | # update sqlnet.ora 243 | print(f'\nUpdating sqlnet.ora to {wallet_folder_abs_path}') 244 | section = 'Updating sqlnet.ora' 245 | sqlnet_ora = os.path.join(wallet_folder, 'sqlnet.ora') 246 | with open(sqlnet_ora, 'w') as f: 247 | f.write(f'WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="{wallet_folder_abs_path}")))\n') 248 | f.write("SSL_SERVER_DN_MATCH=yes\n") 249 | print('sqlnet.ora was updated') 250 | 251 | except oci.exceptions.ServiceError as e: 252 | print("\nError generating wallet, please make sure you have permission to generate wallet !") 253 | print("Policy required - Allow group UsageDownloadGroup to read autonomous-database in compartment XXXXXX") 254 | print("\n" + str(e) + "\n") 255 | raise SystemExit 256 | 257 | except Exception as e: 258 | print("\nError generating wallet - section " + section + "\n" + str(e) + "\n") 259 | raise SystemExit 260 | 261 | except Exception as e: 262 | print("\nError appeared - " + str(e)) 263 | 264 | ############################################ 265 | # print completed 266 | ############################################ 267 | print("\nCompleted at " + get_current_date_time()) 268 | 269 | 270 | ########################################################################## 271 | # Execute Main Process 272 | ########################################################################## 273 | main_process() 274 | -------------------------------------------------------------------------------- /usage2adw_retrieve_secret.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ########################################################################## 3 | # Copyright (c) 2025, Oracle and/or its affiliates. 4 | # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ 5 | # 6 | # DISCLAIMER This is not an official Oracle application, It does not supported by Oracle Support. 7 | # 8 | # usage2adw_retrieve_secret.py 9 | # 10 | # @author: Adi Zohar 11 | # 12 | # Supports Python 3 and above 13 | # 14 | # coding: utf-8 15 | ########################################################################## 16 | # This script required policy to allow to retrieve secret from kms vault 17 | # Allow group UsageDownloadGroup to read secret-bundles in compartment {APPCOMP} 18 | # 19 | ########################################################################## 20 | # 21 | # Modules Included: 22 | # - oci.secrets.SecretsClient 23 | # 24 | # APIs Used: 25 | # - get_secret_bundle 26 | # 27 | ########################################################################## 28 | 29 | import argparse 30 | import datetime 31 | import oci 32 | import base64 33 | 34 | version = "25.05.01" 35 | 36 | 37 | ########################################################################## 38 | # Get Currnet Date Time 39 | ########################################################################## 40 | def get_current_date_time(): 41 | return str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) 42 | 43 | 44 | ########################################################################## 45 | # Create signer 46 | ########################################################################## 47 | def create_signer(cmd): 48 | 49 | # assign default values 50 | config_file = oci.config.DEFAULT_LOCATION 51 | config_section = oci.config.DEFAULT_PROFILE 52 | instant_principle = True 53 | 54 | if cmd.config: 55 | if cmd.config.name: 56 | config_file = cmd.config.name 57 | 58 | if cmd.profile: 59 | instant_principle = (cmd.profile == 'local') 60 | config_section = cmd.profile 61 | 62 | if instant_principle: 63 | try: 64 | signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() 65 | config = {'region': signer.region, 'tenancy': signer.tenancy_id} 66 | return config, signer 67 | except Exception: 68 | print("Error obtaining instance principals certificate, aborting...") 69 | raise SystemExit 70 | else: 71 | config = oci.config.from_file(config_file, config_section) 72 | signer = oci.signer.Signer( 73 | tenancy=config["tenancy"], 74 | user=config["user"], 75 | fingerprint=config["fingerprint"], 76 | private_key_file_location=config.get("key_file"), 77 | pass_phrase=oci.config.get_config_value_or_default(config, "pass_phrase"), 78 | private_key_content=config.get("key_content") 79 | ) 80 | return config, signer 81 | 82 | 83 | ########################################################################## 84 | # set parser 85 | ########################################################################## 86 | def set_parser_arguments(): 87 | parser = argparse.ArgumentParser() 88 | 89 | parser.add_argument('-c', type=argparse.FileType('r'), dest='config', help="Config File") 90 | parser.add_argument('-t', default="", dest='profile', help='Config file section to use (local for instance principle)') 91 | parser.add_argument('-p', default="", dest='proxy', help='Set Proxy (i.e. www-proxy-server.com:80) ') 92 | 93 | parser.add_argument('-secret', default="", dest='secret', help='Secret OCID') 94 | parser.add_argument('-check', action='store_true', default=False, dest='check', help='Run check for Secret Retrival') 95 | 96 | parser.add_argument('--version', action='version', version='%(prog)s ' + version) 97 | 98 | result = parser.parse_args() 99 | 100 | if not (result.secret): 101 | parser.print_help() 102 | print("You must specify secret ocid in order to generate wallet!") 103 | return None 104 | 105 | return result 106 | 107 | 108 | ########################################################################## 109 | # get_secret_password 110 | ########################################################################## 111 | def get_secret_password(config, signer, proxy, secret_id): 112 | 113 | try: 114 | print("\nConnecting to Secret Client Service...") 115 | sclient = oci.secrets.SecretsClient(config, signer=signer) 116 | if proxy: 117 | sclient.base_client.session.proxies = {'https': proxy} 118 | print("Connected.") 119 | 120 | secret_data = sclient.get_secret_bundle(secret_id).data 121 | 122 | print("Secret Retrieved.") 123 | value_bundle_content = secret_data.secret_bundle_content 124 | value_base64 = value_bundle_content.content 125 | value_text_bytes = base64.b64decode(value_base64) 126 | value_text = value_text_bytes.decode('ASCII') 127 | return value_text 128 | 129 | except oci.exceptions.ServiceError as e: 130 | print("\nServiceError retrieving secret at get_secret_password !") 131 | print("\n" + str(e) + "\n") 132 | raise SystemExit 133 | 134 | except Exception as e: 135 | print("\nException retrieving secret at get_secret_password !") 136 | print("\n" + str(e) + "\n") 137 | raise SystemExit 138 | 139 | 140 | ########################################################################## 141 | # Main 142 | ########################################################################## 143 | def main_process(): 144 | try: 145 | 146 | cmd = set_parser_arguments() 147 | if cmd is None: 148 | exit() 149 | config, signer = create_signer(cmd) 150 | 151 | print("\nRunning Secret Retrieval from Vault") 152 | print("Starts at " + get_current_date_time()) 153 | 154 | value_text = get_secret_password(config, signer, cmd.proxy, cmd.secret) 155 | 156 | if cmd.check: 157 | print("Secret Okay") 158 | else: 159 | print("Value=" + str(value_text)) 160 | 161 | except Exception as e: 162 | print("\nError at main_process !") 163 | print("\n" + str(e) + "\n") 164 | raise SystemExit 165 | 166 | 167 | ########################################################################## 168 | # Execute Main Process 169 | ########################################################################## 170 | main_process() 171 | --------------------------------------------------------------------------------