From 53fd619323dc8db8fc8a43cf2a55ed1a52f3c74c Mon Sep 17 00:00:00 2001 From: "saul.gill" Date: Wed, 20 Aug 2025 13:44:03 +0100 Subject: [PATCH] Updated ES Rapp version Updated app and chart to 0.2.16 Added ncmp-sdnc query functionality Added teiv query functionality Updated README with smo install flafour info Altered NRCellDU name parsing Added retrieval of influx token from environment Issue-ID: NONRTRIC-1083 Change-Id: I714ca70b6a11a497876ca45e4ff364930fb3dc1a Signed-off-by: saul.gill --- sample-rapp-generator/es-demo-rapp/README.md | 24 +++++ .../Deployment/HELM/energy-saving-chart/Chart.yaml | 4 +- .../resources/config/config.json | 2 + .../energy-saving-chart/templates/deployment.yaml | 5 + .../HELM/energy-saving-chart/values.yaml | 12 ++- .../Deployment/HELM/energy-saving-rapp-0.2.16.tgz | Bin 0 -> 5228 bytes .../Deployment/HELM/energy-saving-rapp-0.2.5.tgz | Bin 5057 -> 0 bytes .../rapp-energy-saving/Definitions/asd.yaml | 2 +- .../Files/Acm/instances/es-instance.json | 4 +- sample-rapp-generator/es-demo-rapp/src/config.json | 6 +- sample-rapp-generator/es-demo-rapp/src/data.py | 14 ++- sample-rapp-generator/es-demo-rapp/src/main.py | 59 ++++++------ .../es-demo-rapp/src/ncmp_client.py | 102 ++++++++++++--------- .../es-demo-rapp/src/teiv_client.py | 20 ++-- 14 files changed, 158 insertions(+), 96 deletions(-) create mode 100644 sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.16.tgz delete mode 100644 sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.5.tgz diff --git a/sample-rapp-generator/es-demo-rapp/README.md b/sample-rapp-generator/es-demo-rapp/README.md index 8b89ab5..0dee90d 100644 --- a/sample-rapp-generator/es-demo-rapp/README.md +++ b/sample-rapp-generator/es-demo-rapp/README.md @@ -21,6 +21,30 @@ The instructions below describe how to: For a complete guide on the installation of the SMO rApp platform, please follow the instructions [here](https://gerrit.o-ran-sc.org/r/gitweb?p=it/dep.git;a=blob_plain;f=smo-install/README.md;hb=HEAD). +As an additional note, a special flavour of the SMO installation is available for the Energy Saving rApp demo. +This flavour is located in the `smo-install/helm-override/ranpm-pynts-es-rapp` directory. +There is some detail on flavours [here](https://github.com/o-ran-sc/it-dep/blob/master/smo-install/README.md). +This flavour is designed to install the SMO components required for the Energy Saving rapp demo. +After all the other steps in the SMO installation guide are completed, you can run the following command to +install the Energy Saving rApp flavour: + +```bash +./dep/smo-install/scripts/layer-2/2-install-oran.sh ranpm-pynts-es-rapp dev +``` + +Once all the components are installed and ready, you can proceed with the install of the DU simulators. +These will start a flow of sample data through the system, which will be used by the Energy Saving rApp demo. +wait around 10 minutes after all the components are installed before proceeding with the next simulator install. + +```bash +./dep/smo-install/scripts/layer-2/2-install-simulators.sh ranpm-pynts-es-rapp +``` + +```text +NOTE: The installation is just pointed at with the above commands. For the full installation and details of flavours, go to the smo installation docs. +``` +[SMO Install Guide](https://github.com/o-ran-sc/it-dep/blob/master/smo-install/README.md) + ### Energy Saving rApp Deployment Preparation 1. The rApp needs to know the address and port of your chart repository. We can do this by running the following command: ```bash diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/Chart.yaml b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/Chart.yaml index 2fd7fe3..c3680e8 100644 --- a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/Chart.yaml +++ b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/Chart.yaml @@ -32,10 +32,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.5 +version: 0.2.16 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.2.5" +appVersion: "0.2.16" diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/resources/config/config.json b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/resources/config/config.json index e473291..6a25026 100644 --- a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/resources/config/config.json +++ b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/resources/config/config.json @@ -7,6 +7,8 @@ "ncmp_api_name": "{{ .Values.ncmp.apiName }}", "ncmp_resource_name": "{{ .Values.ncmp.resourceName }}", "resource_id": "{{ .Values.ncmp.resourceId}}", + "ncmp_managed_element_id": "{{ .Values.ncmp.managedElementId }}", + "ncmp_gnbdufunction_id": "{{ .Values.ncmp.gnbduFunctionId }}", "influxdb_invoker_id": "{{ .Values.environment.appId }}", "influxdb_api_name": "{{ .Values.influxdb.apiName }}", "influxdb_resource_name": "{{ .Values.influxdb.resourceName }}", diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/templates/deployment.yaml b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/templates/deployment.yaml index 1ce26ac..d624ea6 100644 --- a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/templates/deployment.yaml +++ b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/templates/deployment.yaml @@ -63,6 +63,11 @@ spec: value: {{ .Values.environment.appId | quote }} - name: SME_DISCOVERY_ENDPOINT value: {{ .Values.environment.smeDiscoveryEndpoint | quote }} + - name: INFLUX_TOKEN + valueFrom: + secretKeyRef: + key: token + name: {{ .Values.influxdb.tokenSecretName | quote }} volumeMounts: - mountPath: /app/config.json name: config diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/values.yaml b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/values.yaml index 890579a..885b4dd 100644 --- a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/values.yaml +++ b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-chart/values.yaml @@ -25,7 +25,7 @@ image: repository: "nexus3.onap.org:10001/estdemoimages/es-rapp" pullPolicy: Always # Overrides the image tag whose default is the chart appVersion. - tag: "0.2.5" + tag: "0.2.16" imagePullSecrets: [] nameOverride: "energy-saving-rapp" @@ -103,13 +103,15 @@ environment: influxdb: token: "hIVMgY7vn3M772PSk3yrI2IjeWzybPw0" + # This token secret is part of the smo install. The rapp will expect that this secret is created in the same namespace as the rapp. + tokenSecretName: influxdb-api-token user: "admin" password: "mySuP3rS3cr3tT0keN" bucket: "pm-logg-bucket" org: "est" apiName: "influxdb2-http" resourceName: "root" - timeRange: "-6h" + timeRange: "-5m" measurements: - "ManagedElement=o-du-pynts-1122,ManagedElement=o-du-pynts-1122,GNBDUFunction=1,NRCellDU=1" - "ManagedElement=o-du-pynts-1123,ManagedElement=o-du-pynts-1123,GNBDUFunction=1,NRCellDU=1" @@ -117,9 +119,11 @@ influxdb: ncmp: - apiName: "ncmp-dmi-plugin-http" + apiName: "cps-core-http" resourceName: "root" resourceId: "/_3gpp-common-managed-element:ManagedElement=ManagedElement-002/_3gpp-nr-nrm-gnbdufunction:GNBDUFunction=GNBDUFunction-001/_3gpp-nr-nrm-nrcelldu:NRCellDU=NRCellDU-001/attributes" + managedElementId: "ManagedElement-002" + gnbduFunctionId: "GNBDUFunction-001" kserve: apiName: "es-predictor-http" @@ -128,7 +132,7 @@ kserve: teiv: apiName: "topology-exposure-http" resourceName: "root" - oduFunctionId: "GNBDUFunction-001" + oduFunctionId: "urn:oran:smo:teiv:GNBDUFunction-001" appStartup: command: ["/bin/sh", "-c"] diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.16.tgz b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.16.tgz new file mode 100644 index 0000000000000000000000000000000000000000..1f8013948ea4378a37d98f9543599431b1fd888d GIT binary patch literal 5228 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 literal 0 HcmV?d00001 diff --git a/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.5.tgz b/sample-rapp-generator/es-demo-rapp/rapp-energy-saving/Artifacts/Deployment/HELM/energy-saving-rapp-0.2.5.tgz deleted file mode 100644 index c4b3413df9cbeb3c4197012ae3179be564c6fe0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5057 zcmV;y6F%%8iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PH<$bKADE{mfsn!{khpb4^;3U%9;FJLB4Jk8WexV>#($Ivo#0 zLK12cU;$9Jj-&s62Ma_O1Yag`sJMI0$!%q9VR(t=bwf`NozEb-uOC}`Z z-?g6IR-L)ONkJ+3h`At)1~BP3C{2r>Ex+R*I1v^hC#lqrPT*fSP9Rho0z<~(=WKvE z#S#mLq67!9s85cZrZ@nUrZEYTs>hjBoA}l;_)jhk<9~wU42!R50M?BEqr+CaHvSLV z2c7Nse~I!6;J8%YcTdlI{qx)Y&B^u6@zaX)3gDEbQ%*)>32#o{LZ{U^fXfuqE*)|N zKeCKQ+5*6N##xGeIEiD>@B%m%m``xzJ2je~Q&e5=NrB49{j4EQ0$sRTkHWJwwmL_-YsM2>Yk zwieCOCtC*_NJJHY@`IlFlmytjk!+G}zs}zrXj9CfH|uv>O{xv1|Lv>-a5$ z^nu1$C_(;_5so7mOmnL{h%v)v!P zdwsb45l(ua;OB1dYzHurW6S|Rq+D^pI1nXFs|5Pi%!dRhFKhM0OlwoLqdEKhFUtBg}zZF zEZ}~OwI(94aDWUTh%w9JNQpk=7)cyCVE+q1@(k;WPAFx$ib)12(gRKFYPC8C0L@_o zc${hcn=uB(L~a)9L`bI0kFR07Lv4-(mP)}bEn3bz!#jXXMMS_z$pPunEY#3Y73b0_ z)W!iY0i5ePPRgQ_8g=SfABPzya(c?B#1FEddMJM4EK39Ev|24C;byQ9rD#B6A_*2o z?f?;IY5uxzXHr6?%fHq26kJsDu-nai%-M1EGhWVY$+@Cu3oIYfk2?yy+$?9gYRd zc!=jp{tJdoWGIfOz;Vcu1k*^XvSikzPYbhAU~3(h3}TEX*8d`*ohTI{VVNN-95Xds zatDzK%za~HQ7n|lQ=>#+p-82n`O8)8kx}KzFr5(2sFIK{PCO=3##Xs8ru0VuXmnJ)#v(N@y81+)6V9Ssb%_LPxsxm{0|RqTe&2-zTa8ibE^};?o_? zKgS817+)A>Jf6aUBQ2Yu#2mh#i~4)tR+^A`ABAbA$3VCW!eL9-Zy^Eux&Q zacG#NK}BHdi5DfrOXF-r=sL0GkF^r+-tLXk)KeydQ73+Yh%s)&q2F=SeySj+;1Oj=YL+J zJU;IJb6M)UodnuW0&OROo-qmZ&)wO~aoRrogiXv}S_FX)*Y8#5@QhNMl?$9ZBM~@{ zj~KwM z(@lNK<#P$W%d_*_tIO+~2EPkN z6_Lm8qpy_3SG9^?Tfh0#5;1f0i58)1A~cM%2-ng8Kc6yj!H3!GZH>V0RgFAVx%eU? ziNuMfPe>#);iD*09fI{U`(x&60>UxN4a93pM)0~2*b>>lXDIps#mY$WRq_V_6#xX# zmD*-WbcX@K5Z|lJPDOmhAS_o2-77msi6)4|N?rZZY=ky}A);`PWM~Ye;Zs?`(s=m( z$$c#*A$a#2_u%*Q9_*iAf9#$%bfT_uleRZ)6g)2vufTnLbRQq>pnOAUgdZU9^SC6? zd_+R)tsZl}9(ZPWxw8gMn6ncof@>YDIbJ$2iwUv~M&{M!*=_IS;=Crbltr5=ehe;3 zQ@=VTrVx*p3v@2bokd(ig;YX2uD7XVwRE5*SRxg}>$w9E%WwH@J-c8hh|P*X$=RsPD5rcQ ziWL>!knwxOqZ0Y5jo@`vC}m^+t)tm(d1_gi|J{ypoMJ9~nLcMLz`Fde)2ZiwM|e;ux z(;WggA&RM_h*iyA0<+33;hw~?N;)z%$o0~oBHmKFM!fSFJr{8)^R90!$R)S*{U%aZ zaku^dwdNo=-n?7qG#0WjmDD3%LucjT6NyVXp>hcBKZN%W;nwOhjc%@F&Hq+Zuhge% zwAhWJsy}tVS|u@1F&f}_ZQp9xdB@fnD$CmZpSyw2z;PO@c-Z|f7u;L->BC7c-55H> zIyw!MA#{x6#24dTO?$8+xwOprruk)1!mfzEw@vsZ4YEw16gzU%yT!b!*s-fJh6R+* z@JGfZt_fkWmV6OwFbyiHhg|?|6k@)dyP+8Cyn2m%XyR1f9=C))n^15C7&%!K1V+9K~;af+=|2bu4 z{ueSjB%=hS&)W>XCjaZSJ4f~W@36hy|NSCmoBwU|zis~ar{;f^BUWwaj?gH8Q*Bx= zQ0nB9&q1*TcaylpD{Qj^HZ(H3s&pjKj2##8-)EqNMwm+2SMJs{|M&2x7_+a z#cTj>v8T{F1N+DST`=mt^-qLhMAvDn?7(dHtOih|9^Pc z*{k~hPOG)IJ^%S4W$XX9{(tNLU(ElbG!?r=5O7x5*C#~*)hz{I!T&2626hJzF~^GX zw7s;)zr6QIpCq#z`Ad5Y$_LLDHU$CXlQV|W1j%sxzC`*;;uj~e=1d%#>T}0st1n43 zuUn7FoY?9qr((}b<$O=EaYbQE_6a3%rR8^XvDy!fX~Syq0JLpX-YPm3dmX-pW)vl>nMU~Ywn z(s>|X9|kH-JACKb~KIQf}hvvfI0PQaep&i<+CAusBQbg&Io>9hRu4 zSLW=W3gSy?T8$b*xOrcDC9;93q8U3sDY4K~rJ3jX*$Ur+*G1RRwGBwi`?$d>siIG6 zY)F}ceHvLB<4H6vSm^TEv^iMi#M*N#^Fn+1LAR1)%a6W&)pklJ?B-DAV|UMK&8U2X zEnm>zFrQEf8uk6jb1LOxjqnAFZ~(2NgM-?8y^*lquA=o0PnQj*yrc^Q?nU#zmHGcT zMPK6@m^JzT-a)5+|I^`qr@hVpU!rXD|84%i&Hw+@{J$QDG-uS6S%Nvp?xbTU3;xA8 z`L~L`<0}@OSP0Dj8Z!r)mK%LY{~8ZXeNFQo>iNRl$0lBSf%3}b0;SNpEZ!1~MJiuF zuncJqW0A1rBrFT5xieQ^Wst`-p1q0W+NLu$B*?Ryc@$yeoHQ$*ml|(4zn3W6_-`BkZR5X}jQ{E*!^{wJkVEN^>E$4sDA$Br^Cei%&rlPT1k>@cn#qyr< zJJqju@60aicI8xVQ*--YwYdS7sMKa11wTkk_3){}8ljjtzH7wToQBMG`m1CcP3v9_ z{jVVxR`Hh1KJG89Q`S~P*NmCx4Hwh6t@d<&(O`M?W}(f+h1De{#$4fG@AoT&U~hp~ z2AkhHSev-DSfv{!@<~obYtw>7!{XumT0w<0|J|5kRDSR*#%p<~5SQPbs9MtZRVr=iAKOR`0;5V&~eE-@v#+TV6jwUFKzewPQ}kP5JtUWgTJ40EKtB zzMNAKzSP!jMCsxJVCgE(YFTD1szqPc*)V-hvt)p|!OtDx0($wBLL*hZ4QQ~S#k%L3 z=IZip$e#ZSnd8d*FApRB-2AVzx7Tp~dprOCB4wNZZS%iv{`d0x|Lu{-zsBsnEJBE- zSN@cC33>MB?6rG;%rvTTn5C^mOa89qSnwys3oEu?{|Pg3HNL*$gxueB zY4vYW8vOsNBcET?#ybChbZ}7j|NHH|t^a?C^5_7#{fl!qfJZ$lU43_bz9Ib<+a2j{ z^#sG(4eYa-yJPAbGoi8dH!$=M`$8oPZUB4jgQElch=xgeOX!5%VSY=Z6^)wR`SVsZ zCQ8YzPLQg2>YZ=DDNskrm3=8*`8xw8