Skip to content

Commit 6e5f6ea

Browse files
[smclient] Renew certificates SM client adaptation
Signed-off-by: Mykola Kobets <mykola_kobets@epam.com>
1 parent 94eb166 commit 6e5f6ea

File tree

2 files changed

+129
-66
lines changed

2 files changed

+129
-66
lines changed

smclient/smclient.go

+96-66
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ import (
2727
"github.com/aosedge/aos_common/aoserrors"
2828
"github.com/aosedge/aos_common/aostypes"
2929
"github.com/aosedge/aos_common/api/cloudprotocol"
30+
"github.com/aosedge/aos_common/api/iamanager"
3031
pb "github.com/aosedge/aos_common/api/servicemanager"
3132
"github.com/aosedge/aos_common/utils/cryptutils"
33+
"github.com/aosedge/aos_common/utils/grpchelpers"
3234
"github.com/aosedge/aos_common/utils/pbconvert"
3335
"github.com/golang/protobuf/ptypes/timestamp"
3436
log "github.com/sirupsen/logrus"
3537
"google.golang.org/grpc"
3638
"google.golang.org/grpc/codes"
37-
"google.golang.org/grpc/credentials"
38-
"google.golang.org/grpc/credentials/insecure"
3939
"google.golang.org/grpc/status"
4040
"google.golang.org/protobuf/types/known/timestamppb"
4141

@@ -77,6 +77,7 @@ type SMClient struct {
7777
alertChannel <-chan interface{}
7878
monitoringChannel <-chan aostypes.NodeMonitoring
7979
logsChannel <-chan cloudprotocol.PushLog
80+
tlsCertChan <-chan *iamanager.CertInfo
8081
runStatus *launcher.InstancesStatus
8182
}
8283

@@ -87,7 +88,8 @@ type NodeInfoProvider interface {
8788

8889
// CertificateProvider interface to get certificate.
8990
type CertificateProvider interface {
90-
GetCertificate(certType string) (certURL, ketURL string, err error)
91+
GetCertificate(certType string, issuer []byte, serial string) (certURL, ketURL string, err error)
92+
SubscribeCertChanged(certType string) (<-chan *iamanager.CertInfo, error)
9193
}
9294

9395
// NodeConfigProcessor node configuration handler.
@@ -160,10 +162,7 @@ func New(config *config.Config, nodeInfoProvider NodeInfoProvider, certificatePr
160162
layersProcessor: layersProcessor, launcher: launcher, nodeConfigProcessor: nodeConfigProcessor,
161163
monitoringProvider: monitoringProvider, logsProvider: logsProvider, networkManager: networkManager,
162164
closeChannel: make(chan struct{}, 1),
163-
}
164-
165-
if err := cmClient.createConnection(config, certificateProvider, cryptcoxontext, insecure); err != nil {
166-
return nil, aoserrors.Wrap(err)
165+
tlsCertChan: make(<-chan *iamanager.CertInfo),
167166
}
168167

169168
nodeInfo, err := nodeInfoProvider.GetCurrentNodeInfo()
@@ -174,6 +173,18 @@ func New(config *config.Config, nodeInfoProvider NodeInfoProvider, certificatePr
174173
cmClient.nodeID = nodeInfo.NodeID
175174
cmClient.nodeType = nodeInfo.NodeType
176175

176+
if err := cmClient.createConnection(config, certificateProvider, cryptcoxontext, insecure); err != nil {
177+
return nil, aoserrors.Wrap(err)
178+
}
179+
180+
if !insecure {
181+
if cmClient.tlsCertChan, err = certificateProvider.SubscribeCertChanged(config.CertStorage); err != nil {
182+
return nil, aoserrors.Wrap(err)
183+
}
184+
185+
go cmClient.processTlsCertChanged()
186+
}
187+
177188
if cmClient.launcher != nil {
178189
cmClient.runtimeStatusChannel = launcher.RuntimeStatusChannel()
179190
}
@@ -197,21 +208,11 @@ func New(config *config.Config, nodeInfoProvider NodeInfoProvider, certificatePr
197208
func (client *SMClient) Close() (err error) {
198209
log.Debug("Close SM client")
199210

200-
if client.stream != nil {
201-
err = client.stream.CloseSend()
202-
}
203-
204-
if client.connection != nil {
205-
errCloseConn := client.connection.Close()
206-
207-
if err != nil {
208-
err = errCloseConn
209-
}
210-
}
211-
212211
close(client.closeChannel)
213212

214-
return aoserrors.Wrap(err)
213+
client.closeGRPCConnection()
214+
215+
return nil
215216
}
216217

217218
/***********************************************************************************************************************
@@ -222,72 +223,101 @@ func (client *SMClient) createConnection(
222223
config *config.Config, provider CertificateProvider,
223224
cryptcoxontext *cryptutils.CryptoContext, insecureConn bool,
224225
) (err error) {
225-
log.Debug("Connecting to CM...")
226-
227-
var secureOpt grpc.DialOption
228-
229-
if insecureConn {
230-
secureOpt = grpc.WithTransportCredentials(insecure.NewCredentials())
231-
} else {
232-
certURL, keyURL, err := provider.GetCertificate(config.CertStorage)
233-
if err != nil {
234-
return aoserrors.Wrap(err)
235-
}
236-
237-
tlsConfig, err := cryptcoxontext.GetClientMutualTLSConfig(certURL, keyURL)
238-
if err != nil {
239-
return aoserrors.Wrap(err)
240-
}
241-
242-
secureOpt = grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
226+
if err := client.register(config, provider, cryptcoxontext, insecureConn); err != nil {
227+
return err
243228
}
244229

245-
ctx, cancel := context.WithTimeout(context.Background(), cmRequestTimeout)
246-
defer cancel()
230+
go func() {
231+
for {
232+
if err = client.processMessages(); err != nil {
233+
if errors.Is(err, io.EOF) {
234+
log.Debug("Connection is closed")
235+
} else {
236+
log.Errorf("Connection error: %v", aoserrors.Wrap(err))
237+
}
238+
}
247239

248-
if client.connection, err = grpc.DialContext(ctx, config.CMServerURL, secureOpt, grpc.WithBlock()); err != nil {
249-
return aoserrors.Wrap(err)
250-
}
240+
log.Debugf("Reconnect to CM in %v...", cmReconnectTimeout)
251241

252-
log.Debug("Connected to CM")
242+
client.closeGRPCConnection()
253243

254-
go func() {
255-
err := client.register()
244+
reconnectionLoop:
245+
for {
246+
select {
247+
case <-client.closeChannel:
248+
log.Debug("Disconnected from CM")
256249

257-
for {
258-
if err != nil && len(client.closeChannel) == 0 {
259-
log.Errorf("Error register to CM: %v", aoserrors.Wrap(err))
260-
} else {
261-
if err = client.processMessages(); err != nil {
262-
if errors.Is(err, io.EOF) {
263-
log.Debug("Connection is closed")
250+
return
251+
252+
case <-time.After(cmReconnectTimeout):
253+
if err := client.register(config, provider, cryptcoxontext, insecureConn); err != nil {
254+
log.WithField("err", err).Debug("Reconnection failed")
264255
} else {
265-
log.Errorf("Connection error: %v", aoserrors.Wrap(err))
256+
break reconnectionLoop
266257
}
267258
}
268259
}
260+
}
261+
}()
269262

270-
log.Debugf("Reconnect to CM in %v...", cmReconnectTimeout)
263+
return nil
264+
}
271265

272-
select {
273-
case <-client.closeChannel:
274-
log.Debugf("Disconnected from CM")
266+
func (client *SMClient) processTlsCertChanged() {
267+
for {
268+
select {
269+
case <-client.tlsCertChan:
270+
log.Debug("TLS certificate changed")
275271

276-
return
272+
client.closeGRPCConnection()
277273

278-
case <-time.After(cmReconnectTimeout):
279-
err = client.register()
280-
}
274+
case <-client.closeChannel:
275+
return
281276
}
282-
}()
277+
}
278+
}
279+
280+
func (client *SMClient) openGRPCConnection(config *config.Config, provider CertificateProvider,
281+
cryptcoxontext *cryptutils.CryptoContext, insecureConn bool,
282+
) (err error) {
283+
log.Debug("Connecting to CM...")
284+
285+
if client.connection, err = grpchelpers.CreateProtectedConnection(
286+
config.CertStorage, config.CMServerURL, cmRequestTimeout, cryptcoxontext, provider, insecureConn); err != nil {
287+
return aoserrors.Wrap(err)
288+
}
283289

284290
return nil
285291
}
286292

287-
func (client *SMClient) register() (err error) {
293+
func (client *SMClient) closeGRPCConnection() {
294+
client.Lock()
295+
defer client.Unlock()
296+
297+
log.Debug("Closing CM connection...")
298+
299+
if client.stream != nil {
300+
if err := client.stream.CloseSend(); err != nil {
301+
log.WithField("err", err).Error("SMClient failed send close")
302+
}
303+
}
304+
305+
if client.connection != nil {
306+
client.connection.Close()
307+
client.connection = nil
308+
}
309+
}
310+
311+
func (client *SMClient) register(config *config.Config, provider CertificateProvider,
312+
cryptcoxontext *cryptutils.CryptoContext, insecureConn bool,
313+
) (err error) {
288314
client.Lock()
289315
defer client.Unlock()
290316

317+
if err := client.openGRPCConnection(config, provider, cryptcoxontext, insecureConn); err != nil {
318+
return err
319+
}
320+
291321
log.Debug("Registering to CM...")
292322

293323
if client.stream, err = pb.NewSMServiceClient(client.connection).RegisterSM(context.Background()); err != nil {
@@ -332,7 +362,7 @@ func (client *SMClient) processMessages() (err error) {
332362
if err != nil {
333363
if code, ok := status.FromError(err); ok {
334364
if code.Code() == codes.Canceled {
335-
log.Debug("SM client connection closed")
365+
log.Debug("CM client connection closed")
336366
return nil
337367
}
338368
}
@@ -380,7 +410,7 @@ func (client *SMClient) processMessages() (err error) {
380410
func (client *SMClient) processGetNodeConfigStatus() {
381411
version, err := client.nodeConfigProcessor.GetNodeConfigStatus()
382412

383-
status := &pb.NodeConfigStatus{Version: version}
413+
status := &pb.NodeConfigStatus{Version: version, NodeId: client.nodeID, NodeType: client.nodeType}
384414

385415
if err != nil {
386416
status.Error = pbconvert.ErrorInfoToPB(&cloudprotocol.ErrorInfo{Message: err.Error()})

smclient/smclient_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,39 @@ func TestSMRegistration(t *testing.T) {
159159
}
160160
}
161161

162+
func TestDisconnected(t *testing.T) {
163+
server, err := newTestServer(serverURL)
164+
if err != nil {
165+
t.Fatalf("Can't create test server: %v", err)
166+
}
167+
168+
nodeInfoProvider := &testNodeInfoProvider{nodeInfo: cloudprotocol.NodeInfo{NodeID: "nodeID", NodeType: "typeType"}}
169+
170+
client, err := smclient.New(&config.Config{CMServerURL: serverURL}, nodeInfoProvider, nil, nil, nil, nil,
171+
&testNodeConfigProcessor{}, nil, nil, nil, nil, nil, true)
172+
if err != nil {
173+
t.Fatalf("Can't create SM client: %v", err)
174+
}
175+
defer client.Close()
176+
177+
if err = server.waitNodeConfigStatus(nodeInfoProvider.nodeInfo.NodeID,
178+
nodeInfoProvider.nodeInfo.NodeType); err != nil {
179+
t.Fatalf("SM registration error: %v", err)
180+
}
181+
182+
server.close()
183+
server, err = newTestServer(serverURL)
184+
if err != nil {
185+
t.Fatalf("Can't create test server: %v", err)
186+
}
187+
defer server.close()
188+
189+
if err = server.waitNodeConfigStatus(nodeInfoProvider.nodeInfo.NodeID,
190+
nodeInfoProvider.nodeInfo.NodeType); err != nil {
191+
t.Fatalf("SM registration error: %v", err)
192+
}
193+
}
194+
162195
func TestMonitoringNotifications(t *testing.T) {
163196
currentTime := time.Now()
164197
pbCurrentTime := timestamppb.New(currentTime)

0 commit comments

Comments
 (0)