From 01b28aa717590fc18b6b711099d1fed6ab8ffd69 Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Tue, 18 Jul 2023 15:01:24 +0200 Subject: [PATCH 1/6] First custom-metrics-python-SDK asset release --- .../oci-monitoring/custom-metrics/README.md | 16 + .../LICENSE | 35 ++ .../README.md | 180 +++++++++++ ...cs-python-SDK-services-limit_solution1.png | Bin 0 -> 128853 bytes .../Scripts/postServiceLimitsMetricsIAM.py | 300 ++++++++++++++++++ 5 files changed, 531 insertions(+) create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/README.md create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/LICENSE create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Diagrams/custom-metrics-python-SDK-services-limit_solution1.png create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/README.md new file mode 100644 index 000000000..ea821fe4c --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/README.md @@ -0,0 +1,16 @@ + +# Custom Metrics + +In this section will bring some examples about how to create OCI Monitoring custom metric namespaces to extend the default, out-of-the-box, OCI Monitoring metrics for OCI resources. + +# Team Publications + +- [Using python SDK to create OCI Monitoring custom metric namespace: Services Limit monitoring example use case](./custom-metric-python-SDK-services-limit-monitoring/README.md) + +# License + +Copyright (c) 2023 Oracle and/or its affiliates. + +Licensed under the Universal Permissive License (UPL), Version 1.0. + +See [LICENSE](https://github.com/oracle-devrel/technology-engineering/blob/folder-structure/LICENSE) for more details. \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/LICENSE b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/LICENSE new file mode 100644 index 000000000..fe1109d44 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/LICENSE @@ -0,0 +1,35 @@ +Copyright (c) 2023 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md new file mode 100644 index 000000000..506d7dc9f --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md @@ -0,0 +1,180 @@ + +# Using python SDK to create OCI Monitoring custom metric namespace: Services Limit monitoring example use case + +## 1. INTRODUCTION +Describes how any user can create an OCI Monitoring ***custom metric namespace*** to being able to extend the default services metric namespaces. For that, we'll support on python SDK to create an script that can be run in an OCI VM (using instance principals authentication), or any other external system (using OCI IAM principals). To cover this educational example, we'll use as an example the creation of a custom metric namespace to monitor the OCI Services Limits usage. With this custom metric namespace, OCI alarms can be created and OCI Notification Service can be used to send the alarm information by different means to allow to create proactively a Service Limit Service Request to increase the limit before causing any disruption in the running services or services to be provisioned. + +## 2. SOLUTION +We can see the overall architecture in the following logical diagram: + +![Logical diagram](./files/Diagrams/custom-metrics-python-SDK-services-limit_solution1.png) + +The script will take care of gathering the OCI Services Limits information and post as a custom metric namespace. The metrics where to post the data will be: + +1. **used**: This is the amount of the Service Limit that it is being used +2. **max_limit**: This is the amount of the Service Limit that we can use (and increase with a SR) +3. **available**: This is the remaining amount of the Service Limit that we can use until get the max_limit + +Not all the Services Limits are equal as they depend of the scope they have (Global, Regional or Availability Domain). We'll introduce the characteristics of a Service Limit as **Dimensions** of the metric, so we can select the Service Limit, the limit name and the scope to filter the specific limit. Thus, we'll have as **Dimensions**: + +1. **service_name**: The name of the OCI Service that the Service Limit belongs to (e.g.: Compute) +2. **limit_name**: The name of the Service Limit (e.g.: bm-standard2-52-count) +3. **AD**: If the Service Limit has an AD availability, we can filter for the AD where we would like to filter the metric + +With this raw data, we could be able to build Alarm Definitions on the specific Services Limits that we would like to monitor, as usually customers do not use all the possible OCI services. + +Optionally, they could use any OCI Notification Service to being notified when the alarm fires receiving the notification message in any of the supported options. Some of them will enable the integration with 3rd party services. + +## 3. SCRIPT'S LOGIC + +Here we'll focus in reviewing the logic behind using the OCI Python SDK to get the objectives to monitor the Services Limits with OCI Monitoring. + +We use 3 different OCI services API calls to gather the needed information to create the custom metric namespace for the Services Limit monitoring, these are: + +1. [Identity and Access Management Service API](https://docs.oracle.com/en-us/iaas/api/#/en/identity/20160918/): To use the [ListAvailabilityDomains](https://docs.oracle.com/en-us/iaas/api/#/en/identity/20160918/AvailabilityDomain/ListAvailabilityDomains) API Call to get the list of the availability domains existing in the input tenancy. +2. [Monitoring API](https://docs.oracle.com/en-us/iaas/api/#/en/monitoring/20180401/): To use the [PostMetricData](https://docs.oracle.com/en-us/iaas/api/#/en/monitoring/20180401/MetricData/PostMetricData), to post the metrics information in the existing (or non yet existing) custom service metric namespace. If it doesn't exist yet, it just creates it so we don't need to explicitly create it before. +3. [Service Limits API](https://docs.oracle.com/en-us/iaas/api/#/en/limits/20181025/): To use the [ListLimitsDefinition](https://docs.oracle.com/en-us/iaas/api/#/en/limits/20181025/LimitDefinitionSummary/ListLimitDefinitions) to get the full list of Service Limits in a given compartment and the [GetResouceAvailability](https://docs.oracle.com/en-us/iaas/api/#/en/limits/20181025/ResourceAvailability/GetResourceAvailability), to gather the used and available limits depending in the scope (AD, regional, whole tenancy), of the known Service Limits from the previous list. + +Basically the **logic** is: + +```` +Start +Gather the IAM user connection details from OCI Config +Set compartment_ocid +Initialize the clients for the different API calls (IAM, Monitoring, Service Limits) +Gather the full list of Service Limits Definitions sorted by Service Limit name +For the list of Service Limit names + If the scope is Availability Domain + For every AD + Get the limits and usage for the Service Limit name within this AD + Post in the custom metric namespace the metric with the dimension of the Service Limit, name and AD with the resources used, available and the service limit maximum + For the non-AD Service Limit names (Global or Regional) + Get the limits and usage for the Service Limit name + Post in the custom metric namespace the metric with the dimension of the Service Limit and name with the resources used, available and the service limit maximum +End +```` + +## 4. GETTING STARTED + +To execute the script: + +1. Ensure that the requirements are met with your desired variant (using IAM user or Instance Principals) +2. Upload the script into your administration VM inside OCI (IAM user or Instance Principals), or outside OCI (IAM user only) +3. Edit the script and put your OCI tenancy root compartment OCID in the compartment_ocid variable +4. To execute the script: + * For the IAM User principals authentication method, execute: + ```` + $ python3 serviceLimitsMetricsIAM.py + ```` + * The script is available [here](./files/Scripts/postServiceLimitsMetricsIAM.py) + * For the Instance principal authentication method, execute: + ```` + $ python3 serviceLimitsMetricsIP.py + ```` + * The script is available **TBD** + + +## 5. REQUIREMENTS + +We have different requirements depending on the variant of this asset that we would use: + +1. **IAM User** + * An existing OCI IAM user with an API signing key + * An .oci/config profile for the tenancy, with the previous IAM user details + * A policy granting the user to: + * inspect resource-availability in tenancy + * inspect limits in tenancy + * use metrics in tenancy + +2. **Instance Principal** + * ***TBD*** + +3. ***Common requirements*** +The VM where to run the script must have installed python3 with the following required packages installed with pip: + * **oci** + +## 6. INPUT + +The required input is the ***compartment_ocid*** with the OCID of your tenancy root compartment. Replace the value of the variable at the beginning of the script. + +## 7. OUTPUT + +Every time the script is run, it will feed a custom metric namespace called "**limits_metrics**" in the tenancy's root compartment with the information of the Services Limits usage. + +You can check the custom metric extension from the OCI Metrics Explorer, where you will be able also to create an alarms from an specific metric query. + +## 8.KNOWN PROBLEMS + +None at this point. + +## 9.RELEASE NOTES + +There 2 scripts with same code except for the OCI authentication. Both scripts will be maintained in parallel with same versions: + +2023-07-18 (version 0.1). Initial public release. + + + + + + + + + + + + + + + + + + + + + +## Objectives + +* Overview of OCI Full Stack Disaster Recovery Service +* Gain knowledge on DR concepts and terminology and FSDR components +* Understand the different OCI interfaces available to manage FSDR service +* Explains how the service works +* Shows some typical use cases and supported OCI services OOB +* Shows how the provisioning operations can be done with the Console/OCI CLI +* Shows how the DR plan executions operations can be done with the Console/OCI CLI +* Provided OCI CLI Cheat Sheets + +## Pre-requirements + +* Basic knowledge of OCI Compute, Storage and DB Services +* Knowledge on Disaster Recovery practices are desired + +## Inputs + +N/A + +## Outputs + +[WorkshopFSDROperations_v0.2.pdf](./files/EXP#01o_WorkshopFSDROperations_v0.2.pdf) + +## Stakeholders + +* Architect teams +* Operation teams +* Development teams + +## Guidelines + +N/A + +# Release notes + +2023-07-12 (version 0.2). Initial public release. + +# License + +Copyright (c) 2023 Oracle and/or its affiliates. + +Licensed under the Universal Permissive License (UPL), Version 1.0. + +See [LICENSE](https://github.com/oracle-devrel/technology-engineering/blob/folder-structure/LICENSE) for more details. diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Diagrams/custom-metrics-python-SDK-services-limit_solution1.png b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Diagrams/custom-metrics-python-SDK-services-limit_solution1.png new file mode 100644 index 0000000000000000000000000000000000000000..a3162ede8eaf9d88e9da2f6c1ffca3a9a62f5702 GIT binary patch literal 128853 zcmY&=1CXT467FaRJGO1xc8_iD*t28Xwr$(?j&0kUa>rRW-ZBI6a*oO0j`tFQ@u>wL+gh8?I^ls+#hoqf>54r>-ek6sl zVz8_a2JWoj+Q3gX<7a9u*H>R&4o!1S;ZCIE%`}sBY8@^v&SUHi9ru%*4u246v4Ep| z#d49srm}fBL+1s#_ky*@kC{C+#wVU>2gVHUHN=*h2Ol(|v+O*JPmN#({u(n!Tc<_S z2h6LkjRFXenKm7T>eH;E5;Qx13IDWf&mt+2GY4Yb zwd9C4Of5c5ryM}_`QzNcx8BISdIVs=E}b+%TD8KOb_8E-hF4s2s{eOTJGn&qI139- zdsu$n(Lmf7pRqb<@K_Q)0coCQlUPW80fc|n*6FDjnVdCxZId#H6l&vYF-*YHpoWoF z_u7jcjcKkDhxS&@40*6^WKD#_0+Az28oEX1n)fJ&QvmCq%42Lw=EIW4SprMWAJq}A zgHf&3i2cxnB*B(-z8pD7!ZSfk@y|)91GRQYxMUZw%VMrL`z^mPa>d9#Q%8^=gHN%l z)40jKmt%qQp?6$>Zhypq4{&p!4->MnM|11}=!2D36$uk*fimAI8u~SiH}L8N0mS!cpV9 zA2k{InXV25mhjl;U(rqUadd7;%XsCP7DzbJJ@% zi}zbsfU+;;BCIm+{BIvsfbGXMEOeFOEZO`P%ci=>^ zF%7~M2&)yM(UgMO9)88rGn3!tzP0AH?G4 zhj`M;Yj65LW#Te5wR#$xwdy46*A5lTrHC_-j$s1l!%gD|ul{2Cv4lW(%1oEFbLVI2 zOvl4Y&I-MzWQ=Ikt27vT-=P zT!t~`-jhbLaofycD&L6<2!R;ziHrY=P_jALY#3zPM!*8W70@1x!F@rAWnn|~?{TBr z;bduU5T-zmSz&lhq(5j19!j|P>@D&@am^P2-Z&66PVGF=;H17_jh-do8ifHyi%4&BIl1h7HQ7;)(-5gBctE zym?BhrHJwBGq)KBc;jg~_u8&;9BsjZ)oOrWG0%d-;NR^EdwT-#3sv7s=Lwnxc+4U8 z$|`#(ZQcaKtNy5?{Xn3ky~7?t%n=z#7O7Kn!X2wHT%sP2f_2TkDAm*Njk1Q9sHjhP zLjr||#w%Fq1+MBauJPW7z(gCnDy%=LG}%O1)BQ=p1Im;wQG5Xd>5lf&RM&QEgqC5w z*9L3{VJ^olXhj%EZ-7)9Bc{Iq)QMGV3!{z}O$u&hFk;Db!i?PK8}~EFvn*DwK2N_F z>PMfLApgLpFJ^S^r6v-PE3iPQ=^t24itg!p|7Kdm#vles1ZOMuz;_6%;oCf9n><61X?6 z*dEOVVcZi@-p9XY34ehqXTe{btP5tR05rzM8O$0LtBvy#w{2yvV(~+&TwOBF#xtYj zgqJroaRl^OjN9cfC|Xeznt?x9q#Ij&`HirE*BL+->#Ptdgc~U@6Up{g6%z|+GLq^= zsI>fCgg6NCCC%)xoO{LHqEoH$9usp0HX7b2r^w3;XSUt<#5UV(LX>JZJgS?jf8!jOtY39 z<$~+IpSj&@JO9Tc|M2C2Ihp>Jq{vv^OfXF&IsO`Ib0z-e#CGNg_zm`S>!o;x9ARe<$=sgA83exl*?W(X{pj2J ze4oWpurxvP`B8%$(%rr-5%G-;vxckJ_tw{i#-Fl+td4*USn|{$}HZW4lgk74EFw4J;xPli9G2)^L&!OZe zX})(gKnks3TmW*|H^B49GA#=3rkhHouO${?si^-p3MeQ7Wh~Wi zh*(_FTwfJVA7Xe9lvH&xC6c6OqLh=`GTtyU2@|x|hH5~p00OE4!PWD&5Lv4!M3{QQ z@5VTIBxProu$Hxb_OPEm_t~J7W_oionW$zsMNrsWrv6juzODK(gdT}GgPKV_K~@Po zMyq0Bpv~{j%g&htB2EZ?G*5WDBxEG|R)%*N`i+Hun;U z(GssK+3=!*rWmQ~{<5|G+Pkosg00FK_YCBp<_I8gj=zPy{8I06xrtdi>UoFExji9a(I%g2*E2I`v*N)FfpQ3%&P^Q5l z$`*3b*7?rC0-G?L6NXAt<|uNYDDDV6@vAnmQao}tuNGL0lC9R840j7`FRk!UPz#~U z5HScKFJ2z;2!iH@W*{HH{ThztvXyb*=sq5Tki$!&f`a1EzD+g(;@TX<8%S$!ri;=R zaJtd^*dmpV1MfL$72*{RXolW+7a!VUvL z0l5?Hq5m3Z0>r;>5DD_SAK@!pE=y%RAN-cL+-`P`0mlNwGyDjx2fLRI?|Hpx(T4aC z^Iu^m1OgyKW$@)S;6wv%!4lj_7QviDniFYWjGLLR2hE~}DfppCCvf|I0vaWD6a@Oe z?)uG#C#x5x2lM2$xMKe8QXhy=0QMjsIT-!p)GsQfKs_A*o7=u9dWs98#@FcGi5#jM zW)61TpLRkaO-&K<$QCGp;voWH_99KifJ%5f4W|FCO+bX-z87}()jG-Q^RfOizw9CS zIIQb}^#oDQH6;uO%)!?i=rmB2)$yMt&i%f=am>KPU|~^zO|4IWW>w3|5zlNRv|hyF zMr8Va-3L$e504gy=>I@{e$INlqsqfPsqUYPTzrSRUndl{ChtL-Szmqu;Gj zto;0JMhzShB;uFh8(%ABNC+9n<@u)u^RIkM@NiP5CrR_W7zN$t$KycZZa%YDh4?Ls zx+0&!GZ{*|IS5C-Ljnuf_R{|t;l0E_wj~c_j7W>yH?8 zN)qBUU8tg^wVjZvN~u_oqTP0*1v#-kS$3B)T~Rd^Z|&EN&Q2wKHHaAckiL*A^F@vS z-_imK8Q?{p#^G3QxVpUkdJo}kIhU`YbwEpyFtX_6K^JwVBnA=C_hG;Uim&usbX{5= z9@_Cd)9J>-M+z$tY5up1ZF3 zVJc1I;|$?4D0BGt3)K1l#J{3@cV5q)VSKOnzy6ONK`$wA-A?vZ%HN2!nKX`ANNxA! zb~_|UPl#eyL+y!%6HB`~gAT)&VRg}2OZxW1$wL=yMi(!=qCEVSZXv~ChY@1mA2=?C zi!bgdg_RxsB>4$Nbn^tZwyq-8FDpe%-h<n}ccy?_nfke~6;Jq>5oyTMbLzA8cJD z=iN-haj!h{cCPNKYFq+*QG3ryITbHVxHQn`YX@(DJtmx;8p3Rds4wbk94j$Y@6QsXH^E2QtWH?YCjwMhq!&{*JE7lu89MKJZtkg99`~B_ zZ)`wZGd_rw)M#+);At}|d#25a#OIWr z;=fg=q&!>a9Ejcr^j;^>%o)FGzT)}KajF4~_R6UC(oMU`PtQ<2NEErQ_mR?S_e!^st8bkBZsutEawZ6x)b$U0Du+iD@E~`OgEgS0%RqtcMKz>WEdIub`Rkww1<@iZ)9d?=a4&0m`ray@$8Uf!)7@IRi_uU!t^LZN z-Q6Iy?TE+Gag#A2ZzoIh=#3x)QMt7}p=1r5T z{qdo%(KJkwJO7*WwuH{3H3(O;Uo;S_;tBJa_o_gRnNBw^0)zi9yhfjXQr4ITbS!&R zXllK)S{4q!XKNzb-zkt1#_V|X?W&}>-BK&bR&B#@5y?vZQYv{(JI44~5sR4g8GaU! zw{TxdnYtsZPWD-Kj8_aD6-s8Z$Yk6O%bi~}>~$v|ugD;MO%sK#M zrz&N)Ra(kv@@7ylX|wU(ZRjkv+pMbH@r+27>9DqmG6b>H|sgi{{Ta^s5 z^TBRsO&!a7L)`{yJ%`uR$oKf7S z$ccEr|4iW+2d~0CXJX*l zDJNQ|y5PoeYktXUoae8}(GGB4EIzEUwMvSa#3n_Z&4$%pVkJMQsj*GYD-vaDAtGY$ ziF)D+MHv#+tUl!ax;X#(oDcbYyZh65@o*;3U)$v`v(3VQ_Iu7GrA>P5tF_Ei4^2H2wLO!t|RYyP(r|88P*TL7ZVp~SZ00r8iC z(OjBh!?RXDoa^WYJoUQO^h4BcxT!A9VvILb)58Nqa213p$%w9~Bor!tv2%cLR1 zwi=UWIDCglRB2hnGji6gcbV7YTQ~*->`$5HRN4D<@x;f8hvNyUd4d4G3FI{`UBFc7 z5TTzHJMT z)E22??<^S3!#4`?r0{05yEG4xoUZ|iCNFH^f|$OI2CTuCJv=PFbUC!?Zclh=Vq`ht zF3-BAt-E~^;PA*vbCUVRag|Kt`d?6 zmq%X=ZYY}%slSp=Be`+JP^o^jcRBN zMxTjPZKj9LZEmNkFRt(-C=v^kQfyM@Bs9ka(XcY+b%^AVZ;2ev;2&(37DfjfWgNGf zvAc>Xm1DMs6&mR@p3_b2B|&Nv@|0#EO) zQMnxZRMgmHsu8#rgze9 zg-dO!onZ%m&L@t&wUDqF@zXPV{OB7g1v8Srl$dDmtF6p300dTMX5WG?g;k zWxb|RaHxT=kU{2ByEqhHqO`^ptT8r$TV$jiVC5~rd))~Dk?xm35)G^IsTbA>o@L`v zOt038aMN}HXq%%erK&lnwW}>M)=sh5{Kz&#HjGxfJ>?HT2ChbhoTY#2)A$IeUnoXQ zwSEmCj08DK!iVc%$d|{w9rrMWO9}ri5LdRQ{sfn8Pht^4q<}twLne$6l8);4sacV` z{fFhl&umy>U`Zed|0FJ^ziy5Yf(Jy5CymC62nmJ(1&cKb)_yXo#g`)pC2wzZBdPmw zmHc;0c5JbcP#SEyx)sS+6Z1~R5fD1Ve62>>JS8nuBhlxb1Qo=jC4L-{Sq9JTl#-#+ zQ~$L5OEiqfbxtB$&@xX0Z*YyrY03;+C92P;x>>4NSdV>ut0i7wnjqE$NeQQ<5VEj; zk@Tp(EV`Cg3z+_ui8`m8f7JLVVVQM}Kg@Gtm=+M3;Y)nA4mGQskCwT^d(!+J{iWT8 zhHm`2?kFrwF0*+2APXlT*C-|iXX=2LjKzgoqHbl-0ICm~AV{R{GwB?4N#%Hp zLKWR1`vfM?C@fth9wnKQ>yif{m8j_Uj)7H}lt7+XYo6>gjb|8#M4(RPOLcjEkyZMtS0C=@@aIId~>Q$7u*9Qk=aj@9Dwy~xnlNkGS7O~&?P z6T0~6TWH^>q-huYm?AcxWxQYw!b`ubGW0Db5)=iK)Abnc-7$Ofs5m_SYEhb=j)UUo zJC}qqfG(9$I(Sc)RN1Zxx!C-*Y9pj;vnl&?L8QDS^z;T44Oso87)j%qmR_LqxRU}W z*&&8sF}S}GzH0{L>cSYo(Z*$QVH7ta$5Ki1FB6rQ)-TA|L1mn;qzzBP4IyiJgZl^% z1j+%uLLvu6nNlA!7(&^4!3i^fdE`P^GXDafJO=~?`6VA7t?BypL^6wOHr?DJUNi}X zq|{PA=HB(-(J>;$z(ALzsaxK;(^Ol23O5p*Tq$EjjnBqg*`r1(usaft9S4hPi#vbE zhD(Ub=g&v*37~a;8Py00{A15cPWM%}c)GjI=RY~QQ0+Q#Qzs8klt@EvG7Ca(LUUu2 z$OSZ-@6cQ467aPpQ&(0<#;4##cJ#l zEGOs|`I-`m;W&)teZ9OrZO>CM<~h!`-j+m**b5K5pvb_>0OPq!{N3t^aQN)N-A~V5 z|F+*OaT&{VPA6U+@k0joHC68Hwxb@rW^J~i&OYqNuSRFf)XQ5io9|N}RYs#78Rtj} z06xzd7D@%~p~9FW-)zIkM?YQ|X%5UhN`3qD@p3*+pNM6%;?$vZ zE!Jtz5>i_Qvq}5(;YYjE?Ena14m$g2Twbo{y=2#Z3Xs~((-Gk{ErHw% zVD;Svk~zf~xmns7X`Q%|w0zEO+Ej6stXfjo1ObeDCxMEFY+N!EN9m4%tj(O01VFo- zSje}R4FZYbOqFoVSzL?L5kGpwf*2HZ?N+MHMLgYEr|s=_t`k4jn+BABBMt3=m(g87 z4mrr+Q}n(ysTQHl-G_TX!ADGO@&wG9C=2 z)y>lV7oMZ!S&wzP)TE0k~E0Z%tDq(j3GGtb3RkT z=uLpO=M<5i%SoX`O=5%z7F#onK!#OAHeM7u;%SNJBTM#Li98RM*p4dQv-wq`Kka&j z=HqnKuI(dN7X+?zqg_yqK3+{Zj?{(rD?O!Ap$>@xksl?MJV> zL7+B)nfEH((%B|c3`?B=KaEf2G5~gSJYAFW#b=TULpzl=alB_6F)am8Qawo>=TeXU z#`{;hD^y@R9}$BA5<~S>pweOdZ|5p!2VBn3aUt(kUL0Cc-GvO#4On(d^#AI@5} zD)m8zUjTT?j>px~sCMl4LQyL7Kh2`$|6~?G3!m&1Fx%}|4KV9HR4cvBcODUP?6!sh z`Omy7nzyC8wA+<{M{2UA>$t!vcdEEw zs$Ji6?@JUwvbz8lFFkABmE0Evq@Bx6s!>p2n$ZUvLH7Y9+B;&z)!epqe>QG@x`O7`=P@KF+sWO9v`O|Q>%zt?5&!)~_2p_& zZ6q*mprb=nXS!G9I;v%P#KE>&8ICHN(<(T!42vjFU)~cVype|aI16@nYqe3vrga}r zLWuZp8+^Cgn55)^R8Oab_v1?iiT}-GLJl2;4DLxUK`z%Apqv_3G{!;j+CEikzpzcr z@oJzy$b^%g%12f;X8&?8IKEA-(L&RizFT$jk}}IDX~rBRY$DpD=3-AaGq?e)y5v9~ zldYOlw7-^pm0C6RUUV|n6l<9fuhLd@FOE6O>TSmvG6Z=6NP~dE5oFfbvv;-MV4RbA z^y)apDOuL#xHYw*@L*c!e*A}Gr)>RhsEGV7d<&C82`_$CTljqS2J0@wK~-YEmz zp3`ZS1w>?L&tr>|R+;TUVR)+fF3yOGR4-eNa9&F0<;CILNJOJfo6n_C1XPvUOhVc; zrpO*NL{u;*(97CA@2HWsg?63n+``~4X#dZ6aVjytx@O6%hAvp~p#yRg_f+S8e_D*& zv3tjIu~(O<>^A!jg0JWgnzy@RLR9tsr4k?dUC#Q=6`T}tJzXOBo>mbd;GSnMKDURY zWm11PRb+A4lr|-@vBuj1={61tNdvEFWG0onV#0(^;PM4ys}4MK!_s-3Tr~fHR^t5juP&v zKrA9J4w;Y1#n4FUDk6^bdA`icGiy0}w3!=>u&&#IkJ1rhy~4fM%sT5o13S0fzj3?~ zNRkS6+I#dAYj&A!fF`zlD~x~)4IO)Bkx*f6r2B3S=lL9?1G?PeYC zk2^69hH{XI+vXp+q5)Zx7iJr+=5Fh&TlnTgiyjvbS)j1M%Y}H*biZ-Dm! z1UU6kP?&P9u?BtRR11z5>}vg0`>(N~2@PAsK+2i~0%f{p0mf5RSxP~9_+kEl*hO9# zRb!y2w-g_PM<7qFd&x#mH!vEo^?i{vj1hO#WCXssYnhzb3`-nUqpD*oaE$Lchx+@P z^*sD_(;%k{JY(hM!+SrC0;W4flB<)wQXn|q@)7PF9Ns9c2DjsRio#$EpJ`TT$2Y8ciPev{|J~*EH9Qov{U+5XV1aJzD;$vq(TTw!on2(R@(^XeNzvw+OX<6k9@Ay z`Ru5dR~DwMM_9Jcd4MR7MOnZQmFTW}s}Dy>nMAMi=)Kx#ox*d|Kb{Kuw>^{Nnt{{i z5oW@CjnakZC2}I0Ly*sFmx$7DDV)rcn%yeiNoz-tCM~wuwKEBTD1a?X)@qXIzQY(2 z4oA`WFMbak)w?6$EArDzyebY0XR%5O3QYHXZzycGrRF&s6%sGvhr1L^tK5;ill2-3 z1oAQ}v_%MtgraOGag6At+m^5Y@^J|=y+}Y2>xNZ3`z(GG875PEGs2i3i7Hi;>Ik3hCYyY}aOKehcfGra_5==@MgR^gGzOJ3fck*jEs zG77rOqfP8_N>!q`t}E`Iue30u<9wZKhAQxy|$J z>)N1HRmm45vCEwLe?H+LphBN<}`o(1dS$0A)v>M zV>~JN3(kh|Of_rVaiDFcP{ZzC0^*~Wzw+{ImTi-@y(Y4+ersKyZGI2FYd~hZ2=N5T z525oy26s75z{yQ`>j&LboBpfO>Lx}4f%Mz|lenPoXE=>?J3bHT5-D#gWNI=ZU+U>` ziPvy{`HCBR*CQ+@@g6*?*W4ZVo{?geAdF}M7rAVeUnl5LVe5*!0FBkD$OSyCWwYmg z-j}yr0eWH0BW}px82vCffpPcz}(0+bLn6hSTsWy0XH*XS6FmYD0n<8(Q zTFCPM$Rl*%$~@2x$d*a8_ZiyosW!3PVaN@izy6!WhTgQuF+QMch39^kt@#o6G#FAlLRu=^+40g!9&ZSU0AQv zC~f2G0$SaXon*L=qoSK1{PKV@X>@zP~up55{v{_LOq zCkT|qgq}mR$&SsVQZ2Ox1wz7itvrmruKGw^=DJ^W)9g|~d4$Flc@sojmBAnQm-{xu zwI3#1pm1bIJL zWptsgz{o{7Cu9FgY3pI~Unc3B{j5Rk4JoZP=6H3YbUgY-v_pY#_hG6=@|5iPnWorOmPRS>WH- zx2&_qtzmP$uH_2#I_`?w<~S(^!Z>8&s9h`t9k_!U#uTeOk^y_g{JTfKZ!~VO9Uio< ze(x08EW)T>L806rgrb8r%X3*gmpN`yRN{99s5hk3*13&fP(<=0lKQBqb>;|mzAQ10 zl`mY5S&_5eUsXzH*N_-+#Q@aj4-2T}dS$B!|He|uUX|030O>$W(X z8LgTYl1n0>kJ|fcnmwgux2i)`RF%9JD+#sh{}F6o#6Wt&&AV9E_)(uZ##zEqy?%l~ zVCHoIq%ga4_WUsAp0b}=aRE_4O9B2JVf|z;uesKDerK)fG&V!QGK$+9kry3v--c4v zBI}&*Hn+>NByy%)XOpvz)GUlfgHy&uxoxZ?7qz3+?No8q9Ex122d0^aOco2d;@kp` zuo#R+olSv=khbDr>?C)^kO&qZhm*mYda>+32XqHi7!&U5E$XAODR7h28Y5xP4Q( zl>DO>(o~j1UyQGE&r|;Ys?l!(gb{-w=K)raZks=TBblfYCA<-s1g+F$U2#)JS>0$qfdJ^``3e2EoM+0I` zLmVE*Y;FHr|JQQaw*eRRJ?XAs*=>#)gx`ZVZ#1nLGyhmR|KZC6e1Sp}VRO9F0k~in zPVrcNTLigb%C_?JPcQ&5{RMQ$*YB$$HmL%-=-(!Az+iLc!*#R;dTlOzVEXeK3y?T0 zU@UQ5W;5r3Z`dF#mjgJIRdHvws0H^0|F!^!0x65M#)vKpTOcU2)tL~+|AzYDKDZW0 zPl&;G%%`uPGCujjWySwf`&-}r@Caik+l%*2T3d7f;ktJa1O$-FgmdE^(cob~s&|8h zfD1N|kk3v>&zYY*k)k?c@JtMBWJ-@|$J(qe(BoC#gRbz> z*{DYBoon0uJp_!+I)IM-$G0?VqBmmp%yK#CMU8(B{} zhndDJn!(5H;_yT=2gji2{E~d%tgf>DR+^bfarA0($kgwtdVgyKlnGbm|ISxfkUEj% zbMaGejqTnt!&yiQFxAU75>ir8CZ`pOTdib$Z>5%zRLB-5wWi9dt)D`NBOI8EhrF+T zmq=J%zYvJzaTY`@5L7$p>i>Ns$1~)h5?fdz-X!<4N}dCQFTw~%b7XaSY}0zPl#Xyg z>kPxC3iFRWqtxQg;~S0of?`1?4bvJkGomIn*N36LK%hSq;Vf}j(yZ0v<^Rg#6&^(9 z)@p6V629i^K;>A3_;)EmZyXf5iF=u&CK_ETH8B#g*rsM%^Wj-`Q2%1#H}% zm{h9j(`#LqNsBFg_v4!7r`@a>g_b7PTD^(Pt(I-4W}U}d@}46RrgSlKAIjscNI;TV zq*j^HoD3;)nj@8Q#5oWhwPAQhpSt{*Q&!-9I#f=Egb^(_S`7OzT21K@h?_@Ak(X8` zDAsy3E_ZmPWBbC*izI+zkRgAgqZm6lW|(13e}o|_H)05+4xS_WoE>H$WD;q(4hIwk z-yghW4F{{rFr7?VS_iwtx)n_hyE;SFV_0HOo0$*8&KEx8cg5^62W&LGN{_)%@Fp}m z-NhP4QrHE#ASQ92K!y1DNBqy<2`pmlOd4uY_Jzz-cs*{qI>RrKmy*q-G^!owHk~=} zxPnIz=+70r;BsKaVFu|dzqd>=_d@nzZ1^VL@{yzDdlL!RXt*k)+xRhxBOAG8i*Wlq zfg}oXa13805>t-VomEtKe1j+*=rID-jKyAd5J=R>E(Qdp!iADWW`rUJ_@H*51mbD7 zBz3uW-!kc)41~3D-pQh$Yxod!GxQDRtw9A!n|+;sXJc0Sq7CQBO>CWS%RoadLyl9A{CN%_y)zT9* z!pN;9@@X4n8fY7~)O{-1mymO`mN3VMO_N*iqsp>1_-bgUDRPwf8~1?Uj~d3=qMI%? zA9<#%ML`=UpGult8Sdf%xqmx?b%oFLeQV|~n8AW0X_J4m5UfVhu5VXev+440S$eXo zMo}lNT{24SeXKqC!3`X?V6O-0Y>OAgdi zWhMjDO9K&2I5{S7RLpLOXa8Ldmlr5iyApTO>v%?K!_2YfV&mHLlON&Q8!;4*#9%dXY^7jY zy3r`OWyDPyH3}|D7@ZU0QQg3aKpn!u_V@W(gpUk<)ik%UKpH>c`09o-z ziViF)tWv>c+aIMzzRNQZc0N;cFCtQSRHeP^1 z`RpDdpRWhCSsJ=<1SX%xTYq%&DZ26mrSX;udQ|P>H+RgHfOd5Bg=%;B&>02wvbc0OwgZS-t=AEklxHfoY6{ zxrsCdEVLTe))|J#;{AbHnUyMTXfu2_(FG+?7A54NCm`M+;(>c1jpVI~(`NE=)~8)y zoHt=MBsLbG729iLIs)kbye(1Ty3jU3C6jPu3xoA(*b)}}69fB(Fb4%*`{Hm~_pUpP zZ;fG2h&{vrT>TvUasj!tyLv7 z9MJ)|f@btA8H!kMRWoA&I4%-L@C*8#2{lqm|Gj`cDl9QQ6~A|wnEf!~0(Oq^l3woN zs)5%XCcz)io(7%c?Bk7&0E~(lcqr~|eAm1KaEBW>g=xHX^DE8+KG;fEzAv0@)-yb8 zr!m6?%V@ySS?uB8v*;Mib-ZDlhPbwDEMCsl?IGalaOd>e_&FIiIZ#FYIbLx>?{}D!@Hj@1+Xj-vnqC&IC^L7 z*A+W@>BzL_RZm%4RkEjBSbD)aHFdixCD3EWgv6gJlO#xr2&x9>J3zpOCl zlX&v!F+*xMOdrR*fcWVY8^3RT{6$r*c-qbL3HCdRqhu{PsUt0T;v)_NBbI*Fe-G!1(*-IYc09-0j-~ z@E&Zjm>h^hQs%F$+r?G~ z-LntA_QRm9t;Y_{M*163#q;9_Jf6YB@CwdPWN(12mNvCz^WZ^ifyoGE2`-&zTpSil2}O{ zCnaMOX(1-APdt$GXToSCi!oEYu{e4bm~8t47go6X?NETMEdeA5+FuDw?#h#ydSvXM zc@AN)7bw`^O#K&D;PTVfhja`P9|U-{5(Ew&19$uEOuk*0uQTS2Gj?owP^_fq2Gdi#TcTFjwlsR=+g-+4+D@P9nEaJH z%f^<~me}+5o4DAB*sD5Fi#&6x3d*+02EJoT7zDl;0fNO~c(Ni>Pq0&y|{x}*F#=&Hl*?6ZC1z862iL0xn7Y$$`M-K|B3zAdbcC% zptwormfP3F?+J#R#uF|SIL8u6vxyvWpm@vjlYmQzz>)x_vH?fpzWR8IF|!@r?$*0| zofEQ`#lD8E;7}{h!-ms-^7R+)(HWgui04%2HY~vgC4wZX*dl&+SLqWBgiY&lakdIf zc`aWTm%y$)C_DvuwylaR8b-e@3P`hOg}sM?umWxc8jOE^(kI|T1JRg`+5 z{;?@iI-Os;xl4yy^iYtp8nQsoRB|y;akbU6g^TQzs=C)9@ErL_MZ(ZY$R9B$GFyYP zgPnCWl=AS*1uLM0H6z1a*O}++mIa*smd}XZN{*3XCM|v+E`v_1+@+!~FRUPBH!CQv z8D#LyKJ9RzBAfRso?48K=lFffhI&B4N*TnQ@=H!)qrKI#{T` z3ONrgTuXv{`Js$YXs0#ERDId!I(@#{`)jqQ>$EzAZ&Q4BtWpE1cewdue$n`00q^~N z3ASGU^Vi*IMYL*G3?1mxJ@mz(eFX*m)iLKKk4L!nUf02}fFLSaqW!rf(urfdd|d%1 z1e9cPE~Uk4gK(8t-s&ir-=0=<7Jqziyg_vI@o$5Y@W4^xP{dfj4?%=3rh`x-?qHn6 zkxSIJJzLaJAFZuXPr-^Qi)hc|MoU^OcKUwZi{r^O65E~@{yUjem(|W zMRxvL(J9Vz4h`3SoNMKri&eo#t~Lg;(*%w;qIllX*jKYh(Z;MlyNHj!R1ULr@h`|7 zK#5McnqVStFrPx{&M8}V>-y}XZ|n#vo|sIRTpRD(?#8z_C}X;{X-)BzRDK&VIGNzf zA(#0h&I7+ugIMZr5;kcW+OPE2F?k|UipaV~Ut8mYqvD!%=Xv@*QVr3gO9S6}4eSq3 z<4im31k}3?*`&Q>&(?orabfZnD2|DXk-{BH$^{0Hby%Dqj+`nPtCMagS#RttAACt{!I@f~dWqDcM4RA3qvw&jx;pz#UP?B<$47D#l7IcjIn2U;50oT-nm|GmW zp0{v1fjFdnO!uU*x=rDP_tiLBZ~%JEt6<}C2KzGcV}J{OVRUs7J7e%6b@e~^?BR3s^ZZz6ABS?FP8@Y4Z0Tn~IQppPCksW1?}RHr zJV6F?uC|OdNxfCr?bwadQRJc_vP`*%B{@n_e9H{dZ~>KmW+)IdFKMoQ z_V&|6M=ikyg%c@?&c@H9Z5Zs&aLZ!*5U?bnT-v$)JkW)Sk`^0vQ#YIH6S@SF=@oIVoQZAWGozX2|JU0tW6;^ z$LV<@?CwKOCyaAkBaO>BaV`@zKK6{We_kk>3(Y>{pOuAxoJeo!eL8E1kP}jU4FvSn z_cT&~34ekF5o2Y$0sLAnp7e37-Q0#uG&+jJCQ-kG#;JxUF+*l&vZu{YX&T^pS~Q!l zZ34^2lrgzGWmL8`R=Tn(%*~R&8SG>Q;RxfcMujTD)5yJRcv=$16JO;UdzRHatRsiCpgxor!FdB^i`$JNiI%3I%1OUjXA=)_(xgU`TS>-dHL7$ zdhGKuVL)ck?|uT-!kxH{KOYp{L<-q1&0^1OJ#-JLa{zYv&ja+`0d0Wfhd_Xn^Y*c~ zcMlG~OQyD`<}U|(Znki~Ij!TweHj6N{CZ>tUV2>SC9{|B5vW4{hU1TaV~MXhFq-2;HZIZ`Pt8Uc+! zA0vQi&$12+^3Iz&QK~A+W$UgQ*|c+)+>Zg`M_zheX{$bQ{+aT-yZ$59^$qgL_nj>l zo^*UcxyacvneNWI>T321HIXU^HXZ0-BTzB43bwP^k$shqaKIW8fuF!avaS(c{NOpOG#bK-$sIe>+B@r1hq*xkaN!eQ6Ak)WHDb;)X``+2K8|E~- zWa6lDmA_#XIVT#s>zifs&U)mvSVp3JoypycSIGNMISg*2b6UKAJ^E&6!IWmMJ(lg$ zErA!W+J-plpj4PP%?Ap_kS^-q*;ow{;zv0u)V-Z%HHmugjZ;Jli$d+f`b&BwWWQFTj=V1s;QC;;V;A*RoLJO#7}sMdR092sNU@Vn z;o3KwcQz<(&*U*f)H%Kwess%XS-fPO`dv{HmjCyGW92>bCdkLXf0xXjG+dUi-62On z(?k=tH{RJMzxe#Qav08EbK|3M@4j1p`q^{jD>po(UNYak`gA#J))@Ke-=C4kUsxo(aG6JPaQi%zV(UIWN3N!RrT(D(rure;X!fyXCqsE|UMb z{y|y2q0I*S7oT5*@^y5W5CeYqKf78!c={ZreOtC>hl6f>aFsz^A^Zo{M!v&L*(-fEJB_Mxaj-z_LKFC<)4a&%T6}oUrh1CM{FOjFR`C ze4HE&x91U%tXY%BNeRsR=xk!{$Px4A6;PDIf;{-}!?JzH4msnr(`3x((S_aA5~`-QR$hMP6&X2Vgd9G1 zZtJ~C*j)bO)?2ZdU_d^6>7}jbyF2LZealy@kWHI6%aqBJ)s~;mGF;n?YtyDql}QsP z=3naZ@v7CU<%O4CQgNMdT>tY3+f;7D=SHSd+`Fe5LCV6G$W)-)0-?Xtq<>FIk%dL;)%6H+yS@Qgw8x@Hv+M`OS}?)*)SL^C%=y zM}v4CF?}R7WU;+s$c0t^^~jshMET^~pFCX}n^SnP_b)>ME_m7#A{BxSdPBT#G*V`u zSgew<;-nkJZrrT!)qgYs{S|>UmRI1nqELZHu?*DueKV=G&_s1Ojlcj$fQyW8-nm<* zj~^p*CQVR-vvfAWZyCMfjvZd5tY0{2d&Klf3JqGrtlhF5>kPsbSvT4#?+LGNZi;!w z2NcpTe)X$z+%d<<2j2HS*|K%3eD#`Zu&8F6Cl6-kfq(y7t?$qm86!zs34%a!)>9%y za(BaxH_AyTp122*N~hEE=o3%$m`HVYUp^jPm3Q$o&&Y$1JR;-9j+NhDcbzh)Vpzua z!=L;_>On@Yxa_iSiBxxKvAir7%@g_~k@EZfuCLMz$_CkIB84G}AwAJZVWDHSkY`tQ zbTH0ed(~<3>>KOl-ltc}ThOGCOwcJt40C@dt6}a&Z52D`J8EKTP7u$Bpx_5!O!x$LZYO0)DE5K%hrU|Q7HdE%9?J(eUs?bCf81eU_N zTGYx>@-=u}VK{BvP-U9<-J73;x35t>nlGjj+0TFIN;-?hdJC0sI3hc+e#bruE5{d= zWsPO{PQ+vul&xa|5pgr|eTr7!tP$9s2yo$Nzprp!bNxm0~~?5 zBPPnan(gxPvbWLIYv04@qVNbt0yT5^c=3U3#oz6E;9QZXhnB9Xx#%P;Q{Igv5(%jV z$)QGO!^Vw@sZE?PVUN{+w{71p)w_4g$l=3f=+L39F_PV_TfZK*@(D!%ii?Zo-8E}u z_1kaDgz@8L=dNAy)YDHZ61DK8ljQvuT%f`(U%9fCC}c7jrHMfYTE>nU(;D~IZQG=> zqCzps#-=7!c-yvR)X0(Q-n#mFX>M+o(vlMS_?1_x`-W8JI$Qj~w0G>>DOJet@L|K$ zJxz#b+PeXRC5W zBDoGV&3Kwb%NkplI>#T0Qw7K`bnToQ2W?~_*i#bC7#Tm^}x9E z>nA_1{9_AbhU;VJpX=>0I`I{e9+>v|G0K>NbAY7IpXb{2zcj@oH<$%G@1`~ zru}Ij-`;+kc!{aSGSQjlo3T&lOW~TBbD`SH z33JEGm|>;L=>_MR(X1|?NO|S!49oWEdU12^SZCtJ)gHqifA(y7;JH;w^Y!c-8!+*; zS(z|)7RSLj2kot7X;@yMgrSj2CilTH3+mstpcPD%$+K&!W#0IqG6IW7o5>jFNe+A> zMJ+4`IL__IUJPbv>7NMDY9W6Bs=Hjmtl5SarT(+Bbaxrn z*EIr%00JaIU?jcDX?l$#Y1#XnV2?au=>pTuf~au8)2?Lcn{UeZKp5u1tc}N%nbW7s zPk!(NMGSuOi(d$}C7yiX!VBeNS6m@0SFMuo{P2g;2qHl#FE5w>y83GQ0kkKShoD_~ z`<-`M2?0&-NPG^PHA`mA%zY$C(7yHE@2XBY@1a@S|9$OiGGxdQx%xAok;4#f1=3;O zGU$-M`PN(VQ{;>HUyJ+JtXn5P#Qy8w{HE$)T?@_Ek@M%vFQCzRV)0@|spOBp`<)_p zzy9rSB?S!+?J7?@^;G%nr$6ll>9BwFvB%`kfBPG}jRoZH+i#cO|LISPB-&uJJ5UzN zX{Vf`upwEf0wMY(%KkXCJ>Gp^{^A!q;PHze|5$10h>a&d1&;Z0+Z}f(+(;bnyyu?$ zOX~PZl&yVP=0h9T9{U@9`O6MCQnN)OcN-~{ ztWp`}$0sh+d0qA@y?%Dn8a&rO!(2p41ZKB1&!vE)?M}UiZ2K@O0Wa=(-@JXURa{1*-8?hZ)hp8Y! zH0QhhuDj&KRCXyQl0arMVPF2^2ywA}oczbF#*h0lIgk+z?M z06qQevnnm-m7Q{GNREY>U<4m-5~=52ctL44-US(;DIYuiXPth!GK=Fqyq_eBCUVRh zJNeXh{TgJ7dHJ6&d_g#;ibU_?_rIUFbSf4|QN-jW%(Hq8CWiUli4WGGL(DC($}R9?izPN zv&J-EU%FHUq4ub=vXIoZ$KH!GAIA~UDw23o7}s^b`Hj*Vk>pS#NR8V+Z@aBS-Fk85 z?^zBKUlLl*CwmMel6m<3%{R;QFTSXV6z6_X<{f@`{;gdf8)ByYzQTKSUB?6sqLhRK zZKi8`392q}b!;bH_^5n$@$Kt%cCzSg@70xCR8(cqB%OBDWV!6j!cE}pFLe$()TXWyDE8*zjRkbqsmrr64n<9l}u4))kiR)AbxgczMo`Y;PE@ zg4raAABEbnkHSese-aCW2yANw3A9O}&_1|7w<5ARTPe@H17bdHI5d%#-23KcDMFkJ zCt{u(+k_bq!xvK8N;eB)<-nBH?UUC+K}Fo3fgZ)6geN4}9+5hH>Ik{zLGKDY6yV#n zaeKXb_NKtejHhAd8f*EUBdKMj*Gqcp&;mHo=GxYX%gqz0!Mw$+ zjKh4$_5%xTInYO)A&`M4F@SeYp%V1Nv`-{ZXm}k?BXBSgsD5D8ot2AbebzACHWRUf znV|!fwksQ-S^w|*z2sVnR5V&5g%YV5AWJi6%uo&+*ztblwbxqB`_2Y&An{qhVT1hr zU;h%4hS|_8(FBdei)L-_U9?DPl4#OLp{XF_r2PJd8|2?0CG2R^!bUkC`8npOTxV|u zv?iPr)C{utduU4GJNQX01IQ)ZFnpNg=g#Cu43F%jL=W=bkHTK}`O6+wF?zklY-La(G0F z#H+KiY(U+#Ps@ulA4g*0i5J)5Aa&FjdD28K}iV9ep5TY0X? zz5HDQLiNGZ=i+)C(;qiaNEGPKyB==JIp-*dP8#Jq zSD&FAaZsa0m*wqcE*w`p`s`u(x3=l}Q0g~H8~`+oir?@)OS%#Y*N?_bh- zjR#-6^hEj0MaQWQCN*z&|MbJE14)MxolX9}>&KV3-cO=16;3NW`N?P7+B?s6g(a`G zPd7i0yj}=~3ucT~^VrylrD;JNe9kLQ1`dr*0qymtG*37`hJ@oo7hNRZhiMy$2Z@0f|NJA4 zP;s6BEf(iAc|rokjl!^}V4l^z4?G~Z-Fc^!U~ZI0l)Ug>IPN)b%M&jh=7VW?GI`P@ zMXtQxh3rWRSVrzm4)sAuj413RwU_pIa9$OOBfn^~vqvT`H-}yN5w1(R5aGo`=4OfhIq~trMXpsIs)9x4KS( z7JQ2HtmxgZy^yR_U^|#X%^RLLl?9Tc&PZKv^S3uF^V2OP{?0J$&m;fJYhQtb2!`oX z#FcYJdL~$_%J#{|<`76*t(-V(k}O$YD`P;WP8yH-rAYtDO_sd6VWX54mq3d$R4On? zR$X5&x4#O_J)VL0%^4}h**VwmjethrARyrN zbc{$OY9-=@5h-UVc+9y@bW~A; z-*i+#Squ|9#z*t9XF(X~wwoOvZypvq*K=_X@5HGsJ)6zPs+eTM-J98_u;V16iqog9kc77z=YjYLA#dYN;sH5OFS#Cp~d_ z?%mVbzC9jCz{HIjxCy|C=9Eu7^_0q2{=GDbyyyP=l_}zTKuTyD>B(4_EOu2E5?qRh zJ>%J%P}@b~Ml;SEVEX7e86hcZU$-0Kew}masD=9ewb!a>=`iDO|NN)ys;*YQIX{hZ zJlv}P_V>S+J5dLmKgKc_Dt0DqJhWy_pY)PosuT|PfJo6(h(~-2&94rp5f}&v_Lrn~!WB{8fKEa%@2TLMii`Y$(3(gUjF=9n5jgk=sG*YT)vKeSNW@6A5QXltMZ!U|J(_#b z6*!3xP17#>(1+AK9Xe2;X5^}mepG25NM<;fhK>r@>82KCI!ydVj~b=S1L;+c^QqYB zr>2B+tvGjy8X0=oBa!;}M?NA)9eJcIdHr?y6|^*WBfO^_>8wLLe%v@^M#!?9dD>|m zio{nN-LBKjklytEe9JA$^pK7e{`V_iQEA@^x9h*S{(5DG#xi?aB|2ev4f*gkdIj9; zs}dhVFOOch_P?3I_IOZR^cdz=(OJYZAe%IUBPm2=syvK?+P3SV;rkIBX?SLW>LUJx zp!MmhEbY_cJzk!?`}6lCUUWFY^yqq>Zs4gw>a1>wJ?Ev7faVM5e31;&nx*UZF*XW>j zGK2XzJrSdPidbdi;ex+Rri?6=m0O!+NZ68*AONp!%Sc^1An!f#SeZ9%vRbX417&n- z!n8&VseqG|6QnWi$m_d&5_6#aMm`QDp@WenST=z2=LeR^4R^e#j(63?l#>?qqva1B z&2VvSlCAH3>P+SECI32)+k1}m-d&#eOPVTEyx*{ykP8e1lsO?g@A=p6hr^1_gr4!*%crioO1OD)^(Q`|$QsE}F-!wJle3#a6iD#sV%sYt z=UYA4iDx{<_4hnabzgx8K5m}e4HD_ekqZ{=5l8-g4AUNuJE6rP(W7Gr&!qA*pZb(= z^Ms_xlXK2GOSpN$IZU0Eh1c`b;_vo2(&J%%d1)TWjbxbK488eUoz-preTkr7(Yg zXsN8-S|gWYUKK~hJvYl|95Y3Djizfo@vuj;Aufu`^^xcf{ZJ52((g@KIRZ^DYt-8O z_Xm$hCttl{4}~HZoJX29vXfYlV2+gX@|S16UC4cI;|8fR{c`T~5{ZL^ji?$bGlmz- zhUyyG3B!q5&_YceJ6c86)Et+U8#Y606~lUCW0jd7)XTEyxTEC$=U$d+m1PnQWU=N{ zn+bOzc{rG1xO@SZ&^YzTNv+S!(zmxOZ<>52X~yRXokp-a=uUsrjymP((Yv-UdoI3B zM-@lS93xwIHL8WIN$|S!M!7F(4yb$K@B|7{^n(f??<<3fat<#1O_Go zis|@#PDKFPi!_`p6e^rc1oi zgqHIp=)sHbyg4_6B@lFXOUr-U=^cbv=ouPs9H6 zkvHVa*S9&YX&-rS%Sw`2TohCb@BS5&xU1_dFyoEnls!O&d2F z-s>W=J84SVKD0Da^fF1IXG|`5&F$jTa!z=j!}CZldY*8dxMOFJ6)t%|ubfBE8lx`J zaKZcD=6jB0{dvE=>t0;>`&c|Je}8zXa!yePhcaAzn+s!WDGUK+wNO~l)=(vpAPfPu zvx!zf^npg;5I{f;mzs{Rg6l_RGkdoq=bWN%|KI;9v$sQ_Y&whm1cC3M&5*ElCP!l4 z95s@3>_IcXLL~)FRv_4SL<*z7n3h*Kk;>8=Q%~kp6?$WGW0K8n`E-SN^Y(>ndl@biC%e2==$p=3!g{CT1nIP$mUj4f_Q_kuH z9kt>jgf!|CCe2nrs~_T8(bR^3TqmP6%Q~Gi<2mUus5&CZa5CtxSqIi_ z+_k;syiSc3PFV3`^o|__{K6$x(F=Lf%Wm{mfnVgob z7|p1e)7yF|HB+AW@K2?w<8@>)BhVTLt=5*^8i5MaUmr6V6VO^}5=y4Db)cB0HlaF+ z2BZxB^q`UA#NLkQq0$0SrZg%1ofiL85er(G_>%b$VWF{L69{)GkTc+Wq&RqAONea9 z2?IN5vNS=Aq_YzvBq|W#EH|anRXUvtAo%ySFrLfc4996Ng>O!mH%53rS3)-o8 zHqKLMf|NwWuo^wAtLh4xB+<8uK84BjoFz0xqTGd;RDA$=oN1OP z+}>YC_V>)(NauIbHIsdeCQYpK%|p9FLsg`L@3Q=le_5_T6l3Q+cwKJ=`WCO>gBUq| zcv@-DUbu6B)F`HJKZv$u!JLV~e6P5$bX!0CdAR~njIs0Ty#wX?L7kP!BSBP$=7}ne zl+iWgG);-F{UXq;ZbH{r0%Bugd~w24d1kD31WF-@jI5HKtNA-Mt5*l%E37hQ?qd0B z*5C5awp~&;AztF4jiQfH8vI;ypm|)pahK9q{j(=UcH815J*Bqojm+}B{5?<&dO*ztVXA>2ul)pqh_daY>7O1@w(L1qpGjrT0J>z3qmZ$V!WZg4>(?u$ zHd33Pi&#P=Q)4eH1Obx~cz9wdw%^sgTf6I69mfv4JToILNi%*Qu#d;;aokL@eANZb=qRLFrbcNNNGz6Z*r#Zg&uU!LEjw7*`|z_~ z2aGVPT(X!^Xa*Px-w`qf>KY@a>-XoeE_LEv`{|K|kKnQ)Tn7*sD#OojgGqgXDpK!Lz5MF1XFq!jiWnDAW4f%27S}FG(I(lGWd}&!i~f&Q zTBdpk#yhfqpOUU+-SVt9JWs2nVM4gHiLpsQi~6!=_hISSu%bDc^r3{u2E?P$fN}R8TO1h~cEdoknU00^wdW zYLtu_Ki;D+m0r^;MvRc}r%aLOCr*_0@SN0zfprzt4j#rKKbl3Y0{{X?AWzS_5m!BBK;1;HKIvk`?hUWz*+*g@sB<#^$|pu z5ELX$fR%>bh#G(ro;8X^!#LXcPbLcI?^ue1#CX?qae9PvfO z(wT|+(rl2#6F>dE0St1nC0ef3;<89SLDBovL-A+SY5E`;)<_lWFR9J68@C56w?6_3 zGNfJ20I?Tl%b&|g(|-uS->O1!6yQB!1JFI1nJsfxtrKfrj&!XTBtZd%l8Ur}9h*v@ zM5}}r9D#pSTDkY|pYZp9FM2>N9N@Y4MyQcO{tSo7;d({Ko5K8g{XO9Cfs@h$Y9@%a zT+Ou4&5wTTwr!FLdvk6KKufxCPtvh{d-(vtb7%ban>_d8i_!(!sqy#UFH4s%SFwYF zp>b*jCcs~(PnVkzaJK-lfgXC`0cqHvfdXr9zyH1vz#Ro>N~}{yrH6ygma=H^V(APL zgR5aSs0)MoHcm=XF^d?t=zGMMN=;4mYo+uKsz&>~+#CRzVDD5X9@e zRX>eX!`h&=4+{dY$ORdLwS<+fbYGM|F;H5e;)yelHPQFSOJQuBm7Dh~-zGBdMMs1v znq^MTdF+m6`FOd<%i~eW?VOTtxuh!?1oLDWDBVd+5reXCxkU5Vx~hMB0J#-Pn?y4~ z*K)k>^Z`qO&)3GCDQaUs(O-%_VT|KLlR}y((!`On1O8?d5@}R7p$5`8kkYh+{NB9P zV!7%!GWaC~X2^w2V`afEt9<|GTmacR0LHbIhWN;_bdZMZ7n?O#hIgzb@j+Huu%}Rt zWZ^rq?uS)FI_lxqMY-x*f0}Q5fIKJOFu|(3J0t=7Ec|NxK+3mYhrcv`4^&wX=u7I6 z1)x5+0N9i#ea|~jX@Ll6jDRS;9L5~F?&_=M(xF4;mb>nfOlM_arNkd zVvUsXz-JzsjYrX51PU-SqIejQ>IkIx((emUL7yTLK->iK22vn9(<6WT{K%5-d1O>y z;ik*f*KW`cr7W$oa~X9&PVwg0A)pb@SG440wkk`r{2k2X_8_>Zvk>HxkT_OHy@cbox1dM?DIaL0X#7Ml6>H9r!7buscV4`#-J34+ zS07Ro_>rL4Z&fc|TGxn{U`M8`OAVDR&>Z$_RYMX2Qp8c{)3ulC^~L&I$=EU^2zlKvN7s7wiY&6s=cDV2pZ>~FpIo@By5 zDhlz3@=$g+l)GfvGP(AutCSxV%ZB9ICRDSzR? zU@@m%HnP>tUa>=IYK9>gDC5Uem4rFgmR7xMKBeISXjmDF6kN3a-@X$aDOjN7i%f)pk8A&zuYSAJhHpCHS4>pGf6qzDSCVQyeGVfWYt^izz3(KvUPFz+hW}Bg<-Y zgoou6?%uPfaPHGjS6y8y)ByiQ?s`B0DLi1I1UYctcbC`ebH7ZRCUfV{7Xm5zJPp6} zQf10l1F?f9ees2iy5$xHq}sz*>h9ZbSLHiTJZja1V{qff3XFvWYcVo-o*PX9Y1(%u z{G zFsN>#G%xoLR@CLbnD|z-e{_oSie7)Ju44dTG6<3pP-hf8RduPV`-0!qi=wr;f&yQL z(U+Uz11z#7IZGDo%te6bU=^I#ZqI-=N;B7^pD)2}YI+tH*K*{F?hU1Bc)FMh0HTcB zBf6=8|CGN6jP(HHntAn8DK0iN#2jkMbX08B$XL~6P^Xri&6a?h%pqYtF`*)5v(0P@ z$a9!XR;+gC;dhh=fRYEcj9l(bIA^j1<^r7HIM8Ye46r#YAyx?t&Nl}H6qtg73e7>m zg$`xQh*)lcC*g9 zNU(B7NKs*=9ml4^!U#tZw<0+1qE=?Jm30Zk{T-~2IlyXmhz)0K2;WnHHIxFA!(M=Q zRssA%>|mirtBM>BGyd7_RH1XO8x)9@7)Jm|JROb@2O@L_njN9>QKk^-)+%(UAi9D= zzUBh-M*;3ZnoqE>1=vjixSamA0fDFsOen}AVg@H81{)?Y3MBy@>PhA$e0SW00FU=J z$(D^+N!lPsH{qE8v73!!5%y%u#(`K#yo9t&q{ZR$WrO-L10Er4aQMdoGXoR~QDULV zj<(wE`Pi&*7`569Y-^;@I&s>H?Z?Ro3_c6~Y?bc;O(W$nSu_^3(krW#Eq>gXF>=ox zcSufduF%9!7Y1Q{aO_yI!bzBZDPhF`Zssq)=vhkk6P|ji=<8Sy>}Yz1~`8;tdn)mA+N-Nznc4(st<960wD~P z4aUwu3qV$om@L6!36B<25EM$mp<>3S?ZdAq0!yjqfN3S0o(8;y zK4Q9-M>|H1kbvb~ZOuw`!0{)d_+IF570LnkD>$&Dan`(_1`h1pY|zYA|1K-tBLAnV z?g3pR6<`I}2?^6!yL@@mU}%!Kxe{urDk~PtiCO{rS5Zslm+IRC`2gVofdQWB)(mz* zV4x|VK+34t3~HpPp*V6ZTN2^3;TL}oREHjb`HY$m7-@?Zvk5u9QDV6(7>m1{iyTNv zllg1cgFwW!>Gs~kDVXqCwaJOQ^8DxgJy1nGzzKFmfE0YBB20FZ@t2Vo^&ir?d4f40 z_@#s!pNtNObiD}SMR8|bRzew1Uy4bAy%Xn^r*mU1HR^_$qvI^;Q$KkJ_3U~&*VTu0 z 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 literal 0 HcmV?d00001 diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py new file mode 100644 index 000000000..d43780ff8 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py @@ -0,0 +1,300 @@ +# Copyright (c) 2023 Oracle and/or its affiliates. + +# The Universal Permissive License (UPL), Version 1.0 + +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or data +# (collectively the "Software"), free of charge and under any and all copyright +# rights in the Software, and any and all patent rights owned or freely +# licensable by each licensor hereunder covering either (i) the unmodified +# Software as contributed to or provided by such licensor, or (ii) the Larger +# Works (as defined below), to deal in both + +# (a) the Software, and +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software (each a "Larger Work" to which the Software +# is contributed by such licensors), + +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. + +# This license is subject to the following condition: +# The above copyright notice and either this complete permission notice or at +# a minimum a reference to the UPL must be included in all copies or +# substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +### +# This is a sample python script that post a custom metric (service_limits) to oci monitoring based on Tenancy Service Limits information. +# Run this script on any host with python with access to your tenancy. +# Command: python3 serviceLimitsMetrics.py +# Version: 0.1 +### + +import oci,datetime,json +from pytz import timezone + +# Using IAM user credentials and default profile (~/.oci/config) +from oci.config import from_file +config = from_file() + +# Vars: +# Replace here with your tenancy's root compartment OCID +compartment_ocid = "ocid1.tenancy.oc1....." + +# Start: +now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") +print("[", now,"] Starting OCI Service Metrics limits gathering and customer metrics post...") + +# We gather the list of availability domains in the region +identity_client = oci.identity.IdentityClient(config) +list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) + +# Get the data from response +print(list_availability_domains_response.data) + +# Initialize service client with default config file +monitoring_client = oci.monitoring.MonitoringClient(config,service_endpoint="https://telemetry-ingestion.eu-frankfurt-1.oraclecloud.com") + +# Get Service Limits + +# Initialize service client with default config file +limits_client = oci.limits.LimitsClient(config) + +# Send the request to service, some parameters are not required, see API +# doc for more info +list_limit_definitions_response = limits_client.list_limit_definitions( + compartment_id = compartment_ocid, + sort_by="name", + sort_order="ASC") + +# We iterate the list of all the service limits +for x in list_limit_definitions_response.data: + limit = json.loads(str(x)) + s_name = limit["service_name"] + l_name = limit["name"] + l_scope = limit["scope_type"] + + print ("Service: ", s_name, "Limit: ", l_name, "Scope: ", l_scope) + + # If the resource limit has an AD scope, we have to specify the AD or we'll get an API 400 response + if l_scope == "AD" : + # We have AD scope, we've to gather the limit for all the ADs in the region and include the availabilityDomain + for AD in list_availability_domains_response.data: + + a_domain = json.loads(str(AD)) + print("Availability Domain: ", a_domain) + + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability( + service_name = s_name, + limit_name = l_name, + compartment_id = compartment_ocid, + availability_domain = a_domain["name"]) + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + + # Get the data from response + print(get_resource_availability_response.data) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values( + compartment_id = compartment_ocid, + service_name = s_name, + availability_domain = a_domain["name"], + limit = 1) + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) + + # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) + + # Max limit + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "max_limit", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = max_limit)] + )] + ) + ) + print("Max_limit: ", post_metric_data_response.data) + + # Used + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "used", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = used)] + )] + ) + ) + print("Used: ", post_metric_data_response.data) + + # Available + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "available", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = available)] + )] + ) + ) + print("Available: ", post_metric_data_response.data) + + else : + # We are in GLOBAL or REGION case + + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability( + service_name = s_name, + limit_name = l_name, + compartment_id = compartment_ocid) + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + + # Get the data from response + print(get_resource_availability_response.data) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values( + compartment_id = compartment_ocid, + service_name = s_name, + limit = 1) + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + print(list_limit_values_response.data) + + print("max_limit: ", max_limit) + if max_limit == "null" : + continue + + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) + + # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) + + # Max limit + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "max_limit", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = max_limit)] + )] + ) + ) + print("Max_limit: ", post_metric_data_response.data) + + print("used: ", used) + if used is None : + continue + + # Used + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "used", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = used)] + )] + ) + ) + print("Used: ", post_metric_data_response.data) + + # Available + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "available", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = available)] + )] + ) + ) + print("Available: ", post_metric_data_response.data) + + +# Finish: +now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") +print("[", now,"] Finish OCI Service Metrics limits gathering and customer metrics post.") From 3fe624b0562b87324eebd185dadf4f733ce0243a Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Wed, 19 Jul 2023 14:37:38 +0200 Subject: [PATCH 2/6] Added the Instance Principal script version --- .../README.md | 11 +- .../Scripts/postServiceLimitsMetricsIAM.py | 2 +- .../Scripts/postServiceLimitsMetricsIP.py | 300 ++++++++++++++++++ 3 files changed, 309 insertions(+), 4 deletions(-) create mode 100644 manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md index 506d7dc9f..dbe626303 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md @@ -2,6 +2,7 @@ # Using python SDK to create OCI Monitoring custom metric namespace: Services Limit monitoring example use case ## 1. INTRODUCTION + Describes how any user can create an OCI Monitoring ***custom metric namespace*** to being able to extend the default services metric namespaces. For that, we'll support on python SDK to create an script that can be run in an OCI VM (using instance principals authentication), or any other external system (using OCI IAM principals). To cover this educational example, we'll use as an example the creation of a custom metric namespace to monitor the OCI Services Limits usage. With this custom metric namespace, OCI alarms can be created and OCI Notification Service can be used to send the alarm information by different means to allow to create proactively a Service Limit Service Request to increase the limit before causing any disruption in the running services or services to be provisioned. ## 2. SOLUTION @@ -39,7 +40,7 @@ Basically the **logic** is: ```` Start -Gather the IAM user connection details from OCI Config +Setup the OCI connection authentication (OCI IAM Config or Instance Principals) Set compartment_ocid Initialize the clients for the different API calls (IAM, Monitoring, Service Limits) Gather the full list of Service Limits Definitions sorted by Service Limit name @@ -71,7 +72,7 @@ To execute the script: ```` $ python3 serviceLimitsMetricsIP.py ```` - * The script is available **TBD** + * The script is available [here](./files/Scripts/postServiceLimitsMetricsIP.py) ## 5. REQUIREMENTS @@ -87,7 +88,11 @@ We have different requirements depending on the variant of this asset that we wo * use metrics in tenancy 2. **Instance Principal** - * ***TBD*** + * An existing dynamic group identifying the VM where to run the script as member of the group + * A policy granting the dynamic group to: + * inspect resource-availability in tenancy + * inspect limits in tenancy + * use metrics in tenancy 3. ***Common requirements*** The VM where to run the script must have installed python3 with the following required packages installed with pip: diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py index d43780ff8..47a773bb4 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py @@ -37,7 +37,7 @@ ### # This is a sample python script that post a custom metric (service_limits) to oci monitoring based on Tenancy Service Limits information. # Run this script on any host with python with access to your tenancy. -# Command: python3 serviceLimitsMetrics.py +# Command: python3 postServiceLimitsMetricsIAM.py # Version: 0.1 ### diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py new file mode 100644 index 000000000..05a74b855 --- /dev/null +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py @@ -0,0 +1,300 @@ +# Copyright (c) 2023 Oracle and/or its affiliates. + +# The Universal Permissive License (UPL), Version 1.0 + +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or data +# (collectively the "Software"), free of charge and under any and all copyright +# rights in the Software, and any and all patent rights owned or freely +# licensable by each licensor hereunder covering either (i) the unmodified +# Software as contributed to or provided by such licensor, or (ii) the Larger +# Works (as defined below), to deal in both + +# (a) the Software, and +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software (each a "Larger Work" to which the Software +# is contributed by such licensors), + +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. + +# This license is subject to the following condition: +# The above copyright notice and either this complete permission notice or at +# a minimum a reference to the UPL must be included in all copies or +# substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +### +# This is a sample python script that post a custom metric (service_limits) to oci monitoring based on Tenancy Service Limits information. +# Run this script on any host with python with access to your tenancy. +# Command: python3 postServiceLimitsMetricsIP.py +# Version: 0.1 +### + +import oci,datetime,json +from pytz import timezone + +# Vars: +# Replace here with your tenancy's root compartment OCID +compartment_ocid = "ocid1.tenancy.oc1....." + +# Start: +now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") +print("[", now,"] Starting OCI Service Metrics limits gathering and customer metrics post...") + +# Setup the signer for the instance principal auth method +signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() + +# We gather the list of availability domains in the region +identity_client = oci.identity.IdentityClient(config={}, signer=signer) +list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) + +# Get the data from response +print(list_availability_domains_response.data) + +# Initialize service client with default config file +#monitoring_client = oci.monitoring.MonitoringClient(config={}, signer=signer) +monitoring_client = oci.monitoring.MonitoringClient(config={},service_endpoint="https://telemetry-ingestion.eu-frankfurt-1.oraclecloud.com",signer=signer) + +# Get Service Limits + +# Initialize service client with default config file +limits_client = oci.limits.LimitsClient(config={}, signer=signer) + +# Send the request to service, some parameters are not required, see API +# doc for more info +list_limit_definitions_response = limits_client.list_limit_definitions( + compartment_id = compartment_ocid, + sort_by="name", + sort_order="ASC") + +# We iterate the list of all the service limits +for x in list_limit_definitions_response.data: + limit = json.loads(str(x)) + s_name = limit["service_name"] + l_name = limit["name"] + l_scope = limit["scope_type"] + + print ("Service: ", s_name, "Limit: ", l_name, "Scope: ", l_scope) + + # If the resource limit has an AD scope, we have to specify the AD or we'll get an API 400 response + if l_scope == "AD" : + # We have AD scope, we've to gather the limit for all the ADs in the region and include the availabilityDomain + for AD in list_availability_domains_response.data: + + a_domain = json.loads(str(AD)) + print("Availability Domain: ", a_domain) + + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability( + service_name = s_name, + limit_name = l_name, + compartment_id = compartment_ocid, + availability_domain = a_domain["name"]) + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + + # Get the data from response + print(get_resource_availability_response.data) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values( + compartment_id = compartment_ocid, + service_name = s_name, + availability_domain = a_domain["name"], + limit = 1) + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) + + # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) + + # Max limit + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "max_limit", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = max_limit)] + )] + ) + ) + print("Max_limit: ", post_metric_data_response.data) + + # Used + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "used", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = used)] + )] + ) + ) + print("Used: ", post_metric_data_response.data) + + # Available + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "available", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain["name"] + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = available)] + )] + ) + ) + print("Available: ", post_metric_data_response.data) + + else : + # We are in GLOBAL or REGION case + + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability( + service_name = s_name, + limit_name = l_name, + compartment_id = compartment_ocid) + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + + # Get the data from response + print(get_resource_availability_response.data) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values( + compartment_id = compartment_ocid, + service_name = s_name, + limit = 1) + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + print(list_limit_values_response.data) + + print("max_limit: ", max_limit) + if max_limit == "null" : + continue + + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) + + # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) + + # Max limit + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "max_limit", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = max_limit)] + )] + ) + ) + print("Max_limit: ", post_metric_data_response.data) + + print("used: ", used) + if used is None : + continue + + # Used + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "used", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = used)] + )] + ) + ) + print("Used: ", post_metric_data_response.data) + + # Available + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = "available", + dimensions={ + 'service_name': s_name, + 'limit_name': l_name }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = available)] + )] + ) + ) + print("Available: ", post_metric_data_response.data) + + +# Finish: +now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") +print("[", now,"] Finish OCI Service Metrics limits gathering and customer metrics post.") From 663d304f517c5906ff493f3b064881006a7cf4b3 Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Fri, 21 Jul 2023 11:29:36 +0200 Subject: [PATCH 3/6] Removed unneded content --- .../README.md | 60 +------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md index dbe626303..3c860aa8d 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md @@ -117,66 +117,8 @@ None at this point. There 2 scripts with same code except for the OCI authentication. Both scripts will be maintained in parallel with same versions: 2023-07-18 (version 0.1). Initial public release. - - - - - - - - - - - - - - - - - - - - - -## Objectives - -* Overview of OCI Full Stack Disaster Recovery Service -* Gain knowledge on DR concepts and terminology and FSDR components -* Understand the different OCI interfaces available to manage FSDR service -* Explains how the service works -* Shows some typical use cases and supported OCI services OOB -* Shows how the provisioning operations can be done with the Console/OCI CLI -* Shows how the DR plan executions operations can be done with the Console/OCI CLI -* Provided OCI CLI Cheat Sheets - -## Pre-requirements - -* Basic knowledge of OCI Compute, Storage and DB Services -* Knowledge on Disaster Recovery practices are desired - -## Inputs - -N/A - -## Outputs - -[WorkshopFSDROperations_v0.2.pdf](./files/EXP#01o_WorkshopFSDROperations_v0.2.pdf) - -## Stakeholders - -* Architect teams -* Operation teams -* Development teams - -## Guidelines - -N/A - -# Release notes - -2023-07-12 (version 0.2). Initial public release. -# License +# LICENSE Copyright (c) 2023 Oracle and/or its affiliates. From 8b7663aa10d90d63aaad1a724489fe50f71ac5fe Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Tue, 25 Jul 2023 13:07:07 +0200 Subject: [PATCH 4/6] Implem. script code suggestion and updated README --- .../README.md | 53 +-- .../Scripts/postServiceLimitsMetricsIAM.py | 308 +++++++----------- .../Scripts/postServiceLimitsMetricsIP.py | 303 +++++++---------- 3 files changed, 270 insertions(+), 394 deletions(-) diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md index 3c860aa8d..4e5309d9e 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md @@ -40,9 +40,9 @@ Basically the **logic** is: ```` Start +Parse input arguments (compartment_ocid, region) Setup the OCI connection authentication (OCI IAM Config or Instance Principals) -Set compartment_ocid -Initialize the clients for the different API calls (IAM, Monitoring, Service Limits) +Initialise the clients for the different API calls (IAM, Monitoring, Service Limits) Gather the full list of Service Limits Definitions sorted by Service Limit name For the list of Service Limit names If the scope is Availability Domain @@ -55,27 +55,7 @@ For the list of Service Limit names End ```` -## 4. GETTING STARTED - -To execute the script: - -1. Ensure that the requirements are met with your desired variant (using IAM user or Instance Principals) -2. Upload the script into your administration VM inside OCI (IAM user or Instance Principals), or outside OCI (IAM user only) -3. Edit the script and put your OCI tenancy root compartment OCID in the compartment_ocid variable -4. To execute the script: - * For the IAM User principals authentication method, execute: - ```` - $ python3 serviceLimitsMetricsIAM.py - ```` - * The script is available [here](./files/Scripts/postServiceLimitsMetricsIAM.py) - * For the Instance principal authentication method, execute: - ```` - $ python3 serviceLimitsMetricsIP.py - ```` - * The script is available [here](./files/Scripts/postServiceLimitsMetricsIP.py) - - -## 5. REQUIREMENTS +## 4. REQUIREMENTS We have different requirements depending on the variant of this asset that we would use: @@ -98,16 +78,37 @@ We have different requirements depending on the variant of this asset that we wo The VM where to run the script must have installed python3 with the following required packages installed with pip: * **oci** -## 6. INPUT +## 5. INPUT -The required input is the ***compartment_ocid*** with the OCID of your tenancy root compartment. Replace the value of the variable at the beginning of the script. +The required input arguments are: -## 7. OUTPUT +* **compartment_ocid** with the OCID of your tenancy root compartment.  +* **region** where you want to get the Services Limits with regional scope and where to publish metrics + +## 6. OUTPUT Every time the script is run, it will feed a custom metric namespace called "**limits_metrics**" in the tenancy's root compartment with the information of the Services Limits usage. You can check the custom metric extension from the OCI Metrics Explorer, where you will be able also to create an alarms from an specific metric query. +## 7. GETTING STARTED + +To execute the script: + +1. Ensure that the requirements are met with your desired variant (using IAM user or Instance Principals) +2. Upload the script into your administration VM inside OCI (IAM user or Instance Principals), or outside OCI (IAM user only) +3. To execute the script: + * For the IAM User principals authentication method, execute: + ```` + $ python3 serviceLimitsMetricsIAM.py -c/--compartment_ocid -r/--region + ```` + * The script is available [here](./files/Scripts/postServiceLimitsMetricsIAM.py) + * For the Instance principal authentication method, execute: + ```` + $ python3 serviceLimitsMetricsIP.py -c/--compartment_ocid -r/--region + ```` + * The script is available [here](./files/Scripts/postServiceLimitsMetricsIP.py) + ## 8.KNOWN PROBLEMS None at this point. diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py index 47a773bb4..753176302 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py @@ -38,41 +38,138 @@ # This is a sample python script that post a custom metric (service_limits) to oci monitoring based on Tenancy Service Limits information. # Run this script on any host with python with access to your tenancy. # Command: python3 postServiceLimitsMetricsIAM.py -# Version: 0.1 +# Version: 0.2 ### -import oci,datetime,json +import oci,datetime,json,argparse +from oci.config import from_file from pytz import timezone -# Using IAM user credentials and default profile (~/.oci/config) -from oci.config import from_file -config = from_file() +# Functions definition -# Vars: -# Replace here with your tenancy's root compartment OCID -compartment_ocid = "ocid1.tenancy.oc1....." +# postMetric: posts custom monitoring metric information for compartment, metric(used,available,max_limit) and with its dimensions (service, limit name and availability domain(if AD specific)) +def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): + if a_domain is None: + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = m_name, + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = value)] + )] + ) + ) + else: + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = m_name, + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = value)] + )] + ) + ) + return post_metric_data_response + +# getServiceLimitsUsage: gets the existing limits for a service and limit name in a compartment and, if AD specific, for its AD +def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): + if a_domain is None: + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values(compartment_id = compartment_ocid, service_name = s_name, limit = 1) + else: + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid, availability_domain = a_domain) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values(compartment_id = compartment_ocid, service_name = s_name, availability_domain = a_domain, limit = 1) + + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + # We create the return type data dictionary + values = { + "used": used, + "available": available, + "max_limit": max_limit + } + return json.dumps(values) + + +# Parse the input arguments +argParser = argparse.ArgumentParser() +argParser.add_argument("-c", "--compartment_ocid", help="Your root's compartment OCID, typically tenancy OCID",required=True) +argParser.add_argument("-r", "--region", help="The region where you want to get the Services Limits. E.g.: eu-frankfurt-1", required=True) +args = argParser.parse_args() +compartment_ocid = args.compartment_ocid +region = args.region # Start: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") print("[", now,"] Starting OCI Service Metrics limits gathering and customer metrics post...") +# Using IAM user credentials and default profile (~/.oci/config) +config = from_file() +# We change the default profile region for the given region which we want to get services limits information and publish the custom metric +config["region"] = region + # We gather the list of availability domains in the region identity_client = oci.identity.IdentityClient(config) -list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) -# Get the data from response -print(list_availability_domains_response.data) +# Let's check if the provided region is valid and it is among the subscribed regions +list_regions_response = identity_client.list_regions() + +for e in list_regions_response.data: + reg = json.loads(str(e)) + if reg["name"] == region: + break +else: + print("ERROR: Wrong or non-subscribed OCI region, exiting...") + exit() + +try: + list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) +except Exception as ex: + print("ERROR: The given compartment is wrong or you aren't authorized to list the availability domains, exiting...") + exit(1) + +service_endpoint = "https://telemetry-ingestion." + region + ".oraclecloud.com" # Initialize service client with default config file -monitoring_client = oci.monitoring.MonitoringClient(config,service_endpoint="https://telemetry-ingestion.eu-frankfurt-1.oraclecloud.com") +monitoring_client = oci.monitoring.MonitoringClient(config,service_endpoint=service_endpoint) # Get Service Limits # Initialize service client with default config file limits_client = oci.limits.LimitsClient(config) -# Send the request to service, some parameters are not required, see API -# doc for more info +# Send the request to service, some parameters are not required, see API doc for more info list_limit_definitions_response = limits_client.list_limit_definitions( compartment_id = compartment_ocid, sort_by="name", @@ -84,8 +181,6 @@ s_name = limit["service_name"] l_name = limit["name"] l_scope = limit["scope_type"] - - print ("Service: ", s_name, "Limit: ", l_name, "Scope: ", l_scope) # If the resource limit has an AD scope, we have to specify the AD or we'll get an API 400 response if l_scope == "AD" : @@ -93,29 +188,8 @@ for AD in list_availability_domains_response.data: a_domain = json.loads(str(AD)) - print("Availability Domain: ", a_domain) - - # We gather the service limit usage - get_resource_availability_response = limits_client.get_resource_availability( - service_name = s_name, - limit_name = l_name, - compartment_id = compartment_ocid, - availability_domain = a_domain["name"]) - usage = json.loads(str(get_resource_availability_response.data)) - used = usage["used"] - available = usage["available"] - - # Get the data from response - print(get_resource_availability_response.data) - - # We need to gather the service limit limit - list_limit_values_response = limits_client.list_limit_values( - compartment_id = compartment_ocid, - service_name = s_name, - availability_domain = a_domain["name"], - limit = 1) - limit_limit = json.loads(str(list_limit_values_response.data[0])) - max_limit = limit_limit["value"] + + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain["name"])) # Get the timestamp for setup the monitoring metric post information times_stamp = datetime.datetime.now(timezone('UTC')) @@ -123,100 +197,22 @@ # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "max_limit", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = max_limit)] - )] - ) - ) - print("Max_limit: ", post_metric_data_response.data) + postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = int(limit_usage["max_limit"]), a_domain = a_domain["name"]) # Used - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "used", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = used)] - )] - ) - ) - print("Used: ", post_metric_data_response.data) + postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["used"], a_domain = a_domain["name"]) # Available - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "available", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = available)] - )] - ) - ) - print("Available: ", post_metric_data_response.data) + postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "available", s_name = s_name, l_name = l_name, value = limit_usage["available"], a_domain = a_domain["name"]) - else : + else: # We are in GLOBAL or REGION case - # We gather the service limit usage - get_resource_availability_response = limits_client.get_resource_availability( - service_name = s_name, - limit_name = l_name, - compartment_id = compartment_ocid) - usage = json.loads(str(get_resource_availability_response.data)) - used = usage["used"] - available = usage["available"] - - # Get the data from response - print(get_resource_availability_response.data) + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid)) - # We need to gather the service limit limit - list_limit_values_response = limits_client.list_limit_values( - compartment_id = compartment_ocid, - service_name = s_name, - limit = 1) - limit_limit = json.loads(str(list_limit_values_response.data[0])) - max_limit = limit_limit["value"] + max_limit = limit_usage["max_limit"] + used = limit_usage["used"] - print(list_limit_values_response.data) - - print("max_limit: ", max_limit) if max_limit == "null" : continue @@ -226,74 +222,16 @@ # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "max_limit", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = max_limit)] - )] - ) - ) - print("Max_limit: ", post_metric_data_response.data) + postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = max_limit) - print("used: ", used) if used is None : continue # Used - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "used", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = used)] - )] - ) - ) - print("Used: ", post_metric_data_response.data) + postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = used) # Available - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "available", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = available)] - )] - ) - ) - print("Available: ", post_metric_data_response.data) - + postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["available"]) # Finish: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py index 05a74b855..ca33f36bf 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py @@ -38,15 +38,97 @@ # This is a sample python script that post a custom metric (service_limits) to oci monitoring based on Tenancy Service Limits information. # Run this script on any host with python with access to your tenancy. # Command: python3 postServiceLimitsMetricsIP.py -# Version: 0.1 +# Version: 0.2 ### -import oci,datetime,json +import oci,datetime,json,argparse from pytz import timezone -# Vars: -# Replace here with your tenancy's root compartment OCID -compartment_ocid = "ocid1.tenancy.oc1....." +# Functions definition + +# postMetric: posts custom monitoring metric information for compartment, metric(used,available,max_limit) and with its dimensions (service, limit name and availability domain(if AD specific)) +def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): + if a_domain is None: + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = m_name, + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = value)] + )] + ) + ) + else: + post_metric_data_response = monitoring_client.post_metric_data( + post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( + metric_data=[ + oci.monitoring.models.MetricDataDetails( + namespace = "limits_metrics", + compartment_id = compartment_ocid, + name = m_name, + dimensions={ + 'service_name': s_name, + 'limit_name': l_name, + 'availability_domain': a_domain + }, + datapoints=[ + oci.monitoring.models.Datapoint( + timestamp=datetime.datetime.strftime( + times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), + value = value)] + )] + ) + ) + return post_metric_data_response + +# getServiceLimitsUsage: gets the existing limits for a service and limit name in a compartment and, if AD specific, for its AD +def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): + if a_domain is None: + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values(compartment_id = compartment_ocid, service_name = s_name, limit = 1) + else: + # We gather the service limit usage + get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid, availability_domain = a_domain) + + # We need to gather the service limit limit + list_limit_values_response = limits_client.list_limit_values(compartment_id = compartment_ocid, service_name = s_name, availability_domain = a_domain, limit = 1) + + usage = json.loads(str(get_resource_availability_response.data)) + used = usage["used"] + available = usage["available"] + limit_limit = json.loads(str(list_limit_values_response.data[0])) + max_limit = limit_limit["value"] + + # We create the return type data dictionary + values = { + "used": used, + "available": available, + "max_limit": max_limit + } + return json.dumps(values) + + +# Parse the input arguments +argParser = argparse.ArgumentParser() +argParser.add_argument("-c", "--compartment_ocid", help="Your root's compartment OCID, typically tenancy OCID",required=True) +argParser.add_argument("-r", "--region", help="The region where you want to get the Services Limits. E.g.: eu-frankfurt-1", required=True) +args = argParser.parse_args() +compartment_ocid = args.compartment_ocid +region = args.region + # Start: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") @@ -56,20 +138,34 @@ signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner() # We gather the list of availability domains in the region -identity_client = oci.identity.IdentityClient(config={}, signer=signer) -list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) +identity_client = oci.identity.IdentityClient(config={'region': region}, signer=signer) + +# Let's check if the provided region is valid and it is among the subscribed regions +list_regions_response = identity_client.list_regions() + +for e in list_regions_response.data: + reg = json.loads(str(e)) + if reg["name"] == region: + break +else: + print("ERROR: Wrong or non-subscribed OCI region, exiting...") + exit() -# Get the data from response -print(list_availability_domains_response.data) +try: + list_availability_domains_response = identity_client.list_availability_domains(compartment_id = compartment_ocid) +except Exception as ex: + print("ERROR: The given compartment is wrong or you aren't authorized to list the availability domains, exiting...") + exit(1) + +service_endpoint = "https://telemetry-ingestion." + region + ".oraclecloud.com" # Initialize service client with default config file -#monitoring_client = oci.monitoring.MonitoringClient(config={}, signer=signer) -monitoring_client = oci.monitoring.MonitoringClient(config={},service_endpoint="https://telemetry-ingestion.eu-frankfurt-1.oraclecloud.com",signer=signer) +monitoring_client = oci.monitoring.MonitoringClient(config={'region': region},service_endpoint=service_endpoint,signer=signer) # Get Service Limits # Initialize service client with default config file -limits_client = oci.limits.LimitsClient(config={}, signer=signer) +limits_client = oci.limits.LimitsClient(config={'region': region}, signer=signer) # Send the request to service, some parameters are not required, see API # doc for more info @@ -84,8 +180,6 @@ s_name = limit["service_name"] l_name = limit["name"] l_scope = limit["scope_type"] - - print ("Service: ", s_name, "Limit: ", l_name, "Scope: ", l_scope) # If the resource limit has an AD scope, we have to specify the AD or we'll get an API 400 response if l_scope == "AD" : @@ -93,29 +187,8 @@ for AD in list_availability_domains_response.data: a_domain = json.loads(str(AD)) - print("Availability Domain: ", a_domain) - - # We gather the service limit usage - get_resource_availability_response = limits_client.get_resource_availability( - service_name = s_name, - limit_name = l_name, - compartment_id = compartment_ocid, - availability_domain = a_domain["name"]) - usage = json.loads(str(get_resource_availability_response.data)) - used = usage["used"] - available = usage["available"] - - # Get the data from response - print(get_resource_availability_response.data) - - # We need to gather the service limit limit - list_limit_values_response = limits_client.list_limit_values( - compartment_id = compartment_ocid, - service_name = s_name, - availability_domain = a_domain["name"], - limit = 1) - limit_limit = json.loads(str(list_limit_values_response.data[0])) - max_limit = limit_limit["value"] + + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain["name"])) # Get the timestamp for setup the monitoring metric post information times_stamp = datetime.datetime.now(timezone('UTC')) @@ -123,100 +196,22 @@ # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "max_limit", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = max_limit)] - )] - ) - ) - print("Max_limit: ", post_metric_data_response.data) + postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = int(limit_usage["max_limit"]), a_domain = a_domain["name"]) # Used - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "used", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = used)] - )] - ) - ) - print("Used: ", post_metric_data_response.data) + postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["used"], a_domain = a_domain["name"]) # Available - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "available", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name, - 'availability_domain': a_domain["name"] - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = available)] - )] - ) - ) - print("Available: ", post_metric_data_response.data) + postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "available", s_name = s_name, l_name = l_name, value = limit_usage["available"], a_domain = a_domain["name"]) - else : + else: # We are in GLOBAL or REGION case - # We gather the service limit usage - get_resource_availability_response = limits_client.get_resource_availability( - service_name = s_name, - limit_name = l_name, - compartment_id = compartment_ocid) - usage = json.loads(str(get_resource_availability_response.data)) - used = usage["used"] - available = usage["available"] - - # Get the data from response - print(get_resource_availability_response.data) - - # We need to gather the service limit limit - list_limit_values_response = limits_client.list_limit_values( - compartment_id = compartment_ocid, - service_name = s_name, - limit = 1) - limit_limit = json.loads(str(list_limit_values_response.data[0])) - max_limit = limit_limit["value"] + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid)) - print(list_limit_values_response.data) + max_limit = limit_usage["max_limit"] + used = limit_usage["used"] - print("max_limit: ", max_limit) if max_limit == "null" : continue @@ -226,74 +221,16 @@ # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "max_limit", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = max_limit)] - )] - ) - ) - print("Max_limit: ", post_metric_data_response.data) + postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = max_limit) - print("used: ", used) if used is None : continue # Used - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "used", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name - }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = used)] - )] - ) - ) - print("Used: ", post_metric_data_response.data) + postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = used) # Available - post_metric_data_response = monitoring_client.post_metric_data( - post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( - metric_data=[ - oci.monitoring.models.MetricDataDetails( - namespace = "limits_metrics", - compartment_id = compartment_ocid, - name = "available", - dimensions={ - 'service_name': s_name, - 'limit_name': l_name }, - datapoints=[ - oci.monitoring.models.Datapoint( - timestamp=datetime.datetime.strftime( - times_stamp,"%Y-%m-%dT%H:%M:%S.%fZ"), - value = available)] - )] - ) - ) - print("Available: ", post_metric_data_response.data) - + postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["available"]) # Finish: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") From 06fc8e4fce6e2d4c707c6cb9299056a70fe294c2 Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Tue, 25 Jul 2023 13:18:29 +0200 Subject: [PATCH 5/6] updated release notes --- .../custom-metric-python-SDK-services-limit-monitoring/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md index 4e5309d9e..ffd988251 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/README.md @@ -117,6 +117,7 @@ None at this point. There 2 scripts with same code except for the OCI authentication. Both scripts will be maintained in parallel with same versions: +2023-07-25 (version 0.2). compartment_ocid & region are now input arguments. Fixed region wide limits publishing. 2023-07-18 (version 0.1). Initial public release. # LICENSE From 692c92d658540578b34eaf020a847cb316e828e7 Mon Sep 17 00:00:00 2001 From: Pablo Alonso Date: Wed, 2 Aug 2023 13:17:29 +0200 Subject: [PATCH 6/6] Updated and simplified the scripts code --- .../Scripts/postServiceLimitsMetricsIAM.py | 31 +++++++++---------- .../Scripts/postServiceLimitsMetricsIP.py | 31 +++++++++---------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py index 753176302..eea861675 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIAM.py @@ -41,14 +41,17 @@ # Version: 0.2 ### -import oci,datetime,json,argparse +import oci, datetime, json, argparse + from oci.config import from_file from pytz import timezone # Functions definition # postMetric: posts custom monitoring metric information for compartment, metric(used,available,max_limit) and with its dimensions (service, limit name and availability domain(if AD specific)) -def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): +def postMetric(compartment_ocid, m_name, s_name,l_name, value, monitoring_client, a_domain=None): + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) if a_domain is None: post_metric_data_response = monitoring_client.post_metric_data( post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( @@ -93,7 +96,7 @@ def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): return post_metric_data_response # getServiceLimitsUsage: gets the existing limits for a service and limit name in a compartment and, if AD specific, for its AD -def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): +def getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client, a_domain=None): if a_domain is None: # We gather the service limit usage get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid) @@ -189,26 +192,23 @@ def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): a_domain = json.loads(str(AD)) - limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain["name"])) - - # Get the timestamp for setup the monitoring metric post information - times_stamp = datetime.datetime.now(timezone('UTC')) + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client, a_domain["name"])) # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = int(limit_usage["max_limit"]), a_domain = a_domain["name"]) + postMetric(compartment_ocid, "max_limit", s_name, l_name, limit_usage["max_limit"], monitoring_client, a_domain["name"]) # Used - postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["used"], a_domain = a_domain["name"]) + postMetric(compartment_ocid, "used", s_name, l_name, limit_usage["used"], monitoring_client, a_domain = a_domain["name"]) # Available - postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "available", s_name = s_name, l_name = l_name, value = limit_usage["available"], a_domain = a_domain["name"]) + postMetric(compartment_ocid, "available", s_name, l_name, limit_usage["available"], monitoring_client, a_domain = a_domain["name"]) else: # We are in GLOBAL or REGION case - limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid)) + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client)) max_limit = limit_usage["max_limit"] used = limit_usage["used"] @@ -216,22 +216,19 @@ def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): if max_limit == "null" : continue - # Get the timestamp for setup the monitoring metric post information - times_stamp = datetime.datetime.now(timezone('UTC')) - # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = max_limit) + postMetric(compartment_ocid, "max_limit", s_name, l_name, max_limit, monitoring_client) if used is None : continue # Used - postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = used) + postMetric(compartment_ocid, "used", s_name, l_name, used, monitoring_client) # Available - postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["available"]) + postMetric(compartment_ocid, "used", s_name, l_name, limit_usage["available"], monitoring_client) # Finish: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") diff --git a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py index ca33f36bf..b7140cfdf 100644 --- a/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py +++ b/manageability-and-operations/observability-and-manageability/oci-monitoring/custom-metrics/custom-metric-python-SDK-services-limit-monitoring/files/Scripts/postServiceLimitsMetricsIP.py @@ -41,13 +41,16 @@ # Version: 0.2 ### -import oci,datetime,json,argparse +import oci, datetime, json, argparse + from pytz import timezone # Functions definition # postMetric: posts custom monitoring metric information for compartment, metric(used,available,max_limit) and with its dimensions (service, limit name and availability domain(if AD specific)) -def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): +def postMetric(compartment_ocid, m_name, s_name,l_name, value, monitoring_client, a_domain=None): + # Get the timestamp for setup the monitoring metric post information + times_stamp = datetime.datetime.now(timezone('UTC')) if a_domain is None: post_metric_data_response = monitoring_client.post_metric_data( post_metric_data_details=oci.monitoring.models.PostMetricDataDetails( @@ -92,7 +95,7 @@ def postMetric(compartment_ocid, m_name, s_name,l_name, value, a_domain=None): return post_metric_data_response # getServiceLimitsUsage: gets the existing limits for a service and limit name in a compartment and, if AD specific, for its AD -def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): +def getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client, a_domain=None): if a_domain is None: # We gather the service limit usage get_resource_availability_response = limits_client.get_resource_availability(service_name = s_name, limit_name = l_name, compartment_id = compartment_ocid) @@ -188,26 +191,23 @@ def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): a_domain = json.loads(str(AD)) - limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain["name"])) - - # Get the timestamp for setup the monitoring metric post information - times_stamp = datetime.datetime.now(timezone('UTC')) + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client, a_domain["name"])) # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = int(limit_usage["max_limit"]), a_domain = a_domain["name"]) + postMetric(compartment_ocid, "max_limit", s_name, l_name, limit_usage["max_limit"], monitoring_client, a_domain = a_domain["name"]) # Used - postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["used"], a_domain = a_domain["name"]) + postMetric(compartment_ocid, "used", s_name, l_name, limit_usage["used"], monitoring_client, a_domain = a_domain["name"]) # Available - postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "available", s_name = s_name, l_name = l_name, value = limit_usage["available"], a_domain = a_domain["name"]) + postMetric(compartment_ocid, "available", s_name, l_name, limit_usage["available"], monitoring_client, a_domain = a_domain["name"]) else: # We are in GLOBAL or REGION case - limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid)) + limit_usage = json.loads(getServiceLimitsUsage(s_name, l_name, compartment_ocid, limits_client)) max_limit = limit_usage["max_limit"] used = limit_usage["used"] @@ -215,22 +215,19 @@ def getServiceLimitsUsage(s_name, l_name, compartment_ocid, a_domain=None): if max_limit == "null" : continue - # Get the timestamp for setup the monitoring metric post information - times_stamp = datetime.datetime.now(timezone('UTC')) - # Posting custom metrics to oci monitoring for each of the metrics (max, used, available) # Max limit - postMetricMax = postMetric(compartment_ocid = compartment_ocid, m_name = "max_limit", s_name = s_name, l_name = l_name, value = max_limit) + postMetric(compartment_ocid, "max_limit", s_name, l_name, max_limit, monitoring_client) if used is None : continue # Used - postMetricUsed = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = used) + postMetric(compartment_ocid, "used", s_name, l_name, used, monitoring_client) # Available - postMetricAvail = postMetric(compartment_ocid = compartment_ocid, m_name = "used", s_name = s_name, l_name = l_name, value = limit_usage["available"]) + postMetric(compartment_ocid, "used", s_name, l_name, limit_usage["available"], monitoring_client) # Finish: now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S")