Skip to content

Commit

Permalink
[NET-7450] setup crud hooks for APIGateway v2 (#3580)
Browse files Browse the repository at this point in the history
* setup crud hooks for APIGateway v2

* update CRDS and reorganize code in api gateway type

* pass in gateway kind for annotations

* Fix tests

* Fix tests

* register all types needed for test
  • Loading branch information
jm96441n authored Feb 20, 2024
1 parent eaee0dc commit 5242c1b
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 93 deletions.
3 changes: 0 additions & 3 deletions charts/consul/templates/crd-apigateways.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,6 @@ spec:
format: date-time
type: string
type: object
required:
- addresses
- listeners
type: object
type: object
served: true
Expand Down
34 changes: 17 additions & 17 deletions control-plane/api/mesh/v2beta1/api_gateway_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const (
)

func init() {
MeshSchemeBuilder.Register(&GatewayClass{}, &GatewayClassList{}, &APIGateway{}, &APIGatewayList{})
MeshSchemeBuilder.Register(&APIGateway{}, &APIGatewayList{})
}

// +kubebuilder:object:root=true
Expand All @@ -46,22 +46,8 @@ type APIGateway struct {

type APIGatewayStatus struct {
Status `json:"status,omitempty"`
Addresses []GatewayAddress `json:"addresses"`
Listeners []ListenerStatus `json:"listeners"`
}

func (in *APIGatewayList) ReconcileRequests() []reconcile.Request {
requests := make([]reconcile.Request, 0, len(in.Items))

for _, item := range in.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.Name,
Namespace: item.Namespace,
},
})
}
return requests
Addresses []GatewayAddress `json:"addresses,omitempty"`
Listeners []ListenerStatus `json:"listeners,omitempty"`
}

type ListenerStatus struct {
Expand All @@ -85,6 +71,20 @@ type APIGatewayList struct {
Items []*APIGateway `json:"items"`
}

func (in *APIGatewayList) ReconcileRequests() []reconcile.Request {
requests := make([]reconcile.Request, 0, len(in.Items))

for _, item := range in.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.Name,
Namespace: item.Namespace,
},
})
}
return requests
}

func (in *APIGateway) ResourceID(namespace, partition string) *pbresource.ID {
return &pbresource.ID{
Name: in.Name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,6 @@ spec:
format: date-time
type: string
type: object
required:
- addresses
- listeners
type: object
type: object
served: true
Expand Down
39 changes: 23 additions & 16 deletions control-plane/controllers/resources/api-gateway-controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1"
"github.com/hashicorp/consul-k8s/control-plane/gateways"
)

// APIGatewayController reconciles a APIGateway object.
type APIGatewayController struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Controller *ConsulResourceController
Log logr.Logger
Scheme *runtime.Scheme
Controller *ConsulResourceController
GatewayConfig gateways.GatewayConfig
}

// +kubebuilder:rbac:groups=mesh.consul.hashicorp.com,resources=tcproute,verbs=get;list;watch;create;update;patch;delete
Expand All @@ -40,14 +42,29 @@ func (r *APIGatewayController) Reconcile(ctx context.Context, req ctrl.Request)
}

// Call hooks
if !resource.DeletionTimestamp.IsZero() {
if !resource.GetDeletionTimestamp().IsZero() {
logger.Info("deletion event")

if err := r.onDelete(ctx, req, resource); err != nil {
if err := onDelete(ctx, req, r.Client, resource); err != nil {
return ctrl.Result{}, err
}
} else {
if err := r.onCreateUpdate(ctx, req, resource); err != nil {
// Fetch GatewayClassConfig for the gateway
if resource.Namespace == "" {
resource.Namespace = "default"
}

gcc, err := getGatewayClassConfigByGatewayClassName(ctx, r.Client, resource.Spec.GatewayClassName)
if err != nil {
r.Log.Error(err, "unable to get gatewayclassconfig for gateway: %s gatewayclass: %s", resource.Name, resource.Spec.GatewayClassName)
return ctrl.Result{}, err
}

if err := onCreateUpdate(ctx, r.Client, gatewayConfigs{
gcc: gcc,
gatewayConfig: r.GatewayConfig,
}, resource, gateways.APIGatewayAnnotationKind); err != nil {
logger.Error(err, "unable to create/update gateway")
return ctrl.Result{}, err
}
}
Expand All @@ -66,13 +83,3 @@ func (r *APIGatewayController) UpdateStatus(ctx context.Context, obj client.Obje
func (r *APIGatewayController) SetupWithManager(mgr ctrl.Manager) error {
return setupGatewayControllerWithManager[*meshv2beta1.APIGatewayList](mgr, &meshv2beta1.APIGateway{}, r.Client, r, APIGateway_GatewayClassIndex)
}

func (r *APIGatewayController) onCreateUpdate(ctx context.Context, req ctrl.Request, resource *meshv2beta1.APIGateway) error {
// TODO: NET-7449, NET-7450, and NET-7451
return nil
}

func (r *APIGatewayController) onDelete(ctx context.Context, req ctrl.Request, resource *meshv2beta1.APIGateway) error {
// TODO: NET-7449, NET-7450, and NET-7451
return nil
}
20 changes: 16 additions & 4 deletions control-plane/controllers/resources/api-gateway-controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
"google.golang.org/protobuf/testing/protocmp"

logrtest "github.com/go-logr/logr/testr"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -31,10 +34,19 @@ func TestAPIGatewayController_ReconcileResourceExists(t *testing.T) {
ctx := context.Background()

s := runtime.NewScheme()
s.AddKnownTypes(schema.GroupVersion{
Group: "mesh.consul.hashicorp.com",
Version: pbmesh.Version,
}, &v2beta1.APIGateway{}, &v2beta1.APIGatewayList{})
require.NoError(t, corev1.AddToScheme(s))
require.NoError(t, appsv1.AddToScheme(s))
require.NoError(t, rbacv1.AddToScheme(s))
require.NoError(t, v2beta1.AddMeshToScheme(s))
s.AddKnownTypes(
schema.GroupVersion{
Group: "mesh.consul.hashicorp.com",
Version: pbmesh.Version,
},
&v2beta1.APIGateway{},
&v2beta1.GatewayClass{},
&v2beta1.GatewayClassConfig{},
)

apiGW := &v2beta1.APIGateway{
ObjectMeta: metav1.ObjectMeta{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ type gatewayConfigs struct {
// 3. Service
// 4. Role
// 5. RoleBinding
func onCreateUpdate[T gateways.Gateway](ctx context.Context, k8sClient client.Client, cfg gatewayConfigs, resource T) error {
builder := gateways.NewGatewayBuilder[T](resource, cfg.gatewayConfig, cfg.gcc)
func onCreateUpdate[T gateways.Gateway](ctx context.Context, k8sClient client.Client, cfg gatewayConfigs, resource T, gatewayKind string) error {
builder := gateways.NewGatewayBuilder[T](resource, cfg.gatewayConfig, cfg.gcc, gatewayKind)

// Create ServiceAccount
desiredAccount := builder.ServiceAccount()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (r *MeshGatewayController) Reconcile(ctx context.Context, req ctrl.Request)
if err := onCreateUpdate(ctx, r.Client, gatewayConfigs{
gcc: gcc,
gatewayConfig: r.GatewayConfig,
}, resource); err != nil {
}, resource, gateways.MeshGatewayAnnotationKind); err != nil {
return ctrl.Result{}, err
}
}
Expand Down
16 changes: 9 additions & 7 deletions control-plane/gateways/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ type Gateway interface {
// This includes Deployment, Role, Service, and ServiceAccount resources.
// Configuration is combined from the MeshGateway, GatewayConfig, and GatewayClassConfig.
type gatewayBuilder[T Gateway] struct {
gateway T
gcc *meshv2beta1.GatewayClassConfig
config GatewayConfig
gateway T
gcc *meshv2beta1.GatewayClassConfig
config GatewayConfig
gatewayKind string
}

// NewGatewayBuilder returns a new meshGatewayBuilder for the given MeshGateway,
// GatewayConfig, and GatewayClassConfig.
func NewGatewayBuilder[T Gateway](gateway T, gatewayConfig GatewayConfig, gatewayClassConfig *meshv2beta1.GatewayClassConfig) *gatewayBuilder[T] {
func NewGatewayBuilder[T Gateway](gateway T, gatewayConfig GatewayConfig, gatewayClassConfig *meshv2beta1.GatewayClassConfig, gatewayKind string) *gatewayBuilder[T] {
return &gatewayBuilder[T]{
gateway: gateway,
config: gatewayConfig,
gcc: gatewayClassConfig,
gateway: gateway,
config: gatewayConfig,
gcc: gatewayClassConfig,
gatewayKind: gatewayKind,
}
}
5 changes: 3 additions & 2 deletions control-plane/gateways/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (

const (
globalDefaultInstances int32 = 1
meshGatewayAnnotationKind = "mesh-gateway"
MeshGatewayAnnotationKind = "mesh-gateway"
APIGatewayAnnotationKind = "api-gateway"
)

func (b *gatewayBuilder[T]) Deployment() (*appsv1.Deployment, error) {
Expand Down Expand Up @@ -67,7 +68,7 @@ func (b *gatewayBuilder[T]) deploymentSpec() (*appsv1.DeploymentSpec, error) {
Annotations: map[string]string{
// Indicate that this pod is a mesh gateway pod so that the Pod controller,
// consul-k8s CLI, etc. can key off of it
constants.AnnotationGatewayKind: meshGatewayAnnotationKind,
constants.AnnotationGatewayKind: b.gatewayKind,
// It's not logical to add a proxy sidecar since our workload is itself a proxy
constants.AnnotationMeshInject: "false",
// This functionality only applies when proxy sidecars are used
Expand Down
13 changes: 7 additions & 6 deletions control-plane/gateways/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) {
"release": "consul",
},
Annotations: map[string]string{
constants.AnnotationGatewayKind: meshGatewayAnnotationKind,
constants.AnnotationGatewayKind: MeshGatewayAnnotationKind,
constants.AnnotationMeshInject: "false",
constants.AnnotationTransparentProxyOverwriteProbes: "false",
constants.AnnotationGatewayWANSource: "Service",
Expand Down Expand Up @@ -607,7 +607,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) {
"release": "consul",
},
Annotations: map[string]string{
constants.AnnotationGatewayKind: meshGatewayAnnotationKind,
constants.AnnotationGatewayKind: MeshGatewayAnnotationKind,
constants.AnnotationMeshInject: "false",
constants.AnnotationTransparentProxyOverwriteProbes: "false",
constants.AnnotationGatewayWANSource: "Service",
Expand Down Expand Up @@ -918,7 +918,7 @@ func Test_gatewayBuilder_Deployment(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Labels: defaultLabels,
Annotations: map[string]string{
constants.AnnotationGatewayKind: meshGatewayAnnotationKind,
constants.AnnotationGatewayKind: MeshGatewayAnnotationKind,
constants.AnnotationMeshInject: "false",
constants.AnnotationTransparentProxyOverwriteProbes: "false",
constants.AnnotationGatewayWANSource: "Service",
Expand Down Expand Up @@ -1140,9 +1140,10 @@ func Test_gatewayBuilder_Deployment(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &gatewayBuilder[*meshv2beta1.MeshGateway]{
gateway: tt.fields.gateway,
config: tt.fields.config,
gcc: tt.fields.gcc,
gateway: tt.fields.gateway,
config: tt.fields.config,
gcc: tt.fields.gcc,
gatewayKind: MeshGatewayAnnotationKind,
}
got, err := b.Deployment()
if !tt.wantErr && (err != nil) {
Expand Down
6 changes: 3 additions & 3 deletions control-plane/gateways/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestGatewayBuilder_Annotations(t *testing.T) {
},
}

b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig)
b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig, MeshGatewayAnnotationKind)

for _, testCase := range []struct {
Actual map[string]string
Expand Down Expand Up @@ -198,7 +198,7 @@ func TestGatewayBuilder_Labels(t *testing.T) {
},
}

b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig)
b := NewGatewayBuilder[*meshv2beta1.MeshGateway](gateway, GatewayConfig{}, gatewayClassConfig, MeshGatewayAnnotationKind)

for _, testCase := range []struct {
Actual map[string]string
Expand Down Expand Up @@ -298,7 +298,7 @@ func TestGatewayBuilder_LogLevel(t *testing.T) {
},
},
}
b := NewGatewayBuilder(&meshv2beta1.MeshGateway{}, GatewayConfig{LogLevel: testCase.GatewayLogLevel}, gcc)
b := NewGatewayBuilder(&meshv2beta1.MeshGateway{}, GatewayConfig{LogLevel: testCase.GatewayLogLevel}, gcc, MeshGatewayAnnotationKind)

assert.Equal(t, debug, b.logLevelForDataplaneContainer())
})
Expand Down
2 changes: 1 addition & 1 deletion control-plane/gateways/serviceaccount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestNewMeshGatewayBuilder_ServiceAccount(t *testing.T) {
Namespace: "default",
Name: "mesh-gateway",
},
}, GatewayConfig{}, nil)
}, GatewayConfig{}, nil, MeshGatewayAnnotationKind)

expected := &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Expand Down
59 changes: 31 additions & 28 deletions control-plane/subcommand/inject-connect/v2controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,41 +215,44 @@ func (c *Command) configureV2Controllers(ctx context.Context, mgr manager.Manage
return err
}

if err := (&resourceControllers.MeshGatewayController{
Controller: consulResourceController,
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controller").WithName(common.MeshGateway),
Scheme: mgr.GetScheme(),
GatewayConfig: gateways.GatewayConfig{
ConsulConfig: common.ConsulConfig{
Address: c.consul.Addresses,
GRPCPort: consulConfig.GRPCPort,
HTTPPort: consulConfig.HTTPPort,
APITimeout: consulConfig.APITimeout,
},
ImageDataplane: c.flagConsulDataplaneImage,
ImageConsulK8S: c.flagConsulK8sImage,
ConsulTenancyConfig: consulTenancyConfig,
PeeringEnabled: c.flagEnablePeering,
EnableOpenShift: c.flagEnableOpenShift,
AuthMethod: c.consul.ConsulLogin.AuthMethod,
LogLevel: c.flagLogLevel,
LogJSON: c.flagLogJSON,
TLSEnabled: c.consul.UseTLS,
ConsulTLSServerName: c.consul.TLSServerName,
ConsulCACert: string(c.caCertPem),
SkipServerWatch: c.consul.SkipServerWatch,
gatewayConfig := gateways.GatewayConfig{
ConsulConfig: common.ConsulConfig{
Address: c.consul.Addresses,
GRPCPort: consulConfig.GRPCPort,
HTTPPort: consulConfig.HTTPPort,
APITimeout: consulConfig.APITimeout,
},
ImageDataplane: c.flagConsulDataplaneImage,
ImageConsulK8S: c.flagConsulK8sImage,
ConsulTenancyConfig: consulTenancyConfig,
PeeringEnabled: c.flagEnablePeering,
EnableOpenShift: c.flagEnableOpenShift,
AuthMethod: c.consul.ConsulLogin.AuthMethod,
LogLevel: c.flagLogLevel,
LogJSON: c.flagLogJSON,
TLSEnabled: c.consul.UseTLS,
ConsulTLSServerName: c.consul.TLSServerName,
ConsulCACert: string(c.caCertPem),
SkipServerWatch: c.consul.SkipServerWatch,
}

if err := (&resourceControllers.MeshGatewayController{
Controller: consulResourceController,
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controller").WithName(common.MeshGateway),
Scheme: mgr.GetScheme(),
GatewayConfig: gatewayConfig,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", common.MeshGateway)
return err
}

if err := (&resourceControllers.APIGatewayController{
Controller: consulResourceController,
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controller").WithName(common.APIGateway),
Scheme: mgr.GetScheme(),
Controller: consulResourceController,
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controller").WithName(common.APIGateway),
Scheme: mgr.GetScheme(),
GatewayConfig: gatewayConfig,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", common.APIGateway)
return err
Expand Down

0 comments on commit 5242c1b

Please sign in to comment.