Skip to content

Commit

Permalink
controller: dispatch host policy (#67)
Browse files Browse the repository at this point in the history
TODO: write the policy to k8s

---------

Signed-off-by: spacewander <[email protected]>
  • Loading branch information
spacewander authored Nov 29, 2023
1 parent 53bc547 commit 9af1a7f
Show file tree
Hide file tree
Showing 24 changed files with 940 additions and 116 deletions.
5 changes: 5 additions & 0 deletions controller/internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package config

func GoSoPath() string {
return "/etc/libgolang.so"
}
35 changes: 31 additions & 4 deletions controller/internal/controller/httpfilterpolicy_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controller
import (
"context"
"fmt"
"strings"

istiov1b1 "istio.io/client-go/pkg/apis/networking/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -34,7 +35,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"

mosniov1 "mosn.io/moe/controller/api/v1"
"mosn.io/moe/controller/internal/ir"
"mosn.io/moe/controller/internal/translation"
)

// HTTPFilterPolicyReconciler reconciles a HTTPFilterPolicy object
Expand Down Expand Up @@ -65,7 +66,7 @@ func (r *HTTPFilterPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Req
return ctrl.Result{}, fmt.Errorf("failed to list HTTPFilterPolicy: %v", err)
}

state := ir.NewInitState(&logger)
state := translation.NewInitState(&logger)

for _, policy := range policies.Items {
err := validateHTTPFilterPolicy(&policy)
Expand All @@ -88,11 +89,37 @@ func (r *HTTPFilterPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Req

err = validateVirtualService(&virtualService)
if err != nil {
logger.Error(err, "invalid VirtualService", "name", virtualService.Name, "namespace", virtualService.Namespace)
logger.Info("unsupported VirtualService", "name", virtualService.Name, "namespace", virtualService.Namespace, "reason", err.Error())
continue
}

state.AddPolicyForVirtualService(&policy, &virtualService)
for _, gw := range virtualService.Spec.Gateways {
if gw == "mesh" {
logger.Info("skip unsupported mesh gateway", "name", virtualService.Name, "namespace", virtualService.Namespace)
continue
}
if strings.Contains(gw, "/") {
logger.Info("skip gateway from other namespace", "name", virtualService.Name, "namespace", virtualService.Namespace)
continue
}

var gateway istiov1b1.Gateway
err = r.Get(ctx, types.NamespacedName{Name: gw, Namespace: req.Namespace}, &gateway)
if err != nil {
if !apierrors.IsNotFound(err) {
return ctrl.Result{}, err
}
continue
}

err = validateGateway(&gateway)
if err != nil {
logger.Info("unsupported Gateway", "name", gateway.Name, "namespace", gateway.Namespace, "reason", err.Error())
continue
}

state.AddPolicyForVirtualService(&policy, &virtualService, &gateway)
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions controller/internal/controller/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"errors"
"strings"

"google.golang.org/protobuf/encoding/protojson"
istiov1b1 "istio.io/client-go/pkg/apis/networking/v1beta1"
Expand Down Expand Up @@ -41,3 +42,15 @@ func validateVirtualService(vs *istiov1b1.VirtualService) error {
}
return nil
}

func validateGateway(gw *istiov1b1.Gateway) error {
// TODO: support it
for _, svr := range gw.Spec.Servers {
for _, host := range svr.Hosts {
if strings.ContainsRune(host, '/') {
return errors.New("Gateway has host with namespace is not supported")
}
}
}
return nil
}
9 changes: 0 additions & 9 deletions controller/internal/envoyfilter/envoyfilter.go

This file was deleted.

56 changes: 0 additions & 56 deletions controller/internal/ir/data_plane_state.go

This file was deleted.

17 changes: 0 additions & 17 deletions controller/internal/ir/final_state.go

This file was deleted.

27 changes: 0 additions & 27 deletions controller/internal/ir/merged_state.go

This file was deleted.

113 changes: 113 additions & 0 deletions controller/internal/istio/envoyfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package istio

import (
"encoding/json"

"google.golang.org/protobuf/types/known/structpb"
istioapi "istio.io/api/networking/v1alpha3"
istiov1a3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

ctrlcfg "mosn.io/moe/controller/internal/config"
"mosn.io/moe/controller/internal/model"
"mosn.io/moe/pkg/filtermanager"
)

const (
DefaultHttpFilter = "htnn-http-filter"
)

func MustNewStruct(fields map[string]interface{}) *structpb.Struct {
st, err := structpb.NewStruct(fields)
if err != nil {
// NewStruct returns error only when the fields contain non-standard type
panic(err)
}
return st
}

func DefaultEnvoyFilters() map[string]*istiov1a3.EnvoyFilter {
efs := map[string]*istiov1a3.EnvoyFilter{}
efs[DefaultHttpFilter] = &istiov1a3.EnvoyFilter{
ObjectMeta: metav1.ObjectMeta{
Name: DefaultHttpFilter,
},
Spec: istioapi.EnvoyFilter{
ConfigPatches: []*istioapi.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: istioapi.EnvoyFilter_HTTP_FILTER,
Match: &istioapi.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &istioapi.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &istioapi.EnvoyFilter_ListenerMatch{
FilterChain: &istioapi.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &istioapi.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &istioapi.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &istioapi.EnvoyFilter_Patch{
Operation: istioapi.EnvoyFilter_Patch_INSERT_BEFORE,
Value: MustNewStruct(map[string]interface{}{
"name": "envoy.filters.http.golang",
"typed_config": map[string]interface{}{
"@type": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config",
"library_id": "fm",
"library_path": ctrlcfg.GoSoPath(),
"plugin_name": "fm",
},
}),
},
},
},
},
}
return efs
}

func GenerateHostFilter(host *model.VirtualHost, config *filtermanager.FilterManagerConfig) *istiov1a3.EnvoyFilter {
v := map[string]interface{}{}
// This Marshal/Unmarshal trick works around the type check in MustNewStruct
data, _ := json.Marshal(config)
json.Unmarshal(data, &v)
return &istiov1a3.EnvoyFilter{
Spec: istioapi.EnvoyFilter{
ConfigPatches: []*istioapi.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: istioapi.EnvoyFilter_VIRTUAL_HOST,
Match: &istioapi.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &istioapi.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{
RouteConfiguration: &istioapi.EnvoyFilter_RouteConfigurationMatch{
Vhost: &istioapi.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{
Name: host.Name,
},
},
},
},
Patch: &istioapi.EnvoyFilter_Patch{
Operation: istioapi.EnvoyFilter_Patch_MERGE,
Value: MustNewStruct(map[string]interface{}{
"typed_per_filter_config": map[string]interface{}{
"envoy.filters.http.golang": map[string]interface{}{
"@type": "type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.ConfigsPerRoute",
"plugins_config": map[string]interface{}{
"fm": map[string]interface{}{
"config": map[string]interface{}{
"@type": "type.googleapis.com/xds.type.v3.TypedStruct",
"value": v,
},
},
},
},
},
}),
},
},
},
},
}
}
24 changes: 24 additions & 0 deletions controller/internal/istio/envoyfilter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package istio

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
istiov1a3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
"sigs.k8s.io/yaml"
)

func TestDefaultFilters(t *testing.T) {
out := []*istiov1a3.EnvoyFilter{}
for _, ef := range DefaultEnvoyFilters() {
out = append(out, ef)
}
d, _ := yaml.Marshal(out)
actual := string(d)
expFile := filepath.Join("testdata", "default_filters.yml")
d, _ = os.ReadFile(expFile)
want := string(d)
require.Equal(t, want, actual)
}
23 changes: 23 additions & 0 deletions controller/internal/istio/testdata/default_filters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
- metadata:
creationTimestamp: null
name: htnn-http-filter
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.golang
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config
library_id: fm
library_path: /etc/libgolang.so
plugin_name: fm
status: {}
14 changes: 14 additions & 0 deletions controller/internal/model/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package model

import "k8s.io/apimachinery/pkg/types"

type Gateway struct {
NsName *types.NamespacedName
Port uint32
}

type VirtualHost struct {
Gateway *Gateway
NsName *types.NamespacedName
Name string
}
Loading

0 comments on commit 9af1a7f

Please sign in to comment.