Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/github.com/docker/dock…
Browse files Browse the repository at this point in the history
…er-26.1.5incompatible
  • Loading branch information
dplore authored Oct 22, 2024
2 parents 9a32aeb + bd01d73 commit efcb75e
Show file tree
Hide file tree
Showing 19 changed files with 445 additions and 81 deletions.
4 changes: 4 additions & 0 deletions go.yml → .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ on:
jobs:
go:
uses: openconfig/common-ci/.github/workflows/basic_go.yml@125b6b58286d116b216e45c33cb859f547965d61
with:
tests-excludes-regex: integration
race-tests-excludes-regex: integration
coverage-excludes-regex: integration
16 changes: 15 additions & 1 deletion cmd/clio.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ package main

import (
"log"
"path/filepath"

"github.com/openconfig/clio/collector"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/confmap"
"go.opentelemetry.io/collector/confmap/provider/fileprovider"
"go.opentelemetry.io/collector/otelcol"
)

Expand All @@ -30,7 +33,18 @@ func main() {
Version: "1.0.0",
}

if err := runInteractive(otelcol.CollectorSettings{BuildInfo: info, Factories: collector.Components}); err != nil {
settings := otelcol.CollectorSettings{
BuildInfo: info,
Factories: collector.Components,
ConfigProviderSettings: otelcol.ConfigProviderSettings{
ResolverSettings: confmap.ResolverSettings{
URIs: []string{filepath.Join("../config", "config.yaml")},
ProviderFactories: []confmap.ProviderFactory{fileprovider.NewFactory()},
DefaultScheme: "file",
},
},
}
if err := runInteractive(settings); err != nil {
log.Fatal(err)
}
}
Expand Down
4 changes: 3 additions & 1 deletion config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ exporters:
# NOTE: Prior to v0.86.0 use `logging` instead of `debug`.
gnmi:
addr: "0.0.0.0:60302"
# To provide certificates, add the following lines:
# To enable transport security (e.g., mTLS), set the following:
# tp_sec: "mtls"
# ca_file: /certs/ca.crt
# cert_file: /certs/cert.crt
# key_file: /certs/cert.key

Expand Down
9 changes: 9 additions & 0 deletions gnmi/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,21 @@ type Config struct {
// Addr is the listen address of the gNMI server.
Addr string `mapstructure:"addr"`

// TpSec is the transport security used by the gNMI server, i.e., "insecure", "tls", or "mtls".
TpSec string `mapstructure:"tp_sec"`

// CAFile is the CA certificate to use for mTLS.
CAFile string `mapstructure:"ca_file"`

// CertFile is the certificate to use for TLS.
CertFile string `mapstructure:"cert_file"`

// KeyFile is the key to use for TLS.
KeyFile string `mapstructure:"key_file"`

// CredsRefresh is the duration to refresh the credentials.
CredsRefresh string `mapstructure:"creds_refresh"`

// TargetName is the target name of this gNMI server.
TargetName string `mapstructure:"target_name"`

Expand Down
5 changes: 2 additions & 3 deletions gnmi/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/confmap"
"go.opentelemetry.io/collector/confmap/confmaptest"
)

func TestUnmarshalDefaultConfig(t *testing.T) {
factory := NewFactory()
cfg := factory.CreateDefaultConfig()
if err := component.UnmarshalConfig(confmap.New(), cfg); err != nil {
if err := confmap.New().Unmarshal(cfg); err != nil {
t.Errorf("UnmarshalConfig returned error: %v", err)
}

Expand All @@ -42,7 +41,7 @@ func TestUnmarshalConfig(t *testing.T) {
require.NoError(t, err)
factory := NewFactory()
got := factory.CreateDefaultConfig()
if err := component.UnmarshalConfig(cm, got); err != nil {
if err := cm.Unmarshal(got); err != nil {
t.Errorf("UnmarshalConfig returned error: %v", err)
}

Expand Down
17 changes: 6 additions & 11 deletions gnmi/gnmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@ package gnmi

import (
"context"
"fmt"
"net"
"strings"

gpb "github.com/openconfig/gnmi/proto/gnmi"
ompb "go.opentelemetry.io/proto/otlp/metrics/v1"
anypb "google.golang.org/protobuf/types/known/anypb"

"github.com/golang/protobuf/proto"
"github.com/openconfig/magna/lwotgtelem"
"github.com/openconfig/magna/lwotgtelem/gnmit"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/reflection"
"google.golang.org/protobuf/proto"
"k8s.io/klog/v2"
)

Expand All @@ -54,20 +52,17 @@ func NewGNMIExporter(logger *zap.Logger, cfg *Config) (*GNMI, error) {
return nil, err
}

gnmiLis, err := net.Listen("tcp", fmt.Sprintf("%s", cfg.Addr))
gnmiLis, err := net.Listen("tcp", cfg.Addr)
if err != nil {
klog.Exitf("cannot listen on %s, err: %v", cfg.Addr, err)
}

var opts []grpc.ServerOption

if cfg.CertFile != "" {
creds, err := credentials.NewServerTLSFromFile(cfg.CertFile, cfg.KeyFile)
if err != nil {
return nil, fmt.Errorf("cannot create gNMI credentials, %v", err)
}
opts = append(opts, grpc.Creds(creds))
opt, err := gRPCSecurityOption(cfg)
if err != nil {
return nil, err
}
opts = append(opts, opt...)

return &GNMI{
cfg: cfg,
Expand Down
11 changes: 9 additions & 2 deletions gnmi/gnmi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package gnmi

import (
"context"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -71,9 +72,13 @@ func TestHandleMetrics(t *testing.T) {
},
metricCh: make(chan *pmetric.Metrics, 10),
}
var n *gpb.Notification

n := &gpb.Notification{}
var nMu sync.Mutex
updateFn := func(notif *gpb.Notification) error {
n = notif
nMu.Lock()
defer nMu.Unlock()
n.Update = append(n.Update, notif.Update...)
return nil
}

Expand All @@ -85,6 +90,8 @@ func TestHandleMetrics(t *testing.T) {
close(g.metricCh)

time.Sleep(time.Second)
nMu.Lock()
defer nMu.Unlock()
if len(n.Update) != tc.wantCnt {
t.Errorf("missing updates: want %d got %d", tc.wantCnt, len(n.Update))
}
Expand Down
135 changes: 135 additions & 0 deletions gnmi/security.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2024 Google LLC
//
// 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 gnmi

import (
"errors"
"fmt"
"os"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/tls/certprovider/pemfile"
"google.golang.org/grpc/security/advancedtls"
)

const (
// defaultCredsRefreshDuration is the default refresh duration for the credentials.
defaultCredsRefreshDuration = time.Hour
)

func credsRefreshDuration(cfg *Config) (time.Duration, error) {
if cfg.CredsRefresh == "" {
return defaultCredsRefreshDuration, nil
}
return time.ParseDuration(cfg.CredsRefresh)
}

// gRPCSecurityOption returns a gRPC server option based on the transport security
// configuration.
func gRPCSecurityOption(cfg *Config) ([]grpc.ServerOption, error) {
var opts []grpc.ServerOption
var err error

switch cfg.TpSec {
case "", "insecure": // No security option requested.
case "tls":
opts, err = optionTLS(cfg)
case "mtls":
opts, err = optionMutualTLS(cfg)
default:
return nil, fmt.Errorf("unsupported transport security: %q; must be one of: insecure, tls, mtls", cfg.TpSec)
}

if err != nil {
return nil, fmt.Errorf("failed to create gNMI credentials: %v", err)
}

return opts, nil
}

func optionTLS(cfg *Config) ([]grpc.ServerOption, error) {
// Check that all needed files actually exist.
for _, f := range []string{cfg.CertFile, cfg.KeyFile} {
if _, err := os.Stat(f); f == "" || errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("file %q does not exist", f)
}
}

creds, err := credentials.NewServerTLSFromFile(cfg.CertFile, cfg.KeyFile)
if err != nil {
return nil, err
}
return []grpc.ServerOption{grpc.Creds(creds)}, nil
}

func optionMutualTLS(cfg *Config) ([]grpc.ServerOption, error) {

// Check that all needed files actually exist.
for _, f := range []string{cfg.CertFile, cfg.KeyFile, cfg.CAFile} {
if _, err := os.Stat(f); f == "" || errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("file %q does not exist", f)
}
}

// Determine the refresh duration.
crd, err := credsRefreshDuration(cfg)
if err != nil {
return nil, err
}

// Get a provider for the identity credentials.
identity := pemfile.Options{
CertFile: cfg.CertFile,
KeyFile: cfg.KeyFile,
RefreshDuration: crd,
}

identityProvider, err := pemfile.NewProvider(identity)
if err != nil {
return nil, fmt.Errorf("failed to create identity provider: %v", err)
}

// Get a provider for the root credentials.
root := pemfile.Options{
RootFile: cfg.CAFile,
RefreshDuration: crd,
}
rootProvider, err := pemfile.NewProvider(root)
if err != nil {
return nil, fmt.Errorf("failed to create root provider: %v", err)
}

// Setup the mTLS option.
options := &advancedtls.Options{
IdentityOptions: advancedtls.IdentityCertificateOptions{
IdentityProvider: identityProvider,
},
RootOptions: advancedtls.RootCertificateOptions{
RootProvider: rootProvider,
},
RequireClientCert: true,
}

// Setup the server credentials.
creds, err := advancedtls.NewServerCreds(options)
if err != nil {
return nil, fmt.Errorf("failed to create client creds: %v", err)
}

return []grpc.ServerOption{grpc.Creds(creds)}, nil

}
Loading

0 comments on commit efcb75e

Please sign in to comment.