Files
cocos/pkg/clients/grpc/grpc.go
T
Sammy Kerata Oina 8eb1fac9ad NOISSUE - Refactor and update dependencies in the project (#491)
* Refactor and update dependencies in the project

- Updated go.sum to replace `github.com/absmach/magistrala` with `github.com/absmach/supermq` across various modules.
- Removed VSock configuration from environment variables and QEMU arguments.
- Updated QEMU configuration and related tests to remove references to guest CID and VSock.
- Added new HTTP transport layer for API endpoints in the manager.
- Introduced Prometheus monitoring configuration with alert rules and Alertmanager setup.
- Updated service and VM interfaces to remove unused methods and references.
- Refactored tests to align with the new structure and dependencies.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* Add MaxVMs configuration and enforce limit on VM creation

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* Add comprehensive tests for HTTP transport handlers and endpoints

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* Add test case for exceeding maximum number of VMs in TestRun

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* Improve error handling in TestHandlerWithCustomRouter to ensure response writing is checked

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* Update dependencies to latest versions

- Upgrade cel.dev/expr from v0.23.0 to v0.24.0
- Upgrade github.com/absmach/supermq from v0.16.0 to v0.17.0
- Upgrade github.com/cenkalti/backoff from v4.3.0 to v5.0.2
- Upgrade github.com/cncf/xds/go to v0.0.0-20250501225837-2ac532fd4443
- Upgrade github.com/go-chi/chi/v5 from v5.2.1 to v5.2.2
- Upgrade github.com/go-jose/go-jose/v3 from v3.0.3 to v3.0.4
- Upgrade github.com/gofrs/uuid/v5 from v5.3.0 to v5.3.2
- Upgrade github.com/prometheus/client_golang from v1.22.0 to v1.23.0
- Upgrade github.com/prometheus/client_model from v0.6.1 to v0.6.2
- Upgrade github.com/prometheus/common from v0.62.0 to v0.65.0
- Upgrade github.com/prometheus/procfs from v0.15.1 to v0.16.1
- Upgrade go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from v0.60.0 to v0.62.0
- Upgrade go.opentelemetry.io/otel/exporters/otlp/otlptrace from v1.36.0 to v1.37.0
- Upgrade golang.org/x/crypto from v0.39.0 to v0.40.0
- Upgrade golang.org/x/sys from v0.33.0 to v0.34.0
- Upgrade golang.org/x/text from v0.26.0 to v0.27.0
- Upgrade golang.org/x/time from v0.11.0 to v0.12.0
- Upgrade google.golang.org/grpc from v1.73.0 to v1.74.2

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

---------

Signed-off-by: Sammy Oina <sammyoina@gmail.com>
2025-08-05 11:22:02 +02:00

203 lines
4.7 KiB
Go

// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package grpc
import (
"crypto/tls"
"crypto/x509"
"fmt"
"os"
"time"
"github.com/absmach/supermq/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
)
type security int
const (
withoutTLS security = iota
withTLS
withmTLS
withaTLS
withmaTLS
)
const (
AttestationReportSize = 0x4A0
WithMATLS = "with maTLS"
WithATLS = "with aTLS"
WithTLS = "with TLS"
)
var (
errGrpcConnect = errors.New("failed to connect to grpc server")
errGrpcClose = errors.New("failed to close grpc connection")
errCertificateParse = errors.New("failed to parse x509 certificate")
errAttVerification = errors.New("certificat is not self signed")
errFailedToLoadClientCertKey = errors.New("failed to load client certificate and key")
errFailedToLoadRootCA = errors.New("failed to load root ca file")
)
type ClientConfiguration interface {
GetBaseConfig() BaseConfig
}
type BaseConfig struct {
URL string `env:"URL" envDefault:"localhost:7001"`
Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"`
ClientCert string `env:"CLIENT_CERT" envDefault:""`
ClientKey string `env:"CLIENT_KEY" envDefault:""`
ServerCAFile string `env:"SERVER_CA_CERTS" envDefault:""`
}
type AgentClientConfig struct {
BaseConfig
AttestationPolicy string `env:"ATTESTATION_POLICY" envDefault:""`
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
ProductName string `env:"PRODUCT_NAME" envDefault:"Milan"`
}
type ManagerClientConfig struct {
BaseConfig
}
type CVMClientConfig struct {
BaseConfig
}
func (a BaseConfig) GetBaseConfig() BaseConfig {
return a
}
func (a AgentClientConfig) GetBaseConfig() BaseConfig {
return a.BaseConfig
}
func (a CVMClientConfig) GetBaseConfig() BaseConfig {
return a.BaseConfig
}
type Client interface {
Close() error
Secure() string
Connection() *grpc.ClientConn
}
type client struct {
*grpc.ClientConn
cfg ClientConfiguration
secure security
}
var _ Client = (*client)(nil)
func NewClient(cfg ClientConfiguration) (Client, error) {
conn, secure, err := connect(cfg)
if err != nil {
return nil, err
}
return &client{
ClientConn: conn,
cfg: cfg,
secure: secure,
}, nil
}
func (c *client) Close() error {
if err := c.ClientConn.Close(); err != nil {
return errors.Wrap(errGrpcClose, err)
}
return nil
}
func (c *client) Secure() string {
switch c.secure {
case withTLS:
return WithTLS
case withmTLS:
return "with mTLS"
case withaTLS:
return "with aTLS"
case withmaTLS:
return WithMATLS
default:
return "without TLS"
}
}
func (c *client) Connection() *grpc.ClientConn {
return c.ClientConn
}
func connect(cfg ClientConfiguration) (*grpc.ClientConn, security, error) {
opts := []grpc.DialOption{
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
}
secure := withoutTLS
if agcfg, ok := cfg.(AgentClientConfig); ok && agcfg.AttestedTLS {
tc, sec, err := setupATLS(agcfg)
if err != nil {
return nil, secure, err
}
opts = append(opts, grpc.WithTransportCredentials(tc))
secure = sec
} else {
conf := cfg.GetBaseConfig()
transportCreds, sec, err := loadTLSConfig(conf.ServerCAFile, conf.ClientCert, conf.ClientKey)
if err != nil {
return nil, secure, err
}
opts = append(opts, grpc.WithTransportCredentials(transportCreds))
secure = sec
}
conn, err := grpc.Dial(cfg.GetBaseConfig().URL, opts...)
if err != nil {
return nil, secure, errors.Wrap(errGrpcConnect, err)
}
return conn, secure, nil
}
func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.TransportCredentials, security, error) {
tlsConfig := &tls.Config{}
secure := withoutTLS
tc := insecure.NewCredentials()
if serverCAFile != "" {
rootCA, err := os.ReadFile(serverCAFile)
if err != nil {
return nil, secure, errors.Wrap(errFailedToLoadRootCA, err)
}
if len(rootCA) > 0 {
capool := x509.NewCertPool()
if !capool.AppendCertsFromPEM(rootCA) {
return nil, secure, fmt.Errorf("failed to append root ca to tls.Config")
}
tlsConfig.RootCAs = capool
secure = withTLS
tc = credentials.NewTLS(tlsConfig)
}
}
if clientCert != "" || clientKey != "" {
certificate, err := tls.LoadX509KeyPair(clientCert, clientKey)
if err != nil {
return nil, secure, errors.Wrap(errFailedToLoadClientCertKey, err)
}
tlsConfig.Certificates = []tls.Certificate{certificate}
secure = withmTLS
tc = credentials.NewTLS(tlsConfig)
}
return tc, secure, nil
}