diff --git a/agent/config/builder.go b/agent/config/builder.go index 852337d08c..e5dd68557a 100644 --- a/agent/config/builder.go +++ b/agent/config/builder.go @@ -1140,8 +1140,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) { // TODO(CC-6389): Remove once resource-apis is no longer considered experimental and is supported by HCP if stringslice.Contains(rt.Experiments, consul.CatalogResourceExperimentName) && rt.IsCloudEnabled() { // Allow override of this check for development/testing purposes. Should not be used in production - override, err := strconv.ParseBool(os.Getenv("CONSUL_OVERRIDE_HCP_RESOURCE_APIS_CHECK")) - if err != nil || !override { + if !stringslice.Contains(rt.Experiments, consul.HCPAllowV2ResourceAPIs) { return RuntimeConfig{}, fmt.Errorf("`experiments` cannot include 'resource-apis' when HCP `cloud` configuration is set") } } diff --git a/agent/config/builder_test.go b/agent/config/builder_test.go index 6f8fdc9598..2d7a16f9b1 100644 --- a/agent/config/builder_test.go +++ b/agent/config/builder_test.go @@ -581,7 +581,6 @@ func TestBuilder_WarnCloudConfigWithResourceApis(t *testing.T) { name string hcl string expectErr bool - override bool }{ { name: "base_case", @@ -611,9 +610,8 @@ func TestBuilder_WarnCloudConfigWithResourceApis(t *testing.T) { { name: "cloud-config_resource-apis_experiment_override", hcl: ` - experiments = ["resource-apis"] + experiments = ["resource-apis", "hcp-v2-resource-apis"] cloud{ resource_id = "abc" client_id = "abc" client_secret = "abc"}`, - override: true, }, } for _, tc := range tests { @@ -629,13 +627,7 @@ func TestBuilder_WarnCloudConfigWithResourceApis(t *testing.T) { }, }, } - if tc.override { - os.Setenv("CONSUL_OVERRIDE_HCP_RESOURCE_APIS_CHECK", "1") - } _, err := Load(builderOpts) - if tc.override { - os.Unsetenv("CONSUL_OVERRIDE_HCP_RESOURCE_APIS_CHECK") - } if tc.expectErr { require.Error(t, err) require.Contains(t, err.Error(), "cannot include 'resource-apis' when HCP") diff --git a/agent/consul/options.go b/agent/consul/options.go index 88c16bd1a9..7a34ba8272 100644 --- a/agent/consul/options.go +++ b/agent/consul/options.go @@ -67,6 +67,15 @@ func (d Deps) UseV2Tenancy() bool { return false } +// HCPAllowV2Resources returns true if "hcp-v2-resource-apis" is present in the Experiments +// array of the agent config. +func (d Deps) HCPAllowV2Resources() bool { + if stringslice.Contains(d.Experiments, HCPAllowV2ResourceAPIs) { + return true + } + return false +} + type GRPCClientConner interface { ClientConn(datacenter string) (*grpc.ClientConn, error) ClientConnLeader() (*grpc.ClientConn, error) diff --git a/agent/consul/server.go b/agent/consul/server.go index 89bcaf957c..b45789aa9f 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -75,6 +75,7 @@ import ( "github.com/hashicorp/consul/internal/auth" "github.com/hashicorp/consul/internal/catalog" "github.com/hashicorp/consul/internal/controller" + hcpctl "github.com/hashicorp/consul/internal/hcp" "github.com/hashicorp/consul/internal/mesh" proxysnapshot "github.com/hashicorp/consul/internal/mesh/proxy-snapshot" "github.com/hashicorp/consul/internal/multicluster" @@ -142,6 +143,7 @@ const ( CatalogResourceExperimentName = "resource-apis" V2TenancyExperimentName = "v2tenancy" + HCPAllowV2ResourceAPIs = "hcp-v2-resource-apis" ) const ( @@ -477,6 +479,10 @@ type Server struct { // useV2Tenancy is tied to the "v2tenancy" feature flag. useV2Tenancy bool + + // whether v2 resources are enabled for use with HCP + // TODO(CC-6389): Remove once resource-apis is no longer considered experimental and is supported by HCP + hcpAllowV2Resources bool } func (s *Server) DecrementBlockingQueries() uint64 { @@ -567,6 +573,7 @@ func NewServer(config *Config, flat Deps, externalGRPCServer *grpc.Server, registry: flat.Registry, useV2Resources: flat.UseV2Resources(), useV2Tenancy: flat.UseV2Tenancy(), + hcpAllowV2Resources: flat.HCPAllowV2Resources(), } incomingRPCLimiter.Register(s) @@ -961,6 +968,11 @@ func isV1CatalogRequest(rpcName string) bool { } func (s *Server) registerControllers(deps Deps, proxyUpdater ProxyUpdater) error { + hcpctl.RegisterControllers(s.controllerManager, hcpctl.ControllerDependencies{ + ResourceApisEnabled: s.useV2Resources, + HCPAllowV2ResourceApis: s.hcpAllowV2Resources, + }) + // When not enabled, the v1 tenancy bridge is used by default. if s.useV2Tenancy { tenancy.RegisterControllers( diff --git a/agent/consul/testdata/v2-resource-dependencies.md b/agent/consul/testdata/v2-resource-dependencies.md index 9e90a24947..60df5b0f4e 100644 --- a/agent/consul/testdata/v2-resource-dependencies.md +++ b/agent/consul/testdata/v2-resource-dependencies.md @@ -19,6 +19,7 @@ flowchart TD demo/v1/recordlabel demo/v2/album demo/v2/artist + hcp/v2/link internal/v1/tombstone mesh/v2beta1/computedexplicitdestinations --> catalog/v2beta1/service mesh/v2beta1/computedexplicitdestinations --> catalog/v2beta1/workload diff --git a/agent/consul/type_registry.go b/agent/consul/type_registry.go index 8bf093c41a..450cef7e05 100644 --- a/agent/consul/type_registry.go +++ b/agent/consul/type_registry.go @@ -6,6 +6,7 @@ package consul import ( "github.com/hashicorp/consul/internal/auth" "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/hcp" "github.com/hashicorp/consul/internal/mesh" "github.com/hashicorp/consul/internal/multicluster" "github.com/hashicorp/consul/internal/resource" @@ -29,6 +30,7 @@ func NewTypeRegistry() resource.Registry { auth.RegisterTypes(registry) tenancy.RegisterTypes(registry) multicluster.RegisterTypes(registry) + hcp.RegisterTypes(registry) return registry } diff --git a/internal/hcp/exports.go b/internal/hcp/exports.go new file mode 100644 index 0000000000..4df3b6095f --- /dev/null +++ b/internal/hcp/exports.go @@ -0,0 +1,25 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package hcp + +import ( + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/controllers" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/resource" +) + +// RegisterTypes adds all resource types within the "hcp" API group +// to the given type registry +func RegisterTypes(r resource.Registry) { + types.Register(r) +} + +type ControllerDependencies = controllers.Dependencies + +// RegisterControllers registers controllers for the catalog types with +// the given controller Manager. +func RegisterControllers(mgr *controller.Manager, deps ControllerDependencies) { + controllers.Register(mgr, deps) +} diff --git a/internal/hcp/internal/controllers/link/controller.go b/internal/hcp/internal/controllers/link/controller.go new file mode 100644 index 0000000000..1524b81b87 --- /dev/null +++ b/internal/hcp/internal/controllers/link/controller.go @@ -0,0 +1,82 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "context" + + "github.com/hashicorp/consul/internal/resource" + "github.com/hashicorp/consul/proto-public/pbresource" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/hashicorp/consul/internal/controller" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" +) + +func LinkController(resourceApisEnabled bool, hcpAllowV2ResourceApis bool) *controller.Controller { + return controller.NewController("link", pbhcp.LinkType). + WithReconciler(&linkReconciler{ + resourceApisEnabled: resourceApisEnabled, + hcpAllowV2ResourceApis: hcpAllowV2ResourceApis, + }) +} + +type linkReconciler struct { + resourceApisEnabled bool + hcpAllowV2ResourceApis bool +} + +func (r *linkReconciler) Reconcile(ctx context.Context, rt controller.Runtime, req controller.Request) error { + // The runtime is passed by value so replacing it here for the remainder of this + // reconciliation request processing will not affect future invocations. + rt.Logger = rt.Logger.With("resource-id", req.ID, "controller", StatusKey) + + rt.Logger.Trace("reconciling link") + + rsp, err := rt.Client.Read(ctx, &pbresource.ReadRequest{Id: req.ID}) + switch { + case status.Code(err) == codes.NotFound: + rt.Logger.Trace("link has been deleted") + return nil + case err != nil: + rt.Logger.Error("the resource service has returned an unexpected error", "error", err) + return err + } + + res := rsp.Resource + var link pbhcp.Link + if err := res.Data.UnmarshalTo(&link); err != nil { + rt.Logger.Error("error unmarshalling link data", "error", err) + return err + } + + var newStatus *pbresource.Status + if r.resourceApisEnabled && !r.hcpAllowV2ResourceApis { + newStatus = &pbresource.Status{ + ObservedGeneration: res.Generation, + Conditions: []*pbresource.Condition{ConditionDisabled}, + } + } else { + newStatus = &pbresource.Status{ + ObservedGeneration: res.Generation, + Conditions: []*pbresource.Condition{ConditionLinked(link.ResourceId)}, + } + } + + if resource.EqualStatus(res.Status[StatusKey], newStatus, false) { + return nil + } + _, err = rt.Client.WriteStatus(ctx, &pbresource.WriteStatusRequest{ + Id: res.Id, + Key: StatusKey, + Status: newStatus, + }) + + if err != nil { + return err + } + + return nil +} diff --git a/internal/hcp/internal/controllers/link/controller_test.go b/internal/hcp/internal/controllers/link/controller_test.go new file mode 100644 index 0000000000..a0e0be2aa6 --- /dev/null +++ b/internal/hcp/internal/controllers/link/controller_test.go @@ -0,0 +1,122 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "context" + "testing" + + "github.com/stretchr/testify/suite" + + svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/types" + "github.com/hashicorp/consul/internal/resource/resourcetest" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +type controllerSuite struct { + suite.Suite + + ctx context.Context + client *rtest.Client + rt controller.Runtime + + ctl linkReconciler + tenancies []*pbresource.Tenancy +} + +func (suite *controllerSuite) SetupTest() { + suite.ctx = testutil.TestContext(suite.T()) + suite.tenancies = resourcetest.TestTenancies() + client := svctest.NewResourceServiceBuilder(). + WithRegisterFns(types.Register). + WithTenancies(suite.tenancies...). + Run(suite.T()) + + suite.rt = controller.Runtime{ + Client: client, + Logger: testutil.Logger(suite.T()), + } + suite.client = rtest.NewClient(client) +} + +func TestLinkController(t *testing.T) { + suite.Run(t, new(controllerSuite)) +} + +func (suite *controllerSuite) deleteResourceFunc(id *pbresource.ID) func() { + return func() { + suite.client.MustDelete(suite.T(), id) + } +} + +func (suite *controllerSuite) TestController_Ok() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(LinkController(false, false)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + + link := rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + Write(suite.T(), suite.client) + + suite.T().Cleanup(suite.deleteResourceFunc(link.Id)) + + suite.client.WaitForStatusCondition(suite.T(), link.Id, StatusKey, ConditionLinked(linkData.ResourceId)) +} + +func (suite *controllerSuite) TestControllerResourceApisEnabled_LinkDisabled() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(LinkController(true, false)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + // The controller is currently a no-op, so there is nothing to test other than making sure we do not panic + link := rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + Write(suite.T(), suite.client) + + suite.T().Cleanup(suite.deleteResourceFunc(link.Id)) + + suite.client.WaitForStatusCondition(suite.T(), link.Id, StatusKey, ConditionDisabled) +} + +func (suite *controllerSuite) TestControllerResourceApisEnabledWithOverride_LinkNotDisabled() { + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(LinkController(true, true)) + mgr.SetRaftLeader(true) + go mgr.Run(suite.ctx) + + linkData := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + // The controller is currently a no-op, so there is nothing to test other than making sure we do not panic + link := rtest.Resource(pbhcp.LinkType, "global"). + WithData(suite.T(), linkData). + Write(suite.T(), suite.client) + + suite.T().Cleanup(suite.deleteResourceFunc(link.Id)) + + suite.client.WaitForStatusCondition(suite.T(), link.Id, StatusKey, ConditionLinked(linkData.ResourceId)) +} diff --git a/internal/hcp/internal/controllers/link/status.go b/internal/hcp/internal/controllers/link/status.go new file mode 100644 index 0000000000..40ae6b8baf --- /dev/null +++ b/internal/hcp/internal/controllers/link/status.go @@ -0,0 +1,39 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package link + +import ( + "fmt" + + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + StatusKey = "consul.io/hcp/link" + + StatusLinked = "linked" + LinkedReason = "SUCCESS" + DisabledReasonV2ResourcesUnsupported = "DISABLED_V2_RESOURCES_UNSUPPORTED" + + LinkedMessageFormat = "Successfully linked to cluster '%s'" + DisabledResourceAPIsEnabledMessage = "Link is disabled because resource-apis are enabled" +) + +var ( + ConditionDisabled = &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_FALSE, + Reason: DisabledReasonV2ResourcesUnsupported, + Message: DisabledResourceAPIsEnabledMessage, + } +) + +func ConditionLinked(resourceId string) *pbresource.Condition { + return &pbresource.Condition{ + Type: StatusLinked, + State: pbresource.Condition_STATE_TRUE, + Reason: LinkedReason, + Message: fmt.Sprintf(LinkedMessageFormat, resourceId), + } +} diff --git a/internal/hcp/internal/controllers/register.go b/internal/hcp/internal/controllers/register.go new file mode 100644 index 0000000000..82b46c49ee --- /dev/null +++ b/internal/hcp/internal/controllers/register.go @@ -0,0 +1,21 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package controllers + +import ( + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/hcp/internal/controllers/link" +) + +type Dependencies struct { + ResourceApisEnabled bool + HCPAllowV2ResourceApis bool +} + +func Register(mgr *controller.Manager, deps Dependencies) { + mgr.Register(link.LinkController( + deps.ResourceApisEnabled, + deps.HCPAllowV2ResourceApis, + )) +} diff --git a/internal/hcp/internal/types/link.go b/internal/hcp/internal/types/link.go new file mode 100644 index 0000000000..cd8bfe39a2 --- /dev/null +++ b/internal/hcp/internal/types/link.go @@ -0,0 +1,63 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "errors" + + "github.com/hashicorp/consul/internal/resource" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/go-multierror" +) + +type DecodedLink = resource.DecodedResource[*pbhcp.Link] + +var ( + linkConfigurationNameError = errors.New("only a single Link resource is allowed and it must be named global") +) + +func RegisterLink(r resource.Registry) { + r.Register(resource.Registration{ + Type: pbhcp.LinkType, + Proto: &pbhcp.Link{}, + Scope: resource.ScopeCluster, + Validate: ValidateLink, + }) +} + +var ValidateLink = resource.DecodeAndValidate(validateLink) + +func validateLink(res *DecodedLink) error { + var err error + + if res.Id.Name != "global" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "name", + Wrapped: linkConfigurationNameError, + }) + } + + if res.Data.ClientId == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_id", + Wrapped: resource.ErrMissing, + }) + } + + if res.Data.ClientSecret == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "client_secret", + Wrapped: resource.ErrMissing, + }) + } + + if res.Data.ResourceId == "" { + err = multierror.Append(err, resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: resource.ErrMissing, + }) + } + + return err +} diff --git a/internal/hcp/internal/types/link_test.go b/internal/hcp/internal/types/link_test.go new file mode 100644 index 0000000000..feff0703d4 --- /dev/null +++ b/internal/hcp/internal/types/link_test.go @@ -0,0 +1,185 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/anypb" + + "github.com/hashicorp/consul/internal/resource" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" + pbhcp "github.com/hashicorp/consul/proto-public/pbhcp/v2" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +func createCloudLinkResource(t *testing.T, data protoreflect.ProtoMessage) *pbresource.Resource { + res := &pbresource.Resource{ + Id: &pbresource.ID{ + Type: pbhcp.LinkType, + Name: "global", + }, + } + + var err error + res.Data, err = anypb.New(data) + require.NoError(t, err) + return res +} + +func TestValidateLink_Ok(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + require.NoError(t, err) +} + +func TestValidateLink_ParseError(t *testing.T) { + // Any type other than the Link type would work + // to cause the error we are expecting + data := &pbcatalog.IP{Address: "198.18.0.1"} + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + require.Error(t, err) + require.ErrorAs(t, err, &resource.ErrDataParse{}) +} + +func TestValidateLink_InvalidName(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + + res := createCloudLinkResource(t, data) + res.Id.Name = "default" + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "name", + Wrapped: linkConfigurationNameError, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingClientId(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "", + ClientSecret: "abc", + ResourceId: "abc", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "client_id", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingClientSecret(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "", + ResourceId: "abc", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "client_secret", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +func TestValidateLink_MissingResourceId(t *testing.T) { + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "", + } + + res := createCloudLinkResource(t, data) + + err := ValidateLink(res) + + expected := resource.ErrInvalidField{ + Name: "resource_id", + Wrapped: resource.ErrMissing, + } + + var actual resource.ErrInvalidField + require.ErrorAs(t, err, &actual) + require.Equal(t, expected, actual) +} + +// Currently, we have no specific ACLs configured so the default `operator` permissions are required +func TestLinkACLs(t *testing.T) { + registry := resource.NewRegistry() + RegisterLink(registry) + + data := &pbhcp.Link{ + ClientId: "abc", + ClientSecret: "abc", + ResourceId: "abc", + } + link := createCloudLinkResource(t, data) + + cases := map[string]rtest.ACLTestCase{ + "no rules": { + Rules: ``, + Res: link, + ReadOK: rtest.DENY, + WriteOK: rtest.DENY, + ListOK: rtest.DENY, + }, + "link test read": { + Rules: `operator = "read"`, + Res: link, + ReadOK: rtest.ALLOW, + WriteOK: rtest.DENY, + ListOK: rtest.ALLOW, + }, + "link test write": { + Rules: `operator = "write"`, + Res: link, + ReadOK: rtest.ALLOW, + WriteOK: rtest.ALLOW, + ListOK: rtest.ALLOW, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + rtest.RunACLTestCase(t, tc, registry) + }) + } +} diff --git a/internal/hcp/internal/types/types.go b/internal/hcp/internal/types/types.go new file mode 100644 index 0000000000..fe32bd44ed --- /dev/null +++ b/internal/hcp/internal/types/types.go @@ -0,0 +1,10 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package types + +import "github.com/hashicorp/consul/internal/resource" + +func Register(r resource.Registry) { + RegisterLink(r) +} diff --git a/proto-public/pbhcp/v2/link.pb.binary.go b/proto-public/pbhcp/v2/link.pb.binary.go new file mode 100644 index 0000000000..7dbfbebae5 --- /dev/null +++ b/proto-public/pbhcp/v2/link.pb.binary.go @@ -0,0 +1,18 @@ +// Code generated by protoc-gen-go-binary. DO NOT EDIT. +// source: pbhcp/v2/link.proto + +package hcpv2 + +import ( + "google.golang.org/protobuf/proto" +) + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *Link) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *Link) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto-public/pbhcp/v2/link.pb.go b/proto-public/pbhcp/v2/link.pb.go new file mode 100644 index 0000000000..f9ba08261a --- /dev/null +++ b/proto-public/pbhcp/v2/link.pb.go @@ -0,0 +1,191 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: pbhcp/v2/link.proto + +package hcpv2 + +import ( + _ "github.com/hashicorp/consul/proto-public/pbresource" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +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 Link struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceId string `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientSecret string `protobuf:"bytes,3,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` + HcpClusterUrl string `protobuf:"bytes,4,opt,name=hcp_cluster_url,json=hcpClusterUrl,proto3" json:"hcp_cluster_url,omitempty"` +} + +func (x *Link) Reset() { + *x = Link{} + if protoimpl.UnsafeEnabled { + mi := &file_pbhcp_v2_link_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Link) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Link) ProtoMessage() {} + +func (x *Link) ProtoReflect() protoreflect.Message { + mi := &file_pbhcp_v2_link_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Link.ProtoReflect.Descriptor instead. +func (*Link) Descriptor() ([]byte, []int) { + return file_pbhcp_v2_link_proto_rawDescGZIP(), []int{0} +} + +func (x *Link) GetResourceId() string { + if x != nil { + return x.ResourceId + } + return "" +} + +func (x *Link) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *Link) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +func (x *Link) GetHcpClusterUrl() string { + if x != nil { + return x.HcpClusterUrl + } + return "" +} + +var File_pbhcp_v2_link_proto protoreflect.FileDescriptor + +var file_pbhcp_v2_link_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x2f, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x1a, 0x1c, + 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x99, 0x01, 0x0a, + 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x63, 0x70, 0x5f, + 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x68, 0x63, 0x70, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x6c, + 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x01, 0x42, 0xe0, 0x01, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x68, 0x63, 0x70, 0x2e, 0x76, 0x32, 0x42, 0x09, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, + 0x70, 0x62, 0x68, 0x63, 0x70, 0x2f, 0x76, 0x32, 0x3b, 0x68, 0x63, 0x70, 0x76, 0x32, 0xa2, 0x02, + 0x03, 0x48, 0x43, 0x48, 0xaa, 0x02, 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x48, 0x63, 0x70, 0x2e, 0x56, 0x32, 0xca, 0x02, + 0x17, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x23, 0x48, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x48, 0x63, 0x70, 0x5c, + 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x1a, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x3a, 0x3a, 0x48, 0x63, 0x70, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_pbhcp_v2_link_proto_rawDescOnce sync.Once + file_pbhcp_v2_link_proto_rawDescData = file_pbhcp_v2_link_proto_rawDesc +) + +func file_pbhcp_v2_link_proto_rawDescGZIP() []byte { + file_pbhcp_v2_link_proto_rawDescOnce.Do(func() { + file_pbhcp_v2_link_proto_rawDescData = protoimpl.X.CompressGZIP(file_pbhcp_v2_link_proto_rawDescData) + }) + return file_pbhcp_v2_link_proto_rawDescData +} + +var file_pbhcp_v2_link_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_pbhcp_v2_link_proto_goTypes = []interface{}{ + (*Link)(nil), // 0: hashicorp.consul.hcp.v2.Link +} +var file_pbhcp_v2_link_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_pbhcp_v2_link_proto_init() } +func file_pbhcp_v2_link_proto_init() { + if File_pbhcp_v2_link_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pbhcp_v2_link_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Link); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pbhcp_v2_link_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_pbhcp_v2_link_proto_goTypes, + DependencyIndexes: file_pbhcp_v2_link_proto_depIdxs, + MessageInfos: file_pbhcp_v2_link_proto_msgTypes, + }.Build() + File_pbhcp_v2_link_proto = out.File + file_pbhcp_v2_link_proto_rawDesc = nil + file_pbhcp_v2_link_proto_goTypes = nil + file_pbhcp_v2_link_proto_depIdxs = nil +} diff --git a/proto-public/pbhcp/v2/link.proto b/proto-public/pbhcp/v2/link.proto new file mode 100644 index 0000000000..556efd28ac --- /dev/null +++ b/proto-public/pbhcp/v2/link.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package hashicorp.consul.hcp.v2; + +import "pbresource/annotations.proto"; + +message Link { + option (hashicorp.consul.resource.spec) = {scope: SCOPE_CLUSTER}; + + string resource_id = 1; + string client_id = 2; + string client_secret = 3; + string hcp_cluster_url = 4; +} diff --git a/proto-public/pbhcp/v2/link_deepcopy.gen.go b/proto-public/pbhcp/v2/link_deepcopy.gen.go new file mode 100644 index 0000000000..9432d81b1e --- /dev/null +++ b/proto-public/pbhcp/v2/link_deepcopy.gen.go @@ -0,0 +1,27 @@ +// Code generated by protoc-gen-deepcopy. DO NOT EDIT. +package hcpv2 + +import ( + proto "google.golang.org/protobuf/proto" +) + +// DeepCopyInto supports using Link within kubernetes types, where deepcopy-gen is used. +func (in *Link) DeepCopyInto(out *Link) { + proto.Reset(out) + proto.Merge(out, proto.Clone(in)) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Link. Required by controller-gen. +func (in *Link) DeepCopy() *Link { + if in == nil { + return nil + } + out := new(Link) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Link. Required by controller-gen. +func (in *Link) DeepCopyInterface() interface{} { + return in.DeepCopy() +} diff --git a/proto-public/pbhcp/v2/link_json.gen.go b/proto-public/pbhcp/v2/link_json.gen.go new file mode 100644 index 0000000000..cd476920dd --- /dev/null +++ b/proto-public/pbhcp/v2/link_json.gen.go @@ -0,0 +1,22 @@ +// Code generated by protoc-json-shim. DO NOT EDIT. +package hcpv2 + +import ( + protojson "google.golang.org/protobuf/encoding/protojson" +) + +// MarshalJSON is a custom marshaler for Link +func (this *Link) MarshalJSON() ([]byte, error) { + str, err := LinkMarshaler.Marshal(this) + return []byte(str), err +} + +// UnmarshalJSON is a custom unmarshaler for Link +func (this *Link) UnmarshalJSON(b []byte) error { + return LinkUnmarshaler.Unmarshal(b, this) +} + +var ( + LinkMarshaler = &protojson.MarshalOptions{} + LinkUnmarshaler = &protojson.UnmarshalOptions{DiscardUnknown: false} +) diff --git a/proto-public/pbhcp/v2/resources.rtypes.go b/proto-public/pbhcp/v2/resources.rtypes.go new file mode 100644 index 0000000000..646da3ef14 --- /dev/null +++ b/proto-public/pbhcp/v2/resources.rtypes.go @@ -0,0 +1,22 @@ +// Code generated by protoc-gen-resource-types. DO NOT EDIT. + +package hcpv2 + +import ( + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + GroupName = "hcp" + Version = "v2" + + LinkKind = "Link" +) + +var ( + LinkType = &pbresource.Type{ + Group: GroupName, + GroupVersion: Version, + Kind: LinkKind, + } +)