appconfigmgrv2/controllers/istio_service_entries.go (87 lines of code) (raw):
// Copyright 2019 Google LLC
//
// 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.
//
// Copyright 2019 Google LLC. This software is provided as-is,
// without warranty or representation for any use or purpose.
//
package controllers
import (
"context"
"fmt"
"strings"
appconfig "github.com/GoogleCloudPlatform/anthos-appconfig/appconfigmgrv2/api/v1alpha1"
istionet "istio.io/api/networking/v1alpha3"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
// reconcileIstioServiceEntries recociles istio ServiceEntry resources to provide
// allowedEgress functionality.
func (r *AppEnvConfigTemplateV2Reconciler) reconcileIstioServiceEntries(
ctx context.Context,
cfg Config,
in *appconfig.AppEnvConfigTemplateV2,
) error {
list, err := istioServiceEntries(cfg, in)
if err != nil {
return fmt.Errorf("building: %v", err)
}
gvr := istioServiceEntryGVR()
for _, p := range list {
if err := controllerutil.SetControllerReference(in, p, r.Scheme); err != nil {
return err
}
if err := r.upsertUnstructured(ctx, p, gvr, true); err != nil {
return fmt.Errorf("reconciling: %v", err)
}
}
if err := r.garbageCollect(in, unstructuredNames(list), gvr); err != nil {
return fmt.Errorf("garbage collecting: %v", err)
}
return nil
}
func istioServiceEntries(cfg Config, t *appconfig.AppEnvConfigTemplateV2) ([]*unstructured.Unstructured, error) {
list := make([]*unstructured.Unstructured, 0, len(t.Spec.AllowedEgress))
gvk := istioServiceEntryGVK()
// TODO: Validate no duplicate spec.allowedEgress.type fields.
for i := range t.Spec.AllowedEgress {
entry := t.Spec.AllowedEgress[i]
ports, ok := cfg.EgressTypes[entry.Type]
if !ok {
return nil, fmt.Errorf("unknown allowedEgress.type: %v", entry.Type)
}
res := istionet.ServiceEntry_DNS
for _, h := range entry.Hosts {
if strings.Contains(h, "*") {
res = istionet.ServiceEntry_NONE
break
}
}
meta := map[string]interface{}{
"name": istioServiceEntryName(t, i),
"namespace": t.Namespace,
}
spec := &istionet.ServiceEntry{
Hosts: entry.Hosts,
Location: istionet.ServiceEntry_MESH_EXTERNAL,
// TODO: Validation on known types.
Ports: ports,
Resolution: res,
// Apply to same namespace only:
ExportTo: []string{"."},
}
unst, err := unstructuredFromProto(gvk, meta, spec)
if err != nil {
return nil, fmt.Errorf("unstructured from proto: %v", err)
}
list = append(list, unst)
}
return list, nil
}
func istioServiceEntryName(t *appconfig.AppEnvConfigTemplateV2, i int) string {
return fmt.Sprintf("%v-%v", t.Name, t.Spec.AllowedEgress[i].Type)
}
func istioServiceEntryGVK() schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: "networking.istio.io",
Version: "v1alpha3",
Kind: "ServiceEntry",
}
}
func istioServiceEntryGVR() schema.GroupVersionResource {
gvk := istioServiceEntryGVK()
return schema.GroupVersionResource{
Group: gvk.Group,
Version: gvk.Version,
Resource: "serviceentries",
}
}