E2 restart handling added 15/6915/9
authorAnssi Mannila <anssi.mannila@nokia.com>
Fri, 22 Oct 2021 06:52:02 +0000 (09:52 +0300)
committerAnssi Mannila <anssi.mannila@nokia.com>
Wed, 3 Nov 2021 07:24:07 +0000 (09:24 +0200)
- Implementation and unit test are ready

Change-Id: I7b5c52826910a4dcafff8938d414d7e9f57fa2ed
Signed-off-by: Anssi Mannila <anssi.mannila@nokia.com>
16 files changed:
config/submgr-config.yaml
container-tag.yaml
docs/user-guide.rst
go.mod
go.sum
pkg/control/control.go
pkg/control/e2if_state.go [new file with mode: 0644]
pkg/control/e2if_state_test.go [new file with mode: 0644]
pkg/control/metrics.go
pkg/control/registry.go
pkg/control/subscription.go
pkg/control/types.go
pkg/control/ut_ctrl_submgr_test.go
pkg/control/ut_messaging_test.go
pkg/teststube2ap/stubE2.go
releases/container-release-ric-plt-submgr.yaml

index 53d2161..4851734 100644 (file)
@@ -22,6 +22,7 @@
   "e2tRecvMsgTimeout_ms": 2000
   "e2tMaxSubReqTryCount": 2
   "e2tMaxSubDelReqTryCount": 2
+  "checkE2State:" "true"
   "readSubsFromDb": "true"
   "dbTryCount": 200
   "dbRetryForever": "true"
index 1f7b321..8832f84 100644 (file)
@@ -2,4 +2,4 @@
 # By default this file is in the docker build directory,
 # but the location can configured in the JJB template.
 ---
-tag: "0.7.1"
+tag: "0.7.2"
index b376654..2fc08ec 100755 (executable)
@@ -358,6 +358,12 @@ Architecture
     
     Restoring subscriptions from db can be disable via submgr-config.yaml file by setting "readSubsFromDb": "false".
 
+  * E2 connection break
+
+    Subscription Manager subscribes E2 connection status notifications from RNIB. Whenever E2 interface goes up or down Subscription Manager gets notifies. When interface is down
+    subscription is not possible. Subscription Manager rejects new request for the E2 node. Http Reject cause is 503 Subscribe Service Unavailable. When interface goes down
+    Subscription Manager deletes all subscriptions related to the RanName from its memory and database. E2 node and XApp are expected to do the same.
+
 Metrics
 -------
  Subscription Manager adds following statistic counters:
diff --git a/go.mod b/go.mod
index 62a10a5..c8f8b02 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module gerrit.o-ran-sc.org/r/ric-plt/submgr
 
-go 1.12
+go 1.14
 
 replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.8.0
 
@@ -12,6 +12,7 @@ replace gerrit.o-ran-sc.org/r/ric-plt/e2ap => ./e2ap/
 
 require (
        gerrit.o-ran-sc.org/r/ric-plt/e2ap v0.0.0-00010101000000-000000000000
+       gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.2.1
        gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.8.0
        gerrit.o-ran-sc.org/r/ric-plt/xapp-frame v0.0.0-00010101000000-000000000000
        github.com/go-openapi/errors v0.19.3
diff --git a/go.sum b/go.sum
index a0fa7a9..c36348a 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,3 @@
-cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 gerrit.o-ran-sc.org/r/com/golog.git v0.0.2 h1:Ix6SgFuzd6yW6Ur6+qDlGhDO65UYs8PiIkeAL1VaQ2o=
 gerrit.o-ran-sc.org/r/com/golog.git v0.0.2/go.mod h1:A7hUL52YQSO4dFIZNcj76XQ09C9PftAe3LyL7kqBnok=
@@ -16,22 +15,16 @@ gerrit.o-ran-sc.org/r/ric-plt/xapp-frame.git v0.9.3 h1:JokT2aaJkKjYFMayvZHvGb+/I
 gerrit.o-ran-sc.org/r/ric-plt/xapp-frame.git v0.9.3/go.mod h1:foKMPQZ+RlM0Pos2GlEPAg6ux7Y9PRQmCUglYM7/Qt8=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
 github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
@@ -39,45 +32,30 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
-github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
 github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
@@ -87,7 +65,6 @@ github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOX
 github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
 github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
 github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
-github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
 github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
 github.com/go-openapi/errors v0.19.3 h1:7MGZI1ibQDLasvAz8HuhvYk9eNJbJkCOXWsSjjMS+Zc=
 github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
@@ -137,13 +114,9 @@ github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -154,13 +127,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -169,36 +139,24 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU=
 github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
 github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -214,11 +172,9 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
@@ -227,7 +183,6 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -248,21 +203,14 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/segmentio/ksuid v1.0.3 h1:FoResxvleQwYiPAVKe1tMUlEirodZqlqglIuFsdDntY=
 github.com/segmentio/ksuid v1.0.3/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -285,36 +233,25 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68=
 github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
 go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
 go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
 go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56 h1:ZpKuNIejY8P0ExLOVyKhb0WsgG8UdvHXe6TWjY7eL6k=
 golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -326,16 +263,13 @@ golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
 golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -345,7 +279,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -356,7 +289,6 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -364,16 +296,12 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190617190820-da514acc4774 h1:CQVOmarCBFzTx0kbOU0ru54Cvot8SdSrNYjZPhQl+gk=
 golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -382,27 +310,21 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
 google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099 h1:XJP7lxbSxWLOMNdBE4B/STaqVy6L73o0knwj2vIlxnw=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
 k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
index 848b916..87c81ff 100755 (executable)
@@ -71,6 +71,7 @@ var e2tRecvMsgTimeout time.Duration
 var waitRouteCleanup_ms time.Duration
 var e2tMaxSubReqTryCount uint64    // Initial try + retry
 var e2tMaxSubDelReqTryCount uint64 // Initial try + retry
+var checkE2State string
 var readSubsFromDb string
 var dbRetryForever string
 var dbTryCount int
@@ -81,6 +82,8 @@ type Control struct {
        registry          *Registry
        tracker           *Tracker
        restDuplicateCtrl *DuplicateCtrl
+       e2IfState         *E2IfState
+       e2IfStateDb       XappRnibInterface
        e2SubsDb          Sdlnterface
        restSubsDb        Sdlnterface
        CntRecvMsg        uint64
@@ -136,15 +139,21 @@ func NewControl() *Control {
        restDuplicateCtrl := new(DuplicateCtrl)
        restDuplicateCtrl.Init()
 
+       e2IfState := new(E2IfState)
+
        c := &Control{e2ap: new(E2ap),
                registry:          registry,
                tracker:           tracker,
                restDuplicateCtrl: restDuplicateCtrl,
+               e2IfState:         e2IfState,
+               e2IfStateDb:       CreateXappRnibIfInstance(),
                e2SubsDb:          CreateSdl(),
                restSubsDb:        CreateRESTSdl(),
                Counters:          xapp.Metric.RegisterCounterGroup(GetMetricsOpts(), "SUBMGR"),
                LoggerLevel:       4,
        }
+
+       e2IfState.Init(c)
        c.ReadConfigParameters("")
 
        // Register REST handler for testing support
@@ -229,64 +238,83 @@ func (c *Control) ReadRESTSubscriptions() error {
 //-------------------------------------------------------------------
 func (c *Control) ReadConfigParameters(f string) {
 
+       xapp.Logger.Debug("ReadConfigParameters")
+
        c.LoggerLevel = int(xapp.Logger.GetLevel())
-       xapp.Logger.Debug("LoggerLevel %v", c.LoggerLevel)
+       xapp.Logger.Debug("LoggerLevel= %v", c.LoggerLevel)
 
        // viper.GetDuration returns nanoseconds
        e2tSubReqTimeout = viper.GetDuration("controls.e2tSubReqTimeout_ms") * 1000000
        if e2tSubReqTimeout == 0 {
                e2tSubReqTimeout = 2000 * 1000000
+               xapp.Logger.Debug("WARNING: Using hard coded default value for e2tSubReqTimeout")
        }
-       xapp.Logger.Debug("e2tSubReqTimeout %v", e2tSubReqTimeout)
+       xapp.Logger.Debug("e2tSubReqTimeout= %v", e2tSubReqTimeout)
 
        e2tSubDelReqTime = viper.GetDuration("controls.e2tSubDelReqTime_ms") * 1000000
        if e2tSubDelReqTime == 0 {
                e2tSubDelReqTime = 2000 * 1000000
+               xapp.Logger.Debug("WARNING: Using hard coded default value for e2tSubDelReqTime")
        }
-       xapp.Logger.Debug("e2tSubDelReqTime %v", e2tSubDelReqTime)
+       xapp.Logger.Debug("e2tSubDelReqTime= %v", e2tSubDelReqTime)
+
        e2tRecvMsgTimeout = viper.GetDuration("controls.e2tRecvMsgTimeout_ms") * 1000000
        if e2tRecvMsgTimeout == 0 {
                e2tRecvMsgTimeout = 2000 * 1000000
+               xapp.Logger.Debug("WARNING: Using hard coded default value for e2tRecvMsgTimeout")
        }
-       xapp.Logger.Debug("e2tRecvMsgTimeout %v", e2tRecvMsgTimeout)
+       xapp.Logger.Debug("e2tRecvMsgTimeout= %v", e2tRecvMsgTimeout)
 
        e2tMaxSubReqTryCount = viper.GetUint64("controls.e2tMaxSubReqTryCount")
        if e2tMaxSubReqTryCount == 0 {
                e2tMaxSubReqTryCount = 1
+               xapp.Logger.Debug("WARNING: Using hard coded default value for e2tMaxSubReqTryCount")
        }
-       xapp.Logger.Debug("e2tMaxSubReqTryCount %v", e2tMaxSubReqTryCount)
+       xapp.Logger.Debug("e2tMaxSubReqTryCount= %v", e2tMaxSubReqTryCount)
 
        e2tMaxSubDelReqTryCount = viper.GetUint64("controls.e2tMaxSubDelReqTryCount")
        if e2tMaxSubDelReqTryCount == 0 {
                e2tMaxSubDelReqTryCount = 1
+               xapp.Logger.Debug("WARNING: Using hard coded default value for e2tMaxSubDelReqTryCount")
+       }
+       xapp.Logger.Debug("e2tMaxSubDelReqTryCount= %v", e2tMaxSubDelReqTryCount)
+
+       checkE2State = viper.GetString("controls.checkE2State")
+       if checkE2State == "" {
+               checkE2State = "true"
+               xapp.Logger.Debug("WARNING: Using hard coded default value for checkE2State")
        }
-       xapp.Logger.Debug("e2tMaxSubDelReqTryCount %v", e2tMaxSubDelReqTryCount)
+       xapp.Logger.Debug("checkE2State= %v", checkE2State)
 
        readSubsFromDb = viper.GetString("controls.readSubsFromDb")
        if readSubsFromDb == "" {
                readSubsFromDb = "true"
+               xapp.Logger.Debug("WARNING: Using hard coded default value for readSubsFromDb")
        }
-       xapp.Logger.Debug("readSubsFromDb %v", readSubsFromDb)
+       xapp.Logger.Debug("readSubsFromDb= %v", readSubsFromDb)
 
        dbTryCount = viper.GetInt("controls.dbTryCount")
        if dbTryCount == 0 {
                dbTryCount = 200
+               xapp.Logger.Debug("WARNING: Using hard coded default value for dbTryCount")
        }
-       xapp.Logger.Debug("dbTryCount %v", dbTryCount)
+       xapp.Logger.Debug("dbTryCount= %v", dbTryCount)
 
        dbRetryForever = viper.GetString("controls.dbRetryForever")
        if dbRetryForever == "" {
                dbRetryForever = "true"
+               xapp.Logger.Debug("WARNING: Using hard coded default value for dbRetryForever")
        }
-       xapp.Logger.Debug("dbRetryForever %v", dbRetryForever)
+       xapp.Logger.Debug("dbRetryForever= %v", dbRetryForever)
 
        // Internal cfg parameter, used to define a wait time for RMR route clean-up. None default
        // value 100ms used currently only in unittests.
        waitRouteCleanup_ms = viper.GetDuration("controls.waitRouteCleanup_ms") * 1000000
        if waitRouteCleanup_ms == 0 {
                waitRouteCleanup_ms = 5000 * 1000000
+               xapp.Logger.Debug("WARNING: Using hard coded default value for waitRouteCleanup_ms")
        }
-       xapp.Logger.Debug("waitRouteCleanup %v", waitRouteCleanup_ms)
+       xapp.Logger.Debug("waitRouteCleanup= %v", waitRouteCleanup_ms)
 }
 
 //-------------------------------------------------------------------
@@ -389,6 +417,12 @@ func (c *Control) RESTSubscriptionHandler(params interface{}) (*models.Subscript
                c.PrintRESTSubscriptionRequest(p)
        }
 
+       if c.e2IfState.IsE2ConnectionUp(p.Meid) == false {
+               xapp.Logger.Error("No E2 connection for ranName %v", *p.Meid)
+               c.UpdateCounter(cRestReqRejDueE2Down)
+               return nil, common.SubscribeServiceUnavailableCode
+       }
+
        if p.ClientEndpoint == nil {
                err := fmt.Errorf("ClientEndpoint == nil")
                xapp.Logger.Error("%v", err)
@@ -566,15 +600,25 @@ func (c *Control) handleSubscriptionRequest(trans *TransactionXapp, subReqMsg *e
        //
        // Wake subs request
        //
+       subs.OngoingReqCount++
        go c.handleSubscriptionCreate(subs, trans, e2SubscriptionDirectives)
        event, _ := trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
+       subs.OngoingReqCount--
 
        err = nil
        if event != nil {
                switch themsg := event.(type) {
                case *e2ap.E2APSubscriptionResponse:
                        trans.Release()
-                       return themsg, &errorInfo, nil
+                       if c.e2IfState.IsE2ConnectionUp(meid) == true {
+                               return themsg, &errorInfo, nil
+                       } else {
+                               c.registry.RemoveFromSubscription(subs, trans, waitRouteCleanup_ms, c)
+                               c.RemoveSubscriptionFromDb(subs)
+                               err = fmt.Errorf("E2 interface down")
+                               errorInfo.SetInfo(err.Error(), models.SubscriptionInstanceErrorSourceE2Node, "")
+                               return nil, &errorInfo, err
+                       }
                case *e2ap.E2APSubscriptionFailure:
                        err = fmt.Errorf("E2 SubscriptionFailure received")
                        errorInfo.SetInfo(err.Error(), models.SubscriptionInstanceErrorSourceE2Node, "")
@@ -638,6 +682,11 @@ func (c *Control) sendUnsuccesfullResponseNotification(restSubId *string, restSu
 
        c.UpdateCounter(cRestSubFailNotifToXapp)
        xapp.Subscription.Notify(resp, *clientEndpoint)
+
+       if c.e2IfState.IsE2ConnectionUp(&restSubscription.Meid) == false && restSubscription.SubReqOngoing == false {
+               c.registry.DeleteRESTSubscription(restSubId)
+               c.RemoveRESTSubscriptionFromDb(*restSubId)
+       }
 }
 
 //-------------------------------------------------------------------
@@ -667,6 +716,11 @@ func (c *Control) sendSuccesfullResponseNotification(restSubId *string, restSubs
 
        c.UpdateCounter(cRestSubNotifToXapp)
        xapp.Subscription.Notify(resp, *clientEndpoint)
+
+       if c.e2IfState.IsE2ConnectionUp(&restSubscription.Meid) == false && restSubscription.SubReqOngoing == false {
+               c.registry.DeleteRESTSubscription(restSubId)
+               c.RemoveRESTSubscriptionFromDb(*restSubId)
+       }
 }
 
 //-------------------------------------------------------------------
@@ -684,14 +738,17 @@ func (c *Control) RESTSubscriptionDeleteHandler(restSubId string) int {
                xapp.Logger.Error("%s", err.Error())
                if restSubscription == nil {
                        // Subscription was not found
+                       c.UpdateCounter(cRestSubDelRespToXapp)
                        return common.UnsubscribeNoContentCode
                } else {
                        if restSubscription.SubReqOngoing == true {
                                err := fmt.Errorf("Handling of the REST Subscription Request still ongoing %s", restSubId)
                                xapp.Logger.Error("%s", err.Error())
+                               c.UpdateCounter(cRestSubDelFailToXapp)
                                return common.UnsubscribeBadRequestCode
                        } else if restSubscription.SubDelReqOngoing == true {
                                // Previous request for same restSubId still ongoing
+                               c.UpdateCounter(cRestSubDelFailToXapp)
                                return common.UnsubscribeBadRequestCode
                        }
                }
@@ -716,7 +773,6 @@ func (c *Control) RESTSubscriptionDeleteHandler(restSubId string) int {
        }()
 
        c.UpdateCounter(cRestSubDelRespToXapp)
-
        return common.UnsubscribeNoContentCode
 }
 
@@ -750,8 +806,10 @@ func (c *Control) SubscriptionDeleteHandler(restSubId *string, endPoint *string,
        //
        // Wake subs delete
        //
+       subs.OngoingDelCount++
        go c.handleSubscriptionDelete(subs, trans)
        trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
+       subs.OngoingDelCount--
 
        xapp.Logger.Debug("XAPP-SubDelReq: Handling event %s ", idstring(nil, trans, subs))
 
@@ -891,6 +949,11 @@ func (c *Control) handleXAPPSubscriptionRequest(params *xapp.RMRParams) {
        xapp.Logger.Debug("MSG from XAPP: %s", params.String())
        c.UpdateCounter(cSubReqFromXapp)
 
+       if c.e2IfState.IsE2ConnectionUp(&params.Meid.RanName) == false {
+               xapp.Logger.Error("No E2 connection for ranName %v", params.Meid.RanName)
+               return
+       }
+
        subReqMsg, err := c.e2ap.UnpackSubscriptionRequest(params.Payload)
        if err != nil {
                xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, params))
@@ -925,8 +988,10 @@ func (c *Control) handleXAPPSubscriptionRequest(params *xapp.RMRParams) {
 func (c *Control) wakeSubscriptionRequest(subs *Subscription, trans *TransactionXapp) {
 
        e2SubscriptionDirectives, _ := c.GetE2SubscriptionDirectives(nil)
+       subs.OngoingReqCount++
        go c.handleSubscriptionCreate(subs, trans, e2SubscriptionDirectives)
        event, _ := trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
+       subs.OngoingReqCount--
        var err error
        if event != nil {
                switch themsg := event.(type) {
@@ -961,6 +1026,11 @@ func (c *Control) handleXAPPSubscriptionDeleteRequest(params *xapp.RMRParams) {
        xapp.Logger.Debug("MSG from XAPP: %s", params.String())
        c.UpdateCounter(cSubDelReqFromXapp)
 
+       if c.e2IfState.IsE2ConnectionUp(&params.Meid.RanName) == false {
+               xapp.Logger.Error("No E2 connection for ranName %v", params.Meid.RanName)
+               return
+       }
+
        subDelReqMsg, err := c.e2ap.UnpackSubscriptionDeleteRequest(params.Payload)
        if err != nil {
                xapp.Logger.Error("XAPP-SubDelReq %s", idstring(err, params))
@@ -989,8 +1059,10 @@ func (c *Control) handleXAPPSubscriptionDeleteRequest(params *xapp.RMRParams) {
        //
        // Wake subs delete
        //
+       subs.OngoingDelCount++
        go c.handleSubscriptionDelete(subs, trans)
        trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
+       subs.OngoingDelCount--
 
        xapp.Logger.Debug("XAPP-SubDelReq: Handling event %s ", idstring(nil, trans, subs))
 
diff --git a/pkg/control/e2if_state.go b/pkg/control/e2if_state.go
new file mode 100644 (file)
index 0000000..0f43056
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+package control
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
+       "strings"
+       "sync"
+)
+
+type XappRnibIf struct {
+       XappRnibInterface
+}
+
+func (x *XappRnibIf) XappRnibSubscribe(NotificationCb func(string, ...string), channel string) error {
+       return xapp.Rnib.Subscribe(NotificationCb, channel)
+}
+
+func (x *XappRnibIf) XappRnibGetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError) {
+       return xapp.Rnib.GetListGnbIds()
+}
+func (x *XappRnibIf) XappRnibGetNodeb(inventoryName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError) {
+       nodeInfo, err := xapp.Rnib.GetNodeb(inventoryName)
+       return nodeInfo, err
+}
+
+func CreateXappRnibIfInstance() XappRnibInterface {
+       return new(XappRnibIf)
+}
+
+type E2IfState struct {
+       mutex   sync.Mutex
+       control *Control
+       NbIdMap map[string]string
+}
+
+func (e *E2IfState) Init(c *Control) {
+       e.control = c
+       e.NbIdMap = make(map[string]string, 0)
+       e.ReadE2ConfigurationFromRnib()
+       e.SubscribeChannels()
+}
+
+func (e *E2IfState) NotificationCb(ch string, events ...string) {
+
+       xapp.Logger.Debug("SDL notification received from channel=%s, event=%v", ch, events[0])
+       if len(events) == 0 {
+               xapp.Logger.Error("Invalid SDL notification received: %d", len(events))
+               return
+       }
+
+       if strings.Contains(events[0], "_CONNECTED") {
+               nbId, err := ExtractNbiIdFromString(events[0])
+               if err != nil {
+                       xapp.Logger.Error("NotificationCb CONNECTED len(nbId) == 0 ")
+                       return
+               }
+               xapp.Logger.Debug("E2 CONNECTED. NbId=%s", nbId)
+               e.NbIdMap[nbId] = nbId
+       } else if strings.Contains(events[0], "_DISCONNECTED") {
+               nbId, err := ExtractNbiIdFromString(events[0])
+               if err != nil {
+                       xapp.Logger.Error("NotificationCb DISCONNECTED len(nbId) == 0 ")
+                       return
+               }
+               xapp.Logger.Debug("E2 DISCONNECTED. NbId=%s", nbId)
+               if _, ok := e.NbIdMap[nbId]; ok {
+                       delete(e.NbIdMap, nbId)
+                       e.control.registry.DeleteAllE2Subscriptions(nbId, e.control)
+               }
+       }
+}
+
+func (e *E2IfState) SubscribeChannels() error {
+
+       if err := e.control.e2IfStateDb.XappRnibSubscribe(e.NotificationCb, "RAN_CONNECTION_STATUS_CHANGE"); err != nil {
+               xapp.Logger.Error("Sdl.SubscribeChannel failed: %v", err)
+               return err
+       }
+       xapp.Logger.Debug("Subscription to RAN state changes done!")
+       return nil
+}
+
+func (e *E2IfState) ReadE2ConfigurationFromRnib() {
+
+       xapp.Logger.Debug("ReadE2ConfigurationFromRnib()")
+       nbIdentities, err := e.control.e2IfStateDb.XappRnibGetListGnbIds()
+       if err != nil || len(nbIdentities) == 0 {
+               xapp.Logger.Debug("There are no active NodeBs available: %v", err)
+               e.NbIdMap = make(map[string]string, 0)
+               return
+       }
+
+       for _, nbIdentity := range nbIdentities {
+               if e.isNodeBActive(nbIdentity.InventoryName) == false {
+                       if _, ok := e.NbIdMap[nbIdentity.InventoryName]; ok {
+                               delete(e.NbIdMap, nbIdentity.InventoryName)
+                               e.control.UpdateCounter(cE2StateChangedToDown)
+                               xapp.Logger.Debug("E2 connection DISCONNETED: %v", nbIdentity.InventoryName)
+
+                               // Delete all subscriptions related to InventoryName/nbId
+                               e.control.registry.DeleteAllE2Subscriptions(nbIdentity.InventoryName, e.control)
+                       }
+                       continue
+               }
+
+               if _, ok := e.NbIdMap[nbIdentity.InventoryName]; !ok {
+                       e.NbIdMap[nbIdentity.InventoryName] = nbIdentity.InventoryName
+                       e.control.UpdateCounter(cE2StateChangedToDown)
+                       xapp.Logger.Debug("E2 connection CONNECTED: %v", nbIdentity.InventoryName)
+               }
+       }
+}
+
+func (e *E2IfState) isNodeBActive(inventoryName string) bool {
+       nodeInfo, err := e.control.e2IfStateDb.XappRnibGetNodeb(inventoryName)
+       if err != nil {
+               xapp.Logger.Error("GetNodeb() failed for inventoryName=%s: %v", inventoryName, err)
+               return false
+       }
+       xapp.Logger.Debug("NodeB['%s'] connection status = %d", inventoryName, nodeInfo.ConnectionStatus)
+       return nodeInfo.ConnectionStatus == 1
+}
+
+func (e *E2IfState) IsE2ConnectionUp(nbId *string) bool {
+
+       if checkE2State == "false" {
+               return true
+       }
+
+       if _, ok := e.NbIdMap[*nbId]; ok {
+               return true
+       } else {
+               return false
+       }
+}
+
+func ExtractNbiIdFromString(s string) (string, error) {
+
+       // Expected string formats are below
+       // gnb_208_092_303030_CONNECTED
+       // gnb_208_092_303030_DISCONNECTED
+       // ...
+
+       var nbId string
+       var err error
+       if strings.Contains(s, "_CONNECTED") {
+               splitStringTbl := strings.Split(s, "_CONNECTED")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_DISCONNECTED") {
+               splitStringTbl := strings.Split(s, "_DISCONNECTED")
+               nbId = splitStringTbl[0]
+       }
+       if len(nbId) == 0 {
+               return "", fmt.Errorf("ExtractNbiIdFromString(): len(nbId) == 0 ")
+       }
+       return nbId, err
+}
diff --git a/pkg/control/e2if_state_test.go b/pkg/control/e2if_state_test.go
new file mode 100644 (file)
index 0000000..e4ee848
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+package control
+
+import (
+       "fmt"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
+       "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
+       "strings"
+       "sync"
+       "testing"
+)
+
+var xappRnibMock *XappRnibMock
+
+type XappRnibMock struct {
+       Mutex            sync.Mutex
+       nbIdentityMap    map[string]xapp.RNIBNbIdentity
+       RNIBNodebInfoMap map[string]xapp.RNIBNodebInfo
+       RnibSubscription RnibSubscription // Submgr can have only one subscription
+}
+
+type RnibSubscription struct {
+       Channel string                            // Subscribed channel/topic "RAN_CONNECTION_STATUS_CHANGE"
+       cb      func(ch string, events ...string) // Submgr's call back function
+}
+
+func CreateXappRnibIfMock() *XappRnibMock {
+       fmt.Println("XappRnibMock: CreateXappRnibIfMock()")
+       xappRnibMock = new(XappRnibMock)
+       xappRnibMock.Init()
+       return xappRnibMock
+}
+
+func (x *XappRnibMock) Init() {
+       x.nbIdentityMap = make(map[string]xapp.RNIBNbIdentity, 0)
+       x.RNIBNodebInfoMap = make(map[string]xapp.RNIBNodebInfo, 0)
+}
+
+func TestMock(t *testing.T) {
+
+       // Current UT test cases use these ran names
+       xappRnibMock.CreateGnb("RAN_NAME_1", entities.ConnectionStatus_CONNECTED)
+       xappRnibMock.CreateGnb("RAN_NAME_11", entities.ConnectionStatus_CONNECTED)
+       xappRnibMock.CreateGnb("RAN_NAME_2", entities.ConnectionStatus_CONNECTED)
+
+       xappRnibMock.CreateGnb("gnb_208_092_303030", entities.ConnectionStatus_CONNECTED) // This same value is used in gnb simulator!
+       xappRnibMock.CreateGnb("gnb_208_092_303030", entities.ConnectionStatus_DISCONNECTED)
+
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_UNKNOWN_CONNECTION_STATUS)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_CONNECTED_SETUP_FAILED)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_CONNECTING)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_CONNECTED)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_SHUTTING_DOWN)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_SHUT_DOWN)
+       xappRnibMock.CreateGnb("gnb_369_11105_aaaaa3", entities.ConnectionStatus_DISCONNECTED)
+
+       mainCtrl.c.e2IfState.ReadE2ConfigurationFromRnib()
+       mainCtrl.c.e2IfState.SubscribeChannels()
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_UNKNOWN_CONNECTION_STATUS", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_CONNECTED_SETUP_FAILED", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_CONNECTING", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_CONNECTED", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_SHUTTING_DOWN", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+       if err := xappRnibMock.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", "gnb_369_11105_aaaaa3_DISCONNECTED", "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+}
+
+func (x *XappRnibMock) CreateGnb(gnbId string, connectionStatus entities.ConnectionStatus) {
+
+       xapp.Logger.Debug("XappRnibMock: CreateGnb() gnbId=%v, ConnectionStatus=%v", gnbId, connectionStatus)
+       nb := xapp.RNIBNodebInfo{}
+       nb.NodeType = xapp.RNIBNodeGNB
+       nb.ConnectionStatus = connectionStatus
+       if nb.ConnectionStatus < 0 || nb.ConnectionStatus > 6 {
+               xapp.Logger.Error("XappRnibMock: CreateGnb() Incorrect connectionStatus=%v", nb.ConnectionStatus)
+               return
+       }
+       nb.Ip = "localhost"
+       nb.Port = 5656
+       gnb := xapp.RNIBGnb{}
+
+       gnb.ServedNrCells = nil
+       nb.Configuration = &xapp.RNIBNodebInfoGnb{Gnb: &gnb}
+       nbIdentity := &xapp.RNIBNbIdentity{
+               InventoryName: gnbId,
+               GlobalNbId: &xapp.RNIBGlobalNbId{
+                       PlmnId: "001EF5",
+                       NbId:   "0045FE50",
+               },
+       }
+
+       err := xappRnibMock.XappRnibSaveNodeb(nbIdentity, &nb)
+       if err != nil {
+               xapp.Logger.Error("XappRnibMock: XappRnibSaveNodeb() failed. Error: %v", err)
+       }
+}
+
+func (x *XappRnibMock) XappRnibSaveNodeb(nbIdentity *xapp.RNIBNbIdentity, nodeb *xapp.RNIBNodebInfo) xapp.RNIBIRNibError {
+
+       xapp.Logger.Debug("XappRnibMock: XappRnibSaveNodeb() inventoryName=%v, ConnectionStatus=%v", nbIdentity.InventoryName, nodeb.ConnectionStatus)
+       x.Mutex.Lock()
+       defer x.Mutex.Unlock()
+       x.nbIdentityMap[nbIdentity.InventoryName] = *nbIdentity
+       x.RNIBNodebInfoMap[nbIdentity.InventoryName] = *nodeb
+       return nil
+}
+
+func (x *XappRnibMock) XappRnibGetNodeb(inventoryName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError) {
+
+       x.Mutex.Lock()
+       defer x.Mutex.Unlock()
+       xapp.Logger.Debug("XappRnibMock: XappRnibGetNodeb() inventoryName=%v", inventoryName)
+       nodebInfo, ok := x.RNIBNodebInfoMap[inventoryName]
+       if ok {
+               return &nodebInfo, nil
+       } else {
+               return nil, fmt.Errorf("XappRnibMock: XappRnibGetNodeb() failed: inventoryName=%s:", inventoryName)
+       }
+}
+
+func (x *XappRnibMock) XappRnibSubscribe(cb func(string, ...string), channel string) error {
+
+       if x.RnibSubscription.Channel == "RAN_CONNECTION_STATUS_CHANGE" {
+               xapp.Logger.Debug("XappRnibMock: RAN_CONNECTION_STATUS_CHANGE channel already subscribed")
+               return nil
+       }
+       if x.RnibSubscription.Channel == "" {
+               x.RnibSubscription.cb = cb
+               x.RnibSubscription.Channel = channel
+               xapp.Logger.Debug("XappRnibMock: RAN_CONNECTION_STATUS_CHANGE subscribed")
+               return nil
+       } else {
+               return fmt.Errorf("XappRnibMock: Invalid channel/topic to subscribe: channel = %s", channel)
+       }
+}
+
+func (x *XappRnibMock) XappRnibGetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError) {
+
+       xapp.Logger.Debug("XappRnibMock: XappRnibGetListGnbIds()")
+       x.Mutex.Lock()
+       defer x.Mutex.Unlock()
+       var nbIdentities []*xapp.RNIBNbIdentity
+       for _, nbIdentity := range x.nbIdentityMap {
+               newNbIdentity := entities.NbIdentity{}
+               newNbIdentity = nbIdentity
+               nbIdentities = append(nbIdentities, &newNbIdentity)
+       }
+       xapp.Logger.Debug("XappRnibMock: XappRnibGetListGnbIds(). len(nbIdentities) = %v", len(nbIdentities))
+       return nbIdentities, nil
+}
+
+func (x *XappRnibMock) XappRnibStoreAndPublish(channel string, event string, pairs ...interface{}) error {
+
+       x.Mutex.Lock()
+       defer x.Mutex.Unlock()
+       xapp.Logger.Debug("XappRnibMock: Change published. channel=%s, event=%s", channel, event)
+       if channel != "RAN_CONNECTION_STATUS_CHANGE" || channel == "" || event == "" {
+               xapp.Logger.Debug("XappRnibMock: Invalid change published. channel=%s, event=%s", channel, event)
+       }
+
+       nbId, connectionStatus, err := ExtratNbIdAndConnectionStatus(event)
+       if err != nil {
+               xapp.Logger.Error("XappRnibMock: ExtratNbIdAndConnectionStatus. Err=%s", err)
+       }
+
+       nbIdentity, ok := x.nbIdentityMap[nbId]
+       if ok {
+               nbIdentity.ConnectionStatus = connectionStatus
+       }
+
+       if x.RnibSubscription.cb != nil {
+               x.RnibSubscription.cb(channel, event)
+       } else {
+               xapp.Logger.Error("XappRnibMock: x.RnibSubscription.cb == nil")
+       }
+       return nil
+}
+
+func ExtratNbIdAndConnectionStatus(s string) (string, entities.ConnectionStatus, error) {
+
+       var connectionStatus entities.ConnectionStatus
+       var nbId string
+       if strings.Contains(s, "_UNKNOWN_CONNECTION_STATUS") {
+               connectionStatus = entities.ConnectionStatus_UNKNOWN_CONNECTION_STATUS
+               splitStringTbl := strings.Split(s, "_UNKNOWN_CONNECTION_STATUS")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_CONNECTED") {
+               connectionStatus = entities.ConnectionStatus_CONNECTED
+               splitStringTbl := strings.Split(s, "_CONNECTED")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_DISCONNECTED") {
+               connectionStatus = entities.ConnectionStatus_DISCONNECTED
+               splitStringTbl := strings.Split(s, "_DISCONNECTED")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_CONNECTED_SETUP_FAILED") {
+               connectionStatus = entities.ConnectionStatus_CONNECTED_SETUP_FAILED
+               splitStringTbl := strings.Split(s, "_CONNECTED_SETUP_FAILED")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_CONNECTING") {
+               connectionStatus = entities.ConnectionStatus_CONNECTING
+               splitStringTbl := strings.Split(s, "_CONNECTING")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_SHUTTING_DOWN") {
+               connectionStatus = entities.ConnectionStatus_SHUTTING_DOWN
+               splitStringTbl := strings.Split(s, "_SHUTTING_DOWN")
+               nbId = splitStringTbl[0]
+       } else if strings.Contains(s, "_SHUT_DOWN") {
+               connectionStatus = entities.ConnectionStatus_SHUT_DOWN
+               splitStringTbl := strings.Split(s, "_SHUT_DOWN")
+               nbId = splitStringTbl[0]
+       } else {
+               return "", 0, fmt.Errorf("XappRnibMock: Invalid connection status. %s", s)
+       }
+       if len(nbId) == 0 {
+               return "", 0, fmt.Errorf("ExtractNbiIdFromString(): len(nbId) == 0 ")
+       }
+       return nbId, connectionStatus, nil
+}
index 0f514b4..8493379 100644 (file)
@@ -11,6 +11,7 @@ const (
        cSubRespToXapp          string = "SubRespToXapp"
        cRestSubRespToXapp      string = "RestSubRespToXapp"
        cRestSubFailToXapp      string = "RestSubFailToXapp"
+       cRestReqRejDueE2Down    string = "RestReqRejDueE2Down"
        cRestSubNotifToXapp     string = "RestSubNotifToXapp"
        cRestSubFailNotifToXapp string = "RestSubFailNotifToXapp"
        cSubReqToE2             string = "SubReqToE2"
@@ -26,6 +27,7 @@ const (
        cSubDelRespToXapp       string = "SubDelRespToXapp"
        cRestSubDelReqFromXapp  string = "RestSubDelReqFromXapp"
        cRestSubDelRespToXapp   string = "RestSubDelRespToXapp"
+       cRestSubDelFailToXapp   string = "RestSubDelFailToXapp"
        cSubDelReqToE2          string = "SubDelReqToE2"
        cSubDelReReqToE2        string = "SubDelReReqToE2"
        cSubDelRespFromE2       string = "SubDelRespFromE2"
@@ -37,6 +39,8 @@ const (
        cSDLWriteFailure        string = "SDLWriteFailure"
        cSDLReadFailure         string = "SDLReadFailure"
        cSDLRemoveFailure       string = "SDLRemoveFailure"
+       cE2StateChangedToUp     string = "E2StateChangedToUp"
+       cE2StateChangedToDown   string = "E2StateChangedToDown"
 )
 
 func GetMetricsOpts() []xapp.CounterOpts {
@@ -49,6 +53,7 @@ func GetMetricsOpts() []xapp.CounterOpts {
                {Name: cRestSubReqFromXapp, Help: "The total number of Rest SubscriptionRequest messages received from xApp"},
                {Name: cRestSubRespToXapp, Help: "The total number of Rest SubscriptionResponse messages sent to xApp"},
                {Name: cRestSubFailToXapp, Help: "The total number of Rest SubscriptionFailure messages sent to xApp"},
+               {Name: cRestReqRejDueE2Down, Help: "The total number of Rest SubscriptionRequest messages rejected due E2 Interface down"},
                {Name: cRestSubNotifToXapp, Help: "The total number of successful Rest SubscriptionNotification messages sent to xApp"},
                {Name: cRestSubFailNotifToXapp, Help: "The total number of failure Rest SubscriptionNotification messages sent to xApp"},
                {Name: cSubReqToE2, Help: "The total number of SubscriptionRequest messages sent to E2Term"},
@@ -66,6 +71,7 @@ func GetMetricsOpts() []xapp.CounterOpts {
                {Name: cSubDelRespToXapp, Help: "The total number of SubscriptionDeleteResponse messages sent to xApp"},
                {Name: cRestSubDelReqFromXapp, Help: "The total number of Rest SubscriptionDeleteRequest messages received from xApp"},
                {Name: cRestSubDelRespToXapp, Help: "The total number of Rest SubscriptionDeleteResponse messages sent to xApp"},
+               {Name: cRestSubDelFailToXapp, Help: "The total number of Rest SubscriptionDeleteFailure messages sent to xApp"},
                {Name: cSubDelReqToE2, Help: "The total number of SubscriptionDeleteRequest messages sent to E2Term"},
                {Name: cSubDelReReqToE2, Help: "The total number of SubscriptionDeleteRequest messages resent to E2Term"},
                {Name: cSubDelRespFromE2, Help: "The total number of SubscriptionDeleteResponse messages from E2Term"},
@@ -79,9 +85,14 @@ func GetMetricsOpts() []xapp.CounterOpts {
                {Name: cSDLWriteFailure, Help: "The total number of SDL write failures"},
                {Name: cSDLReadFailure, Help: "The total number of SDL read failures"},
                {Name: cSDLRemoveFailure, Help: "The total number of SDL read failures"},
+
+               // E2 interface state counters
+               {Name: cE2StateChangedToUp, Help: "The total number of E2 interface change connected state"},
+               {Name: cE2StateChangedToDown, Help: "The total number of E2 interface change disconnected state"},
        }
 }
 
 func (c *Control) UpdateCounter(counterName string) {
+       xapp.Logger.Debug("Add counterName=%v", counterName)
        c.Counters[counterName].Inc()
 }
index 4b48687..8c79540 100644 (file)
@@ -181,6 +181,8 @@ func (r *Registry) allocateSubs(trans *TransactionXapp, subReqMsg *e2ap.E2APSubs
                        Meid:             trans.Meid,
                        RMRRouteCreated:  rmrRoutecreated,
                        SubReqMsg:        subReqMsg,
+                       OngoingReqCount:  0,
+                       OngoingDelCount:  0,
                        valid:            true,
                        PolicyUpdate:     false,
                        RetryFromXapp:    false,
@@ -405,7 +407,6 @@ func (r *Registry) RemoveFromSubscription(subs *Subscription, trans *Transaction
        delStatus := subs.EpList.DelEndpoint(trans.GetEndpoint())
        epamount := subs.EpList.Size()
        subId := subs.ReqId.InstanceId
-
        if delStatus == false {
                return nil
        }
@@ -518,3 +519,49 @@ func (r *Registry) SetResetTestFlag(resetTestFlag bool, subs *Subscription) {
                xapp.Logger.Debug("resetTestFlag == false")
        }
 }
+
+func (r *Registry) DeleteAllE2Subscriptions(ranName string, c *Control) {
+
+       xapp.Logger.Debug("Registry: DeleteAllE2Subscriptions()")
+       for subId, subs := range r.register {
+               if subs.Meid.RanName == ranName {
+                       if subs.OngoingReqCount != 0 || subs.OngoingDelCount != 0 {
+                               // Subscription creation or deletion processes need to be processed gracefully till the end.
+                               // Subscription is deleted at end of the process in both cases.
+                               xapp.Logger.Debug("Registry: E2 subscription under prosessing ongoing cannot delete it yet. subId=%v, OngoingReqCount=%v, OngoingDelCount=%v", subId, subs.OngoingReqCount, subs.OngoingDelCount)
+                               continue
+                       } else {
+                               // Delete route
+                               if subs.RMRRouteCreated == true {
+                                       for _, ep := range subs.EpList.Endpoints {
+                                               tmpList := xapp.RmrEndpointList{}
+                                               tmpList.AddEndpoint(&ep)
+                                               subRouteAction := SubRouteInfo{tmpList, uint16(subs.ReqId.InstanceId)}
+                                               if err := r.rtmgrClient.SubscriptionRequestDelete(subRouteAction); err != nil {
+                                                       c.UpdateCounter(cRouteDeleteFail)
+                                               }
+                                       }
+                               }
+                               // Delete E2 subscription from registry and db
+                               xapp.Logger.Debug("Registry: Subscription delete. subId=%v", subId)
+                               delete(r.register, subId)
+                               r.subIds = append(r.subIds, subId)
+                               c.RemoveSubscriptionFromDb(subs)
+                       }
+               }
+       }
+
+       // Delete REST subscription from registry and db
+       for restSubId, restSubs := range r.restSubscriptions {
+               if restSubs.Meid == ranName && restSubs.SubReqOngoing == true || restSubs.SubDelReqOngoing == true {
+                       // Subscription creation or deletion processes need to be processed gracefully till the end.
+                       // Subscription is deleted at end of the process in both cases.
+                       xapp.Logger.Debug("Registry: REST subscription under prosessing ongoing cannot delete it yet. RestSubId=%v, SubReqOngoing=%v, SubDelReqOngoing=%v", restSubId, restSubs.SubReqOngoing, restSubs.SubDelReqOngoing)
+                       continue
+               } else {
+                       xapp.Logger.Debug("Registry: REST subscription delete. subId=%v", restSubId)
+                       delete(r.restSubscriptions, restSubId)
+                       c.RemoveRESTSubscriptionFromDb(restSubId)
+               }
+       }
+}
index 1152520..58f0adf 100644 (file)
@@ -41,6 +41,8 @@ type Subscription struct {
        TheTrans         TransactionIf                 // Ongoing transaction
        SubReqMsg        *e2ap.E2APSubscriptionRequest // Subscription information
        SubRFMsg         interface{}                   // Subscription information
+       OngoingReqCount  int                           // Subscription create process is ongoing. In merge case it can ongoing for more than one endpoint
+       OngoingDelCount  int                           // Subscription delete process is ongoing. In merge case it can ongoing for more than one endpoint
        PolicyUpdate     bool                          // This is true when policy subscrition is being updated. Used not to send delete for update after timeout or restart
        RetryFromXapp    bool                          // Retry form xApp for subscription that already exist
        SubRespRcvd      bool                          // Subscription response received
index 93cddb0..22c8bc4 100644 (file)
@@ -23,6 +23,7 @@ import (
        "time"
 
        "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
+       "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
 )
 
 //-----------------------------------------------------------------------------
@@ -71,3 +72,10 @@ func (e *ErrorInfo) SetInfo(errorCause string, errorSource string, timeoutType s
        e.ErrorSource = errorSource
        e.TimeoutType = timeoutType
 }
+
+type XappRnibInterface interface {
+       XappRnibSubscribe(cb func(string, ...string), channel string) error
+       XappRnibGetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError)
+       XappRnibStoreAndPublish(channel string, event string, pairs ...interface{}) error
+       XappRnibGetNodeb(inventoryName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError)
+}
index e514cb0..8d559bd 100644 (file)
@@ -59,8 +59,9 @@ func createSubmgrControl(srcId teststub.RmrSrcId, rtgSvc teststub.RmrRtgSvc) *te
        mainCtrl.c.LoggerLevel = int(xapp.Logger.GetLevel())
        xapp.Logger.Debug("Test: LoggerLevel %v", mainCtrl.c.LoggerLevel)
        xapp.Logger.Debug("Replacing real db with test db")
-       mainCtrl.c.e2SubsDb = CreateMock()             // This overrides real E2 Subscription database for testing
-       mainCtrl.c.restSubsDb = CreateRestSubsDbMock() // This overrides real REST Subscription database for testing
+       mainCtrl.c.e2SubsDb = CreateMock()              // This overrides real E2 Subscription database for testing
+       mainCtrl.c.restSubsDb = CreateRestSubsDbMock()  // This overrides real REST Subscription database for testing
+       mainCtrl.c.e2IfStateDb = CreateXappRnibIfMock() // This overrides real RNIB database for testing
        xapp.SetReadyCB(mainCtrl.ReadyCB, nil)
        go xapp.RunWithParams(mainCtrl.c, false)
        mainCtrl.WaitCB()
@@ -337,7 +338,7 @@ func (mc *testingSubmgrControl) VerifyCounterValues(t *testing.T) {
                }
        }
 
-       // Check that not any unexpected counter are added
+       // Check that not any unexpected counter are added (this is not working correctly!)
        for _, currentCounter := range currentCountersMap {
                if _, ok := toBeAddedCountersMap[currentCounter.Name]; ok == false {
                        if beforeCounter, ok := countersBeforeMap[currentCounter.Name]; ok == true {
@@ -455,3 +456,13 @@ func (mc *testingSubmgrControl) sendPostRequest(t *testing.T, addr string, path
        mc.TestLog(t, "%s", respBody)
        return
 }
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func (mc *testingSubmgrControl) SetE2State(t *testing.T, ranNameState string) {
+
+       if err := mc.c.e2IfStateDb.XappRnibStoreAndPublish("RAN_CONNECTION_STATUS_CHANGE", ranNameState, "key1", "data1"); err != nil {
+               t.Errorf("XappRnibStoreAndPublish failed: %v", err)
+       }
+}
index e10cdff..fd411bf 100644 (file)
 package control
 
 import (
+       //"os"
        "strings"
        "testing"
        "time"
 
        "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
        "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap_wrapper"
+       "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
        "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/teststube2ap"
        "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
        "github.com/stretchr/testify/assert"
 )
 
 func TestSuiteSetup(t *testing.T) {
-       // The effect of this call shall endure thgough the UT suite!
-       // If this causes any issues, the previout interface can be restored
+       // The effect of this call shall endure though the UT suite!
+       // If this causes any issues, the previous interface can be restored
        // like this:git log
        // SetPackerIf(e2ap_wrapper.NewAsn1E2APPacker())
 
        SetPackerIf(e2ap_wrapper.NewUtAsn1E2APPacker())
-
        mainCtrl.c.restDuplicateCtrl.Init()
 
 }
+func TestRanStatusChangeViaSDLNotification(t *testing.T) {
+
+       // Current UT test cases use these ran names
+       xappRnibMock.CreateGnb("RAN_NAME_1", entities.ConnectionStatus_DISCONNECTED)
+       xappRnibMock.CreateGnb("RAN_NAME_11", entities.ConnectionStatus_DISCONNECTED)
+       xappRnibMock.CreateGnb("RAN_NAME_2", entities.ConnectionStatus_DISCONNECTED)
+
+       mainCtrl.c.e2IfState.ReadE2ConfigurationFromRnib()
+       mainCtrl.c.e2IfState.SubscribeChannels()
+
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED")
+       mainCtrl.SetE2State(t, "RAN_NAME_2_CONNECTED")
+       mainCtrl.SetE2State(t, "RAN_NAME_11_CONNECTED")
+}
+
+//-----------------------------------------------------------------------------
+// TestRESTSubReqAfterE2ConnBreak
+//
+//   stub                             stub
+// +-------+        +---------+    +---------+
+// | xapp  |        | submgr  |    | e2term  |
+// +-------+        +---------+    +---------+
+//     |                 |              |
+//     |         [E2 Conn. DOWN]        |
+//     |                 |              |
+//     | RESTSubReq      |              |
+//     |---------------->|              |
+//     |     RESTSubFail |              |
+//     |<----------------|              |
+//     |                 |              |
+//
+//-----------------------------------------------------------------------------
+
+func TestRESTSubReqAfterE2ConnBreak(t *testing.T) {
+       CaseBegin("TestRESTSubReqAfterE2ConnBreak")
+
+       mainCtrl.CounterValuesToBeVeriefied(t, CountersToBeAdded{
+               Counter{cRestSubReqFromXapp, 1},
+               Counter{cRestReqRejDueE2Down, 1},
+       })
+
+       // E2 disconnect after E2term has received response
+       mainCtrl.SetE2State(t, "RAN_NAME_1_DISCONNECTED")
+       // Req
+       const subReqCount int = 1
+       params := xappConn1.GetRESTSubsReqReportParams(subReqCount)
+       xappConn1.SendRESTSubsReq(t, params)
+
+       // Restore E2 connection for following test cases
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED")
+
+       mainCtrl.VerifyCounterValues(t)
+}
+
+//-----------------------------------------------------------------------------
+// TestRESTSubReqE2ConnBreak
+//
+//   stub                             stub
+// +-------+        +---------+    +---------+
+// | xapp  |        | submgr  |    | e2term  |
+// +-------+        +---------+    +---------+
+//     |                 |              |
+//     | RESTSubReq      |              |
+//     |---------------->|              |
+//     |     RESTSubResp |              |
+//     |<----------------|              |
+//     |                 | SubReq       |
+//     |                 |------------->|
+//     |                 |      SubResp |
+//     |                 |<-------------|
+//     |                 |              |
+//     |         [E2 Conn. DOWN]        |
+//     |        [Int. SUBS DELETE]      |
+//     |                 |              |
+//     |      RESTNotif(unsuccessful)   |
+//     |<----------------|              |
+//     |                 |              |
+//     |                 |              |
+//
+//-----------------------------------------------------------------------------
+func TestRESTSubReqE2ConnBreak(t *testing.T) {
+       CaseBegin("TestRESTSubReqE2ConnBreak")
+
+       mainCtrl.CounterValuesToBeVeriefied(t, CountersToBeAdded{
+               Counter{cRestSubReqFromXapp, 1},
+               Counter{cRestSubRespToXapp, 1},
+               Counter{cSubReqToE2, 1},
+               Counter{cSubRespFromE2, 1},
+               Counter{cRestSubFailNotifToXapp, 1},
+       })
+
+       // Req
+       const subReqCount int = 1
+       params := xappConn1.GetRESTSubsReqReportParams(subReqCount)
+       restSubId := xappConn1.SendRESTSubsReq(t, params)
+
+       crereq, cremsg := e2termConn1.RecvSubsReq(t)
+       xappConn1.ExpectRESTNotification(t, restSubId)
+
+       // E2 disconnect after E2term has received response
+       mainCtrl.SetE2State(t, "RAN_NAME_1_DISCONNECTED")
+
+       e2termConn1.SendSubsResp(t, crereq, cremsg)
+       e2SubsId := xappConn1.WaitRESTNotification(t, restSubId)
+
+       <-time.After(time.Second * 1)
+       assert.Equal(t, 0, len(mainCtrl.c.registry.register))
+       assert.Equal(t, 0, len(mainCtrl.c.registry.restSubscriptions))
+
+       subIds, register, err := mainCtrl.c.ReadAllSubscriptionsFromSdl()
+       if err != nil {
+               xapp.Logger.Error("%v", err)
+       } else {
+               assert.Equal(t, 65534, len(subIds)) // range 1-65535 , FFFF = 65535
+               assert.Equal(t, 0, len(register))
+       }
+
+       restSubscriptions, err := mainCtrl.c.ReadAllRESTSubscriptionsFromSdl()
+       if err != nil {
+               xapp.Logger.Error("%v", err)
+       } else {
+               assert.Equal(t, 0, len(restSubscriptions))
+       }
+
+       // Restore E2 connection for following test cases
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED")
+
+       // Wait that subs is cleaned
+       waitSubsCleanup(t, e2SubsId, 10)
+       mainCtrl.VerifyCounterValues(t)
+}
+
+//-----------------------------------------------------------------------------
+// TestRESTSubscriptionDeleteAfterE2ConnectionBreak
+//
+//   stub                             stub
+// +-------+        +---------+    +---------+
+// | xapp  |        | submgr  |    | e2term  |
+// +-------+        +---------+    +---------+
+//     |                 |              |
+//     |            [SUBS CREATE]       |
+//     |                 |              |
+//     |           [E2 Conn. DOWN]      |
+//     |                 |              |
+//     | RESTSubDelReq   |              |
+//     |---------------->|              |
+//     |                 |              |
+//     |  RESTSubDelResp |              |
+//     |<----------------|              |
+//     |                 |              |
+//     |  [No valid subscription found] |
+//     |                 |              |
+//
+//-----------------------------------------------------------------------------
+func TestRESTSubscriptionDeleteAfterE2ConnectionBreak(t *testing.T) {
+       xapp.Logger.Debug("TEST: TestRESTSubscriptionDeleteAfterE2ConnectionBreak")
+
+       mainCtrl.CounterValuesToBeVeriefied(t, CountersToBeAdded{
+               Counter{cRestSubReqFromXapp, 1},
+               Counter{cRestSubRespToXapp, 1},
+               Counter{cSubReqToE2, 1},
+               Counter{cSubRespFromE2, 1},
+               Counter{cRestSubNotifToXapp, 1},
+               Counter{cRestSubDelReqFromXapp, 1},
+               Counter{cRestSubDelRespToXapp, 1},
+       })
+
+       // Req
+       var params *teststube2ap.RESTSubsReqParams = nil
+       restSubId, e2SubsId := createSubscription(t, xappConn1, e2termConn1, params)
+
+       // E2 disconnect after E2term has received response
+       mainCtrl.SetE2State(t, "RAN_NAME_1_DISCONNECTED")
+
+       // Del
+       xappConn1.SendRESTSubsDelReq(t, &restSubId)
+
+       <-time.After(time.Second * 1)
+       assert.Equal(t, 0, len(mainCtrl.c.registry.register))
+       assert.Equal(t, 0, len(mainCtrl.c.registry.restSubscriptions))
+
+       subIds, register, err := mainCtrl.c.ReadAllSubscriptionsFromSdl()
+       if err != nil {
+               xapp.Logger.Error("%v", err)
+       } else {
+               assert.Equal(t, 65534, len(subIds)) // range 1-65535 , FFFF = 65535
+               assert.Equal(t, 0, len(register))
+       }
+
+       restSubscriptions, err := mainCtrl.c.ReadAllRESTSubscriptionsFromSdl()
+       if err != nil {
+               xapp.Logger.Error("%v", err)
+       } else {
+               assert.Equal(t, 0, len(restSubscriptions))
+       }
+
+       // Restore E2 connection for following test cases
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED")
+
+       // Wait that subs is cleaned
+       mainCtrl.wait_subs_clean(t, e2SubsId, 10)
+
+       xappConn1.TestMsgChanEmpty(t)
+       e2termConn1.TestMsgChanEmpty(t)
+       mainCtrl.wait_registry_empty(t, 10)
+       mainCtrl.VerifyCounterValues(t)
+}
+
+//-----------------------------------------------------------------------------
+// TestRESTOtherE2ConnectionChanges
+//
+
+//   stub                             stub
+// +-------+        +---------+    +---------+
+// | xapp  |        | submgr  |    | e2term  |
+// +-------+        +---------+    +---------+
+//     |                 |              |
+//     |            [SUBS CREATE]       |
+//     |                 |              |
+//     |  [E2 CONNECTED_SETUP_FAILED]   |
+//     |         [E2 CONNECTING]        |
+//     |        [E2 SHUTTING_DOWN]      |
+//     |          [E2 SHUT_DOWN]        |
+//     |                 |              |
+//     |            [SUBS DELETE]       |
+//     |                 |              |
+//
+//-----------------------------------------------------------------------------
+func TestRESTOtherE2ConnectionChanges(t *testing.T) {
+       xapp.Logger.Debug("TEST: TestRESTOtherE2ConnectionChanges")
+
+       mainCtrl.CounterValuesToBeVeriefied(t, CountersToBeAdded{
+               Counter{cRestSubReqFromXapp, 1},
+               Counter{cRestSubRespToXapp, 1},
+               Counter{cSubReqToE2, 1},
+               Counter{cSubRespFromE2, 1},
+               Counter{cRestSubNotifToXapp, 1},
+               Counter{cRestSubDelReqFromXapp, 1},
+               Counter{cSubDelReqToE2, 1},
+               Counter{cSubDelRespFromE2, 1},
+               Counter{cRestSubDelRespToXapp, 1},
+       })
+
+       // Req
+       params := xappConn1.GetRESTSubsReqReportParams(subReqCount)
+       restSubId := xappConn1.SendRESTSubsReq(t, params)
+
+       crereq, cremsg := e2termConn1.RecvSubsReq(t)
+       xappConn1.ExpectRESTNotification(t, restSubId)
+       e2termConn1.SendSubsResp(t, crereq, cremsg)
+       e2SubsId := xappConn1.WaitRESTNotification(t, restSubId)
+
+       // Submgr should not react any other connection state changes than CONNECTED and DISCONNECTED
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED_SETUP_FAILED")
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTING")
+       mainCtrl.SetE2State(t, "RAN_NAME_1_SHUTTING_DOWN")
+       mainCtrl.SetE2State(t, "RAN_NAME_1_SHUT_DOWN")
+
+       // Del
+       xappConn1.SendRESTSubsDelReq(t, &restSubId)
+       delreq, delmsg := e2termConn1.RecvSubsDelReq(t)
+       e2termConn1.SendSubsDelResp(t, delreq, delmsg)
+
+       // Restore E2 connection for following test cases
+       mainCtrl.SetE2State(t, "RAN_NAME_1_CONNECTED")
+
+       // Wait that subs is cleaned
+       waitSubsCleanup(t, e2SubsId, 10)
+       mainCtrl.VerifyCounterValues(t)
+}
 
 //-----------------------------------------------------------------------------
 // TestRESTSubReqAndDeleteOkWithE2apUtWrapper
index 719f214..d6421e5 100644 (file)
@@ -705,25 +705,25 @@ func (tc *E2Stub) expectNotification(t *testing.T, restSubsId string, expectErro
        tc.restSubsIdList = []string{restSubsId}
        xapp.Subscription.SetResponseCB(tc.ListedRestNotifHandler)
        if tc.requestCount == 0 {
-               tc.TestError(t, "### NO REST notifications SET received for endpoint=%s, request zount ZERO! (%v)", tc.clientEndpoint, tc)
+               tc.TestError(t, "### NO REST notifications SET received for endpoint=%s, request zount ZERO! (%v)", tc.clientEndpoint, *tc)
        }
        go func() {
                select {
                case e2Ids := <-tc.CallBackListedNotifications:
                        if tc.requestCount == 0 {
-                               tc.TestError(t, "### REST notification count unexpectedly ZERO for %s (%v)", restSubsId, tc)
+                               tc.TestError(t, "### REST notification count unexpectedly ZERO for %s (%v)", restSubsId, *tc)
                        } else if e2Ids.RestSubsId != restSubsId {
-                               tc.TestError(t, "### Unexpected REST notifications received, expected %s bunt got %s instead| (%v)", e2Ids.RestSubsId, restSubsId, tc)
+                               tc.TestError(t, "### Unexpected REST notifications received, expected %s bunt got %s instead| (%v)", e2Ids.RestSubsId, restSubsId, *tc)
                        } else if e2Ids.ErrorCause == "" && expectError == "allFail" {
-                               tc.TestError(t, "### Unexpected ok cause received from REST notifications |%s:%s| (%v)", e2Ids.RestSubsId, restSubsId, tc)
+                               tc.TestError(t, "### Unexpected ok cause received from REST notifications |%s:%s| (%v)", e2Ids.RestSubsId, restSubsId, *tc)
                        } else if e2Ids.ErrorCause != "" && expectError == "allOk" {
-                               tc.TestError(t, "### Unexpected ErrorCause: (%s), ErrorSource: (%s), TimeoutType: (%s) received from REST notifications |%s:%s| (%v)", e2Ids.ErrorCause, e2Ids.ErrorSource, e2Ids.TimeoutType, e2Ids.RestSubsId, restSubsId, tc)
+                               tc.TestError(t, "### Unexpected ErrorCause: (%s), ErrorSource: (%s), TimeoutType: (%s) received from REST notifications |%s:%s| (%v)", e2Ids.ErrorCause, e2Ids.ErrorSource, e2Ids.TimeoutType, e2Ids.RestSubsId, restSubsId, *tc)
                        } else {
                                tc.requestCount--
                                if tc.requestCount == 0 {
-                                       tc.Debug("### All expected REST notifications received for %s (%v)", e2Ids.RestSubsId, tc)
+                                       tc.Debug("### All expected REST notifications received for %s (%v)", e2Ids.RestSubsId, *tc)
                                } else {
-                                       tc.Debug("### Expected REST notifications received for %s, (%v)", e2Ids.RestSubsId, tc)
+                                       tc.Debug("### Expected REST notifications received for %s, (%v)", e2Ids.RestSubsId, *tc)
                                }
                                if e2Ids.ErrorCause != "" && expectError == "allFail" {
                                        tc.Debug("### REST Notification: RestSubsId: %s, ErrorCause: %s, ErrorSource: (%s), TimeoutType: (%s)", e2Ids.RestSubsId, e2Ids.ErrorCause, e2Ids.ErrorSource, e2Ids.TimeoutType)
@@ -748,10 +748,10 @@ func (tc *E2Stub) WaitRESTNotification(t *testing.T, restSubsId string) uint32 {
        select {
        case e2SubsId := <-tc.ListedRESTNotifications:
                if e2SubsId.RestSubsId == restSubsId {
-                       tc.Debug("### Expected REST notifications received %s, e2SubsId %v for endpoint=%s, (%v)", e2SubsId.RestSubsId, e2SubsId.E2SubsId, tc.clientEndpoint, tc)
+                       tc.Debug("### Expected REST notifications received %s, e2SubsId %v for endpoint=%v, (%v)", e2SubsId.RestSubsId, e2SubsId.E2SubsId, tc.clientEndpoint, *tc)
                        return e2SubsId.E2SubsId
                } else {
-                       tc.TestError(t, "### Unexpected REST notification %s received, expected %s for endpoint=%s, (%v)", e2SubsId.RestSubsId, restSubsId, tc.clientEndpoint, tc)
+                       tc.TestError(t, "### Unexpected REST notification %s received, expected %v for endpoint=%v, (%v)", e2SubsId.RestSubsId, restSubsId, tc.clientEndpoint, *tc)
                        xapp.Logger.Debug("CALL STACK:\n %s", stack)
                        return 0
                }
@@ -796,7 +796,7 @@ func (tc *E2Stub) WaitAnyRESTNotification(t *testing.T) uint32 {
 func (tc *E2Stub) ListedRestNotifHandler(resp *clientmodel.SubscriptionResponse) {
 
        if len(tc.restSubsIdList) == 0 {
-               tc.Error("Unexpected listed REST notifications received for endpoint=%s, expected restSubsId list size was ZERO!", tc.clientEndpoint)
+               tc.Error("Unexpected listed REST notifications received for endpoint=%v, expected restSubsId list size was ZERO!", tc.clientEndpoint)
        } else {
                for i, subsId := range tc.restSubsIdList {
                        if *resp.SubscriptionID == subsId {
@@ -813,7 +813,7 @@ func (tc *E2Stub) ListedRestNotifHandler(resp *clientmodel.SubscriptionResponse)
                                //                              }
 
                                if len(tc.restSubsIdList) == 0 {
-                                       tc.Debug("All listed REST notifications received for endpoint=%s", tc.clientEndpoint)
+                                       tc.Debug("All listed REST notifications received for endpoint=%v", tc.clientEndpoint)
                                }
 
                                return
index 3afa1fc..5c2143e 100644 (file)
@@ -7,4 +7,4 @@ project: ric-plt/submgr
 ref: 6c63019f4daa458507decc19f2d742681e2053b4
 containers:
     - name: ric-plt-submgr
-      version: 0.7.1
+      version: 0.7.2