blob: 84f707bce2bf2bd8d0d3a27ac8edaddd442b96cb [file] [log] [blame]
Kent Hagerman2f0d0552020-04-23 17:28:52 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package core
18
19import (
20 "context"
21 "errors"
22 "time"
23
Maninderdfadc982020-10-28 14:04:33 +053024 "github.com/opencord/voltha-lib-go/v4/pkg/db"
25 "github.com/opencord/voltha-lib-go/v4/pkg/db/kvstore"
26 "github.com/opencord/voltha-lib-go/v4/pkg/log"
27 "github.com/opencord/voltha-lib-go/v4/pkg/probe"
Kent Hagerman2f0d0552020-04-23 17:28:52 -040028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
Rohan Agrawal31f21802020-06-12 05:38:46 +000032func newKVClient(ctx context.Context, storeType string, address string, timeout time.Duration) (kvstore.Client, error) {
33 logger.Infow(ctx, "kv-store-type", log.Fields{"store": storeType})
Kent Hagerman2f0d0552020-04-23 17:28:52 -040034 switch storeType {
Kent Hagerman2f0d0552020-04-23 17:28:52 -040035 case "etcd":
Rohan Agrawal31f21802020-06-12 05:38:46 +000036 return kvstore.NewEtcdClient(ctx, address, timeout, log.FatalLevel)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040037 }
38 return nil, errors.New("unsupported-kv-store")
39}
40
41func stopKVClient(ctx context.Context, kvClient kvstore.Client) {
42 // Release all reservations
43 if err := kvClient.ReleaseAllReservations(ctx); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +000044 logger.Infow(ctx, "fail-to-release-all-reservations", log.Fields{"error": err})
Kent Hagerman2f0d0552020-04-23 17:28:52 -040045 }
46 // Close the DB connection
Rohan Agrawal31f21802020-06-12 05:38:46 +000047 kvClient.Close(ctx)
Kent Hagerman2f0d0552020-04-23 17:28:52 -040048}
49
50// waitUntilKVStoreReachableOrMaxTries will wait until it can connect to a KV store or until maxtries has been reached
51func waitUntilKVStoreReachableOrMaxTries(ctx context.Context, kvClient kvstore.Client, maxRetries int, retryInterval time.Duration) error {
Rohan Agrawal31f21802020-06-12 05:38:46 +000052 logger.Infow(ctx, "verifying-KV-store-connectivity", log.Fields{"retries": maxRetries, "retryInterval": retryInterval})
Kent Hagerman2f0d0552020-04-23 17:28:52 -040053 count := 0
54 for {
55 if !kvClient.IsConnectionUp(ctx) {
Rohan Agrawal31f21802020-06-12 05:38:46 +000056 logger.Info(ctx, "KV-store-unreachable")
Kent Hagerman2f0d0552020-04-23 17:28:52 -040057 if maxRetries != -1 {
58 if count >= maxRetries {
59 return status.Error(codes.Unavailable, "kv store unreachable")
60 }
61 }
62 count++
63
64 // Take a nap before retrying
65 select {
66 case <-ctx.Done():
67 //ctx canceled
68 return ctx.Err()
69 case <-time.After(retryInterval):
70 }
Rohan Agrawal31f21802020-06-12 05:38:46 +000071 logger.Infow(ctx, "retry-KV-store-connectivity", log.Fields{"retryCount": count, "maxRetries": maxRetries, "retryInterval": retryInterval})
Kent Hagerman2f0d0552020-04-23 17:28:52 -040072 } else {
73 break
74 }
75 }
76 probe.UpdateStatusFromContext(ctx, "kv-store", probe.ServiceStatusRunning)
Rohan Agrawal31f21802020-06-12 05:38:46 +000077 logger.Info(ctx, "KV-store-reachable")
Kent Hagerman2f0d0552020-04-23 17:28:52 -040078 return nil
79}
80
81/*
82 * Thread to monitor kvstore Liveness (connection status)
83 *
84 * This function constantly monitors Liveness State of kvstore as reported
85 * periodically by backend and updates the Status of kv-store service registered
86 * with rw_core probe.
87 *
88 * If no liveness event has been seen within a timeout, then the thread will
89 * perform a "liveness" check attempt, which will in turn trigger a liveness event on
90 * the liveness channel, true or false depending on whether the attempt succeeded.
91 *
92 * The gRPC server in turn monitors the state of the readiness probe and will
93 * start issuing UNAVAILABLE response while the probe is not ready.
94 */
95func monitorKVStoreLiveness(ctx context.Context, backend *db.Backend, liveProbeInterval, notLiveProbeInterval time.Duration) {
Rohan Agrawal31f21802020-06-12 05:38:46 +000096 logger.Info(ctx, "start-monitoring-kvstore-liveness")
Kent Hagerman2f0d0552020-04-23 17:28:52 -040097
98 // Instruct backend to create Liveness channel for transporting state updates
Rohan Agrawal31f21802020-06-12 05:38:46 +000099 livenessChannel := backend.EnableLivenessChannel(ctx)
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400100
Rohan Agrawal31f21802020-06-12 05:38:46 +0000101 logger.Debug(ctx, "enabled-kvstore-liveness-channel")
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400102
103 // Default state for kvstore is alive for rw_core
104 timeout := liveProbeInterval
105loop:
106 for {
107 timeoutTimer := time.NewTimer(timeout)
108 select {
109
110 case liveness := <-livenessChannel:
Rohan Agrawal31f21802020-06-12 05:38:46 +0000111 logger.Debugw(ctx, "received-liveness-change-notification", log.Fields{"liveness": liveness})
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400112
113 if !liveness {
114 probe.UpdateStatusFromContext(ctx, "kv-store", probe.ServiceStatusNotReady)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000115 logger.Info(ctx, "kvstore-set-server-notready")
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400116
117 timeout = notLiveProbeInterval
118
119 } else {
120 probe.UpdateStatusFromContext(ctx, "kv-store", probe.ServiceStatusRunning)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000121 logger.Info(ctx, "kvstore-set-server-ready")
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400122
123 timeout = liveProbeInterval
124 }
125
126 if !timeoutTimer.Stop() {
127 <-timeoutTimer.C
128 }
129
130 case <-ctx.Done():
131 break loop
132
133 case <-timeoutTimer.C:
Rohan Agrawal31f21802020-06-12 05:38:46 +0000134 logger.Info(ctx, "kvstore-perform-liveness-check-on-timeout")
Kent Hagerman2f0d0552020-04-23 17:28:52 -0400135
136 // Trigger Liveness check if no liveness update received within the timeout period.
137 // The Liveness check will push Live state to same channel which this routine is
138 // reading and processing. This, do it asynchronously to avoid blocking for
139 // backend response and avoid any possibility of deadlock
140 go backend.PerformLivenessCheck(ctx)
141 }
142 }
143}