diff --git a/Dockerfile.sut b/Dockerfile.sut new file mode 100644 index 00000000..f1380eb4 --- /dev/null +++ b/Dockerfile.sut @@ -0,0 +1,24 @@ +FROM golang:1.26 AS builder +WORKDIR /app +COPY bootz/go.mod bootz/go.sum ./ +# Map local monax repository so go mod download can resolve the replace directive inside Docker. +COPY monax /monax +RUN go mod download +COPY bootz . +RUN CGO_ENABLED=0 GOOS=linux go build -o /bootz-sut ./server/sut +RUN mkdir -p /www_dir +RUN mkdir -p server/sut + +FROM gcr.io/distroless/static-debian12:latest +WORKDIR /app +COPY --from=builder /bootz-sut /app/bootz-sut +COPY --from=builder /www_dir /www +COPY --from=builder /app/server/sut /app/server/sut +COPY bootz/testdata /app/testdata +# Set WORKDIR to /app/server/sut so relative paths in flags (../../testdata) resolve to /app/testdata. +WORKDIR /app/server/sut +# DHCP needs to run as root. +USER root +HEALTHCHECK --interval=5s --timeout=2s --start-period=3s --retries=3 \ + CMD ["/app/bootz-sut", "--healthcheck"] +ENTRYPOINT ["/app/bootz-sut"] \ No newline at end of file diff --git a/dhcp/Dockerfile b/dhcp/Dockerfile index 08a38508..418efe07 100644 --- a/dhcp/Dockerfile +++ b/dhcp/Dockerfile @@ -5,14 +5,11 @@ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o /bootz-dhcp ./dhcp/main -# hadolint ignore=DL3007 FROM gcr.io/distroless/static-debian12:nonroot COPY --from=builder /bootz-dhcp /bootz-dhcp # DHCP needs to run as root to bind to port 67 and use raw sockets. -# hadolint ignore=DL3002 USER nonroot +HEALTHCHECK --interval=5s --timeout=2s --start-period=3s --retries=3 \ + CMD ["/bootz-dhcp", "--healthcheck"] ENTRYPOINT ["/bootz-dhcp"] -HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ - CMD pgrep dhcp || exit 1 - diff --git a/dhcp/deploy/deployment.yaml b/dhcp/deploy/deployment.yaml new file mode 100644 index 00000000..6eea9989 --- /dev/null +++ b/dhcp/deploy/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bootz-dhcp + labels: + app: bootz-dhcp +spec: + replicas: 1 + selector: + matchLabels: + app: bootz-dhcp + template: + metadata: + labels: + app: bootz-dhcp + spec: + containers: + - image: bootz-dhcp + name: bootz-dhcp + args: + - -i=eth0 + - -records=4c:5d:3c:ef:de:60,10.0.0.2/24,10.0.0.1 + - -dns=8.8.8.8 + - -bootz_urls=http://bootz-server:8080 + - -sut_addr=:4001 + ports: + - containerPort: 67 + protocol: UDP + name: dhcp + - containerPort: 4001 + protocol: TCP + name: grpc + securityContext: + runAsUser: 0 + capabilities: + add: + - NET_ADMIN + imagePullPolicy: Never diff --git a/dhcp/deploy/kubernetes.txtpb b/dhcp/deploy/kubernetes.txtpb new file mode 100644 index 00000000..6da779bd --- /dev/null +++ b/dhcp/deploy/kubernetes.txtpb @@ -0,0 +1,27 @@ +# proto-file: proto/monax.proto +# proto-message: monax.Library + +components: { + id: "DHCP" + kind: "kubernetes" + provided_interfaces: { + name: "dhcp" + dhcp: { + service_name: "bootz-dhcp" + } + } + provided_interfaces: { + name: "grpc" + grpc: { + service_name: "bootz.DHCPService" + } + } + parameters: { + [type.googleapis.com/monax.kubernetes.KubernetesComponentParameters] { + deployment_path: "deployment.yaml" + service_path: "service.yaml" + wait_for_deployment_timeout_sec: 60 + wait_for_service_timeout_sec: 60 + } + } +} \ No newline at end of file diff --git a/dhcp/deploy/service.yaml b/dhcp/deploy/service.yaml new file mode 100644 index 00000000..2fe56bdc --- /dev/null +++ b/dhcp/deploy/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: bootz-dhcp +spec: + ports: + - name: dhcp + port: 67 + protocol: UDP + targetPort: 67 + - name: grpc + port: 4001 + protocol: TCP + targetPort: 4001 + selector: + app: bootz-dhcp diff --git a/dhcp/plugins/slease/slease.go b/dhcp/plugins/slease/slease.go index 02eda55f..210be940 100644 --- a/dhcp/plugins/slease/slease.go +++ b/dhcp/plugins/slease/slease.go @@ -203,3 +203,23 @@ func parseRecord6(r string) (string, net.IP, error) { } return parts[0], ip, nil } + +// AddRecord4 adds an IPv4 lease record dynamically. +func AddRecord4(mac string, ip net.IP, mask net.IPMask, gw net.IP) { + muRw.Lock() + defer muRw.Unlock() + ipv4Records[mac] = &ipv4Entry{ + ip: ip, + netmask: mask, + gateway: gw, + } + log.Infof("Dynamically added ipv4 record: %v, %v, %v, %v", mac, ip, mask, gw) +} + +// RemoveRecord4 removes an IPv4 lease record dynamically. +func RemoveRecord4(mac string) { + muRw.Lock() + defer muRw.Unlock() + delete(ipv4Records, mac) + log.Infof("Dynamically removed ipv4 record for MAC: %v", mac) +} diff --git a/dhcp/sutserver/sutserver.go b/dhcp/sutserver/sutserver.go new file mode 100644 index 00000000..a48fb67e --- /dev/null +++ b/dhcp/sutserver/sutserver.go @@ -0,0 +1,90 @@ +// Copyright 2026 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 +// +// https://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 sutserver + +import ( + "context" + "fmt" + "net" + "net/netip" + + log "github.com/golang/glog" + "github.com/openconfig/bootz/dhcp/plugins/slease" + pb "github.com/openconfig/bootz/server/tests/proto/sut" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +type Server struct { + pb.UnimplementedDHCPServiceServer + grpcServer *grpc.Server +} + +func New() *Server { + return &Server{} +} + +// Start starts the DHCP SUT gRPC server. +func (s *Server) Start(addr string) error { + lis, err := net.Listen("tcp", addr) + if err != nil { + return err + } + s.grpcServer = grpc.NewServer() + pb.RegisterDHCPServiceServer(s.grpcServer, s) + reflection.Register(s.grpcServer) + log.Infof("Starting DHCP SUT gRPC server on %s", addr) + go func() { + if err := s.grpcServer.Serve(lis); err != nil { + log.Errorf("DHCP SUT gRPC server failed: %v", err) + } + }() + return nil +} + +// Stop stops the DHCP SUT gRPC server. +func (s *Server) Stop() { + if s.grpcServer != nil { + s.grpcServer.GracefulStop() + } +} + +// CreateLease creates a DHCP lease dynamically. +func (s *Server) CreateLease(ctx context.Context, req *pb.CreateLeaseRequest) (*pb.CreateLeaseResponse, error) { + ip, err := netip.ParseAddr(req.GetIpAddress()) + if err != nil { + return nil, err + } + gw := net.ParseIP(req.GetGateway()) + if gw == nil { + return nil, fmt.Errorf("invalid gateway: %s", req.GetGateway()) + } + + mask := net.CIDRMask(int(req.GetMaskLen()), ip.BitLen()) + + for _, mac := range req.GetMacAddresses() { + slease.AddRecord4(mac, net.ParseIP(req.GetIpAddress()), mask, gw) + } + + return &pb.CreateLeaseResponse{}, nil +} + +// RemoveLease removes a DHCP lease dynamically. +func (s *Server) RemoveLease(ctx context.Context, req *pb.RemoveLeaseRequest) (*pb.RemoveLeaseResponse, error) { + for _, mac := range req.GetMacAddresses() { + slease.RemoveRecord4(mac) + } + return &pb.RemoveLeaseResponse{}, nil +} \ No newline at end of file diff --git a/go.mod b/go.mod index 0cf56c76..ff651838 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,10 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20260407060928-11b94ed970f2 github.com/openconfig/attestz v0.6.12 github.com/openconfig/gnmi v0.14.1 + github.com/openconfig/gnoigo v0.0.0-20240820205259-23ac4e061cc2 github.com/openconfig/gnsi v1.9.1 + github.com/openconfig/monax v0.0.0-20260603195803-1899be60f203 + github.com/openconfig/ondatra v0.12.2 go.mozilla.org/pkcs7 v0.9.0 google.golang.org/grpc v1.81.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 @@ -19,33 +22,114 @@ require ( ) require ( + bitbucket.org/creachadair/stringset v0.0.14 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.1.1+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/imdario/mergo v0.3.14 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/jstemmer/go-junit-report/v2 v2.1.0 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/morikuni/aec v1.1.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect + github.com/open-traffic-generator/snappi/gosnappi v1.33.3 // indirect + github.com/openconfig/gnoi v0.5.0 // indirect + github.com/openconfig/gnpsi v0.3.2 // indirect + github.com/openconfig/gocloser v0.0.0-20220310182203-c6c950ed3b0b // indirect + github.com/openconfig/goyang v1.6.0 // indirect + github.com/openconfig/gribi v1.8.1 // indirect + github.com/openconfig/ygnmi v0.11.1 // indirect + github.com/openconfig/ygot v0.34.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/p4lang/p4runtime v1.4.1 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.48.0 // indirect + golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect + golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.51.0 // indirect - golang.org/x/sys v0.42.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.41.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.2 // indirect + k8s.io/apimachinery v0.29.2 // indirect + k8s.io/client-go v0.29.2 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 6788462b..c81c63c1 100644 --- a/go.sum +++ b/go.sum @@ -1,52 +1,161 @@ +bitbucket.org/creachadair/stringset v0.0.14 h1:t1ejQyf8utS4GZV/4fM+1gvYucggZkfhb+tMobDxYOE= +bitbucket.org/creachadair/stringset v0.0.14/go.mod h1:Ej8fsr6rQvmeMDf6CCWMWGb14H9mz8kmDgPPTdiVT0w= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb h1:aZTKxMminKeQWHtzJBbV8TttfTxzdJ+7iEJFE6FmUzg= github.com/chappjc/logrus-prefix v0.0.0-20180227015900-3a1d64819adb/go.mod h1:xzXc1S/L+64uglB3pw54o8kqyM6KFYpTeC9Q6+qZIu8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coredhcp/coredhcp v0.0.0-20260217182248-a0841cb3038f h1:Bj+yhDYB9fypuXEJimRf9iRqHenZ/lqR7OPJ8e4GGQs= github.com/coredhcp/coredhcp v0.0.0-20260217182248-a0841cb3038f/go.mod h1:S6hmg58KixGhVg8FRxJhr2tSFKxqW+1umjwHiEqGwlo= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I= +github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= 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/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc= github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/h-fam/errdiff v1.0.2 h1:rPsW4ob2fMOIulwTEoZXaaUIuud7XUudw5SLKTZj3Ss= github.com/h-fam/errdiff v1.0.2/go.mod h1:FOzgnHXSEE3rRvmGXgmiqWl+H3lwLywYm9CSXqXrSTg= +github.com/imdario/mergo v0.3.14 h1:fOqeC1+nCuuk6PKQdg9YmosXX7Y7mHX6R/0ZldI9iHo= +github.com/imdario/mergo v0.3.14/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20260407060928-11b94ed970f2 h1:G3irkWwmpl0vH/nn83K2AHqLUZweC7XAONuwXy/w9Co= github.com/insomniacslk/dhcp v0.0.0-20260407060928-11b94ed970f2/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report/v2 v2.1.0 h1:X3+hPYlSczH9IMIpSC9CQSZA0L+BipYafciZUWHEmsc= +github.com/jstemmer/go-junit-report/v2 v2.1.0/go.mod h1:mgHVr7VUo5Tn8OLVr1cKnLuEy0M92wdRntM99h7RkgQ= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -54,6 +163,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -65,47 +178,134 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= +github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/open-traffic-generator/snappi/gosnappi v1.33.3 h1:W6KAKxJDoMQFGeW5CbB3ud5iPt6BHRdsqcvZsSOBTUw= +github.com/open-traffic-generator/snappi/gosnappi v1.33.3/go.mod h1:TMOADoJ42+c+8GAnFWJBhv3QqGw+4rohj+L0JiGikgs= github.com/openconfig/attestz v0.6.12 h1:1dqpxFFiIoCCS4NRJS9htjEw76Zx5FbIgp9WW+ayA2Q= github.com/openconfig/attestz v0.6.12/go.mod h1:OPoBdd/4FTnXRlRd7/PyhVB4oWL0NqXMP2b0RofThYI= +github.com/openconfig/gnmi v0.10.0/go.mod h1:Y9os75GmSkhHw2wX8sMsxfI7qRGAEcDh8NTa5a8vj6E= github.com/openconfig/gnmi v0.14.1 h1:qKMuFvhIRR2/xxCOsStPQ25aKpbMDdWr3kI+nP9bhMs= github.com/openconfig/gnmi v0.14.1/go.mod h1:whr6zVq9PCU8mV1D0K9v7Ajd3+swoN6Yam9n8OH3eT0= +github.com/openconfig/gnoi v0.5.0 h1:r0cbY1biqAcVLCUjsQjF3UZlU1yZAgbmW24dK0R53MI= +github.com/openconfig/gnoi v0.5.0/go.mod h1:qjMeFac9SfHyedDWjUU/x4pozK4kvgBngdIO1MwjhCs= +github.com/openconfig/gnoigo v0.0.0-20240820205259-23ac4e061cc2 h1:TnKY8BNb0j7JFlrrvsfUaJgO76ZCjmGUmkgwso+Co9Y= +github.com/openconfig/gnoigo v0.0.0-20240820205259-23ac4e061cc2/go.mod h1:pCijvudnCsk0fuj0JV1cWprfFQsrOD9VwFuF6gWZQsI= +github.com/openconfig/gnpsi v0.3.2 h1:+bl1bXMOTrWOcGydWB+8wGgvxlgvL8Y6joAiWFU5sog= +github.com/openconfig/gnpsi v0.3.2/go.mod h1:+Qj2PwadJ/jvGkH6H/A3XO9ZRKQRVtl3A30ubwz0M18= github.com/openconfig/gnsi v1.9.1 h1:0XpYlG/99YWVIm6gFTVkxlwiXcU/tBla9MDLChLNBMM= github.com/openconfig/gnsi v1.9.1/go.mod h1:r1OgFdQdbVB6PdamWM6nW85MKLlRCYwCd9Gx/tm2/Gw= +github.com/openconfig/gocloser v0.0.0-20220310182203-c6c950ed3b0b h1:NSYuxdlOWLldNpid1dThR6Dci96juXioUguMho6aliI= +github.com/openconfig/gocloser v0.0.0-20220310182203-c6c950ed3b0b/go.mod h1:uhC/ybmPapgeyAL2b9ZrUQ+DZE+DB+J+/7377PX+lek= +github.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU= +github.com/openconfig/goyang v1.6.0 h1:JjnPbLY1/y28VyTO67LsEV0TaLWNiZyDcsppGq4F4is= +github.com/openconfig/goyang v1.6.0/go.mod h1:sdNZi/wdTZyLNBNfgLzmmbi7kISm7FskMDKKzMY+x1M= +github.com/openconfig/gribi v1.8.1 h1:asucWuDLssIo2Tm9gEgaMSExRL/ZmHUyaMt0FMz9NrI= +github.com/openconfig/gribi v1.8.1/go.mod h1:e2QZrJAWSmSgzAaZ6mjI0mGfOw3bT+bOZCdG72sPciA= +github.com/openconfig/grpctunnel v0.0.0-20220819142823-6f5422b8ca70/go.mod h1:OmTWe7RyZj2CIzIgy4ovEBzCLBJzRvWSZmn7u02U9gU= +github.com/openconfig/grpctunnel v0.1.0 h1:EN99qtlExZczgQgp5ANnHRC/Rs62cAG+Tz2BQ5m/maM= +github.com/openconfig/grpctunnel v0.1.0/go.mod h1:G04Pdu0pml98tdvXrvLaU+EBo3PxYfI9MYqpvdaEHLo= +github.com/openconfig/ondatra v0.12.2 h1:q7MmP551Q2SJAuv29i8fFx89RR3wWO5R+E5+DNwuWIw= +github.com/openconfig/ondatra v0.12.2/go.mod h1:HEyMGzKbgGDUfowayPpr45PcNz7QRjm8WI2q5R+2lcc= +github.com/openconfig/testt v0.0.0-20220311054427-efbb1a32ec07 h1:X631iD/B0ximGFb5P9LY5wHju4SiedxUhc5UZEo7VSw= +github.com/openconfig/testt v0.0.0-20220311054427-efbb1a32ec07/go.mod h1:bmpU0kIsCiXuncozViVuQx1HqolC3C94H7lD9KKmoTo= +github.com/openconfig/ygnmi v0.11.1 h1:tIHlAinvOX+8jA2YTk4ACb7IOQe1PXsjT41Ci7E2KUk= +github.com/openconfig/ygnmi v0.11.1/go.mod h1:naCxQR+/wBItM82ilJXWgapCRkrx8bphBmUHXJmRhuQ= +github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs= +github.com/openconfig/ygot v0.29.20 h1:XHLpwCN91QuKc2LAvnEqtCmH8OuxgLlErDhrdl2mJw8= +github.com/openconfig/ygot v0.29.20/go.mod h1:K8HbrPm/v8/emtGQ9+RsJXx6UPKC5JzS/FqK7pN+tMo= +github.com/openconfig/ygot v0.34.0 h1:9OkVjy3SGi4mbvAZc4HTQBU9u4MT6k4j5DdX+hgRiC4= +github.com/openconfig/ygot v0.34.0/go.mod h1:eMNQHrJpanet+pQoBw/P3ua4sLY/tRTXyJ7ALkWCvl4= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/p4lang/p4runtime v1.4.1 h1:YdtDyDReeGEmSvuxqR8iefSTnttRSW5jWJWtpgCSFv4= +github.com/p4lang/p4runtime v1.4.1/go.mod h1:OWAP4Wh9uKGnQjleslObpFE0REP78b5gR1pHyYmvNPQ= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/protocolbuffers/txtpbfmt v0.0.0-20220608084003-fc78c767cd6a/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -114,46 +314,82 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8 github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.mozilla.org/pkcs7 v0.9.0 h1:yM4/HS9dYv7ri2biPtxt8ikvB37a980dg69/pKmS+eI= go.mozilla.org/pkcs7 v0.9.0/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 h1:cfuy3bXmLJS7M1RZmAL6SuhGtKUp2KEsrm00OlAXkq4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1/go.mod h1:22jr92C6KwlwItJmQzfixzQM3oyyuYLCfHiMY+rpsPU= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= +go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= +golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= +golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= 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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -161,47 +397,126 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 h1:/WILD1UcXj/ujCxgoL/DvRgt2CP3txG8+FwkUbb9110= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1/go.mod h1:YNKnb2OAApgYn2oYY47Rn7alMr1zWjb2U8Q0aoGWiNc= +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= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 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.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= +k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= +k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= +k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= +k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= +k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/http/Dockerfile b/http/Dockerfile index 39b00203..d1270ad5 100644 --- a/http/Dockerfile +++ b/http/Dockerfile @@ -5,16 +5,12 @@ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -o /bootz-http ./http/main -# hadolint ignore=DL3007 FROM gcr.io/distroless/static-debian12:nonroot WORKDIR /www COPY --from=builder /bootz-http /bootz-http # HTTP server might need to run as root to bind to port 80. -# hadolint ignore=DL3002 USER nonroot +HEALTHCHECK --interval=5s --timeout=2s --start-period=3s --retries=3 \ + CMD ["/bootz-http", "--healthcheck"] ENTRYPOINT ["/bootz-http"] -CMD ["-address", ":8080"] - -HEALTHCHECK --interval=30s --timeout=3s \ - CMD curl -f http://localhost:8080/health || exit 1 diff --git a/http/deploy/deployment.yaml b/http/deploy/deployment.yaml new file mode 100644 index 00000000..c1ae0fc9 --- /dev/null +++ b/http/deploy/deployment.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bootz-http + labels: + app: bootz-http +spec: + replicas: 1 + selector: + matchLabels: + app: bootz-http + template: + metadata: + labels: + app: bootz-http + spec: + containers: + - image: bootz-http + name: bootz-http + args: + - -address=:80 + - -folder=/www + - -sut_addr=:4002 + - -public_url=http://bootz-http + ports: + - containerPort: 80 + name: http + - containerPort: 4002 + name: grpc + imagePullPolicy: Never diff --git a/http/deploy/kubernetes.txtpb b/http/deploy/kubernetes.txtpb new file mode 100644 index 00000000..864c8ea4 --- /dev/null +++ b/http/deploy/kubernetes.txtpb @@ -0,0 +1,27 @@ +# proto-file: proto/monax.proto +# proto-message: monax.Library + +components: { + id: "HTTP" + kind: "kubernetes" + provided_interfaces: { + name: "http" + http: { + service_name: "bootz-http" + } + } + provided_interfaces: { + name: "grpc" + grpc: { + service_name: "bootz.ImageService" + } + } + parameters: { + [type.googleapis.com/monax.kubernetes.KubernetesComponentParameters] { + deployment_path: "deployment.yaml" + service_path: "service.yaml" + wait_for_deployment_timeout_sec: 60 + wait_for_service_timeout_sec: 60 + } + } +} \ No newline at end of file diff --git a/http/deploy/service.yaml b/http/deploy/service.yaml new file mode 100644 index 00000000..61e034cc --- /dev/null +++ b/http/deploy/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: bootz-http +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + - name: grpc + port: 4002 + protocol: TCP + targetPort: 4002 + selector: + app: bootz-http + diff --git a/http/sutserver/sutserver.go b/http/sutserver/sutserver.go new file mode 100644 index 00000000..10d283b1 --- /dev/null +++ b/http/sutserver/sutserver.go @@ -0,0 +1,132 @@ +// Copyright 2026 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 +// +// https://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 sutserver + +import ( + "context" + "fmt" + "io" + "net" + "net/http" + "os" + "path/filepath" + + log "github.com/golang/glog" + bootzpb "github.com/openconfig/bootz/proto/bootz" + "github.com/openconfig/bootz/server/sutstate" + pb "github.com/openconfig/bootz/server/tests/proto/sut" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +type Server struct { + pb.UnimplementedImageServiceServer + grpcServer *grpc.Server + folder string + publicURL string +} + +func New(folder string, publicURL string) *Server { + return &Server{ + folder: folder, + publicURL: publicURL, + } +} + +// Start starts the HTTP SUT gRPC server. +func (s *Server) Start(addr string) error { + lis, err := net.Listen("tcp", addr) + if err != nil { + return err + } + s.grpcServer = grpc.NewServer() + pb.RegisterImageServiceServer(s.grpcServer, s) + reflection.Register(s.grpcServer) + log.Infof("Starting HTTP SUT gRPC server on %s", addr) + go func() { + if err := s.grpcServer.Serve(lis); err != nil { + log.Errorf("HTTP SUT gRPC server failed: %v", err) + } + }() + return nil +} + +// Stop stops the HTTP SUT gRPC server. +func (s *Server) Stop() { + if s.grpcServer != nil { + s.grpcServer.GracefulStop() + } +} + +// Upload handles image upload/download instructions. +func (s *Server) Upload(ctx context.Context, req *pb.UploadRequest) (*pb.UploadResponse, error){ + img := req.GetImage() + if img == nil { + return nil, fmt.Errorf("image is required") + } + + downloadURL := img.GetDownloadUri() + finalURL := downloadURL + + if img.GetReuploadToSut() { + filename := fmt.Sprintf("%s-%s", img.GetName(), img.GetVersion()) + localPath := filepath.Join(s.folder, filename) + + log.Infof("Downloading image from %s to %s", downloadURL, localPath) + if err := downloadFile(ctx, downloadURL, localPath); err != nil { + return nil, fmt.Errorf("failed to download image: %w", err) + } + + finalURL = fmt.Sprintf("%s/%s", s.publicURL, filename) + log.Infof("Image re-uploaded, available at: %s", finalURL) + } + + resp := &pb.UploadResponse{ + Image: &bootzpb.SoftwareImage{ + Name: img.GetName(), + Version: img.GetVersion(), + Url: finalURL, + OsImageHash: img.GetOsImageHash(), + HashAlgorithm: img.GetHashAlgorithm(), + }, + } + sutstate.SetSoftwareImage(resp.Image) + return resp, nil +} + +func downloadFile(ctx context.Context, url string, filepath string) error { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return err + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("bad status: %s", resp.Status) + } + + out, err := os.Create(filepath) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + return err +} diff --git a/server/controller/controller.go b/server/controller/controller.go new file mode 100644 index 00000000..ff850568 --- /dev/null +++ b/server/controller/controller.go @@ -0,0 +1,148 @@ +// Copyright 2026 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 +// +// https://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 controller + +import ( + "context" + "net" + "sync" + + log "github.com/golang/glog" + "github.com/openconfig/bootz/server/sutstate" + pb "github.com/openconfig/bootz/server/tests/proto/sut" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +type Server struct { + pb.UnimplementedBootzControllerServer + grpcServer *grpc.Server + publicURL string + + mu sync.Mutex + subscribers []chan *pb.SubscribeResponse +} + +func New(publicURL string) *Server { + return &Server{ + publicURL: publicURL, + } +} + +// Start starts the BootzController SUT gRPC server. +func (s *Server) Start(addr string) error { + lis, err := net.Listen("tcp", addr) + if err != nil { + return err + } + s.grpcServer = grpc.NewServer() + pb.RegisterBootzControllerServer(s.grpcServer, s) + reflection.Register(s.grpcServer) + log.Infof("Starting BootzController SUT gRPC server on %s", addr) + go func() { + if err := s.grpcServer.Serve(lis); err != nil { + log.Errorf("BootzController SUT gRPC server failed: %v", err) + } + }() + return nil +} + +// Stop stops the BootzController SUT gRPC server. +func (s *Server) Stop() { + if s.grpcServer != nil { + s.grpcServer.GracefulStop() + } + s.mu.Lock() + defer s.mu.Unlock() + for _, ch := range s.subscribers { + close(ch) + } + s.subscribers = nil +} + +func (s *Server) SetBootstrapData(ctx context.Context, req *pb.SetBootstrapDataRequest) (*pb.SetBootstrapDataResponse, error) { + sutstate.SetBootstrapData(req.GetBootstrapData()) + log.Infof("BootzController: Set bootstrap data") + return &pb.SetBootstrapDataResponse{}, nil +} + +func (s *Server) SetSecurityArtifacts(ctx context.Context, req *pb.SetSecurityArtifactsRequest) (*pb.SetSecurityArtifactsResponse, error) { + sutstate.SetSecurityArtifacts(req.GetSecurityArtifacts()) + log.Infof("BootzController: Set security artifacts") + return &pb.SetSecurityArtifactsResponse{}, nil +} + +func (s *Server) SetRecoveryData(ctx context.Context, req *pb.SetRecoveryDataRequest) (*pb.SetRecoveryDataResponse, error) { + sutstate.SetRecoveryData(req.GetRecoveryData()) + log.Infof("BootzController: Set recovery data") + return &pb.SetRecoveryDataResponse{}, nil +} + +func (s *Server) GetBootzURL(ctx context.Context, req *pb.GetBootzURLRequest) (*pb.GetBootzURLResponse, error) { + return &pb.GetBootzURLResponse{ + BootzUrl: s.publicURL, + }, nil +} + +// NotifyEvent is called by the device-facing service to notify subscribers of events. +func (s *Server) NotifyEvent(resp *pb.SubscribeResponse) { + s.mu.Lock() + defer s.mu.Unlock() + for _, ch := range s.subscribers { + select { + case ch <- resp: + default: + log.Warningf("Subscriber channel full, dropping event: %v", resp) + } + } +} + +func (s *Server) Subscribe(req *pb.SubscribeRequest, stream pb.BootzController_SubscribeServer) error { + ch := make(chan *pb.SubscribeResponse, 100) + + s.mu.Lock() + s.subscribers = append(s.subscribers, ch) + s.mu.Unlock() + + defer func() { + s.mu.Lock() + for i, c := range s.subscribers { + if c == ch { + s.subscribers = append(s.subscribers[:i], s.subscribers[i+1:]...) + break + } + } + s.mu.Unlock() + close(ch) + }() + + log.Infof("BootzController: New subscriber registered") + + for { + select { + case <-stream.Context().Done(): + log.Infof("BootzController: Subscriber context done") + return stream.Context().Err() + case resp, ok := <-ch: + if !ok { + return nil + } + if err := stream.Send(resp); err != nil { + log.Errorf("Failed to send event to subscriber: %v", err) + return err + } + } + } +} \ No newline at end of file diff --git a/server/server.go b/server/server.go index 05db3253..56e333a8 100644 --- a/server/server.go +++ b/server/server.go @@ -36,6 +36,7 @@ import ( "google.golang.org/grpc/credentials" bpb "github.com/openconfig/bootz/proto/bootz" + sutpb "github.com/openconfig/bootz/server/tests/proto/sut" ) // Server is the bootz emulator server. @@ -55,6 +56,11 @@ func (s *Server) Stop() { s.serv.GracefulStop() } +// SetNotifyFn sets the notification function for SUT events. +func (s *Server) SetNotifyFn(fn func(*sutpb.SubscribeResponse)) { + s.service.SetNotifyFn(fn) +} + // bootzServerOpts is used to pass optional args to NewServer. type bootzServerOpts interface { isbootzServerOpts() @@ -183,4 +189,4 @@ func StartImageServer(opt *ImgSrvOpts) error { Folder: opt.ImagesLocation, } return http.Start(conf) -} +} \ No newline at end of file diff --git a/server/service/service.go b/server/service/service.go index 2fed7141..32a9eddf 100644 --- a/server/service/service.go +++ b/server/service/service.go @@ -46,6 +46,7 @@ import ( epb "github.com/openconfig/attestz/proto/tpm_enrollz" bpb "github.com/openconfig/bootz/proto/bootz" + sutpb "github.com/openconfig/bootz/server/tests/proto/sut" ) const ( @@ -101,8 +102,14 @@ type EntityManager interface { // Service represents the server and entity manager. type Service struct { bpb.UnimplementedBootstrapServer - em EntityManager - tpm20 biz.TPM20Utils + em EntityManager + tpm20 biz.TPM20Utils + NotifyFn func(*sutpb.SubscribeResponse) +} + +// SetNotifyFn sets the notification function for SUT events. +func (s *Service) SetNotifyFn(fn func(*sutpb.SubscribeResponse)) { + s.NotifyFn = fn } type streamSession struct { @@ -274,6 +281,14 @@ func (s *Service) BootstrapStream(stream bpb.Bootstrap_BootstrapStreamServer) er session.clientNonce = bootstrapReq.GetNonce() log.Infof("Received initial BootstrapRequest: %+v", bootstrapReq) + if s.NotifyFn != nil { + s.NotifyFn(&sutpb.SubscribeResponse{ + Event: &sutpb.SubscribeResponse_GetBootstrapDataRequest{ + GetBootstrapDataRequest: bootstrapReq, + }, + }) + } + chassis, err := initializeChassis(ctx, bootstrapReq) if err != nil { return status.Errorf(codes.InvalidArgument, "failed to build entity lookup from request: %v", err) @@ -406,6 +421,14 @@ func (s *Service) BootstrapStream(stream bpb.Bootstrap_BootstrapStreamServer) er log.Infof("Received ReportStatusRequest from %s: %+v", session.chassis.ActiveSerial, req.ReportStatusRequest) session.status = req.ReportStatusRequest + if s.NotifyFn != nil { + s.NotifyFn(&sutpb.SubscribeResponse{ + Event: &sutpb.SubscribeResponse_ReportStatusRequest{ + ReportStatusRequest: req.ReportStatusRequest, + }, + }) + } + if session.currentState == stateInitial { log.Info("Received ReportStatusRequest on a new stream. Starting re-authentication...") chassis, err := initializeChassis(ctx, req.ReportStatusRequest) @@ -459,6 +482,14 @@ func (s *Service) BootstrapStreamV1(stream bpb.Bootstrap_BootstrapStreamV1Server log.Infof("Received initial BootstrapRequest: %+v", req.BootstrapRequest) session.clientNonce = req.BootstrapRequest.GetNonce() + if s.NotifyFn != nil { + s.NotifyFn(&sutpb.SubscribeResponse{ + Event: &sutpb.SubscribeResponse_GetBootstrapDataRequest{ + GetBootstrapDataRequest: req.BootstrapRequest, + }, + }) + } + if response, err = s.createChallengeRequest(session, req.BootstrapRequest); err != nil { return err } @@ -657,6 +688,14 @@ func (s *Service) BootstrapStreamV1(stream bpb.Bootstrap_BootstrapStreamV1Server log.Infof("Received ReportStatusRequest from %s: %+v", session.chassis.ActiveSerial, req.ReportStatusRequest) session.status = req.ReportStatusRequest + if s.NotifyFn != nil { + s.NotifyFn(&sutpb.SubscribeResponse{ + Event: &sutpb.SubscribeResponse_ReportStatusRequest{ + ReportStatusRequest: req.ReportStatusRequest, + }, + }) + } + // Check whether this is a new stream. if session.currentState == stateInitial { log.Info("This is a new stream. Starting re-authentication...") @@ -1027,4 +1066,4 @@ func New(em EntityManager, tpm20 biz.TPM20Utils) *Service { em: em, tpm20: tpm20, } -} +} \ No newline at end of file diff --git a/server/sut/deploy/deployment.yaml b/server/sut/deploy/deployment.yaml new file mode 100644 index 00000000..d25117f6 --- /dev/null +++ b/server/sut/deploy/deployment.yaml @@ -0,0 +1,52 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: bootz-sut + labels: + app: bootz-sut +spec: + replicas: 1 + selector: + matchLabels: + app: bootz-sut + template: + metadata: + labels: + app: bootz-sut + spec: + containers: + - image: bootz-sut + name: bootz-sut + args: + - -bootz_addr=:15006 + - -bootz_sut_addr=:4003 + - -dhcp_sut_addr=:4001 + - -dhcp_intf=eth0 + - -http_addr=:80 + - -http_sut_addr=:4002 + - -http_public_url=http://bootz-sut + ports: + - containerPort: 15006 + protocol: TCP + name: bootz + - containerPort: 4003 + protocol: TCP + name: controller + - containerPort: 4001 + protocol: TCP + name: dhcp-sut + - containerPort: 67 + protocol: UDP + name: dhcp + - containerPort: 80 + protocol: TCP + name: http + - containerPort: 4002 + protocol: TCP + name: http-sut + securityContext: + runAsUser: 0 + capabilities: + add: + - NET_ADMIN + imagePullPolicy: Never \ No newline at end of file diff --git a/server/sut/deploy/kubernetes.txtpb b/server/sut/deploy/kubernetes.txtpb new file mode 100644 index 00000000..6b296fb8 --- /dev/null +++ b/server/sut/deploy/kubernetes.txtpb @@ -0,0 +1,33 @@ +# proto-file: proto/monax.proto +# proto-message: monax.Library + +components: { + id: "BootzSUT" + kind: "kubernetes" + provided_interfaces: { + name: "dhcp_service" + grpc: { + service_name: "bootz.DHCPService" + } + } + provided_interfaces: { + name: "image_service" + grpc: { + service_name: "bootz.ImageService" + } + } + provided_interfaces: { + name: "controller_service" + grpc: { + service_name: "bootz.BootzController" + } + } + parameters: { + [type.googleapis.com/monax.kubernetes.KubernetesComponentParameters] { + deployment_path: "deployment.yaml" + service_path: "service.yaml" + wait_for_deployment_timeout_sec: 60 + wait_for_service_timeout_sec: 60 + } + } +} \ No newline at end of file diff --git a/server/sut/deploy/service.yaml b/server/sut/deploy/service.yaml new file mode 100644 index 00000000..8989a39a --- /dev/null +++ b/server/sut/deploy/service.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Service +metadata: + name: bootz-sut +spec: + ports: + - name: bootz + port: 15006 + protocol: TCP + targetPort: 15006 + - name: controller + port: 4003 + protocol: TCP + targetPort: 4003 + - name: dhcp-sut + port: 4001 + protocol: TCP + targetPort: 4001 + - name: dhcp + port: 67 + protocol: UDP + targetPort: 67 + - name: http + port: 80 + protocol: TCP + targetPort: 80 + - name: http-sut + port: 4002 + protocol: TCP + targetPort: 4002 + type: NodePort + selector: + app: bootz-sut \ No newline at end of file diff --git a/server/sut/main.go b/server/sut/main.go new file mode 100644 index 00000000..b56e0381 --- /dev/null +++ b/server/sut/main.go @@ -0,0 +1,233 @@ +// Copyright 2026 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 +// +// https://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 main + +import ( + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "flag" + + "net" + "os" + "os/signal" + "strings" + "syscall" + "time" + + log "github.com/golang/glog" + + "github.com/openconfig/bootz/dhcp" + dhcpsut "github.com/openconfig/bootz/dhcp/sutserver" + "github.com/openconfig/bootz/http" + httpsut "github.com/openconfig/bootz/http/sutserver" + "github.com/openconfig/bootz/server" + "github.com/openconfig/bootz/server/controller" + "github.com/openconfig/bootz/server/entitymanager" + artifacts "github.com/openconfig/bootz/testdata" +) + +var ( + // Bootz server flags + bootzAddr = flag.String("bootz_addr", ":15006", "The [ip:]port to start the Bootz server.") + bootzSutAddr = flag.String("bootz_sut_addr", ":4003", "The [ip:]port to start the BootzController SUT gRPC server.") + inventoryConfig = flag.String("inv_config", "../../testdata/inventory_local.prototxt", +"Devices' config files to be loaded by inventory manager") + generateOVsFor = flag.String("generate_ovs_for", "123A,123B", "Comma-separated list of control card serial numbers to generate OVs for.") + vendorCACert = flag.String("vendor_ca_cert", "../../testdata/vendor_ca_cert.txt", "Vendor CA certificate file.") + vendorCAKey = flag.String("vendor_ca_key", "../../testdata/vendor_ca_key.txt", "Vendor CA private key file.") + + // DHCP flags + dhcpIntf = flag.String("dhcp_intf", "", "Network interface to use for DHCP server. If empty, standard DHCP server won't start.") + dhcpSutAddr = flag.String("dhcp_sut_addr", ":4001", "The [ip:]port to start the DHCP SUT gRPC server.") + dhcpRecords = flag.String("dhcp_records", "", "Initial list of DHCP records separated by a semi-colon (format: mac,ip/mask,gw).") + dhcpDns = flag.String("dhcp_dns", "8.8.8.8", "List of DNS servers separated by a semi-colon.") + + // HTTP flags + httpAddr = flag.String("http_addr", ":80", "The address 'IP:port' to use for HTTP server.") + httpFolder = flag.String("http_folder", "/www", "The local folder to serve files from.") + httpSutAddr = flag.String("http_sut_addr", ":4002", "The [ip:]port to start the HTTP SUT gRPC server.") + httpPublicURL = flag.String("http_public_url", "http://bootz-http", "The public URL of this HTTP server that the DUT can access.") + healthcheck = flag.Bool("healthcheck", false, "Run healthcheck for all SUT services and exit.") +) + +func main() { + flag.Parse() + + if *healthcheck { + runHealthcheck() + return + } + + log.Infof("=============================================================================") + log.Infof("========================= Monolithic SUT Emulator ===========================") + log.Infof("=============================================================================") + + // 1. Load Security Artifacts + tlsCert, err := tls.LoadX509KeyPair(*vendorCACert, *vendorCAKey) + if err != nil { + log.Exitf("Invalid vendor CA cert/key pair: %v.", err) + } + cert, err := x509.ParseCertificate(tlsCert.Certificate[0]) + if err != nil { + log.Exitf("Failed to parse vendor CA cert: %v.", err) + } + rsaKey, ok := tlsCert.PrivateKey.(*rsa.PrivateKey) + if !ok { + log.Exitf("Failed to parse vendor CA key as an RSA key") + } + + log.Infof("Setting up server security artifacts: OC, OVs, PDC, VendorCA") + serials := strings.Split(*generateOVsFor, ",") + sa, err := artifacts.GenerateSecurityArtifacts(serials, "Google", cert, rsaKey) + if err != nil { + log.Exitf("Failed to generate security artifacts: %v", err) + } + + // 2. Initialize Entity Manager + em, err := entitymanager.New(*inventoryConfig, sa) + if err != nil { + log.Exitf("unable to initiate inventory manager: %v", err) + } + + // 3. Start Bootz Server (device-facing) + bootzServer, err := server.NewServer(*bootzAddr, em, sa) + if err != nil { + log.Exitf("Failed to create Bootz server: %v", err) + } + go func() { + if err := bootzServer.Start(); err != nil { + log.Errorf("Bootz server failed: %v", err) + } + }() + log.Infof("Bootz server started on %s", *bootzAddr) + + // 4. Start Bootz Controller (test-facing) + bootzURL := *bootzAddr + if strings.HasPrefix(bootzURL, ":") { + bootzURL = "bootz://bootz-server" + bootzURL // Default hostname in k8s + } else { + bootzURL = "bootz://" + bootzURL + } + controllerServer := controller.New(bootzURL) + if err := controllerServer.Start(*bootzSutAddr); err != nil { + log.Exitf("Failed to start BootzController SUT server: %v", err) + } + + // Link them! + bootzServer.SetNotifyFn(controllerServer.NotifyEvent) + log.Infof("Linked Bootz server and Controller") + + // 5. Start DHCP SUT Server and optionally DHCP server + dhcpSutServer := dhcpsut.New() + if err := dhcpSutServer.Start(*dhcpSutAddr); err != nil { + log.Exitf("Failed to start DHCP SUT server: %v", err) + } + + if *dhcpIntf != "" { + addressMap := make(map[string]*dhcp.Entry) + if *dhcpRecords != "" { + for _, r := range strings.Split(*dhcpRecords, ";") { + parts := strings.Split(r, ",") + if len(parts) >= 2 { + e := &dhcp.Entry{IP: parts[1]} + if len(parts) > 2 { + e.Gw = parts[2] + } + addressMap[parts[0]] = e + } + } + } + dhcpConf := &dhcp.Config{ + Interface: *dhcpIntf, + DNS: strings.Split(*dhcpDns, ";"), + AddressMap: addressMap, + BootzURLs: []string{bootzURL}, + } + if err := dhcp.Start(dhcpConf); err != nil { + log.Errorf("Failed to start DHCP server: %v", err) + } else { + log.Infof("DHCP server started on %s", *dhcpIntf) + } + } + + // 6. Start HTTP SUT Server and HTTP server + httpSutServer := httpsut.New(*httpFolder, *httpPublicURL) + if err := httpSutServer.Start(*httpSutAddr); err != nil { + log.Exitf("Failed to start HTTP SUT server: %v", err) + } + + httpConf := &http.Config{ + Address: *httpAddr, + Folder: *httpFolder, + } + if err := http.Start(httpConf); err != nil { + log.Errorf("Failed to start HTTP server: %v", err) + } else { + log.Infof("HTTP server started on %s", *httpAddr) + } + + // 7. Wait for shutdown signal + sigchan := make(chan os.Signal, 1) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Infof("Shutting down SUT emulator...") + + // Stop all servers + bootzServer.Stop() + controllerServer.Stop() + dhcpSutServer.Stop() + if *dhcpIntf != "" { + dhcp.Stop() + } + httpSutServer.Stop() + http.Stop() + + log.Infof("SUT emulator shut down successfully") +} + +func runHealthcheck() { + targets := []struct { + name string + addr string + }{ + {"Bootz Secure", *bootzAddr}, + {"Bootz Controller SUT", *bootzSutAddr}, + {"DHCP SUT", *dhcpSutAddr}, + {"HTTP SUT", *httpSutAddr}, + {"HTTP File Server", *httpAddr}, + } + + failed := false + for _, t := range targets { + addr := t.addr + if strings.HasPrefix(addr, ":") { + addr = "127.0.0.1" + addr + } + conn, err := net.DialTimeout("tcp", addr, 1*time.Second) + if err != nil { + log.Errorf("Healthcheck failed for %s (%s): %v", t.name, addr, err) + failed = true + } else { + conn.Close() + } + } + + if failed { + os.Exit(1) + } + log.Infof("All SUT services are healthy!") + os.Exit(0) +} diff --git a/server/sutstate/sutstate.go b/server/sutstate/sutstate.go new file mode 100644 index 00000000..da4963b9 --- /dev/null +++ b/server/sutstate/sutstate.go @@ -0,0 +1,87 @@ +// Copyright 2026 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 +// +// https://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 sutstate holds the shared state for the monolithic SUT emulator. +package sutstate + +import ( + "sync" + + bootzpb "github.com/openconfig/bootz/proto/bootz" + testpb "github.com/openconfig/bootz/server/tests/proto/test" +) + +var ( + mu sync.RWMutex + softwareImage *bootzpb.SoftwareImage + bootstrapData *testpb.BootstrapData + securityArtifacts *testpb.SecurityArtifacts + recoveryData *testpb.DUTRecoveryData +) + +// SetSoftwareImage sets the active software image. +func SetSoftwareImage(img *bootzpb.SoftwareImage) { + mu.Lock() + defer mu.Unlock() + softwareImage = img +} + +// GetSoftwareImage returns the active software image. +func GetSoftwareImage() *bootzpb.SoftwareImage { + mu.RLock() + defer mu.RUnlock() + return softwareImage +} + +// SetBootstrapData sets the active bootstrap data. +func SetBootstrapData(data *testpb.BootstrapData) { + mu.Lock() + defer mu.Unlock() + bootstrapData = data +} + +// GetBootstrapData returns the active bootstrap data. +func GetBootstrapData() *testpb.BootstrapData { + mu.RLock() + defer mu.RUnlock() + return bootstrapData +} + +// SetSecurityArtifacts sets the active security artifacts. +func SetSecurityArtifacts(sa *testpb.SecurityArtifacts) { + mu.Lock() + defer mu.Unlock() + securityArtifacts = sa +} + +// GetSecurityArtifacts returns the active security artifacts. +func GetSecurityArtifacts() *testpb.SecurityArtifacts { + mu.RLock() + defer mu.RUnlock() + return securityArtifacts +} + +// SetRecoveryData sets the active recovery data. +func SetRecoveryData(data *testpb.DUTRecoveryData) { + mu.Lock() + defer mu.Unlock() + recoveryData = data +} + +// GetRecoveryData returns the active recovery data. +func GetRecoveryData() *testpb.DUTRecoveryData { + mu.RLock() + defer mu.RUnlock() + return recoveryData +} \ No newline at end of file diff --git a/server/tests/monax_integration/abstract_sut.txtpb b/server/tests/monax_integration/abstract_sut.txtpb new file mode 100644 index 00000000..e1f4485b --- /dev/null +++ b/server/tests/monax_integration/abstract_sut.txtpb @@ -0,0 +1,21 @@ +# proto-file: proto/monax.proto +# proto-message: monax.AbstractSut + +required_interfaces: { + name: "dhcp_service" + grpc: { + service_name: "bootz.DHCPService" + } +} +required_interfaces: { + name: "image_service" + grpc: { + service_name: "bootz.ImageService" + } +} +required_interfaces: { + name: "controller_service" + grpc: { + service_name: "bootz.BootzController" + } +} \ No newline at end of file diff --git a/server/tests/monax_integration/bootz_test.go b/server/tests/monax_integration/bootz_test.go new file mode 100644 index 00000000..7931ec4a --- /dev/null +++ b/server/tests/monax_integration/bootz_test.go @@ -0,0 +1,106 @@ +// Copyright 2026 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 +// +// https://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 monax_integration + +import ( + "context" + "testing" + "time" + + "flag" + + log "github.com/golang/glog" + "github.com/openconfig/monax" + "github.com/openconfig/monax/monaxtest" + "github.com/openconfig/monax/runtime/kubernetesruntime" + + pbgrpc "github.com/openconfig/bootz/server/tests/proto/sut" +) + +var ( + config monax.Config + sut *monax.SUT +) + +func init() { + config.RegisterFlags(nil) +} + +func TestMain(m *testing.M) { + ctx := context.Background() + + flag.Parse() + defer log.Flush() + if testing.Short() { + log.WarningContext(ctx, "Skipping SUT test in short mode") + return + } + + newRuntimeFn := kubernetesruntime.New + + var err error + // Start the SUT (system under test) components only. This is independent of Ondatra and + // does not require a testbed or binding. + sut, err = monaxtest.Start(ctx, &config, newRuntimeFn) + if err != nil { + log.ExitContextf(ctx, "Failed to start SUT: %v", err) + } + defer func() { + if err := sut.Stop(ctx); err != nil { + log.ErrorContextf(ctx, "Failed to stop SUT: %v", err) + } + }() + + m.Run() +} + +func TestSUTConnectivity(t *testing.T) { + ctx, cancel := context.WithTimeout(t.Context(), 30*time.Second) + defer cancel() + + if err := sut.Status(ctx); err != nil { + t.Fatalf("SUT is unhealthy: %v", err) + } + + // 1. Dial and verify DHCP SUT service + t.Run("DHCP Service", func(t *testing.T) { + dhcpConn, err := sut.Interfaces().GRPC(ctx, "bootz.DHCPService") + if err != nil { + t.Fatalf("Failed to connect to SUT DHCPService: %v", err) + } + dhcpClient := pbgrpc.NewDHCPServiceClient(dhcpConn) + t.Logf("Successfully established gRPC channel to SUT DHCPService: %v", dhcpClient) + }) + + // 2. Dial and verify Image SUT service + t.Run("Image Service", func(t *testing.T) { + imageConn, err := sut.Interfaces().GRPC(ctx, "bootz.ImageService") + if err != nil { + t.Fatalf("Failed to connect to SUT ImageService: %v", err) + } + imageClient := pbgrpc.NewImageServiceClient(imageConn) + t.Logf("Successfully established gRPC channel to SUT ImageService: %v", imageClient) + }) + + // 3. Dial and verify BootzController SUT service + t.Run("BootzController Service", func(t *testing.T) { + controllerConn, err := sut.Interfaces().GRPC(ctx, "bootz.BootzController") + if err != nil { + t.Fatalf("Failed to connect to SUT BootzController: %v", err) + } + controllerClient := pbgrpc.NewBootzControllerClient(controllerConn) + t.Logf("Successfully established gRPC channel to SUT BootzController: %v", controllerClient) + }) +} \ No newline at end of file diff --git a/server/tests/monax_integration/bootz_test_kubernetes.sh b/server/tests/monax_integration/bootz_test_kubernetes.sh new file mode 100644 index 00000000..7a251d89 --- /dev/null +++ b/server/tests/monax_integration/bootz_test_kubernetes.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# Copyright 2026 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 +# +# https://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. + +# Run the bootz services test in an existing Kubernetes cluster. + +readonly SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +readonly BOOTZ_DIR="$( cd -- "${SCRIPT_DIR}/../../.." &> /dev/null && pwd )" +readonly MONAX_DIR="$( cd -- "${BOOTZ_DIR}/../monax" &> /dev/null && pwd )" + +function build_and_load_image() { + local name=$1 + local dockerfile=$2 + + echo "Building image ${name}..." + if ! docker build \ + --file "${BOOTZ_DIR}/${dockerfile}" \ + --tag "${name}:latest" \ + "${BOOTZ_DIR}/.."; then + echo "Could not build ${name}" >&2 + exit 1 + fi + + echo "Loading image ${name} into kind cluster ${KIND_CLUSTER}..." + if ! kind load docker-image "${name}:latest" --name "${KIND_CLUSTER}"; then + echo "Could not load ${name} into cluster ${KIND_CLUSTER}" >&2 + exit 1 + fi +} + +function run_test() { + # Run the test from Bootz root directory to ensure local package imports resolve correctly. + cd "${BOOTZ_DIR}" + GOROOT= go test -v server/tests/monax_integration/bootz_test.go \ + --abstract_sut="${BOOTZ_DIR}/server/tests/monax_integration/abstract_sut.txtpb" \ + --library="${BOOTZ_DIR}/server/tests/monax_integration/kubernetes_library.txtpb" \ + --runtime_parameters="${BOOTZ_DIR}/server/tests/monax_integration/kubernetes_runtime_parame +ters.txtpb" \ + --alsologtostderr +} + +function main() { + if [[ -z "${KIND_CLUSTER}" ]]; then + echo "Error: KIND_CLUSTER is not set." >&2 + echo "Please set 'KIND_CLUSTER=your_kind_cluster_name' before running this script." >&2 + exit 1 + fi + + build_and_load_image "bootz-sut" "Dockerfile.sut" + + run_test +} + +main "$@" \ No newline at end of file diff --git a/server/tests/monax_integration/cleanup_sut.sh b/server/tests/monax_integration/cleanup_sut.sh new file mode 100644 index 00000000..2e88b708 --- /dev/null +++ b/server/tests/monax_integration/cleanup_sut.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# Copyright 2026 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 +# +# https://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. + +# Force purge all lingering SUT resources from the Kind cluster default namespace. + +echo "========================================================" +# 1. Delete deployment and services +echo "Deleting bootz-sut deployments and services..." +kubectl delete deployment bootz-sut --ignore-not-found=true +kubectl delete service bootz-sut --ignore-not-found=true + +# 2. Force delete ConfigMaps (avoiding garbage collection delays) +echo "Purging bootz-sut ConfigMaps..." +kubectl delete configmap bootz-sut --ignore-not-found=true --grace-period=0 --force + +# 3. Wait for resources to be fully expunged +echo "Waiting for resource cleanup to settle..." +sleep 5 + +echo "Active default namespace resources:" +kubectl get all +echo "========================================================" +echo "Cleanup complete. Ready to start SUT." \ No newline at end of file diff --git a/server/tests/monax_integration/kubernetes_library.txtpb b/server/tests/monax_integration/kubernetes_library.txtpb new file mode 100644 index 00000000..af375991 --- /dev/null +++ b/server/tests/monax_integration/kubernetes_library.txtpb @@ -0,0 +1,4 @@ +# proto-file: proto/monax.proto +# proto-message: monax.Library + +libraries: "../../sut/deploy/kubernetes.txtpb" \ No newline at end of file diff --git a/server/tests/monax_integration/kubernetes_runtime_parameters.txtpb b/server/tests/monax_integration/kubernetes_runtime_parameters.txtpb new file mode 100644 index 00000000..bc638a94 --- /dev/null +++ b/server/tests/monax_integration/kubernetes_runtime_parameters.txtpb @@ -0,0 +1,12 @@ +# proto-file: proto/monax.proto +# proto-message: monax.RuntimeParameters + +parameters: { + [type.googleapis.com/monax.kubernetes.KubernetesRuntimeParameters]: { + name: "bootz" + kubernetes: { + kubeconfig_path: "${HOME}/.kube/config" + service_type: SERVICE_TYPE_NODE_PORT + } + } +} \ No newline at end of file diff --git a/server/tests/monax_integration/runner/runner.go b/server/tests/monax_integration/runner/runner.go new file mode 100644 index 00000000..98a71a45 --- /dev/null +++ b/server/tests/monax_integration/runner/runner.go @@ -0,0 +1,348 @@ +// Copyright 2026 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 +// +// https://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 runner contains the integration test runner for the Bootz SUT. +package runner + +import ( + "context" + "fmt" + "testing" + "time" + + "flag" + log "github.com/golang/glog" + "google.golang.org/protobuf/encoding/prototext" + "github.com/openconfig/gnoigo/factoryreset" + "github.com/openconfig/gnoigo" + "github.com/openconfig/monax" + "github.com/openconfig/monax/monaxondatratest" + "github.com/openconfig/monax/runtime/kubernetesruntime" + "github.com/openconfig/ondatra/binding" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra" + + bootzpb "github.com/openconfig/bootz/proto/bootz" + pbgrpc "github.com/openconfig/bootz/server/tests/proto/sut" + pb "github.com/openconfig/bootz/server/tests/proto/sut" + dpb "github.com/openconfig/bootz/server/tests/proto/test" +) + +const ( + bootzTimeout = 1 * time.Hour +) + +var ( + config monax.Config + sut *monax.SUT + params *dpb.TestParameters + macAddresses []string +) + +func fetchMACAddresses(t *testing.T, dut *ondatra.DUTDevice) []string { + t.Helper() + var macAddresses []string + for _, intf := range params.GetInterfaceInfo().GetManagementInterfaceNames() { + val, ok := gnmi.Lookup(t, dut, gnmi.OC().Interface(intf).Ethernet().MacAddress( +).State()).Val() + if ok && val != "" { + macAddresses = append(macAddresses, val) + } + } + if len(macAddresses) == 0 { + t.Fatalf("Failed to find any MAC addresses for DUT %s", dut.ID()) + } + return macAddresses +} + +func dhcpService(ctx context.Context, t *testing.T) pbgrpc.DHCPServiceClient { + t.Helper() + dhcpServiceConn, err := sut.Interfaces().GRPC(ctx, "bootz.DHCPService") + if err != nil { + t.Fatalf("Failed to get DHCPService connection: %v", err) + } + return pbgrpc.NewDHCPServiceClient(dhcpServiceConn) +} + +func controllerService(ctx context.Context, t *testing.T) pbgrpc.BootzControllerClient { + t.Helper() + controllerServiceConn, err := sut.Interfaces().GRPC(ctx, "bootz.BootzController") + if err != nil { + t.Fatalf("Failed to get BootzController connection: %v", err) + } + return pbgrpc.NewBootzControllerClient(controllerServiceConn) +} + +func imageService(ctx context.Context, t *testing.T) pbgrpc.ImageServiceClient { + t.Helper() + imageServiceConn, err := sut.Interfaces().GRPC(ctx, "bootz.ImageService") + if err != nil { + t.Fatalf("Failed to get ImageService connection: %v", err) + } + return pbgrpc.NewImageServiceClient(imageServiceConn) +} + +func init() { + config.RegisterFlags(nil) +} + +// Init initializes the Bootz Monax test. +func Init(ctx context.Context, m *testing.M, newBindFn func() (binding.Binding, error)) error { + if !flag.Parsed() { + flag.Parse() + } + newRuntimeFn := kubernetesruntime.New + + var err error + sut, err = monaxondatratest.Init(ctx, &config, newRuntimeFn) + if err != nil { + log.ErrorContextf(ctx, "Failed to initialize SUT: %v", err) + return fmt.Errorf("failed to initialize SUT: %w", err) + } + if newBindFn == nil { + // If no binding function is provided, pass nil to let Ondatra use its globally + // registered binding, which is the standard way Ondatra runs when a binding + // package is imported anonymously (e.g. `import _ "github.com/myorg/ondatrabind"`). + ondatra.RunTests(m, nil) + } else { + ondatra.RunTests(m, newBindFn) + } + return nil +} + +func parseBootzParameters(p *dpb.TestParameters) error { + if p == nil { + return fmt.Errorf("Bootz parameters are required") + } + if p.GetInterfaceInfo() == nil { + return fmt.Errorf("interface_info is required") + } + if p.GetInterfaceInfo().GetDhcpAddress() == "" { + return fmt.Errorf("dhcp_address is required") + } + if p.GetInterfaceInfo().GetDefaultGateway() == "" { + return fmt.Errorf("default_gateway is required") + } + if p.GetInterfaceInfo().GetMaskLength() == 0 { + return fmt.Errorf("mask_length is required") + } + if p.GetOsImage() == nil { + return fmt.Errorf("os_image is required") + } + if p.GetOsImage().GetName() == "" { + return fmt.Errorf("os_image name is required") + } + if p.GetOsImage().GetVersion() == "" { + return fmt.Errorf("os_image version is required") + } + if p.GetOsImage().GetDownloadUri() == "" { + return fmt.Errorf("os_image download_uri is required") + } + if len(p.GetInterfaceInfo().GetManagementInterfaceNames()) == 0 { + return fmt.Errorf("At least one management interface name is required") + } + if p.GetBootstrapData() == nil { + return fmt.Errorf("bootstrap_data is required") + } + params = p + return nil +} + +func waitForBootz(t *testing.T, stream pbgrpc.BootzController_SubscribeClient) error { + t.Helper() + for { + message, err := stream.Recv() + if err != nil { + return err + } + t.Logf("Received message from Bootz controller:\n%v", prototext.Format(message)) + if message.GetError() != "" { + return fmt.Errorf("Bootz controller returned an error to the DUT: %v", +message.GetError()) + } + if message.GetReportStatusRequest() != nil { + switch message.GetReportStatusRequest().GetStatus() { + case bootzpb.ReportStatusRequest_BOOTSTRAP_STATUS_SUCCESS: + t.Logf("Received BOOTSTRAP_STATUS_SUCCESS from DUT") + return nil + case bootzpb.ReportStatusRequest_BOOTSTRAP_STATUS_FAILURE: + return fmt.Errorf("Received BOOTSTRAP_STATUS_FAILURE from DUT: %v", message.GetReportStatusRequest().GetStatusMessage()) + } + } + } +} + +func attemptGNOIFactoryReset(ctx context.Context, t *testing.T, dut *ondatra.DUTDevice) error { + t.Helper() + var err error + for i := 0; i < 3; i++ { + err = func() error { + attemptCtx, cancel := context.WithTimeout(ctx, 45*time.Second) + defer cancel() + + c, err := dut.RawAPIs().BindingDUT().DialGNOI(attemptCtx) + if err != nil { + return fmt.Errorf("failed to dial gNOI: %v", err) + } + op := factoryreset.NewStartOperation().ZeroFill(false).FactoryOS(false) + _, err = gnoigo.Execute(attemptCtx, c, op) + if err != nil { + return fmt.Errorf("failed to execute gNOI factory reset: %v", err) + } + return nil + }() + if err == nil { + t.Logf("Successfully factory reset DUT over gNOI") + return nil + } + t.Logf("Attempt %d to factory reset over gNOI failed: %v", i+1, err) + if i < 2 { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(10 * time.Second): + } + } + } + return fmt.Errorf("failed to factory reset DUT over gNOI after 3 attempts: last error %v", err) +} + + + +func fetchDUT(t *testing.T) *ondatra.DUTDevice { + t.Helper() + duts := ondatra.DUTs(t) + if len(duts) != 1 { + t.Fatalf("expected exactly 1 DUT, got %d", len(duts)) + } + for _, dut := range duts { + return dut + } + t.Fatalf("internal error: Failed to find DUT") + return nil +} + +// Run executes the Bootz test. +func Run(t *testing.T, parameters *dpb.TestParameters) { + t.Helper() + ctx := t.Context() + if err := parseBootzParameters(parameters); err != nil { + t.Fatalf("Failed to parse bootz parameters: %v", err) + } + if err := sut.Status(ctx); err != nil { + t.Fatalf("SUT is unhealthy: %v", err) + } + t.Logf("Getting DUT info") + dut := fetchDUT(t) + t.Logf("Found DUT with ID: %q", dut.ID()) + macAddresses = fetchMACAddresses(t, dut) + t.Logf("Found DUT MAC addresses: %v", macAddresses) + + waitCtx, cancel := context.WithTimeout(ctx, bootzTimeout) + defer cancel() + + // 1. Prepare the OS image in the Image Service. + imageService := imageService(waitCtx, t) + uploadReq := &pb.UploadRequest{ + Image: params.GetOsImage(), + } + uploadResp, err := imageService.Upload(waitCtx, uploadReq) + if err != nil { + t.Fatalf("Failed to upload image to Image Server: %v", err) + } + t.Logf("Upload() response:\n%v", prototext.Format(uploadResp)) + + // 2. Set Bootstrap Data and Security Artifacts for the DUT. + controllerService := controllerService(waitCtx, t) + + setBootReq := &pb.SetBootstrapDataRequest{ + BootstrapData: params.GetBootstrapData(), + } + if _, err := controllerService.SetBootstrapData(waitCtx, setBootReq); err != nil { + t.Fatalf("Failed to set Bootstrap data: %v", err) + } + t.Logf("Set Bootstrap data for DUT") + + if params.GetSecurityArtifacts() != nil { + setSecReq := &pb.SetSecurityArtifactsRequest{ + SecurityArtifacts: params.GetSecurityArtifacts(), + } + if _, err := controllerService.SetSecurityArtifacts(waitCtx, setSecReq); err != + nil { + t.Fatalf("Failed to set Security Artifacts: %v", err) + } + t.Logf("Set Security Artifacts for DUT") + } + + if params.GetRecoveryData() != nil { + setRecReq := &pb.SetRecoveryDataRequest{ + RecoveryData: params.GetRecoveryData(), + } + if _, err := controllerService.SetRecoveryData(waitCtx, setRecReq); err != nil { + t.Fatalf("Failed to set Recovery Data: %v", err) + } + t.Logf("Set Recovery Data for DUT") + } + + // 3. Discover the Bootz URL. + bootzURLResp, err := controllerService.GetBootzURL(waitCtx, &pb.GetBootzURLRequest{}) + if err != nil { + t.Fatalf("Failed to get Bootz URL: %v", err) + } + t.Logf("GetBootzURL() response:\n%v", prototext.Format(bootzURLResp)) + + // 4. Create the DHCP lease. + dhcpService := dhcpService(waitCtx, t) + createLeaseReq := &pb.CreateLeaseRequest{ + BootzServerAddress: bootzURLResp.GetBootzUrl(), + IpAddress: params.GetInterfaceInfo().GetDhcpAddress(), + MacAddresses: macAddresses, + MaskLen: params.GetInterfaceInfo().GetMaskLength(), + Gateway: params.GetInterfaceInfo().GetDefaultGateway(), + } + if _, err := dhcpService.CreateLease(waitCtx, createLeaseReq); err != nil { + t.Fatalf("Failed to create DHCP lease: %v", err) + } + t.Logf("Created DHCP lease for MAC addresses: %v", macAddresses) + + // 5. Factory Reset the DUT. + if err := attemptGNOIFactoryReset(waitCtx, t, dut); err != nil { + t.Logf("Failed to factory reset DUT over gNOI: %v", err) + t.Logf("Assuming DUT is in ZTP loop and continuing with Bootz") + } + + // 6. Start listening for Bootz status reports. + stream, err := controllerService.Subscribe(waitCtx, &pb.SubscribeRequest{}) + if err != nil { + t.Fatalf("Failed to subscribe to Bootz status reports: %v", err) + } + + t.Logf("Listening for Bootz status reports from DUT") + + errChan := make(chan error, 1) + go func() { + errChan <- waitForBootz(t, stream) + }() + + select { + case err := <-errChan: + if err != nil { + t.Fatalf("Bootz failed: %v", err) + } + t.Logf("Bootz succeeded for DUT %s", dut.ID()) + case <-waitCtx.Done(): + t.Fatalf("Bootz timed out after %v", bootzTimeout) + } +} + diff --git a/server/tests/monax_integration/testbed.textproto b/server/tests/monax_integration/testbed.textproto new file mode 100644 index 00000000..9c2285da --- /dev/null +++ b/server/tests/monax_integration/testbed.textproto @@ -0,0 +1,6 @@ +# proto-file: github.com/openconfig/ondatra/proto/testbed.proto +# proto-message: ondatra.Testbed + +duts { + id: "dut" +} \ No newline at end of file diff --git a/server/tests/proto/sut/sut.pb.go b/server/tests/proto/sut/sut.pb.go new file mode 100644 index 00000000..7968ef1b --- /dev/null +++ b/server/tests/proto/sut/sut.pb.go @@ -0,0 +1,945 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.29.3 +// source: github.com/openconfig/bootz/server/tests/proto/sut.proto + +package sut + +import ( + bootz "github.com/openconfig/bootz/proto/bootz" + test "github.com/openconfig/bootz/server/tests/proto/test" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CreateLeaseRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // MAC addresses to associate with this DHCP lease. For modular devices, this + // allows either control card to acquire the lease. + MacAddresses []string `protobuf:"bytes,1,rep,name=mac_addresses,json=macAddresses,proto3" json:"mac_addresses,omitempty"` + // The IP address to associate with this lease. Note, for a modular chassis + // only the active control card will acquire the lease, so only one IP + // address should be provided. + // For example, "192.168.1.100" or "2001:db8::2". + IpAddress string `protobuf:"bytes,2,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` + // The mask length of the lease IP address. For example, "24" for IPv4 or + // "120" for IPv6. + MaskLen int32 `protobuf:"varint,3,opt,name=mask_len,json=maskLen,proto3" json:"mask_len,omitempty"` + // The gateway IP address. For example,"192.168.1.1" or "2001:db8::1". + Gateway string `protobuf:"bytes,4,opt,name=gateway,proto3" json:"gateway,omitempty"` + // The address of the Bootz server to be included in the DHCP response. It + // should have the format: bootz://:. For example: + // * IPv6: bootz://[2001:db8::1]:12345 + // * IPv4: bootz://192.168.1.1:12345 + BootzServerAddress string `protobuf:"bytes,5,opt,name=bootz_server_address,json=bootzServerAddress,proto3" json:"bootz_server_address,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateLeaseRequest) Reset() { + *x = CreateLeaseRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateLeaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateLeaseRequest) ProtoMessage() {} + +func (x *CreateLeaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateLeaseRequest.ProtoReflect.Descriptor instead. +func (*CreateLeaseRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateLeaseRequest) GetMacAddresses() []string { + if x != nil { + return x.MacAddresses + } + return nil +} + +func (x *CreateLeaseRequest) GetIpAddress() string { + if x != nil { + return x.IpAddress + } + return "" +} + +func (x *CreateLeaseRequest) GetMaskLen() int32 { + if x != nil { + return x.MaskLen + } + return 0 +} + +func (x *CreateLeaseRequest) GetGateway() string { + if x != nil { + return x.Gateway + } + return "" +} + +func (x *CreateLeaseRequest) GetBootzServerAddress() string { + if x != nil { + return x.BootzServerAddress + } + return "" +} + +type CreateLeaseResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateLeaseResponse) Reset() { + *x = CreateLeaseResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateLeaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateLeaseResponse) ProtoMessage() {} + +func (x *CreateLeaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateLeaseResponse.ProtoReflect.Descriptor instead. +func (*CreateLeaseResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{1} +} + +type RemoveLeaseRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The MAC addresses to remove the DHCP lease for. + MacAddresses []string `protobuf:"bytes,1,rep,name=mac_addresses,json=macAddresses,proto3" json:"mac_addresses,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RemoveLeaseRequest) Reset() { + *x = RemoveLeaseRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoveLeaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveLeaseRequest) ProtoMessage() {} + +func (x *RemoveLeaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveLeaseRequest.ProtoReflect.Descriptor instead. +func (*RemoveLeaseRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{2} +} + +func (x *RemoveLeaseRequest) GetMacAddresses() []string { + if x != nil { + return x.MacAddresses + } + return nil +} + +type RemoveLeaseResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RemoveLeaseResponse) Reset() { + *x = RemoveLeaseResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoveLeaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveLeaseResponse) ProtoMessage() {} + +func (x *RemoveLeaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveLeaseResponse.ProtoReflect.Descriptor instead. +func (*RemoveLeaseResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{3} +} + +type UploadRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Details about the OS to be made available to the DUT. If `reupload_to_sut` + // is true, the service should fetch the image from the provided URL and make + // it available on a URL that the DUT can access. This final URL should be + // included in the `image.url` field of the response. If `reupload_to_sut` is + // false, the provided URL will be used directly in the `image.url` field of + // the response. + Image *test.OSImage `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadRequest) Reset() { + *x = UploadRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadRequest) ProtoMessage() {} + +func (x *UploadRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadRequest.ProtoReflect.Descriptor instead. +func (*UploadRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{4} +} + +func (x *UploadRequest) GetImage() *test.OSImage { + if x != nil { + return x.Image + } + return nil +} + +type UploadResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The final Bootz SoftwareImage that the Bootz controller SUT should provide + // to the DUT during the Bootz test. + Image *bootz.SoftwareImage `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadResponse) Reset() { + *x = UploadResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadResponse) ProtoMessage() {} + +func (x *UploadResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadResponse.ProtoReflect.Descriptor instead. +func (*UploadResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{5} +} + +func (x *UploadResponse) GetImage() *bootz.SoftwareImage { + if x != nil { + return x.Image + } + return nil +} + +type SetBootstrapDataRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The data to be used by the Bootz SUT during the Bootz test. + BootstrapData *test.BootstrapData `protobuf:"bytes,1,opt,name=bootstrap_data,json=bootstrapData,proto3" json:"bootstrap_data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetBootstrapDataRequest) Reset() { + *x = SetBootstrapDataRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetBootstrapDataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetBootstrapDataRequest) ProtoMessage() {} + +func (x *SetBootstrapDataRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetBootstrapDataRequest.ProtoReflect.Descriptor instead. +func (*SetBootstrapDataRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{6} +} + +func (x *SetBootstrapDataRequest) GetBootstrapData() *test.BootstrapData { + if x != nil { + return x.BootstrapData + } + return nil +} + +type SetBootstrapDataResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetBootstrapDataResponse) Reset() { + *x = SetBootstrapDataResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetBootstrapDataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetBootstrapDataResponse) ProtoMessage() {} + +func (x *SetBootstrapDataResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetBootstrapDataResponse.ProtoReflect.Descriptor instead. +func (*SetBootstrapDataResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{7} +} + +type SetSecurityArtifactsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The security artifacts to be used by the Bootz SUT during the Bootz test. + SecurityArtifacts *test.SecurityArtifacts `protobuf:"bytes,1,opt,name=security_artifacts,json=securityArtifacts,proto3" json:"security_artifacts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetSecurityArtifactsRequest) Reset() { + *x = SetSecurityArtifactsRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetSecurityArtifactsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetSecurityArtifactsRequest) ProtoMessage() {} + +func (x *SetSecurityArtifactsRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetSecurityArtifactsRequest.ProtoReflect.Descriptor instead. +func (*SetSecurityArtifactsRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{8} +} + +func (x *SetSecurityArtifactsRequest) GetSecurityArtifacts() *test.SecurityArtifacts { + if x != nil { + return x.SecurityArtifacts + } + return nil +} + +type SetSecurityArtifactsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetSecurityArtifactsResponse) Reset() { + *x = SetSecurityArtifactsResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetSecurityArtifactsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetSecurityArtifactsResponse) ProtoMessage() {} + +func (x *SetSecurityArtifactsResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetSecurityArtifactsResponse.ProtoReflect.Descriptor instead. +func (*SetSecurityArtifactsResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{9} +} + +type GetBootzURLRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBootzURLRequest) Reset() { + *x = GetBootzURLRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBootzURLRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBootzURLRequest) ProtoMessage() {} + +func (x *GetBootzURLRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBootzURLRequest.ProtoReflect.Descriptor instead. +func (*GetBootzURLRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{10} +} + +type GetBootzURLResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The Bootz URL that the DUT should use to contact the Bootz SUT. + // This URL will be of the format: bootz://:. For + // example: + // * IPv6: bootz://[2001:db8::1]:12345 + // * IPv4: bootz://192.168.1.1:12345 + BootzUrl string `protobuf:"bytes,1,opt,name=bootz_url,json=bootzUrl,proto3" json:"bootz_url,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetBootzURLResponse) Reset() { + *x = GetBootzURLResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetBootzURLResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBootzURLResponse) ProtoMessage() {} + +func (x *GetBootzURLResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBootzURLResponse.ProtoReflect.Descriptor instead. +func (*GetBootzURLResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{11} +} + +func (x *GetBootzURLResponse) GetBootzUrl() string { + if x != nil { + return x.BootzUrl + } + return "" +} + +type SubscribeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubscribeRequest) Reset() { + *x = SubscribeRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubscribeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubscribeRequest) ProtoMessage() {} + +func (x *SubscribeRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead. +func (*SubscribeRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{12} +} + +type SubscribeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Event: + // + // *SubscribeResponse_GetBootstrapDataRequest + // *SubscribeResponse_ReportStatusRequest + Event isSubscribeResponse_Event `protobuf_oneof:"event"` + // The error, if any, that was returned to the DUT in response to this event. + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubscribeResponse) Reset() { + *x = SubscribeResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubscribeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubscribeResponse) ProtoMessage() {} + +func (x *SubscribeResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubscribeResponse.ProtoReflect.Descriptor instead. +func (*SubscribeResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{13} +} + +func (x *SubscribeResponse) GetEvent() isSubscribeResponse_Event { + if x != nil { + return x.Event + } + return nil +} + +func (x *SubscribeResponse) GetGetBootstrapDataRequest() *bootz.GetBootstrapDataRequest { + if x != nil { + if x, ok := x.Event.(*SubscribeResponse_GetBootstrapDataRequest); ok { + return x.GetBootstrapDataRequest + } + } + return nil +} + +func (x *SubscribeResponse) GetReportStatusRequest() *bootz.ReportStatusRequest { + if x != nil { + if x, ok := x.Event.(*SubscribeResponse_ReportStatusRequest); ok { + return x.ReportStatusRequest + } + } + return nil +} + +func (x *SubscribeResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type isSubscribeResponse_Event interface { + isSubscribeResponse_Event() +} + +type SubscribeResponse_GetBootstrapDataRequest struct { + // The GetBootstrapDataRequest that the DUT sends to the Bootz SUT. + GetBootstrapDataRequest *bootz.GetBootstrapDataRequest `protobuf:"bytes,1,opt,name=get_bootstrap_data_request,json=getBootstrapDataRequest,proto3,oneof"` +} + +type SubscribeResponse_ReportStatusRequest struct { + // The ReportStatusRequest that the DUT sends to the Bootz SUT. + ReportStatusRequest *bootz.ReportStatusRequest `protobuf:"bytes,2,opt,name=report_status_request,json=reportStatusRequest,proto3,oneof"` +} + +func (*SubscribeResponse_GetBootstrapDataRequest) isSubscribeResponse_Event() {} + +func (*SubscribeResponse_ReportStatusRequest) isSubscribeResponse_Event() {} + +type SetRecoveryDataRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The recovery data to be used by the Bootz SUT after the test is complete. + RecoveryData *test.DUTRecoveryData `protobuf:"bytes,1,opt,name=recovery_data,json=recoveryData,proto3" json:"recovery_data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetRecoveryDataRequest) Reset() { + *x = SetRecoveryDataRequest{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetRecoveryDataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetRecoveryDataRequest) ProtoMessage() {} + +func (x *SetRecoveryDataRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetRecoveryDataRequest.ProtoReflect.Descriptor instead. +func (*SetRecoveryDataRequest) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{14} +} + +func (x *SetRecoveryDataRequest) GetRecoveryData() *test.DUTRecoveryData { + if x != nil { + return x.RecoveryData + } + return nil +} + +type SetRecoveryDataResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetRecoveryDataResponse) Reset() { + *x = SetRecoveryDataResponse{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetRecoveryDataResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetRecoveryDataResponse) ProtoMessage() {} + +func (x *SetRecoveryDataResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetRecoveryDataResponse.ProtoReflect.Descriptor instead. +func (*SetRecoveryDataResponse) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP(), []int{15} +} + +var File_github_com_openconfig_bootz_server_tests_proto_sut_proto protoreflect.FileDescriptor + +const file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDesc = "" + + "\n" + + "8github.com/openconfig/bootz/server/tests/proto/sut.proto\x12\x05bootz\x1a-github.com/openconfig/bootz/proto/bootz.proto\x1a9github.com/openconfig/bootz/server/tests/proto/test.proto\"\xbf\x01\n" + + "\x12CreateLeaseRequest\x12#\n" + + "\rmac_addresses\x18\x01 \x03(\tR\fmacAddresses\x12\x1d\n" + + "\n" + + "ip_address\x18\x02 \x01(\tR\tipAddress\x12\x19\n" + + "\bmask_len\x18\x03 \x01(\x05R\amaskLen\x12\x18\n" + + "\agateway\x18\x04 \x01(\tR\agateway\x120\n" + + "\x14bootz_server_address\x18\x05 \x01(\tR\x12bootzServerAddress\"\x15\n" + + "\x13CreateLeaseResponse\"9\n" + + "\x12RemoveLeaseRequest\x12#\n" + + "\rmac_addresses\x18\x01 \x03(\tR\fmacAddresses\"\x15\n" + + "\x13RemoveLeaseResponse\"5\n" + + "\rUploadRequest\x12$\n" + + "\x05image\x18\x01 \x01(\v2\x0e.bootz.OSImageR\x05image\"<\n" + + "\x0eUploadResponse\x12*\n" + + "\x05image\x18\x01 \x01(\v2\x14.bootz.SoftwareImageR\x05image\"V\n" + + "\x17SetBootstrapDataRequest\x12;\n" + + "\x0ebootstrap_data\x18\x01 \x01(\v2\x14.bootz.BootstrapDataR\rbootstrapData\"\x1a\n" + + "\x18SetBootstrapDataResponse\"f\n" + + "\x1bSetSecurityArtifactsRequest\x12G\n" + + "\x12security_artifacts\x18\x01 \x01(\v2\x18.bootz.SecurityArtifactsR\x11securityArtifacts\"\x1e\n" + + "\x1cSetSecurityArtifactsResponse\"\x14\n" + + "\x12GetBootzURLRequest\"2\n" + + "\x13GetBootzURLResponse\x12\x1b\n" + + "\tbootz_url\x18\x01 \x01(\tR\bbootzUrl\"\x12\n" + + "\x10SubscribeRequest\"\xe3\x01\n" + + "\x11SubscribeResponse\x12]\n" + + "\x1aget_bootstrap_data_request\x18\x01 \x01(\v2\x1e.bootz.GetBootstrapDataRequestH\x00R\x17getBootstrapDataRequest\x12P\n" + + "\x15report_status_request\x18\x02 \x01(\v2\x1a.bootz.ReportStatusRequestH\x00R\x13reportStatusRequest\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05errorB\a\n" + + "\x05event\"U\n" + + "\x16SetRecoveryDataRequest\x12;\n" + + "\rrecovery_data\x18\x01 \x01(\v2\x16.bootz.DUTRecoveryDataR\frecoveryData\"\x19\n" + + "\x17SetRecoveryDataResponse2\x9d\x01\n" + + "\vDHCPService\x12F\n" + + "\vCreateLease\x12\x19.bootz.CreateLeaseRequest\x1a\x1a.bootz.CreateLeaseResponse\"\x00\x12F\n" + + "\vRemoveLease\x12\x19.bootz.RemoveLeaseRequest\x1a\x1a.bootz.RemoveLeaseResponse\"\x002G\n" + + "\fImageService\x127\n" + + "\x06Upload\x12\x14.bootz.UploadRequest\x1a\x15.bootz.UploadResponse\"\x002\xab\x03\n" + + "\x0fBootzController\x12U\n" + + "\x10SetBootstrapData\x12\x1e.bootz.SetBootstrapDataRequest\x1a\x1f.bootz.SetBootstrapDataResponse\"\x00\x12a\n" + + "\x14SetSecurityArtifacts\x12\".bootz.SetSecurityArtifactsRequest\x1a#.bootz.SetSecurityArtifactsResponse\"\x00\x12R\n" + + "\x0fSetRecoveryData\x12\x1d.bootz.SetRecoveryDataRequest\x1a\x1e.bootz.SetRecoveryDataResponse\"\x00\x12F\n" + + "\vGetBootzURL\x12\x19.bootz.GetBootzURLRequest\x1a\x1a.bootz.GetBootzURLResponse\"\x00\x12B\n" + + "\tSubscribe\x12\x17.bootz.SubscribeRequest\x1a\x18.bootz.SubscribeResponse\"\x000\x01B4Z2github.com/openconfig/bootz/server/tests/proto/sutb\x06proto3" + +var ( + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescOnce sync.Once + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescData []byte +) + +func file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescGZIP() []byte { + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescOnce.Do(func() { + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDesc), len(file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDesc))) + }) + return file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDescData +} + +var file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_github_com_openconfig_bootz_server_tests_proto_sut_proto_goTypes = []any{ + (*CreateLeaseRequest)(nil), // 0: bootz.CreateLeaseRequest + (*CreateLeaseResponse)(nil), // 1: bootz.CreateLeaseResponse + (*RemoveLeaseRequest)(nil), // 2: bootz.RemoveLeaseRequest + (*RemoveLeaseResponse)(nil), // 3: bootz.RemoveLeaseResponse + (*UploadRequest)(nil), // 4: bootz.UploadRequest + (*UploadResponse)(nil), // 5: bootz.UploadResponse + (*SetBootstrapDataRequest)(nil), // 6: bootz.SetBootstrapDataRequest + (*SetBootstrapDataResponse)(nil), // 7: bootz.SetBootstrapDataResponse + (*SetSecurityArtifactsRequest)(nil), // 8: bootz.SetSecurityArtifactsRequest + (*SetSecurityArtifactsResponse)(nil), // 9: bootz.SetSecurityArtifactsResponse + (*GetBootzURLRequest)(nil), // 10: bootz.GetBootzURLRequest + (*GetBootzURLResponse)(nil), // 11: bootz.GetBootzURLResponse + (*SubscribeRequest)(nil), // 12: bootz.SubscribeRequest + (*SubscribeResponse)(nil), // 13: bootz.SubscribeResponse + (*SetRecoveryDataRequest)(nil), // 14: bootz.SetRecoveryDataRequest + (*SetRecoveryDataResponse)(nil), // 15: bootz.SetRecoveryDataResponse + (*test.OSImage)(nil), // 16: bootz.OSImage + (*bootz.SoftwareImage)(nil), // 17: bootz.SoftwareImage + (*test.BootstrapData)(nil), // 18: bootz.BootstrapData + (*test.SecurityArtifacts)(nil), // 19: bootz.SecurityArtifacts + (*bootz.GetBootstrapDataRequest)(nil), // 20: bootz.GetBootstrapDataRequest + (*bootz.ReportStatusRequest)(nil), // 21: bootz.ReportStatusRequest + (*test.DUTRecoveryData)(nil), // 22: bootz.DUTRecoveryData +} +var file_github_com_openconfig_bootz_server_tests_proto_sut_proto_depIdxs = []int32{ + 16, // 0: bootz.UploadRequest.image:type_name -> bootz.OSImage + 17, // 1: bootz.UploadResponse.image:type_name -> bootz.SoftwareImage + 18, // 2: bootz.SetBootstrapDataRequest.bootstrap_data:type_name -> bootz.BootstrapData + 19, // 3: bootz.SetSecurityArtifactsRequest.security_artifacts:type_name -> bootz.SecurityArtifacts + 20, // 4: bootz.SubscribeResponse.get_bootstrap_data_request:type_name -> bootz.GetBootstrapDataRequest + 21, // 5: bootz.SubscribeResponse.report_status_request:type_name -> bootz.ReportStatusRequest + 22, // 6: bootz.SetRecoveryDataRequest.recovery_data:type_name -> bootz.DUTRecoveryData + 0, // 7: bootz.DHCPService.CreateLease:input_type -> bootz.CreateLeaseRequest + 2, // 8: bootz.DHCPService.RemoveLease:input_type -> bootz.RemoveLeaseRequest + 4, // 9: bootz.ImageService.Upload:input_type -> bootz.UploadRequest + 6, // 10: bootz.BootzController.SetBootstrapData:input_type -> bootz.SetBootstrapDataRequest + 8, // 11: bootz.BootzController.SetSecurityArtifacts:input_type -> bootz.SetSecurityArtifactsRequest + 14, // 12: bootz.BootzController.SetRecoveryData:input_type -> bootz.SetRecoveryDataRequest + 10, // 13: bootz.BootzController.GetBootzURL:input_type -> bootz.GetBootzURLRequest + 12, // 14: bootz.BootzController.Subscribe:input_type -> bootz.SubscribeRequest + 1, // 15: bootz.DHCPService.CreateLease:output_type -> bootz.CreateLeaseResponse + 3, // 16: bootz.DHCPService.RemoveLease:output_type -> bootz.RemoveLeaseResponse + 5, // 17: bootz.ImageService.Upload:output_type -> bootz.UploadResponse + 7, // 18: bootz.BootzController.SetBootstrapData:output_type -> bootz.SetBootstrapDataResponse + 9, // 19: bootz.BootzController.SetSecurityArtifacts:output_type -> bootz.SetSecurityArtifactsResponse + 15, // 20: bootz.BootzController.SetRecoveryData:output_type -> bootz.SetRecoveryDataResponse + 11, // 21: bootz.BootzController.GetBootzURL:output_type -> bootz.GetBootzURLResponse + 13, // 22: bootz.BootzController.Subscribe:output_type -> bootz.SubscribeResponse + 15, // [15:23] is the sub-list for method output_type + 7, // [7:15] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_github_com_openconfig_bootz_server_tests_proto_sut_proto_init() } +func file_github_com_openconfig_bootz_server_tests_proto_sut_proto_init() { + if File_github_com_openconfig_bootz_server_tests_proto_sut_proto != nil { + return + } + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes[13].OneofWrappers = []any{ + (*SubscribeResponse_GetBootstrapDataRequest)(nil), + (*SubscribeResponse_ReportStatusRequest)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDesc), len(file_github_com_openconfig_bootz_server_tests_proto_sut_proto_rawDesc)), + NumEnums: 0, + NumMessages: 16, + NumExtensions: 0, + NumServices: 3, + }, + GoTypes: file_github_com_openconfig_bootz_server_tests_proto_sut_proto_goTypes, + DependencyIndexes: file_github_com_openconfig_bootz_server_tests_proto_sut_proto_depIdxs, + MessageInfos: file_github_com_openconfig_bootz_server_tests_proto_sut_proto_msgTypes, + }.Build() + File_github_com_openconfig_bootz_server_tests_proto_sut_proto = out.File + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_goTypes = nil + file_github_com_openconfig_bootz_server_tests_proto_sut_proto_depIdxs = nil +} + diff --git a/server/tests/proto/sut/sut_grpc.pb.go b/server/tests/proto/sut/sut_grpc.pb.go new file mode 100644 index 00000000..5c315454 --- /dev/null +++ b/server/tests/proto/sut/sut_grpc.pb.go @@ -0,0 +1,583 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// 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. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.2 +// - protoc v5.29.3 +// source: github.com/openconfig/bootz/server/tests/proto/sut.proto + +package sut + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + DHCPService_CreateLease_FullMethodName = "/bootz.DHCPService/CreateLease" + DHCPService_RemoveLease_FullMethodName = "/bootz.DHCPService/RemoveLease" +) + +// DHCPServiceClient is the client API for DHCPService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// DHCP Service +// The DHCP service is responsible for managing DHCP leases for the DUT and +// responding to DHCP requests. +type DHCPServiceClient interface { + // CreateLease creates a DHCP lease for the DUT. + CreateLease(ctx context.Context, in *CreateLeaseRequest, opts ...grpc.CallOption) (*CreateLeaseResponse, error) + // RemoveLease deletes a DHCP lease for the DUT. + RemoveLease(ctx context.Context, in *RemoveLeaseRequest, opts ...grpc.CallOption) (*RemoveLeaseResponse, error) +} + +type dHCPServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDHCPServiceClient(cc grpc.ClientConnInterface) DHCPServiceClient { + return &dHCPServiceClient{cc} +} + +func (c *dHCPServiceClient) CreateLease(ctx context.Context, in *CreateLeaseRequest, opts ...grpc.CallOption) (*CreateLeaseResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateLeaseResponse) + err := c.cc.Invoke(ctx, DHCPService_CreateLease_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *dHCPServiceClient) RemoveLease(ctx context.Context, in *RemoveLeaseRequest, opts ...grpc.CallOption) (*RemoveLeaseResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RemoveLeaseResponse) + err := c.cc.Invoke(ctx, DHCPService_RemoveLease_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DHCPServiceServer is the server API for DHCPService service. +// All implementations must embed UnimplementedDHCPServiceServer +// for forward compatibility. +// +// DHCP Service +// The DHCP service is responsible for managing DHCP leases for the DUT and +// responding to DHCP requests. +type DHCPServiceServer interface { + // CreateLease creates a DHCP lease for the DUT. + CreateLease(context.Context, *CreateLeaseRequest) (*CreateLeaseResponse, error) + // RemoveLease deletes a DHCP lease for the DUT. + RemoveLease(context.Context, *RemoveLeaseRequest) (*RemoveLeaseResponse, error) + mustEmbedUnimplementedDHCPServiceServer() +} + +// UnimplementedDHCPServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedDHCPServiceServer struct{} + +func (UnimplementedDHCPServiceServer) CreateLease(context.Context, *CreateLeaseRequest) (*CreateLeaseResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateLease not implemented") +} +func (UnimplementedDHCPServiceServer) RemoveLease(context.Context, *RemoveLeaseRequest) (*RemoveLeaseResponse, error) { + return nil, status.Error(codes.Unimplemented, "method RemoveLease not implemented") +} +func (UnimplementedDHCPServiceServer) mustEmbedUnimplementedDHCPServiceServer() {} +func (UnimplementedDHCPServiceServer) testEmbeddedByValue() {} + +// UnsafeDHCPServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DHCPServiceServer will +// result in compilation errors. +type UnsafeDHCPServiceServer interface { + mustEmbedUnimplementedDHCPServiceServer() +} + +func RegisterDHCPServiceServer(s grpc.ServiceRegistrar, srv DHCPServiceServer) { + // If the following call panics, it indicates UnimplementedDHCPServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&DHCPService_ServiceDesc, srv) +} + +func _DHCPService_CreateLease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateLeaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DHCPServiceServer).CreateLease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DHCPService_CreateLease_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DHCPServiceServer).CreateLease(ctx, req.(*CreateLeaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DHCPService_RemoveLease_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveLeaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DHCPServiceServer).RemoveLease(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DHCPService_RemoveLease_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DHCPServiceServer).RemoveLease(ctx, req.(*RemoveLeaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// DHCPService_ServiceDesc is the grpc.ServiceDesc for DHCPService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DHCPService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "bootz.DHCPService", + HandlerType: (*DHCPServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateLease", + Handler: _DHCPService_CreateLease_Handler, + }, + { + MethodName: "RemoveLease", + Handler: _DHCPService_RemoveLease_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/openconfig/bootz/server/tests/proto/sut.proto", +} + +const ( + ImageService_Upload_FullMethodName = "/bootz.ImageService/Upload" +) + +// ImageServiceClient is the client API for ImageService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Image Service +// The Image Service provides an interface to upload images. +type ImageServiceClient interface { + // Upload makes the provided OS image available to the Bootz SUT for + // download during the Bootz test. + Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) +} + +type imageServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewImageServiceClient(cc grpc.ClientConnInterface) ImageServiceClient { + return &imageServiceClient{cc} +} + +func (c *imageServiceClient) Upload(ctx context.Context, in *UploadRequest, opts ...grpc.CallOption) (*UploadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadResponse) + err := c.cc.Invoke(ctx, ImageService_Upload_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ImageServiceServer is the server API for ImageService service. +// All implementations must embed UnimplementedImageServiceServer +// for forward compatibility. +// +// Image Service +// The Image Service provides an interface to upload images. +type ImageServiceServer interface { + // Upload makes the provided OS image available to the Bootz SUT for + // download during the Bootz test. + Upload(context.Context, *UploadRequest) (*UploadResponse, error) + mustEmbedUnimplementedImageServiceServer() +} + +// UnimplementedImageServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedImageServiceServer struct{} + +func (UnimplementedImageServiceServer) Upload(context.Context, *UploadRequest) (*UploadResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Upload not implemented") +} +func (UnimplementedImageServiceServer) mustEmbedUnimplementedImageServiceServer() {} +func (UnimplementedImageServiceServer) testEmbeddedByValue() {} + +// UnsafeImageServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ImageServiceServer will +// result in compilation errors. +type UnsafeImageServiceServer interface { + mustEmbedUnimplementedImageServiceServer() +} + +func RegisterImageServiceServer(s grpc.ServiceRegistrar, srv ImageServiceServer) { + // If the following call panics, it indicates UnimplementedImageServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&ImageService_ServiceDesc, srv) +} + +func _ImageService_Upload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ImageServiceServer).Upload(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ImageService_Upload_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ImageServiceServer).Upload(ctx, req.(*UploadRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ImageService_ServiceDesc is the grpc.ServiceDesc for ImageService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ImageService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "bootz.ImageService", + HandlerType: (*ImageServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Upload", + Handler: _ImageService_Upload_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/openconfig/bootz/server/tests/proto/sut.proto", +} + +const ( + BootzController_SetBootstrapData_FullMethodName = "/bootz.BootzController/SetBootstrapData" + BootzController_SetSecurityArtifacts_FullMethodName = "/bootz.BootzController/SetSecurityArtifacts" + BootzController_SetRecoveryData_FullMethodName = "/bootz.BootzController/SetRecoveryData" + BootzController_GetBootzURL_FullMethodName = "/bootz.BootzController/GetBootzURL" + BootzController_Subscribe_FullMethodName = "/bootz.BootzController/Subscribe" +) + +// BootzControllerClient is the client API for BootzController service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// BootzController Service +// The BootzController service provides an interface to configure the responses +// that will be returned by the Bootz SUT. Ideally, this RPC service is hosted +// on the same SUT as the device-facing Bootz service but that is not a +// requirement. +type BootzControllerClient interface { + // Sets the bootstrap data that the Bootz SUT should use during the Bootz test + // when replying to the DUT. + SetBootstrapData(ctx context.Context, in *SetBootstrapDataRequest, opts ...grpc.CallOption) (*SetBootstrapDataResponse, error) + // Sets the security artifacts that the Bootz SUT should use during the Bootz + // test when replying to the DUT. + SetSecurityArtifacts(ctx context.Context, in *SetSecurityArtifactsRequest, opts ...grpc.CallOption) (*SetSecurityArtifactsResponse, error) + // SetRecoveryData sets the recovery data that the Bootz SUT should use after + // the test is complete. + SetRecoveryData(ctx context.Context, in *SetRecoveryDataRequest, opts ...grpc.CallOption) (*SetRecoveryDataResponse, error) + // Returns the Bootz URL that the DUT should use to contact the Bootz SUT. + GetBootzURL(ctx context.Context, in *GetBootzURLRequest, opts ...grpc.CallOption) (*GetBootzURLResponse, error) + // Subscribe allows the test to subscribe to events from the Bootz SUT. + Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SubscribeResponse], error) +} + +type bootzControllerClient struct { + cc grpc.ClientConnInterface +} + +func NewBootzControllerClient(cc grpc.ClientConnInterface) BootzControllerClient { + return &bootzControllerClient{cc} +} + +func (c *bootzControllerClient) SetBootstrapData(ctx context.Context, in *SetBootstrapDataRequest, opts ...grpc.CallOption) (*SetBootstrapDataResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetBootstrapDataResponse) + err := c.cc.Invoke(ctx, BootzController_SetBootstrapData_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bootzControllerClient) SetSecurityArtifacts(ctx context.Context, in *SetSecurityArtifactsRequest, opts ...grpc.CallOption) (*SetSecurityArtifactsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetSecurityArtifactsResponse) + err := c.cc.Invoke(ctx, BootzController_SetSecurityArtifacts_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bootzControllerClient) SetRecoveryData(ctx context.Context, in *SetRecoveryDataRequest, opts ...grpc.CallOption) (*SetRecoveryDataResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetRecoveryDataResponse) + err := c.cc.Invoke(ctx, BootzController_SetRecoveryData_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bootzControllerClient) GetBootzURL(ctx context.Context, in *GetBootzURLRequest, opts ...grpc.CallOption) (*GetBootzURLResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetBootzURLResponse) + err := c.cc.Invoke(ctx, BootzController_GetBootzURL_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bootzControllerClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SubscribeResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &BootzController_ServiceDesc.Streams[0], BootzController_Subscribe_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[SubscribeRequest, SubscribeResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type BootzController_SubscribeClient = grpc.ServerStreamingClient[SubscribeResponse] + +// BootzControllerServer is the server API for BootzController service. +// All implementations must embed UnimplementedBootzControllerServer +// for forward compatibility. +// +// BootzController Service +// The BootzController service provides an interface to configure the responses +// that will be returned by the Bootz SUT. Ideally, this RPC service is hosted +// on the same SUT as the device-facing Bootz service but that is not a +// requirement. +type BootzControllerServer interface { + // Sets the bootstrap data that the Bootz SUT should use during the Bootz test + // when replying to the DUT. + SetBootstrapData(context.Context, *SetBootstrapDataRequest) (*SetBootstrapDataResponse, error) + // Sets the security artifacts that the Bootz SUT should use during the Bootz + // test when replying to the DUT. + SetSecurityArtifacts(context.Context, *SetSecurityArtifactsRequest) (*SetSecurityArtifactsResponse, error) + // SetRecoveryData sets the recovery data that the Bootz SUT should use after + // the test is complete. + SetRecoveryData(context.Context, *SetRecoveryDataRequest) (*SetRecoveryDataResponse, error) + // Returns the Bootz URL that the DUT should use to contact the Bootz SUT. + GetBootzURL(context.Context, *GetBootzURLRequest) (*GetBootzURLResponse, error) + // Subscribe allows the test to subscribe to events from the Bootz SUT. + Subscribe(*SubscribeRequest, grpc.ServerStreamingServer[SubscribeResponse]) error + mustEmbedUnimplementedBootzControllerServer() +} + +// UnimplementedBootzControllerServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedBootzControllerServer struct{} + +func (UnimplementedBootzControllerServer) SetBootstrapData(context.Context, *SetBootstrapDataRequest) (*SetBootstrapDataResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SetBootstrapData not implemented") +} +func (UnimplementedBootzControllerServer) SetSecurityArtifacts(context.Context, *SetSecurityArtifactsRequest) (*SetSecurityArtifactsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SetSecurityArtifacts not implemented") +} +func (UnimplementedBootzControllerServer) SetRecoveryData(context.Context, *SetRecoveryDataRequest) (*SetRecoveryDataResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SetRecoveryData not implemented") +} +func (UnimplementedBootzControllerServer) GetBootzURL(context.Context, *GetBootzURLRequest) (*GetBootzURLResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetBootzURL not implemented") +} +func (UnimplementedBootzControllerServer) Subscribe(*SubscribeRequest, grpc.ServerStreamingServer[SubscribeResponse]) error { + return status.Error(codes.Unimplemented, "method Subscribe not implemented") +} +func (UnimplementedBootzControllerServer) mustEmbedUnimplementedBootzControllerServer() {} +func (UnimplementedBootzControllerServer) testEmbeddedByValue() {} + +// UnsafeBootzControllerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BootzControllerServer will +// result in compilation errors. +type UnsafeBootzControllerServer interface { + mustEmbedUnimplementedBootzControllerServer() +} + +func RegisterBootzControllerServer(s grpc.ServiceRegistrar, srv BootzControllerServer) { + // If the following call panics, it indicates UnimplementedBootzControllerServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&BootzController_ServiceDesc, srv) +} + +func _BootzController_SetBootstrapData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetBootstrapDataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BootzControllerServer).SetBootstrapData(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BootzController_SetBootstrapData_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BootzControllerServer).SetBootstrapData(ctx, req.(*SetBootstrapDataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BootzController_SetSecurityArtifacts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetSecurityArtifactsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BootzControllerServer).SetSecurityArtifacts(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BootzController_SetSecurityArtifacts_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BootzControllerServer).SetSecurityArtifacts(ctx, req.(*SetSecurityArtifactsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BootzController_SetRecoveryData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetRecoveryDataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BootzControllerServer).SetRecoveryData(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BootzController_SetRecoveryData_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BootzControllerServer).SetRecoveryData(ctx, req.(*SetRecoveryDataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BootzController_GetBootzURL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBootzURLRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BootzControllerServer).GetBootzURL(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BootzController_GetBootzURL_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BootzControllerServer).GetBootzURL(ctx, req.(*GetBootzURLRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _BootzController_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(SubscribeRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(BootzControllerServer).Subscribe(m, &grpc.GenericServerStream[SubscribeRequest, SubscribeResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type BootzController_SubscribeServer = grpc.ServerStreamingServer[SubscribeResponse] + +// BootzController_ServiceDesc is the grpc.ServiceDesc for BootzController service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BootzController_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "bootz.BootzController", + HandlerType: (*BootzControllerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SetBootstrapData", + Handler: _BootzController_SetBootstrapData_Handler, + }, + { + MethodName: "SetSecurityArtifacts", + Handler: _BootzController_SetSecurityArtifacts_Handler, + }, + { + MethodName: "SetRecoveryData", + Handler: _BootzController_SetRecoveryData_Handler, + }, + { + MethodName: "GetBootzURL", + Handler: _BootzController_GetBootzURL_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "Subscribe", + Handler: _BootzController_Subscribe_Handler, + ServerStreams: true, + }, + }, + Metadata: "github.com/openconfig/bootz/server/tests/proto/sut.proto", +} \ No newline at end of file diff --git a/server/tests/proto/test/test.pb.go b/server/tests/proto/test/test.pb.go new file mode 100644 index 00000000..465f8ff7 --- /dev/null +++ b/server/tests/proto/test/test.pb.go @@ -0,0 +1,821 @@ +// Copyright 2026 Google Inc. All Rights Reserved. +// +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.29.3 +// source: github.com/openconfig/bootz/server/tests/proto/test.proto + +package test + +import ( + bootz "github.com/openconfig/bootz/proto/bootz" + authz "github.com/openconfig/gnsi/authz" + pathz "github.com/openconfig/gnsi/pathz" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Top level message that contains all the parameters for a Bootz test. This +// message is used to configure the Bootz SUT and the DUT. +type TestParameters struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The hostname of the DUT. This uniquely identifies the DUT. + Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` + // The OS image that should be installed on the DUT. + OsImage *OSImage `protobuf:"bytes,2,opt,name=os_image,json=osImage,proto3" json:"os_image,omitempty"` + // The bootstrap data that should be returned to the DUT by the Bootz SUT + // as part of the test. This may be a valid config (for use in positive + // test cases) or it may be an invalid config (for use in negative test + // cases). If the latter, the test should include recovery bootstrap data + // to allow the DUT to be recovered after the test. See the + // `recovery_data` field below for more details. + BootstrapData *BootstrapData `protobuf:"bytes,3,opt,name=bootstrap_data,json=bootstrapData,proto3" json:"bootstrap_data,omitempty"` + // The security artifacts that the Bootz SUT should use during bootstrapping. + SecurityArtifacts *SecurityArtifacts `protobuf:"bytes,4,opt,name=security_artifacts,json=securityArtifacts,proto3" json:"security_artifacts,omitempty"` + // Information about the DUT's interfaces for use during DHCP and Bootz. + InterfaceInfo *InterfaceInfo `protobuf:"bytes,5,opt,name=interface_info,json=interfaceInfo,proto3" json:"interface_info,omitempty"` + // The boot mode that the Bootz SUT should use during bootstrapping. If set to + // SECURE, the SUT must be configured with ownership vouchers and an ownership + // certificate to provide to the DUT. If unset, the test will use SECURE + // mode. + BootMode bootz.BootMode `protobuf:"varint,6,opt,name=boot_mode,json=bootMode,proto3,enum=bootz.BootMode" json:"boot_mode,omitempty"` + // The expected state of the DUT after bootstrapping. + WantBootzState *BootzState `protobuf:"bytes,7,opt,name=want_bootz_state,json=wantBootzState,proto3" json:"want_bootz_state,omitempty"` + // If this field is not set, the Bootz SUT will not provide any additional + // bootstrap data after the test, and it will be the responsibility of the + // test runner to recover the DUT through other means. + RecoveryData *DUTRecoveryData `protobuf:"bytes,8,opt,name=recovery_data,json=recoveryData,proto3" json:"recovery_data,omitempty"` + // The duration of the test. If the DUT has not reported the expected final + // status by the time this duration has elapsed, the test will be marked as + // failed and the Bootz SUT will provide the `recovery_data` if it + // is set. + Timeout *durationpb.Duration `protobuf:"bytes,9,opt,name=timeout,proto3" json:"timeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TestParameters) Reset() { + *x = TestParameters{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TestParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestParameters) ProtoMessage() {} + +func (x *TestParameters) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestParameters.ProtoReflect.Descriptor instead. +func (*TestParameters) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{0} +} + +func (x *TestParameters) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *TestParameters) GetOsImage() *OSImage { + if x != nil { + return x.OsImage + } + return nil +} + +func (x *TestParameters) GetBootstrapData() *BootstrapData { + if x != nil { + return x.BootstrapData + } + return nil +} + +func (x *TestParameters) GetSecurityArtifacts() *SecurityArtifacts { + if x != nil { + return x.SecurityArtifacts + } + return nil +} + +func (x *TestParameters) GetInterfaceInfo() *InterfaceInfo { + if x != nil { + return x.InterfaceInfo + } + return nil +} + +func (x *TestParameters) GetBootMode() bootz.BootMode { + if x != nil { + return x.BootMode + } + return bootz.BootMode(0) +} + +func (x *TestParameters) GetWantBootzState() *BootzState { + if x != nil { + return x.WantBootzState + } + return nil +} + +func (x *TestParameters) GetRecoveryData() *DUTRecoveryData { + if x != nil { + return x.RecoveryData + } + return nil +} + +func (x *TestParameters) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +// Contains data used for recovering the DUT after a test. Any fields set +// in these messages will overwrite the existing DUT data for the test. Fields +// that are unset will be ignored and the existing DUT data for those fields +// will be retained. For example, if the `recovery_data` field is set with a +// `BootstrapData` message that has only the `boot_config` field set, then only +// the boot config will be overwritten on the DUT and the credentials, pathz +// policy, authz policy and certz profiles from the original `bootstrap_data` +// will be retained. +type DUTRecoveryData struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Recovery bootstrap data. + RecoveryBootstrapData *BootstrapData `protobuf:"bytes,1,opt,name=recovery_bootstrap_data,json=recoveryBootstrapData,proto3" json:"recovery_bootstrap_data,omitempty"` + // Recovery OS image data. + RecoveryOsImage *OSImage `protobuf:"bytes,2,opt,name=recovery_os_image,json=recoveryOsImage,proto3" json:"recovery_os_image,omitempty"` + // Recovery security artifact data. + RecoverySecurityArtifacts *SecurityArtifacts `protobuf:"bytes,3,opt,name=recovery_security_artifacts,json=recoverySecurityArtifacts,proto3" json:"recovery_security_artifacts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DUTRecoveryData) Reset() { + *x = DUTRecoveryData{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DUTRecoveryData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DUTRecoveryData) ProtoMessage() {} + +func (x *DUTRecoveryData) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DUTRecoveryData.ProtoReflect.Descriptor instead. +func (*DUTRecoveryData) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{1} +} + +func (x *DUTRecoveryData) GetRecoveryBootstrapData() *BootstrapData { + if x != nil { + return x.RecoveryBootstrapData + } + return nil +} + +func (x *DUTRecoveryData) GetRecoveryOsImage() *OSImage { + if x != nil { + return x.RecoveryOsImage + } + return nil +} + +func (x *DUTRecoveryData) GetRecoverySecurityArtifacts() *SecurityArtifacts { + if x != nil { + return x.RecoverySecurityArtifacts + } + return nil +} + +// Contains information about an OS image on the DUT. +type OSImage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The name of the OS. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The version of the OS. + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + // The location of the OS image. This can be an HTTP URL or any other type of + // URI that can be used to download the OS image. + DownloadUri string `protobuf:"bytes,3,opt,name=download_uri,json=downloadUri,proto3" json:"download_uri,omitempty"` + // If true, the SUT will fetch the OS image from this location, load it to + // memory and make it available to the DUT via an HTTP URL. This is useful + // for cases where the above download_uri is not accessible to the DUT, but + // is accessible to the SUT. + ReuploadToSut bool `protobuf:"varint,4,opt,name=reupload_to_sut,json=reuploadToSut,proto3" json:"reupload_to_sut,omitempty"` + // The hash of the OS image. The format of this field is a + // `hex-string`, identified in RFC6991 as "A hexadecimal string with + // octets represented as hex digits separated by colons. + // The canonical representation uses lowercase characters." + // E.g.: "d9:a5:d1:0b:09:fa:4e:96:f2:40:bf:6a:82:f5" + OsImageHash string `protobuf:"bytes,5,opt,name=os_image_hash,json=osImageHash,proto3" json:"os_image_hash,omitempty"` + // The identity of the hash algorithm used. These hash identities are + // defined in sZTP RFC 8572. There is currently only one hash algorithm + // defined in this spec: + // `ietf-sztp-conveyed-info:sha-256` for the SHA 256 algorithm. + HashAlgorithm string `protobuf:"bytes,6,opt,name=hash_algorithm,json=hashAlgorithm,proto3" json:"hash_algorithm,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OSImage) Reset() { + *x = OSImage{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OSImage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OSImage) ProtoMessage() {} + +func (x *OSImage) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OSImage.ProtoReflect.Descriptor instead. +func (*OSImage) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{2} +} + +func (x *OSImage) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *OSImage) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *OSImage) GetDownloadUri() string { + if x != nil { + return x.DownloadUri + } + return "" +} + +func (x *OSImage) GetReuploadToSut() bool { + if x != nil { + return x.ReuploadToSut + } + return false +} + +func (x *OSImage) GetOsImageHash() string { + if x != nil { + return x.OsImageHash + } + return "" +} + +func (x *OSImage) GetHashAlgorithm() string { + if x != nil { + return x.HashAlgorithm + } + return "" +} + +// Contains information about the bootstrap data that the Bootz SUT should +// return to the DUT. +type BootstrapData struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The boot config to be returned to the DUT by the Bootz SUT. + BootConfig *bootz.BootConfig `protobuf:"bytes,1,opt,name=boot_config,json=bootConfig,proto3" json:"boot_config,omitempty"` + // The credentials to be returned to the DUT by the Bootz SUT. + Credentials *bootz.Credentials `protobuf:"bytes,2,opt,name=credentials,proto3" json:"credentials,omitempty"` + // The pathz policy to be returned to the DUT by the Bootz SUT. + Pathz *pathz.UploadRequest `protobuf:"bytes,3,opt,name=pathz,proto3" json:"pathz,omitempty"` + // The authz policy to be returned to the DUT by the Bootz SUT. + Authz *authz.UploadRequest `protobuf:"bytes,4,opt,name=authz,proto3" json:"authz,omitempty"` + // The certz profiles to be returned to the DUT by the Bootz SUT. + CertzProfiles *bootz.CertzProfiles `protobuf:"bytes,5,opt,name=certz_profiles,json=certzProfiles,proto3" json:"certz_profiles,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BootstrapData) Reset() { + *x = BootstrapData{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BootstrapData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BootstrapData) ProtoMessage() {} + +func (x *BootstrapData) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BootstrapData.ProtoReflect.Descriptor instead. +func (*BootstrapData) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{3} +} + +func (x *BootstrapData) GetBootConfig() *bootz.BootConfig { + if x != nil { + return x.BootConfig + } + return nil +} + +func (x *BootstrapData) GetCredentials() *bootz.Credentials { + if x != nil { + return x.Credentials + } + return nil +} + +func (x *BootstrapData) GetPathz() *pathz.UploadRequest { + if x != nil { + return x.Pathz + } + return nil +} + +func (x *BootstrapData) GetAuthz() *authz.UploadRequest { + if x != nil { + return x.Authz + } + return nil +} + +func (x *BootstrapData) GetCertzProfiles() *bootz.CertzProfiles { + if x != nil { + return x.CertzProfiles + } + return nil +} + +// Contains information about the security artifacts that the Bootz SUT should +// use during bootstrapping. If not provided in this message, the Bootz SUT +// must attempt to fetch them from another source (e.g. a secure database). It +// is the responsibility of the test runner to ensure these artifacts are +// stored and handled securely. +type SecurityArtifacts struct { + state protoimpl.MessageState `protogen:"open.v1"` + // A mapping of control card serial number to Ownership Voucher that the Bootz + // SUT should use during bootstrapping. The format of the value in this map is + // a CMS message (RFC 5652). + OwnershipVouchers map[string][]byte `protobuf:"bytes,1,rep,name=ownership_vouchers,json=ownershipVouchers,proto3" json:"ownership_vouchers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // A mapping of control card serial number to TPM Endorsement Key (EK) + // for use in the BootstrapStream HMAC challenge. The format of the value in + // this map is a PEM-encoded RSA public key. + Eks map[string][]byte `protobuf:"bytes,2,rep,name=eks,proto3" json:"eks,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // A mapping of control card serial number to TPM Platform Primary Key (PPK) + // for use in the BootstrapStream HMAC challenge. The format of the value + // in this map is a PEM-encoded RSA public key. + Ppks map[string][]byte `protobuf:"bytes,3,rep,name=ppks,proto3" json:"ppks,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // The x509 certificate that the Bootz SUT should use to sign bootstrap + // responses. This certificate must have a chain of trust leading up to the + // Pinned Domain Cert that exists within the Ownership Voucher. The format of + // this field is a PEM-encoded x509 certificate. + OcCert string `protobuf:"bytes,4,opt,name=oc_cert,json=ocCert,proto3" json:"oc_cert,omitempty"` + // The corresponding private key for the above OC certificate. + // The format of this field is a PEM-encoded private key. + OcPrivateKey string `protobuf:"bytes,5,opt,name=oc_private_key,json=ocPrivateKey,proto3" json:"oc_private_key,omitempty"` + // A certificate that corresponds to the CA that signed the DUT's + // IDevID certificate. This field should contain the CA that directly signed + // the DUT's IDevID and not necessarily the Root CA. The format of this + // field is a PEM-encoded x509 certificate. + IdevidCa string `protobuf:"bytes,6,opt,name=idevid_ca,json=idevidCa,proto3" json:"idevid_ca,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SecurityArtifacts) Reset() { + *x = SecurityArtifacts{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SecurityArtifacts) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SecurityArtifacts) ProtoMessage() {} + +func (x *SecurityArtifacts) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SecurityArtifacts.ProtoReflect.Descriptor instead. +func (*SecurityArtifacts) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{4} +} + +func (x *SecurityArtifacts) GetOwnershipVouchers() map[string][]byte { + if x != nil { + return x.OwnershipVouchers + } + return nil +} + +func (x *SecurityArtifacts) GetEks() map[string][]byte { + if x != nil { + return x.Eks + } + return nil +} + +func (x *SecurityArtifacts) GetPpks() map[string][]byte { + if x != nil { + return x.Ppks + } + return nil +} + +func (x *SecurityArtifacts) GetOcCert() string { + if x != nil { + return x.OcCert + } + return "" +} + +func (x *SecurityArtifacts) GetOcPrivateKey() string { + if x != nil { + return x.OcPrivateKey + } + return "" +} + +func (x *SecurityArtifacts) GetIdevidCa() string { + if x != nil { + return x.IdevidCa + } + return "" +} + +// Contains information about the DUT's interfaces for use during DHCP and +// Bootz. +type InterfaceInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The address to assign to the DUT for the DHCP lease. For example, + // "192.168.1.100" or "2001:db8::2". + DhcpAddress string `protobuf:"bytes,1,opt,name=dhcp_address,json=dhcpAddress,proto3" json:"dhcp_address,omitempty"` + // The default gateway for the DUT's management interface. + // This will be provided in the DHCP lease. For example, + // "192.168.1.1" or "2001:db8::1". + DefaultGateway string `protobuf:"bytes,2,opt,name=default_gateway,json=defaultGateway,proto3" json:"default_gateway,omitempty"` + // The mask length for the DUT's management interface. + // This will be provided in the DHCP lease. For example, "24" for IPv4 or + // "120" for IPv6. + MaskLength int32 `protobuf:"varint,3,opt,name=mask_length,json=maskLength,proto3" json:"mask_length,omitempty"` + // Additional addresses (excluding the DHCP address) that the DUT may use to + // communicate with the Bootz SUT. These are addresses that may be used for + // subsequent gRPC connections to Bootz server after the initial connection. + // For example, the DUT may use DHCP address `192.168.1.100` to make the + // initial gRPC connection to Bootz server but the boot config may specify a + // different address `192.168.1.200`. Either of these may be used by the + // device to make the gRPC connection. + AdditionalAddresses []string `protobuf:"bytes,4,rep,name=additional_addresses,json=additionalAddresses,proto3" json:"additional_addresses,omitempty"` + // Name of out of band management interface(s) on the DUT. These will be used + // to discover the MAC addresses to be used in the DHCP lease. + ManagementInterfaceNames []string `protobuf:"bytes,5,rep,name=management_interface_names,json=managementInterfaceNames,proto3" json:"management_interface_names,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InterfaceInfo) Reset() { + *x = InterfaceInfo{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InterfaceInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InterfaceInfo) ProtoMessage() {} + +func (x *InterfaceInfo) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InterfaceInfo.ProtoReflect.Descriptor instead. +func (*InterfaceInfo) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{5} +} + +func (x *InterfaceInfo) GetDhcpAddress() string { + if x != nil { + return x.DhcpAddress + } + return "" +} + +func (x *InterfaceInfo) GetDefaultGateway() string { + if x != nil { + return x.DefaultGateway + } + return "" +} + +func (x *InterfaceInfo) GetMaskLength() int32 { + if x != nil { + return x.MaskLength + } + return 0 +} + +func (x *InterfaceInfo) GetAdditionalAddresses() []string { + if x != nil { + return x.AdditionalAddresses + } + return nil +} + +func (x *InterfaceInfo) GetManagementInterfaceNames() []string { + if x != nil { + return x.ManagementInterfaceNames + } + return nil +} + +// Contains the expected state of the DUT after bootstrapping. +type BootzState struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The expected last status of the SUT after Bootz. For positive test cases + // this should be "BOOTZ_OK". + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BootzState) Reset() { + *x = BootzState{} + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BootzState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BootzState) ProtoMessage() {} + +func (x *BootzState) ProtoReflect() protoreflect.Message { + mi := &file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BootzState.ProtoReflect.Descriptor instead. +func (*BootzState) Descriptor() ([]byte, []int) { + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP(), []int{6} +} + +func (x *BootzState) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +var File_github_com_openconfig_bootz_server_tests_proto_test_proto protoreflect.FileDescriptor + +const file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDesc = "" + + "\n" + + "9github.com/openconfig/bootz/server/tests/proto/test.proto\x12\x05bootz\x1a\x1egoogle/protobuf/duration.proto\x1a-github.com/openconfig/bootz/proto/bootz.proto\x1a,github.com/openconfig/gnsi/authz/authz.proto\x1a,github.com/openconfig/gnsi/pathz/pathz.proto\"\xf7\x03\n" + + "\x0eTestParameters\x12\x1a\n" + + "\bhostname\x18\x01 \x01(\tR\bhostname\x12)\n" + + "\bos_image\x18\x02 \x01(\v2\x0e.bootz.OSImageR\aosImage\x12;\n" + + "\x0ebootstrap_data\x18\x03 \x01(\v2\x14.bootz.BootstrapDataR\rbootstrapData\x12G\n" + + "\x12security_artifacts\x18\x04 \x01(\v2\x18.bootz.SecurityArtifactsR\x11securityArtifacts\x12;\n" + + "\x0einterface_info\x18\x05 \x01(\v2\x14.bootz.InterfaceInfoR\rinterfaceInfo\x12,\n" + + "\tboot_mode\x18\x06 \x01(\x0e2\x0f.bootz.BootModeR\bbootMode\x12;\n" + + "\x10want_bootz_state\x18\a \x01(\v2\x11.bootz.BootzStateR\x0ewantBootzState\x12;\n" + + "\rrecovery_data\x18\b \x01(\v2\x16.bootz.DUTRecoveryDataR\frecoveryData\x123\n" + + "\atimeout\x18\t \x01(\v2\x19.google.protobuf.DurationR\atimeout\"\xf5\x01\n" + + "\x0fDUTRecoveryData\x12L\n" + + "\x17recovery_bootstrap_data\x18\x01 \x01(\v2\x14.bootz.BootstrapDataR\x15recoveryBootstrapData\x12:\n" + + "\x11recovery_os_image\x18\x02 \x01(\v2\x0e.bootz.OSImageR\x0frecoveryOsImage\x12X\n" + + "\x1brecovery_security_artifacts\x18\x03 \x01(\v2\x18.bootz.SecurityArtifactsR\x19recoverySecurityArtifacts\"\xcd\x01\n" + + "\aOSImage\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x02 \x01(\tR\aversion\x12!\n" + + "\fdownload_uri\x18\x03 \x01(\tR\vdownloadUri\x12&\n" + + "\x0freupload_to_sut\x18\x04 \x01(\bR\rreuploadToSut\x12\"\n" + + "\ros_image_hash\x18\x05 \x01(\tR\vosImageHash\x12%\n" + + "\x0ehash_algorithm\x18\x06 \x01(\tR\rhashAlgorithm\"\x9e\x02\n" + + "\rBootstrapData\x122\n" + + "\vboot_config\x18\x01 \x01(\v2\x11.bootz.BootConfigR\n" + + "bootConfig\x124\n" + + "\vcredentials\x18\x02 \x01(\v2\x12.bootz.CredentialsR\vcredentials\x122\n" + + "\x05pathz\x18\x03 \x01(\v2\x1c.gnsi.pathz.v1.UploadRequestR\x05pathz\x122\n" + + "\x05authz\x18\x04 \x01(\v2\x1c.gnsi.authz.v1.UploadRequestR\x05authz\x12;\n" + + "\x0ecertz_profiles\x18\x05 \x01(\v2\x14.bootz.CertzProfilesR\rcertzProfiles\"\xf3\x03\n" + + "\x11SecurityArtifacts\x12^\n" + + "\x12ownership_vouchers\x18\x01 \x03(\v2/.bootz.SecurityArtifacts.OwnershipVouchersEntryR\x11ownershipVouchers\x123\n" + + "\x03eks\x18\x02 \x03(\v2!.bootz.SecurityArtifacts.EksEntryR\x03eks\x126\n" + + "\x04ppks\x18\x03 \x03(\v2\".bootz.SecurityArtifacts.PpksEntryR\x04ppks\x12\x17\n" + + "\aoc_cert\x18\x04 \x01(\tR\x06ocCert\x12$\n" + + "\x0eoc_private_key\x18\x05 \x01(\tR\focPrivateKey\x12\x1b\n" + + "\tidevid_ca\x18\x06 \x01(\tR\bidevidCa\x1aD\n" + + "\x16OwnershipVouchersEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\x1a6\n" + + "\bEksEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\x1a7\n" + + "\tPpksEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"\xed\x01\n" + + "\rInterfaceInfo\x12!\n" + + "\fdhcp_address\x18\x01 \x01(\tR\vdhcpAddress\x12'\n" + + "\x0fdefault_gateway\x18\x02 \x01(\tR\x0edefaultGateway\x12\x1f\n" + + "\vmask_length\x18\x03 \x01(\x05R\n" + + "maskLength\x121\n" + + "\x14additional_addresses\x18\x04 \x03(\tR\x13additionalAddresses\x12<\n" + + "\x1amanagement_interface_names\x18\x05 \x03(\tR\x18managementInterfaceNames\"$\n" + + "\n" + + "BootzState\x12\x16\n" + + "\x06status\x18\x01 \x01(\tR\x06statusB5Z3github.com/openconfig/bootz/server/tests/proto/testb\x06proto3" + +var ( + file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescOnce sync.Once + file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescData []byte +) + +func file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescGZIP() []byte { + file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescOnce.Do(func() { + file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDesc), len(file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDesc))) + }) + return file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDescData +} + +var file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_github_com_openconfig_bootz_server_tests_proto_test_proto_goTypes = []any{ + (*TestParameters)(nil), // 0: bootz.TestParameters + (*DUTRecoveryData)(nil), // 1: bootz.DUTRecoveryData + (*OSImage)(nil), // 2: bootz.OSImage + (*BootstrapData)(nil), // 3: bootz.BootstrapData + (*SecurityArtifacts)(nil), // 4: bootz.SecurityArtifacts + (*InterfaceInfo)(nil), // 5: bootz.InterfaceInfo + (*BootzState)(nil), // 6: bootz.BootzState + nil, // 7: bootz.SecurityArtifacts.OwnershipVouchersEntry + nil, // 8: bootz.SecurityArtifacts.EksEntry + nil, // 9: bootz.SecurityArtifacts.PpksEntry + (bootz.BootMode)(0), // 10: bootz.BootMode + (*durationpb.Duration)(nil), // 11: google.protobuf.Duration + (*bootz.BootConfig)(nil), // 12: bootz.BootConfig + (*bootz.Credentials)(nil), // 13: bootz.Credentials + (*pathz.UploadRequest)(nil), // 14: gnsi.pathz.v1.UploadRequest + (*authz.UploadRequest)(nil), // 15: gnsi.authz.v1.UploadRequest + (*bootz.CertzProfiles)(nil), // 16: bootz.CertzProfiles +} +var file_github_com_openconfig_bootz_server_tests_proto_test_proto_depIdxs = []int32{ + 2, // 0: bootz.TestParameters.os_image:type_name -> bootz.OSImage + 3, // 1: bootz.TestParameters.bootstrap_data:type_name -> bootz.BootstrapData + 4, // 2: bootz.TestParameters.security_artifacts:type_name -> bootz.SecurityArtifacts + 5, // 3: bootz.TestParameters.interface_info:type_name -> bootz.InterfaceInfo + 10, // 4: bootz.TestParameters.boot_mode:type_name -> bootz.BootMode + 6, // 5: bootz.TestParameters.want_bootz_state:type_name -> bootz.BootzState + 1, // 6: bootz.TestParameters.recovery_data:type_name -> bootz.DUTRecoveryData + 11, // 7: bootz.TestParameters.timeout:type_name -> google.protobuf.Duration + 3, // 8: bootz.DUTRecoveryData.recovery_bootstrap_data:type_name -> bootz.BootstrapData + 2, // 9: bootz.DUTRecoveryData.recovery_os_image:type_name -> bootz.OSImage + 4, // 10: bootz.DUTRecoveryData.recovery_security_artifacts:type_name -> bootz.SecurityArtifacts + 12, // 11: bootz.BootstrapData.boot_config:type_name -> bootz.BootConfig + 13, // 12: bootz.BootstrapData.credentials:type_name -> bootz.Credentials + 14, // 13: bootz.BootstrapData.pathz:type_name -> gnsi.pathz.v1.UploadRequest + 15, // 14: bootz.BootstrapData.authz:type_name -> gnsi.authz.v1.UploadRequest + 16, // 15: bootz.BootstrapData.certz_profiles:type_name -> bootz.CertzProfiles + 7, // 16: bootz.SecurityArtifacts.ownership_vouchers:type_name -> bootz.SecurityArtifacts.OwnershipVouchersEntry + 8, // 17: bootz.SecurityArtifacts.eks:type_name -> bootz.SecurityArtifacts.EksEntry + 9, // 18: bootz.SecurityArtifacts.ppks:type_name -> bootz.SecurityArtifacts.PpksEntry + 19, // [19:19] is the sub-list for method output_type + 19, // [19:19] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name +} + +func init() { file_github_com_openconfig_bootz_server_tests_proto_test_proto_init() } +func file_github_com_openconfig_bootz_server_tests_proto_test_proto_init() { + if File_github_com_openconfig_bootz_server_tests_proto_test_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDesc), len(file_github_com_openconfig_bootz_server_tests_proto_test_proto_rawDesc)), + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_openconfig_bootz_server_tests_proto_test_proto_goTypes, + DependencyIndexes: file_github_com_openconfig_bootz_server_tests_proto_test_proto_depIdxs, + MessageInfos: file_github_com_openconfig_bootz_server_tests_proto_test_proto_msgTypes, + }.Build() + File_github_com_openconfig_bootz_server_tests_proto_test_proto = out.File + file_github_com_openconfig_bootz_server_tests_proto_test_proto_goTypes = nil + file_github_com_openconfig_bootz_server_tests_proto_test_proto_depIdxs = nil +}