diff --git a/charts/consul/templates/crd-apigateways.yaml b/charts/consul/templates/crd-apigateways.yaml index cca95dae89..a01d40c027 100644 --- a/charts/consul/templates/crd-apigateways.yaml +++ b/charts/consul/templates/crd-apigateways.yaml @@ -293,9 +293,6 @@ spec: format: date-time type: string type: object - required: - - addresses - - listeners type: object type: object served: true diff --git a/control-plane/api/mesh/v2beta1/api_gateway_types.go b/control-plane/api/mesh/v2beta1/api_gateway_types.go index fdea0d4422..18bd4ad5b1 100644 --- a/control-plane/api/mesh/v2beta1/api_gateway_types.go +++ b/control-plane/api/mesh/v2beta1/api_gateway_types.go @@ -25,7 +25,7 @@ const ( ) func init() { - MeshSchemeBuilder.Register(&GatewayClass{}, &GatewayClassList{}, &APIGateway{}, &APIGatewayList{}) + MeshSchemeBuilder.Register(&APIGateway{}, &APIGatewayList{}) } // +kubebuilder:object:root=true @@ -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 { @@ -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, diff --git a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml index e2664016fe..7b0d2a54b9 100644 --- a/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml +++ b/control-plane/config/crd/bases/mesh.consul.hashicorp.com_apigateways.yaml @@ -289,9 +289,6 @@ spec: format: date-time type: string type: object - required: - - addresses - - listeners type: object type: object served: true diff --git a/control-plane/controllers/resources/api-gateway-controller.go b/control-plane/controllers/resources/api-gateway-controller.go index 2728ef74df..87333beb6f 100644 --- a/control-plane/controllers/resources/api-gateway-controller.go +++ b/control-plane/controllers/resources/api-gateway-controller.go @@ -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 @@ -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 } } @@ -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 -} diff --git a/control-plane/controllers/resources/api-gateway-controller_test.go b/control-plane/controllers/resources/api-gateway-controller_test.go index 2bb4eee1c2..6b907647ec 100644 --- a/control-plane/controllers/resources/api-gateway-controller_test.go +++ b/control-plane/controllers/resources/api-gateway-controller_test.go @@ -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" @@ -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{ diff --git a/control-plane/controllers/resources/gateway_controller_crud.go b/control-plane/controllers/resources/gateway_controller_crud.go index e1ab407dd0..a2eae79811 100644 --- a/control-plane/controllers/resources/gateway_controller_crud.go +++ b/control-plane/controllers/resources/gateway_controller_crud.go @@ -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() diff --git a/control-plane/controllers/resources/mesh_gateway_controller.go b/control-plane/controllers/resources/mesh_gateway_controller.go index a49b2bdb40..71bd4e3d46 100644 --- a/control-plane/controllers/resources/mesh_gateway_controller.go +++ b/control-plane/controllers/resources/mesh_gateway_controller.go @@ -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 } } diff --git a/control-plane/gateways/builder.go b/control-plane/gateways/builder.go index 36209a8d19..35e8384b3f 100644 --- a/control-plane/gateways/builder.go +++ b/control-plane/gateways/builder.go @@ -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, } } diff --git a/control-plane/gateways/deployment.go b/control-plane/gateways/deployment.go index 9e7fef2838..5bab84dec8 100644 --- a/control-plane/gateways/deployment.go +++ b/control-plane/gateways/deployment.go @@ -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) { @@ -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 diff --git a/control-plane/gateways/deployment_test.go b/control-plane/gateways/deployment_test.go index 2444d02e3d..24e5fa67a2 100644 --- a/control-plane/gateways/deployment_test.go +++ b/control-plane/gateways/deployment_test.go @@ -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", @@ -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", @@ -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", @@ -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) { diff --git a/control-plane/gateways/metadata_test.go b/control-plane/gateways/metadata_test.go index 88958c1d5c..5b4861c1d0 100644 --- a/control-plane/gateways/metadata_test.go +++ b/control-plane/gateways/metadata_test.go @@ -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 @@ -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 @@ -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()) }) diff --git a/control-plane/gateways/serviceaccount_test.go b/control-plane/gateways/serviceaccount_test.go index 3f6fa6f24f..7436beb683 100644 --- a/control-plane/gateways/serviceaccount_test.go +++ b/control-plane/gateways/serviceaccount_test.go @@ -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{ diff --git a/control-plane/subcommand/inject-connect/v2controllers.go b/control-plane/subcommand/inject-connect/v2controllers.go index 13f83a12cc..fce6968ad6 100644 --- a/control-plane/subcommand/inject-connect/v2controllers.go +++ b/control-plane/subcommand/inject-connect/v2controllers.go @@ -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