blob: 895235347d97f0e1477a71a97e2f20b0522d5dc4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 controllers
import (
"context"
"fmt"
"github.com/apache/submarine/submarine-cloud-v3/controllers/util"
"reflect"
istiov1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
submarineapacheorgv1 "github.com/apache/submarine/submarine-cloud-v3/api/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
func (r *SubmarineReconciler) newSubmarineVirtualService(ctx context.Context, submarine *submarineapacheorgv1.Submarine) *istiov1alpha3.VirtualService {
virtualService, err := util.ParseVirtualService(virtualServiceYamlPath)
if err != nil {
r.Log.Error(err, "ParseVirtualService")
}
virtualService.Namespace = submarine.Namespace
// Virtualservice is optional
// so that if user makes a declaration, we need to modify the configuration
specVirtual := submarine.Spec.Virtualservice
if specVirtual != nil {
virtualserviceHosts := specVirtual.Hosts
if virtualserviceHosts != nil && len(virtualserviceHosts) > 0 {
// Use `Hosts` defined in submarine spec
virtualService.Spec.Hosts = virtualserviceHosts
}
virtualserviceGateways := specVirtual.Gateways
if virtualserviceGateways != nil && len(virtualserviceGateways) > 0 {
// Use `Gateways` defined in submarine spec
virtualService.Spec.Gateways = virtualserviceGateways
} else {
virtualService.Spec.Gateways[0] = fmt.Sprintf("%s/submarine-gateway", r.Namespace)
}
} else {
virtualService.Spec.Gateways[0] = fmt.Sprintf("%s/submarine-gateway", r.Namespace)
}
err = controllerutil.SetControllerReference(submarine, virtualService, r.Scheme)
if err != nil {
r.Log.Error(err, "Set VirtualService ControllerReference")
}
return virtualService
}
// createVirtualService is a function to create VirtualService.
// Reference: https://github.com/apache/submarine/blob/master/submarine-cloud-v3/artifacts/submarine-virtualservice.yaml
func (r *SubmarineReconciler) createVirtualService(ctx context.Context, submarine *submarineapacheorgv1.Submarine) error {
r.Log.Info("Enter createIngress")
virtualService := &istiov1alpha3.VirtualService{}
err := r.Get(ctx, types.NamespacedName{Name: virtualServiceName, Namespace: submarine.Namespace}, virtualService)
// If the resource doesn't exist, we'll create it
if errors.IsNotFound(err) {
virtualService = r.newSubmarineVirtualService(ctx, submarine)
err = r.Create(ctx, virtualService)
r.Log.Info("Create VirtualService", "name", virtualService.Name)
} else {
newVirtualService := r.newSubmarineVirtualService(ctx, submarine)
// compare if there are same
if !CompareVirtualService(virtualService, newVirtualService) {
// update meta with uid
newVirtualService.ObjectMeta = virtualService.ObjectMeta
err = r.Update(ctx, newVirtualService)
r.Log.Info("Update VirtualService", "name", virtualService.Name)
}
}
// If an error occurs during Get/Create, we'll requeue the item so we can
// attempt processing again later. This could have been caused by a
// temporary network failure, or any other transient reason.
if err != nil {
return err
}
if !metav1.IsControlledBy(virtualService, submarine) {
msg := fmt.Sprintf(MessageResourceExists, virtualService.Name)
r.Recorder.Event(submarine, corev1.EventTypeWarning, ErrResourceExists, msg)
return fmt.Errorf(msg)
}
return nil
}
// CompareVirtualService will determine if two VirtualServices are equal
func CompareVirtualService(oldVirtualService, newVirtualService *istiov1alpha3.VirtualService) bool {
// spec.hosts
if !util.CompareSlice(oldVirtualService.Spec.Hosts, newVirtualService.Spec.Hosts) {
return false
}
// spec.gateways
if !util.CompareSlice(oldVirtualService.Spec.Gateways, newVirtualService.Spec.Gateways) {
return false
}
// spec.http
if !reflect.DeepEqual(oldVirtualService.Spec.Http, newVirtualService.Spec.Http) {
return false
}
return true
}