Skip to content

Commit

Permalink
feat: support protocol field (#24)
Browse files Browse the repository at this point in the history
* feat: support protocol fields

* fix: revert changes to dockerfile

* fix: add comment explaining http gateway logic

* fix: mv HTTP1 HTTP
  • Loading branch information
randalljohnson authored Jan 2, 2024
1 parent 1fea877 commit eb2dc38
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 22 deletions.
37 changes: 36 additions & 1 deletion .codegen/preserved-assets/gateway_namespace_gateway_proxy.go.bak
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func MutateGatewayNamespaceGatewayProxy(

// create a gateway object for each port requested
for _, portSpec := range parent.Spec.Ports {

if portSpec.Protocol != "HTTP" {
continue
}

target := unstructuredObj.DeepCopy()

spec, found, err := unstructured.NestedMap(target.Object, "spec")
Expand All @@ -60,7 +65,12 @@ func MutateGatewayNamespaceGatewayProxy(
return mutatedGateways, fmt.Errorf("spec field not found in gateway object: %w", err)
}

spec["bindPort"] = portSpec.Port
bindPort, err := getUnprivilegedPort(portSpec.Port, parent.Spec.Ports)
if err != nil {
return mutatedGateways, fmt.Errorf("failed to get unprivileged port: %w", err)
}

spec["bindPort"] = bindPort
spec["ssl"] = portSpec.SSL

if err := unstructured.SetNestedMap(target.Object, spec, "spec"); err != nil {
Expand All @@ -74,3 +84,28 @@ func MutateGatewayNamespaceGatewayProxy(

return mutatedGateways, nil
}

// getUnprivilegedPort returns an unprivileged port if the port is privileged.
func getUnprivilegedPort(port int64, portSpec []gatewayv1alpha1.PortSpec) (int64, error) {
if port < 1 {
return port, fmt.Errorf("port %d is invalid, must be greater than 0", port)
}
if port < 1024 {
unprivilegedPort := port + 8000
if !isPortInUse(unprivilegedPort, portSpec) {
return unprivilegedPort, nil
}
return port, fmt.Errorf("port %d is already in use", unprivilegedPort)
}
return port, nil
}

// isPortInUse returns true if the requested port is already in use.
func isPortInUse(port int64, portSpec []gatewayv1alpha1.PortSpec) bool {
for _, portSpec := range portSpec {
if portSpec.Port == int64(port) {
return true
}
}
return false
}
12 changes: 10 additions & 2 deletions .codegen/preserved-assets/glooedge_types.go.bak
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,17 @@ type GlooEdgeSpec struct {

// PortSpec defines a port which gets implemented as a Gateway resource.
type PortSpec struct {
// Name of the port to create.
Name string `json:"name,omitempty"`
Port int64 `json:"port,omitempty"`
SSL bool `json:"ssl,omitempty"`

// Port number to use for the port.
Port int64 `json:"port,omitempty"`

// Indicates whether the port should be secured via TLS.
SSL bool `json:"ssl,omitempty"`

// Protocol to use for the port. Defaults to HTTP.
Protocol string `json:"protocol,omitempty"`
}

type GlooEdgeCollectionSpec struct {
Expand Down
99 changes: 99 additions & 0 deletions .codegen/preserved-assets/service_namespace_gateway_proxy.go.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
Copyright 2023.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mutate

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/nukleros/operator-builder-tools/pkg/controller/workload"
"github.com/nukleros/operator-builder-tools/pkg/resources"

gatewayv1alpha1 "github.com/nukleros/support-services-operator/apis/gateway/v1alpha1"
orchestrationv1alpha1 "github.com/nukleros/support-services-operator/apis/orchestration/v1alpha1"
)

// MutateServiceNamespaceGatewayProxy mutates the Service resource with name gateway-proxy.
func MutateServiceNamespaceGatewayProxy(
original client.Object,
parent *gatewayv1alpha1.GlooEdge, collection *orchestrationv1alpha1.SupportServices,
reconciler workload.Reconciler, req *workload.Request,
) ([]client.Object, error) {
// if either the reconciler or request are found to be nil, return the base object.
if reconciler == nil || req == nil {
return []client.Object{original}, nil
}

// convert object to unstructured
service, err := resources.ToUnstructured(original)
if err != nil {
return []client.Object{original}, fmt.Errorf("failed to convert client.Object to unstructured object: %w", err)
}

existingPorts, found, err := unstructured.NestedSlice(service.Object, "spec", "ports")
if err != nil {
return []client.Object{original}, fmt.Errorf("failed to retrieve spec field for gateway: %w", err)
}
if !found {
return []client.Object{original}, fmt.Errorf("spec field not found in gateway object: %w", err)
}

newPorts := []interface{}{}
// create a port object for each port requested
for _, portSpec := range parent.Spec.Ports {
port := map[string]interface{}{}

existingPorts = removeDuplicatePorts(portSpec.Port, existingPorts)

targetPort, err := getUnprivilegedPort(portSpec.Port, parent.Spec.Ports)
if err != nil {
return []client.Object{original}, err
}

port["port"] = portSpec.Port
port["targetPort"] = targetPort
port["protocol"] = "TCP"
port["name"] = portSpec.Name

newPorts = append(newPorts, port)
}

newPorts = append(newPorts, existingPorts...)

err = unstructured.SetNestedSlice(service.Object, newPorts, "spec", "ports")
if err != nil {
return []client.Object{original}, fmt.Errorf("failed to set ports field for service: %w", err)
}

return []client.Object{service}, nil
}

// removeDuplicatePorts removes any ports that have the same port number as the one passed in.
func removeDuplicatePorts(port int64, ports []interface{}) []interface{} {
deduplicated := []interface{}{}
for _, p := range ports {
if pMap, ok := p.(map[string]interface{}); ok {
if pMap["port"].(int64) == port {
continue
}
}
deduplicated = append(deduplicated, p)
}
return deduplicated
}
4 changes: 2 additions & 2 deletions apis/certificates/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the certificates v1alpha1 API group.
//+kubebuilder:object:generate=true
//+groupName=certificates.support-services.nukleros.io
// +kubebuilder:object:generate=true
// +groupName=certificates.support-services.nukleros.io
package v1alpha1

import (
Expand Down
10 changes: 5 additions & 5 deletions apis/gateway/v1alpha1/externaldns/config_route53.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ func CreateSecretNamespaceExternalDnsRoute53(
// controlled by field: zoneType
// +kubebuilder:validation:Enum=private;public
// Type of DNS hosted zone to manage.
"EXTERNAL_DNS_AWS_ZONE_TYPE": parent.Spec.ZoneType,
"EXTERNAL_DNS_DOMAIN_FILTER": parent.Spec.DomainName, // controlled by field: domainName
"EXTERNAL_DNS_POLICY": "sync",
"AWS_ACCESS_KEY_ID": "",
"AWS_SECRET_ACCESS_KEY": "",
"EXTERNAL_DNS_AWS_ZONE_TYPE": parent.Spec.ZoneType,
"EXTERNAL_DNS_DOMAIN_FILTER": parent.Spec.DomainName, // controlled by field: domainName
"EXTERNAL_DNS_POLICY": "sync",
"AWS_ACCESS_KEY_ID": "",
"AWS_SECRET_ACCESS_KEY": "",
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ package mutate

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"

"github.com/nukleros/operator-builder-tools/pkg/controller/workload"
"github.com/nukleros/operator-builder-tools/pkg/resources"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"

gatewayv1alpha1 "github.com/nukleros/support-services-operator/apis/gateway/v1alpha1"
orchestrationv1alpha1 "github.com/nukleros/support-services-operator/apis/orchestration/v1alpha1"
Expand All @@ -50,6 +50,12 @@ func MutateGatewayNamespaceGatewayProxy(

// create a gateway object for each port requested
for _, portSpec := range parent.Spec.Ports {

// only create a gateway object for http ports
if strings.ToLower(portSpec.Protocol) != "http" {
continue
}

target := unstructuredObj.DeepCopy()

spec, found, err := unstructured.NestedMap(target.Object, "spec")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ func MutateServiceNamespaceGatewayProxy(
return []client.Object{original}, fmt.Errorf("failed to convert client.Object to unstructured object: %w", err)
}

// target := unstructuredObj.DeepCopy()
existingPorts, found, err := unstructured.NestedSlice(service.Object, "spec", "ports")
if err != nil {
return []client.Object{original}, fmt.Errorf("failed to retrieve spec field for gateway: %w", err)
Expand Down
12 changes: 10 additions & 2 deletions apis/gateway/v1alpha1/glooedge_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,17 @@ type GlooEdgeSpec struct {

// PortSpec defines a port which gets implemented as a Gateway resource.
type PortSpec struct {
// Name of the port to create.
Name string `json:"name,omitempty"`
Port int64 `json:"port,omitempty"`
SSL bool `json:"ssl,omitempty"`

// Port number to use for the port.
Port int64 `json:"port,omitempty"`

// Indicates whether the port should be secured via TLS.
SSL bool `json:"ssl,omitempty"`

// Protocol to use for the port. Defaults to HTTP.
Protocol string `json:"protocol,omitempty"`
}

type GlooEdgeCollectionSpec struct {
Expand Down
4 changes: 2 additions & 2 deletions apis/gateway/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the gateway v1alpha1 API group.
//+kubebuilder:object:generate=true
//+groupName=gateway.support-services.nukleros.io
// +kubebuilder:object:generate=true
// +groupName=gateway.support-services.nukleros.io
package v1alpha1

import (
Expand Down
29 changes: 27 additions & 2 deletions apis/gateway/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions apis/orchestration/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the orchestration v1alpha1 API group
//+kubebuilder:object:generate=true
//+groupName=orchestration.support-services.nukleros.io
// +kubebuilder:object:generate=true
// +groupName=orchestration.support-services.nukleros.io
package v1alpha1

import (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,18 @@ spec:
Gateway resource.
properties:
name:
description: Name of the port to create.
type: string
port:
description: Port number to use for the port.
format: int64
type: integer
protocol:
description: Protocol to use for the port. Defaults to HTTP.
type: string
ssl:
description: Indicates whether the port should be secured via
TLS.
type: boolean
type: object
type: array
Expand Down

0 comments on commit eb2dc38

Please sign in to comment.