diff --git a/Jenkinsfile.uni b/Jenkinsfile.uni new file mode 100644 index 000000000..5fde614a1 --- /dev/null +++ b/Jenkinsfile.uni @@ -0,0 +1,462 @@ +@Library(value = 'msaas-shared-lib', changelog = false) _ + +// the kustomize overlay folder +deployment_overlay_root_folder = "environments" + +def dockerRegistryName = 'docker.intuit.com' + +def dockerRegistryCredsId = 'service-mesh-docker-cred' +def ptNameVersion = "admiral-${UUID.randomUUID().toString().toLowerCase()}" + +def jenkins_pod_label = "admiral-podman-build-pod-label" + +commitSha = '' + +envMap = [:] + +node { + config = setupMsaasPipeline('msaas-config.yaml') +} + +pipeline { + + agent { + kubernetes { + label "${jenkins_pod_label}" + yamlFile 'KubernetesPods.yaml' + } + } + + environment { + GO_INSTALL = "/go_install" + GO_VERSION = "1.18.linux-amd64" + GOROOT = "${env.GO_INSTALL + '/go'}" + GOPRIVATE="github.intuit.com" + PATH = "${env.PATH + ':' + env.GOROOT + '/bin'}" + VERBOSE = 1 + PIPELINE_BUILD = true + DEP_PATH = "/home/jenkins/go/bin/" + + //from msaas generated + service_name = "admiral" + asset_id = "8287766806579881856" + heliograph_asset_id = "721719432597284573" + heliograph_application_name = "heliograph" + application_name = "admiral" // *** update the Application Name you wish to use for metrics + + l1 = "services" + l2 = "mesh" + region = "usw2" + //deployable_branches = ["master"] + repo = "services/mesh/admiral/service" + image = "${repo}/${service_name}" + argocd_server = "prod-cto.argocd.paas-cplane-prod-west2.a.intuit.com" + //cluster_server = "api-servicemesh-ppd-cl6-w-as0hn2-606934661.us-west-2.elb.amazonaws.com" + //argocd_password = "argocd-${service_name}" + argocd_password="argocd-admiral-iks1" + ptNameVersion = "${service_name}-${UUID.randomUUID().toString().toLowerCase()}" + deploy_repo = "github.intuit.com/services-mesh/admiral-deployment.git" + registry = "docker.intuit.com" + codecov_url = "https://codecov.tools.a.intuit.com" + metrics_api_url = "https://engineeringmetrics.api.intuit.com/ingest/opmetrics/" + cd_image_version = "0.4" + docker_image_version = "18.09.1" + + kson_compnt = "sample" + app_wait_timeout = 1200 + stage_timeout = 22 + git_timeout = 2 + pipelineStartTime = 0 + commit_id = "" + git_tag = "" + admiralTag = "placeholder" + heliographTag = "placeholder" + serviceAssetId = "8287766806579881856" + GIT_TOKEN = credentials('GIT_TOKEN') + commitSha = sh(returnStdout: true, script: 'git rev-parse --short=5 HEAD').trim() + IMAGE_TAG="$GIT_BRANCH-${commitSha}" + } + stages { + stage('pre-build-setup') { + steps { + script { + pipelineStartTime = System.currentTimeMillis() + container('podman') { + sh ''' + yum group install "Development Tools" -y + yum install wget -y + yum install git-core -y + + make --version + + mkdir -p -m 777 $GO_INSTALL + mkdir -p -m 755 /root/go/bin + wget -q -O $GO_INSTALL/go.tar.gz https://dl.google.com/go/go$GO_VERSION.tar.gz + tar -C $GO_INSTALL -xzf $GO_INSTALL/go.tar.gz + go version + go env + + mkdir -p /workspace/go/src/github.com/istio-ecosystem/admiral + + cp -R . /workspace/go/src/github.com/istio-ecosystem/admiral + ls -l + mkdir -p /home/jenkins/go/bin + curl -v https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + + git config --global url."https://git:${GIT_TOKEN}@github.intuit.com".insteadOf "https://github.intuit.com" + ''' + } + } + } + } + + stage('build') { + steps { + script { + container('podman') { + withEnv(["HUB=docker.intuit.com/strategic/services/service-mesh/service/admiral", "TAG=$GIT_BRANCH-${commitSha}", "VERSION=1.1-${commitSha}", "GOPATH=/workspace/go", "DOCKERFILE=Dockerfile.admiral.intuit"]) + { + withCredentials([usernamePassword(credentialsId: "admiral-docker-login", passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) + { + sh "cd /workspace/go/src/github.com/istio-ecosystem/admiral" + sh "make build" + admiralTag = IMAGE_TAG + } + } + } + } + } + } + + stage('push') { + steps { + script { + container('podman') { + withEnv(["HUB=docker.intuit.com/strategic/services/service-mesh/service/admiral", "TAG=${GIT_BRANCH}:${commitSha}", "VERSION=0.1", "GOPATH=/workspace/go", "DOCKERFILE=Dockerfile.admiral.intuit"]) { + withCredentials([usernamePassword(credentialsId: "admiral-docker-login", passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) { + echo 'Login to registry..' + sh "podman login ${dockerRegistryName} -u ${DOCKER_USERNAME} --password ${DOCKER_PASSWORD} --storage-driver=overlay" + sh "make podman-build TAG=${IMAGE_TAG} IMAGE=${HUB}" + retry(10) { + sh "make podman-publish TAG=${IMAGE_TAG} IMAGE=${HUB}" + } + } + } + } + } + } + } + + // CPD Image Certification + stage('CPD Certification') { + steps { + withCredentials([usernamePassword(credentialsId: "twistlock-cpd-scan", passwordVariable: 'SCAN_PASSWORD', usernameVariable: 'SCAN_USER'), usernamePassword(credentialsId: "admiral-docker-login", passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) { + withEnv(["HUB=docker.intuit.com/strategic/services/service-mesh/service/admiral", "TAG=$GIT_BRANCH-${commitSha}", 'SCAN_SERVER=https://artifactscan.a.intuit.com:8083', 'ENABLE_COLORING=true', 'CMX_PROJECT_NAME=Intuit.servicesmesh.admiral', "ASSET_ID=${serviceAssetId}"]) { + container('cpd2') { + intuitCPD2Podman(config, "-i ${HUB}:${IMAGE_TAG} --buildfile ./admiral/docker/Dockerfile.admiral", "admiral-docker-login") + } + } + } + } + } + + stage('Deployments') { + agent { + kubernetes { + label 'mypod-argo' + defaultContainer 'argo' + yaml """ + apiVersion: v1 + kind: Pod + metadata: + labels: + app: argo + spec: + containers: + - name: argo + image: docker.intuit.com/dev/deploy/cd/argocd-utils:stable + command: + - cat + tty: true + """ + } + } + stages { + stage('Setup') { + steps { + script { + sh "mkdir -p temp" + sh "chmod 777 temp" + cdProjectFolder = 'temp/admiral-deployment' + + withCredentials([usernamePassword(credentialsId: 'github-svc-sbseg-ci', passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { + sh "git clone https://${GIT_USERNAME}:${GIT_PASSWORD}@${deploy_repo} ${cdProjectFolder} --branch traffic-config" + } + } + } + } + + // TODO: this is temporary. Will be fixed when this Jenkinsfile is refactored to + // follow paved road pattern + + stage('QA Deploy usw2') { + steps { + script { + envDir = EnvType.qal.getEnvName() + updateEnvTag(envDir) + iksType = "ppd" + appName = "${l1}-${service_name}-${region}" + echo "Starting deploy" + iStage(appName, 'qal') { + deployGitOps('qal', appName, 'eksapi-ip-paas-ppd-usw2-k8s-4b2287f4b1224d2a.elb.us-west-2.amazonaws.com', envDir) + } + } + } + } + + stage('QA Deploy use2') { + steps { + script { + envDir = "qal-use2-eks" + updateEnvTag(envDir) + appName = "${l1}-${service_name}-use2" + echo "Starting deploy to use2" + iStage(appName, 'qal') { + deployGitOps('qal', appName, 'eksapi-ip-paas-ppd-use2-k8s-028d96a47bb50e2d.elb.us-east-2.amazonaws.com', envDir) + } + } + } + } + + } + } + + + } + + + + } + +def deployGitOps(String envName, String appName, String server, String envDir) { + withCredentials([string(credentialsId: "${argocd_password}", variable: 'ARGOCD_PASS')]) { + println("Deploying to ${appName}") + + sh("/argocd login ${argocd_server} --name context --insecure --username admin --password $ARGOCD_PASS") + sh("argocd version --client") + sh "/argocd app create --name ${appName}-${envName} --repo https://${deploy_repo} --revision traffic-config --path ${deployment_overlay_root_folder}/${envDir}/ --upsert --project ${l1}-${l2}-${service_name} --dest-namespace ${appName}-${envName} --dest-server=https://${server}" + sh "/argocd app sync ${appName}-${envName}" + sh "/argocd app wait ${appName}-${envName} --timeout ${app_wait_timeout}" + } + } + +def updateEnvTag(String envDir) { + withEnv(["HUB=docker.intuit.com/strategic/services/service-mesh/service"]) { + cdProjectFolder = 'temp/admiral-deployment' + dir(cdProjectFolder) { + withCredentials([usernamePassword(credentialsId: 'github-svc-sbseg-ci', passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { + + sh "git pull" + + heliographTag = readFile "heliograph-tag.txt" + + echo admiralTag + echo heliographTag + + def dirPath = "${deployment_overlay_root_folder}/" + envDir + + sh "chmod 777 ${deployment_overlay_root_folder}" + sh "chmod 777 ${dirPath}" + dir(dirPath) { + sh "/usr/local/bin/kustomize edit set image ${HUB}/heliograph:${heliographTag}" + sh "/usr/local/bin/kustomize edit set image ${HUB}/admiral:${admiralTag}" + } + sh 'git config --global user.email "heliographCD@intuit.com"' + sh 'git config --global user.name "Heliograph CD"' + sh "git add -A" + sh 'git commit --allow-empty -m "MESH-194 updating release tag"' + sh "git push https://${GIT_USERNAME}:${GIT_PASSWORD}@${deploy_repo} traffic-config" + } + } + } +} + + +def iStage(name, Closure closure) { + iStage(name, null, closure) +} + +def iStage(name, envName, Closure closure) { + def metricsType = 'pipelinestage' + def stageName = name + if (envName != null && !envName.isEmpty()) { + metricsType = 'deployment' + stageName = "deploy $envName" + } + reportMetrics(metricsType, envName, name) { + stage(stageName) { + def result = closure.call() + //return result + } + } +} + +def reportMetrics(steps) { + reportMetrics('pipeline', null, null) { + steps() + } +} + +// report metrics to speed dashboard +def reportMetrics(metricsType, envName, name, steps) { + def start = System.currentTimeMillis() + try { + steps() + def end = System.currentTimeMillis() + _prepareAndSendMetrics(metricsType, start, end, envName, name, true) + } catch (err) { + echo "Report Metrics of type $metricsType failed with error: ${err}" + def end = System.currentTimeMillis() + _prepareAndSendMetrics(metricsType, start, end, envName, name, false) + throw err + } +} + +def _prepareAndSendMetrics(metricsType, startMillis, endMillis, envName, name, status) { + def startTime = currentTimeStr(new Date(startMillis)) + def endTime = currentTimeStr(new Date(endMillis)) + def totalTime = (endMillis - startMillis) / 1000 + + if (metricsType == 'deployment') { + _populateEnvMap(envName, endMillis) + //report admiral deployment to ODL + _postToDataLake(_getDepIdxJSON(name, envName, status, startTime, endTime, true), metricsType) + //report heliograph deployment to ODL + _postToDataLake(_getDepIdxJSON(name, envName, status, startTime, endTime, false), metricsType) + _postToDataLake(_getStgIdxJSON("deploy $envName", status, startTime, endTime, totalTime), 'pipelinestage') + } else if (metricsType == 'pipelinestage') { + _postToDataLake(_getStgIdxJSON(name, status, startTime, endTime, totalTime), metricsType) + } else if (metricsType == 'pipeline') { + _postToDataLake(_getPLIdxJSON(status, startTime, endTime, totalTime), metricsType) + } +} + +def _getDepIdxJSON(appName, envName, status, startTime, endTime, admiral) { + def final_asset_id = asset_id + def final_app_name = application_name + def final_tag = admiralTag + def final_sha = commitSha + if (!admiral) { + final_asset_id = heliograph_asset_id + final_app_name = heliograph_application_name + final_tag = heliographTag + final_sha = heliographTag + } + def metricsJson = """ + { + "deployTool" : "Jenkins Pipeline", + "applicationName" : "${final_app_name}", + "applicationVersion" : "${final_sha.trim()}", + "commitId" : "${final_tag.trim()}", + "deployStartTime" : "${startTime}", + "assetId" : "${final_asset_id}", + "jobUrl" : "${env.BUILD_URL}", + "clusterName" : "${argocd_server}", + "namespace" : "${final_app_name}-${envName}", + "deployTarget": "AWS", + "package": { + "name": "ksonnet", + "version": "0.0.1" + }, + "envName" : "${envName}", + "deployEndTime" : "${endTime}", + "lastUpdated" : "${endTime}", + "deployed" : ${status} + }""" + return metricsJson +} + +def _getPLIdxJSON(status, startTime, endTime, totalTime) { + def mapJSONString = JsonOutput.toJson(envMap) + def metricsJson = """ + { + "pipelineId" : "${ptNameVersion}", + "pipelineName" : "${service_name}", + "assetId" : "${asset_id}", + "commitId": "${commitSha}", + "pipelineTool" : "Jenkins Pipeline", + "applicationName" : "${application_name}", + "target" : "AWS", + "startTime" : "${startTime}", + "endTime" : "${endTime}", + "totalTime" : ${totalTime}, + "success" : ${status}, + "envDeployTime": ${mapJSONString} + }""" + return metricsJson + +} + +def _getStgIdxJSON(stageName, status, startTime, endTime, totalTime) { + def metricsJson = """ + { + "pipelineId" : "${ptNameVersion}", + "stageName" : "${stageName}", + "pipelineTool" : "Jenkins Pipeline", + "stageType": "cd_stage", + "assetId" : "${asset_id}", + "commitId": "${commitSha}", + "applicationName" : "${application_name}", + "target" : "AWS", + "startTime" : "${startTime}", + "endTime" : "${endTime}", + "totalTime" : ${totalTime}, + "success" : ${status} + }""" + return metricsJson +} + +def _postToDataLake(metricsJson, metricsType) { + def apiURL = metrics_api_url + metricsType + "/snapshot/" + try { + echo metricsJson + withCredentials([string(credentialsId: 'metrics_api_key', variable: 'API_KEY')]) { + def response = httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', httpMode: 'POST', + customHeaders: [[name: 'x-api-key', value: "$API_KEY"]], requestBody: metricsJson, url: apiURL + } + } + catch (err) { + echo "error sending to metrics: ${err}" + } +} + +def _populateEnvMap(envName, endMillis) { + def totalTimeToEnvMin = (endMillis - pipelineStartTime) / (1000 * 60) + if (envName == EnvType.qal.toString()) { + envMap.put(EnvType.qal.toString(), totalTimeToEnvMin) + } else if (envName == EnvType.e2e.toString()) { + envMap.put(EnvType.e2e.toString(), totalTimeToEnvMin) + } else if (envName == EnvType.prd.toString()) { + envMap.put(EnvType.prd.toString(), totalTimeToEnvMin) + } +} + +static currentTimeStr(Date time) { + return time.format("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone('UTC')) +} + +enum EnvType { + qal('qal-eks-usw2'), + e2e('e2e-eks-usw2'), + prd('prd-eks-usw2') + + EnvType(String name) { + this.envName = name + } + + private final String envName + + String getEnvName() { + envName + } +} diff --git a/admiral/cmd/admiral/cmd/root.go b/admiral/cmd/admiral/cmd/root.go index 7716256da..3823f12e6 100644 --- a/admiral/cmd/admiral/cmd/root.go +++ b/admiral/cmd/admiral/cmd/root.go @@ -146,6 +146,8 @@ func GetRootCmd(args []string) *cobra.Command { "If Routing Policy feature needs to be enabled") rootCmd.PersistentFlags().StringArrayVar(¶ms.ExcludedIdentityList, "excluded_identity_list", []string{}, "List of identities which should be excluded from getting processed") + rootCmd.PersistentFlags().StringVar(¶ms.TrafficConfigNamespace, "traffic-config-namespace", "admiral", "namespace where Heliograph will create traffic config object.") + rootCmd.PersistentFlags().BoolVar(¶ms.TrafficConfigPersona, "traffic_config_persona", false, "Admiral Bootstrapped to generate Throttling & Routing Configurations") return rootCmd } diff --git a/admiral/pkg/apis/admiral/v1/register.go b/admiral/pkg/apis/admiral/v1/register.go index 6e2205a4a..257248a85 100644 --- a/admiral/pkg/apis/admiral/v1/register.go +++ b/admiral/pkg/apis/admiral/v1/register.go @@ -54,6 +54,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &GlobalTrafficPolicyList{}, &RoutingPolicy{}, &RoutingPolicyList{}, + &TrafficConfig{}, + &TrafficConfigList{}, ) // register the type in the scheme diff --git a/admiral/pkg/apis/admiral/v1/type.go b/admiral/pkg/apis/admiral/v1/type.go index 259fb00e1..5c78cae81 100644 --- a/admiral/pkg/apis/admiral/v1/type.go +++ b/admiral/pkg/apis/admiral/v1/type.go @@ -7,7 +7,7 @@ import ( // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -//generic cdr object to wrap the dependency api +// generic cdr object to wrap the dependency api type Dependency struct { meta_v1.TypeMeta `json:",inline"` meta_v1.ObjectMeta `json:"metadata"` @@ -30,7 +30,7 @@ type DependencyList struct { Items []Dependency `json:"items"` } -//generic cdr object to wrap the GlobalTrafficPolicy api +// generic cdr object to wrap the GlobalTrafficPolicy api // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type GlobalTrafficPolicy struct { @@ -56,7 +56,7 @@ type GlobalTrafficPolicyList struct { Items []GlobalTrafficPolicy `json:"items"` } -//generic cdr object to wrap the GlobalTrafficPolicy api +// generic cdr object to wrap the GlobalTrafficPolicy api // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type RoutingPolicy struct { @@ -81,3 +81,119 @@ type RoutingPolicyList struct { Items []RoutingPolicy `json:"items"` } + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// TrafficConfig is the Schema for the TrafficConfigs API +type TrafficConfig struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ObjectMeta `json:"metadata,omitempty"` + + Spec TrafficConfigSpec `json:"spec,omitempty"` + Status TrafficConfigStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// TrafficConfigList contains a list of TrafficConfig +type TrafficConfigList struct { + meta_v1.TypeMeta `json:",inline"` + meta_v1.ListMeta `json:"metadata,omitempty"` + Items []TrafficConfig `json:"items"` +} + +// QuotaGroupSpec defines the desired state of QuotaGroup specified by the user +type TrafficConfigSpec struct { + WorkloadEnv []string `json:"workloadEnvs"` + EdgeService *EdgeService `json:"edgeService"` + QuotaGroup *QuotaGroup `json:"quotaGroup"` +} + +type EdgeService struct { + DynamicRouting []*DynamicRouting `json:"dynamicRouting"` + Filters []*Filter `json:"filters"` + Routes []*Route `json:"routes"` +} + +type QuotaGroup struct { + TotalQuotaGroup []*TotalQuotaGroup `json:"totalQuotaGroups"` + AppQuotaGroups []*AppQuotaGroup `json:"appQuotaGroups,omitempty"` +} + +type Route struct { + Name string `json:"name"` + Inbound string `json:"inbound"` + Outbound string `json:"outbound"` + FilterSelector string `json:"filterSelector"` + WorkloadEnvSelectors []string `json:"workloadEnvSelectors"` + Timeout int `json:"timeout"` +} + +type Filter struct { + Name string `json:"name"` + Retries Retry `json:"retries"` + Options []string `json:"options"` +} + +type Retry struct { + Attempts int `json:"attempts"` + PerTryTimeout string `json:"perTryTimeout"` +} + +type DynamicRouting struct { + Name string `json:"name"` + Url string `json:"url"` + CacheKeyAlgorithm string `json:"cacheKeyAlgorithm"` + TtlSec int `json:"ttlSec"` + Local bool `json:"local"` +} + +type TotalQuotaGroup struct { + Name string `json:"name"` + Description string `json:"description"` + Quotas *[]Quota `json:"quotas"` + WorkloadEnvSelectors []string `json:"workloadEnvSelectors"` + RegionLevelLimit bool `json:"regionLevelLimit"` + CPULimit *int `json:"cpuLimit,omitempty"` + MemoryLimit *int `json:"memoryLimit,omitempty"` + PodLevelThreshold *int `json:"podLevelThreshold"` + FailureModeBehaviour string `json:"failureModeBehaviour"` + AdaptiveConcurrency *AdaptiveConcurrency `json:"adaptiveConcurrency,omitempty"` +} +type AppQuotaGroup struct { + Name string `json:"name"` + Description string `json:"description"` + Quotas *[]Quota `json:"quotas"` + AssociatedApps []string `json:"associatedApps"` + WorkloadEnvSelectors []string `json:"workloadEnvSelectors"` +} + +type AdaptiveConcurrency struct { + LatencyThreshold string `json:"latencyThreshold"` + SkippedURLs []string `json:"skippedURLs"` + SampleAggregatePercentile int `json:"sampleAggregatePercentile"` + ConcurrencyUpdateInterval string `json:"concurrencyUpdateInterval"` + MinRTTCalInterval string `json:"minRTTCalInterval"` + MinRTTCalJitter int `json:"minRTTCalJitter"` + MinRTTCalRequestCount int `json:"minRTTCalRequestCount"` + MinRTTCalMinConcurrency int `json:"minRTTCalMinConcurrency"` + Enabled bool `json:"enabled"` +} + +type Quota struct { + Name string `json:"name"` + TimePeriod string `json:"timePeriod"` + MaxAmount int `json:"maxAmount"` + KeyType string `json:"keyType"` + Algorithm string `json:"algorithm"` + Behaviour string `json:"behaviour"` + Rule string `json:"rule"` + Methods []string `json:"methods,omitempty"` +} + +// TrafficConfigStatus defines the observed state of TrafficConfig +type TrafficConfigStatus struct { + Message string `json:"message"` + LastAppliedConfigVersion string `json:"lastAppliedConfigVersion"` + LastUpdateTime meta_v1.Time `json:"lastUpdateTime"` + Status bool `json:"status"` +} diff --git a/admiral/pkg/apis/admiral/v1/zz_generated.deepcopy.go b/admiral/pkg/apis/admiral/v1/zz_generated.deepcopy.go index df3933f28..91d51a120 100644 --- a/admiral/pkg/apis/admiral/v1/zz_generated.deepcopy.go +++ b/admiral/pkg/apis/admiral/v1/zz_generated.deepcopy.go @@ -25,6 +25,62 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdaptiveConcurrency) DeepCopyInto(out *AdaptiveConcurrency) { + *out = *in + if in.SkippedURLs != nil { + in, out := &in.SkippedURLs, &out.SkippedURLs + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdaptiveConcurrency. +func (in *AdaptiveConcurrency) DeepCopy() *AdaptiveConcurrency { + if in == nil { + return nil + } + out := new(AdaptiveConcurrency) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppQuotaGroup) DeepCopyInto(out *AppQuotaGroup) { + *out = *in + if in.Quotas != nil { + in, out := &in.Quotas, &out.Quotas + *out = new([]Quota) + if **in != nil { + in, out := *in, *out + *out = make([]Quota, len(*in)) + copy(*out, *in) + } + } + if in.AssociatedApps != nil { + in, out := &in.AssociatedApps, &out.AssociatedApps + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.WorkloadEnvSelectors != nil { + in, out := &in.WorkloadEnvSelectors, &out.WorkloadEnvSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppQuotaGroup. +func (in *AppQuotaGroup) DeepCopy() *AppQuotaGroup { + if in == nil { + return nil + } + out := new(AppQuotaGroup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Dependency) DeepCopyInto(out *Dependency) { *out = *in @@ -102,6 +158,93 @@ func (in *DependencyStatus) DeepCopy() *DependencyStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DynamicRouting) DeepCopyInto(out *DynamicRouting) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DynamicRouting. +func (in *DynamicRouting) DeepCopy() *DynamicRouting { + if in == nil { + return nil + } + out := new(DynamicRouting) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EdgeService) DeepCopyInto(out *EdgeService) { + *out = *in + if in.DynamicRouting != nil { + in, out := &in.DynamicRouting, &out.DynamicRouting + *out = make([]*DynamicRouting, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(DynamicRouting) + **out = **in + } + } + } + if in.Filters != nil { + in, out := &in.Filters, &out.Filters + *out = make([]*Filter, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Filter) + (*in).DeepCopyInto(*out) + } + } + } + if in.Routes != nil { + in, out := &in.Routes, &out.Routes + *out = make([]*Route, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Route) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EdgeService. +func (in *EdgeService) DeepCopy() *EdgeService { + if in == nil { + return nil + } + out := new(EdgeService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Filter) DeepCopyInto(out *Filter) { + *out = *in + out.Retries = in.Retries + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Filter. +func (in *Filter) DeepCopy() *Filter { + if in == nil { + return nil + } + out := new(Filter) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GlobalTrafficPolicy) DeepCopyInto(out *GlobalTrafficPolicy) { *out = *in @@ -179,6 +322,97 @@ func (in *GlobalTrafficPolicyStatus) DeepCopy() *GlobalTrafficPolicyStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Quota) DeepCopyInto(out *Quota) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Quota. +func (in *Quota) DeepCopy() *Quota { + if in == nil { + return nil + } + out := new(Quota) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *QuotaGroup) DeepCopyInto(out *QuotaGroup) { + *out = *in + if in.TotalQuotaGroup != nil { + in, out := &in.TotalQuotaGroup, &out.TotalQuotaGroup + *out = make([]*TotalQuotaGroup, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TotalQuotaGroup) + (*in).DeepCopyInto(*out) + } + } + } + if in.AppQuotaGroups != nil { + in, out := &in.AppQuotaGroups, &out.AppQuotaGroups + *out = make([]*AppQuotaGroup, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(AppQuotaGroup) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new QuotaGroup. +func (in *QuotaGroup) DeepCopy() *QuotaGroup { + if in == nil { + return nil + } + out := new(QuotaGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Retry) DeepCopyInto(out *Retry) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Retry. +func (in *Retry) DeepCopy() *Retry { + if in == nil { + return nil + } + out := new(Retry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Route) DeepCopyInto(out *Route) { + *out = *in + if in.WorkloadEnvSelectors != nil { + in, out := &in.WorkloadEnvSelectors, &out.WorkloadEnvSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. +func (in *Route) DeepCopy() *Route { + if in == nil { + return nil + } + out := new(Route) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RoutingPolicy) DeepCopyInto(out *RoutingPolicy) { *out = *in @@ -255,3 +489,162 @@ func (in *RoutingPolicyStatus) DeepCopy() *RoutingPolicyStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TotalQuotaGroup) DeepCopyInto(out *TotalQuotaGroup) { + *out = *in + if in.Quotas != nil { + in, out := &in.Quotas, &out.Quotas + *out = new([]Quota) + if **in != nil { + in, out := *in, *out + *out = make([]Quota, len(*in)) + copy(*out, *in) + } + } + if in.WorkloadEnvSelectors != nil { + in, out := &in.WorkloadEnvSelectors, &out.WorkloadEnvSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.CPULimit != nil { + in, out := &in.CPULimit, &out.CPULimit + *out = new(int) + **out = **in + } + if in.MemoryLimit != nil { + in, out := &in.MemoryLimit, &out.MemoryLimit + *out = new(int) + **out = **in + } + if in.PodLevelThreshold != nil { + in, out := &in.PodLevelThreshold, &out.PodLevelThreshold + *out = new(int) + **out = **in + } + if in.AdaptiveConcurrency != nil { + in, out := &in.AdaptiveConcurrency, &out.AdaptiveConcurrency + *out = new(AdaptiveConcurrency) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TotalQuotaGroup. +func (in *TotalQuotaGroup) DeepCopy() *TotalQuotaGroup { + if in == nil { + return nil + } + out := new(TotalQuotaGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficConfig) DeepCopyInto(out *TrafficConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficConfig. +func (in *TrafficConfig) DeepCopy() *TrafficConfig { + if in == nil { + return nil + } + out := new(TrafficConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficConfig) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficConfigList) DeepCopyInto(out *TrafficConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TrafficConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficConfigList. +func (in *TrafficConfigList) DeepCopy() *TrafficConfigList { + if in == nil { + return nil + } + out := new(TrafficConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrafficConfigList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficConfigSpec) DeepCopyInto(out *TrafficConfigSpec) { + *out = *in + if in.WorkloadEnv != nil { + in, out := &in.WorkloadEnv, &out.WorkloadEnv + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.EdgeService != nil { + in, out := &in.EdgeService, &out.EdgeService + *out = new(EdgeService) + (*in).DeepCopyInto(*out) + } + if in.QuotaGroup != nil { + in, out := &in.QuotaGroup, &out.QuotaGroup + *out = new(QuotaGroup) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficConfigSpec. +func (in *TrafficConfigSpec) DeepCopy() *TrafficConfigSpec { + if in == nil { + return nil + } + out := new(TrafficConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrafficConfigStatus) DeepCopyInto(out *TrafficConfigStatus) { + *out = *in + in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficConfigStatus. +func (in *TrafficConfigStatus) DeepCopy() *TrafficConfigStatus { + if in == nil { + return nil + } + out := new(TrafficConfigStatus) + in.DeepCopyInto(out) + return out +} diff --git a/admiral/pkg/client/clientset/versioned/clientset.go b/admiral/pkg/client/clientset/versioned/clientset.go index e41fbf878..9705bc353 100644 --- a/admiral/pkg/client/clientset/versioned/clientset.go +++ b/admiral/pkg/client/clientset/versioned/clientset.go @@ -20,7 +20,6 @@ package versioned import ( "fmt" - "log" "net/http" admiralv1 "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned/typed/admiral/v1" @@ -107,7 +106,7 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, func NewForConfigOrDie(c *rest.Config) *Clientset { cs, err := NewForConfig(c) if err != nil { - log.Fatal(err) + panic(err) } return cs } diff --git a/admiral/pkg/client/clientset/versioned/fake/register.go b/admiral/pkg/client/clientset/versioned/fake/register.go index c4b336251..848b92a3d 100644 --- a/admiral/pkg/client/clientset/versioned/fake/register.go +++ b/admiral/pkg/client/clientset/versioned/fake/register.go @@ -37,14 +37,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/admiral/pkg/client/clientset/versioned/scheme/register.go b/admiral/pkg/client/clientset/versioned/scheme/register.go index 6d706b8f2..ecfd07411 100644 --- a/admiral/pkg/client/clientset/versioned/scheme/register.go +++ b/admiral/pkg/client/clientset/versioned/scheme/register.go @@ -37,14 +37,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/admiral_client.go b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/admiral_client.go index 3c6f1dde8..2beeeae37 100644 --- a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/admiral_client.go +++ b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/admiral_client.go @@ -31,6 +31,7 @@ type AdmiralV1Interface interface { DependenciesGetter GlobalTrafficPoliciesGetter RoutingPoliciesGetter + TrafficConfigsGetter } // AdmiralV1Client is used to interact with features provided by the admiral.io group. @@ -50,6 +51,10 @@ func (c *AdmiralV1Client) RoutingPolicies(namespace string) RoutingPolicyInterfa return newRoutingPolicies(c, namespace) } +func (c *AdmiralV1Client) TrafficConfigs(namespace string) TrafficConfigInterface { + return newTrafficConfigs(c, namespace) +} + // NewForConfig creates a new AdmiralV1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_admiral_client.go b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_admiral_client.go index 69aa7524a..f4839f2d9 100644 --- a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_admiral_client.go +++ b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_admiral_client.go @@ -40,6 +40,10 @@ func (c *FakeAdmiralV1) RoutingPolicies(namespace string) v1.RoutingPolicyInterf return &FakeRoutingPolicies{c, namespace} } +func (c *FakeAdmiralV1) TrafficConfigs(namespace string) v1.TrafficConfigInterface { + return &FakeTrafficConfigs{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeAdmiralV1) RESTClient() rest.Interface { diff --git a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_trafficconfig.go b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_trafficconfig.go new file mode 100644 index 000000000..2c4f48645 --- /dev/null +++ b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/fake/fake_trafficconfig.go @@ -0,0 +1,142 @@ +/* +Copyright The Kubernetes Authors. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + admiralv1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeTrafficConfigs implements TrafficConfigInterface +type FakeTrafficConfigs struct { + Fake *FakeAdmiralV1 + ns string +} + +var trafficconfigsResource = schema.GroupVersionResource{Group: "admiral.io", Version: "v1", Resource: "trafficconfigs"} + +var trafficconfigsKind = schema.GroupVersionKind{Group: "admiral.io", Version: "v1", Kind: "TrafficConfig"} + +// Get takes name of the trafficConfig, and returns the corresponding trafficConfig object, and an error if there is any. +func (c *FakeTrafficConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *admiralv1.TrafficConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(trafficconfigsResource, c.ns, name), &admiralv1.TrafficConfig{}) + + if obj == nil { + return nil, err + } + return obj.(*admiralv1.TrafficConfig), err +} + +// List takes label and field selectors, and returns the list of TrafficConfigs that match those selectors. +func (c *FakeTrafficConfigs) List(ctx context.Context, opts v1.ListOptions) (result *admiralv1.TrafficConfigList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(trafficconfigsResource, trafficconfigsKind, c.ns, opts), &admiralv1.TrafficConfigList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &admiralv1.TrafficConfigList{ListMeta: obj.(*admiralv1.TrafficConfigList).ListMeta} + for _, item := range obj.(*admiralv1.TrafficConfigList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested trafficConfigs. +func (c *FakeTrafficConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(trafficconfigsResource, c.ns, opts)) + +} + +// Create takes the representation of a trafficConfig and creates it. Returns the server's representation of the trafficConfig, and an error, if there is any. +func (c *FakeTrafficConfigs) Create(ctx context.Context, trafficConfig *admiralv1.TrafficConfig, opts v1.CreateOptions) (result *admiralv1.TrafficConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(trafficconfigsResource, c.ns, trafficConfig), &admiralv1.TrafficConfig{}) + + if obj == nil { + return nil, err + } + return obj.(*admiralv1.TrafficConfig), err +} + +// Update takes the representation of a trafficConfig and updates it. Returns the server's representation of the trafficConfig, and an error, if there is any. +func (c *FakeTrafficConfigs) Update(ctx context.Context, trafficConfig *admiralv1.TrafficConfig, opts v1.UpdateOptions) (result *admiralv1.TrafficConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(trafficconfigsResource, c.ns, trafficConfig), &admiralv1.TrafficConfig{}) + + if obj == nil { + return nil, err + } + return obj.(*admiralv1.TrafficConfig), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTrafficConfigs) UpdateStatus(ctx context.Context, trafficConfig *admiralv1.TrafficConfig, opts v1.UpdateOptions) (*admiralv1.TrafficConfig, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(trafficconfigsResource, "status", c.ns, trafficConfig), &admiralv1.TrafficConfig{}) + + if obj == nil { + return nil, err + } + return obj.(*admiralv1.TrafficConfig), err +} + +// Delete takes name of the trafficConfig and deletes it. Returns an error if one occurs. +func (c *FakeTrafficConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(trafficconfigsResource, c.ns, name, opts), &admiralv1.TrafficConfig{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTrafficConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(trafficconfigsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &admiralv1.TrafficConfigList{}) + return err +} + +// Patch applies the patch and returns the patched trafficConfig. +func (c *FakeTrafficConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *admiralv1.TrafficConfig, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(trafficconfigsResource, c.ns, name, pt, data, subresources...), &admiralv1.TrafficConfig{}) + + if obj == nil { + return nil, err + } + return obj.(*admiralv1.TrafficConfig), err +} diff --git a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/generated_expansion.go b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/generated_expansion.go index 5fdd32779..d1f483841 100644 --- a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/generated_expansion.go +++ b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/generated_expansion.go @@ -23,3 +23,5 @@ type DependencyExpansion interface{} type GlobalTrafficPolicyExpansion interface{} type RoutingPolicyExpansion interface{} + +type TrafficConfigExpansion interface{} diff --git a/admiral/pkg/client/clientset/versioned/typed/admiral/v1/trafficconfig.go b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/trafficconfig.go new file mode 100644 index 000000000..b9a041eff --- /dev/null +++ b/admiral/pkg/client/clientset/versioned/typed/admiral/v1/trafficconfig.go @@ -0,0 +1,195 @@ +/* +Copyright The Kubernetes Authors. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + "time" + + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + scheme "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned/scheme" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// TrafficConfigsGetter has a method to return a TrafficConfigInterface. +// A group's client should implement this interface. +type TrafficConfigsGetter interface { + TrafficConfigs(namespace string) TrafficConfigInterface +} + +// TrafficConfigInterface has methods to work with TrafficConfig resources. +type TrafficConfigInterface interface { + Create(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.CreateOptions) (*v1.TrafficConfig, error) + Update(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.UpdateOptions) (*v1.TrafficConfig, error) + UpdateStatus(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.UpdateOptions) (*v1.TrafficConfig, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.TrafficConfig, error) + List(ctx context.Context, opts metav1.ListOptions) (*v1.TrafficConfigList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TrafficConfig, err error) + TrafficConfigExpansion +} + +// trafficConfigs implements TrafficConfigInterface +type trafficConfigs struct { + client rest.Interface + ns string +} + +// newTrafficConfigs returns a TrafficConfigs +func newTrafficConfigs(c *AdmiralV1Client, namespace string) *trafficConfigs { + return &trafficConfigs{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the trafficConfig, and returns the corresponding trafficConfig object, and an error if there is any. +func (c *trafficConfigs) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TrafficConfig, err error) { + result = &v1.TrafficConfig{} + err = c.client.Get(). + Namespace(c.ns). + Resource("trafficconfigs"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TrafficConfigs that match those selectors. +func (c *trafficConfigs) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TrafficConfigList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TrafficConfigList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("trafficconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested trafficConfigs. +func (c *trafficConfigs) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("trafficconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a trafficConfig and creates it. Returns the server's representation of the trafficConfig, and an error, if there is any. +func (c *trafficConfigs) Create(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.CreateOptions) (result *v1.TrafficConfig, err error) { + result = &v1.TrafficConfig{} + err = c.client.Post(). + Namespace(c.ns). + Resource("trafficconfigs"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficConfig). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a trafficConfig and updates it. Returns the server's representation of the trafficConfig, and an error, if there is any. +func (c *trafficConfigs) Update(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.UpdateOptions) (result *v1.TrafficConfig, err error) { + result = &v1.TrafficConfig{} + err = c.client.Put(). + Namespace(c.ns). + Resource("trafficconfigs"). + Name(trafficConfig.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficConfig). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *trafficConfigs) UpdateStatus(ctx context.Context, trafficConfig *v1.TrafficConfig, opts metav1.UpdateOptions) (result *v1.TrafficConfig, err error) { + result = &v1.TrafficConfig{} + err = c.client.Put(). + Namespace(c.ns). + Resource("trafficconfigs"). + Name(trafficConfig.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(trafficConfig). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the trafficConfig and deletes it. Returns an error if one occurs. +func (c *trafficConfigs) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("trafficconfigs"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *trafficConfigs) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("trafficconfigs"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched trafficConfig. +func (c *trafficConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TrafficConfig, err error) { + result = &v1.TrafficConfig{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("trafficconfigs"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/admiral/pkg/client/informers/externalversions/admiral/v1/interface.go b/admiral/pkg/client/informers/externalversions/admiral/v1/interface.go index 074940d63..5a43e27e9 100644 --- a/admiral/pkg/client/informers/externalversions/admiral/v1/interface.go +++ b/admiral/pkg/client/informers/externalversions/admiral/v1/interface.go @@ -30,6 +30,8 @@ type Interface interface { GlobalTrafficPolicies() GlobalTrafficPolicyInformer // RoutingPolicies returns a RoutingPolicyInformer. RoutingPolicies() RoutingPolicyInformer + // TrafficConfigs returns a TrafficConfigInformer. + TrafficConfigs() TrafficConfigInformer } type version struct { @@ -57,3 +59,8 @@ func (v *version) GlobalTrafficPolicies() GlobalTrafficPolicyInformer { func (v *version) RoutingPolicies() RoutingPolicyInformer { return &routingPolicyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } + +// TrafficConfigs returns a TrafficConfigInformer. +func (v *version) TrafficConfigs() TrafficConfigInformer { + return &trafficConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/admiral/pkg/client/informers/externalversions/admiral/v1/trafficconfig.go b/admiral/pkg/client/informers/externalversions/admiral/v1/trafficconfig.go new file mode 100644 index 000000000..5b6e72c75 --- /dev/null +++ b/admiral/pkg/client/informers/externalversions/admiral/v1/trafficconfig.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes Authors. + +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + "context" + time "time" + + admiralv1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + versioned "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned" + internalinterfaces "github.com/istio-ecosystem/admiral/admiral/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/client/listers/admiral/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TrafficConfigInformer provides access to a shared informer and lister for +// TrafficConfigs. +type TrafficConfigInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TrafficConfigLister +} + +type trafficConfigInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTrafficConfigInformer constructs a new informer for TrafficConfig type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTrafficConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTrafficConfigInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTrafficConfigInformer constructs a new informer for TrafficConfig type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTrafficConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AdmiralV1().TrafficConfigs(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AdmiralV1().TrafficConfigs(namespace).Watch(context.TODO(), options) + }, + }, + &admiralv1.TrafficConfig{}, + resyncPeriod, + indexers, + ) +} + +func (f *trafficConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTrafficConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *trafficConfigInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&admiralv1.TrafficConfig{}, f.defaultInformer) +} + +func (f *trafficConfigInformer) Lister() v1.TrafficConfigLister { + return v1.NewTrafficConfigLister(f.Informer().GetIndexer()) +} diff --git a/admiral/pkg/client/informers/externalversions/generic.go b/admiral/pkg/client/informers/externalversions/generic.go index 5c3bd2d05..fe6e7f8f1 100644 --- a/admiral/pkg/client/informers/externalversions/generic.go +++ b/admiral/pkg/client/informers/externalversions/generic.go @@ -59,6 +59,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Admiral().V1().GlobalTrafficPolicies().Informer()}, nil case v1.SchemeGroupVersion.WithResource("routingpolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Admiral().V1().RoutingPolicies().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("trafficconfigs"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Admiral().V1().TrafficConfigs().Informer()}, nil } diff --git a/admiral/pkg/client/listers/admiral/v1/expansion_generated.go b/admiral/pkg/client/listers/admiral/v1/expansion_generated.go index c5813b12f..bb8a2d2ef 100644 --- a/admiral/pkg/client/listers/admiral/v1/expansion_generated.go +++ b/admiral/pkg/client/listers/admiral/v1/expansion_generated.go @@ -41,3 +41,11 @@ type RoutingPolicyListerExpansion interface{} // RoutingPolicyNamespaceListerExpansion allows custom methods to be added to // RoutingPolicyNamespaceLister. type RoutingPolicyNamespaceListerExpansion interface{} + +// TrafficConfigListerExpansion allows custom methods to be added to +// TrafficConfigLister. +type TrafficConfigListerExpansion interface{} + +// TrafficConfigNamespaceListerExpansion allows custom methods to be added to +// TrafficConfigNamespaceLister. +type TrafficConfigNamespaceListerExpansion interface{} diff --git a/admiral/pkg/client/listers/admiral/v1/trafficconfig.go b/admiral/pkg/client/listers/admiral/v1/trafficconfig.go new file mode 100644 index 000000000..952f57be2 --- /dev/null +++ b/admiral/pkg/client/listers/admiral/v1/trafficconfig.go @@ -0,0 +1,99 @@ +/* +Copyright The Kubernetes Authors. + +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TrafficConfigLister helps list TrafficConfigs. +// All objects returned here must be treated as read-only. +type TrafficConfigLister interface { + // List lists all TrafficConfigs in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.TrafficConfig, err error) + // TrafficConfigs returns an object that can list and get TrafficConfigs. + TrafficConfigs(namespace string) TrafficConfigNamespaceLister + TrafficConfigListerExpansion +} + +// trafficConfigLister implements the TrafficConfigLister interface. +type trafficConfigLister struct { + indexer cache.Indexer +} + +// NewTrafficConfigLister returns a new TrafficConfigLister. +func NewTrafficConfigLister(indexer cache.Indexer) TrafficConfigLister { + return &trafficConfigLister{indexer: indexer} +} + +// List lists all TrafficConfigs in the indexer. +func (s *trafficConfigLister) List(selector labels.Selector) (ret []*v1.TrafficConfig, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TrafficConfig)) + }) + return ret, err +} + +// TrafficConfigs returns an object that can list and get TrafficConfigs. +func (s *trafficConfigLister) TrafficConfigs(namespace string) TrafficConfigNamespaceLister { + return trafficConfigNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TrafficConfigNamespaceLister helps list and get TrafficConfigs. +// All objects returned here must be treated as read-only. +type TrafficConfigNamespaceLister interface { + // List lists all TrafficConfigs in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1.TrafficConfig, err error) + // Get retrieves the TrafficConfig from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1.TrafficConfig, error) + TrafficConfigNamespaceListerExpansion +} + +// trafficConfigNamespaceLister implements the TrafficConfigNamespaceLister +// interface. +type trafficConfigNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TrafficConfigs in the indexer for a given namespace. +func (s trafficConfigNamespaceLister) List(selector labels.Selector) (ret []*v1.TrafficConfig, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.TrafficConfig)) + }) + return ret, err +} + +// Get retrieves the TrafficConfig from the indexer for a given namespace and name. +func (s trafficConfigNamespaceLister) Get(name string) (*v1.TrafficConfig, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("trafficconfig"), name) + } + return obj.(*v1.TrafficConfig), nil +} diff --git a/admiral/pkg/clusters/envoyfilter-operations.go b/admiral/pkg/clusters/envoyfilter-operations.go new file mode 100644 index 000000000..f3a7daeb5 --- /dev/null +++ b/admiral/pkg/clusters/envoyfilter-operations.go @@ -0,0 +1,612 @@ +package clusters + +import ( + "context" + "encoding/json" + "errors" + "fmt" + structPb "github.com/golang/protobuf/ptypes/struct" + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + "github.com/istio-ecosystem/admiral/admiral/pkg/controller/common" + "github.com/istio-ecosystem/admiral/admiral/pkg/manager" + log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/structpb" + networkingv1alpha3 "istio.io/api/networking/v1alpha3" + "istio.io/client-go/pkg/apis/networking/v1alpha3" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strconv" + "strings" +) + +type ScalableThrottleFilterObj struct { + Name string `json:"Name"` + Description string `json:"Description"` + WorkLoadLimit bool `json:"workloadLimit,omitempty"` + AssociatedApps []string `json:"AssociatedApps,omitempty"` + Quotas []v1.Quota `json:"quotas"` +} + +type FastThrottleFilterObj struct { + Name string `json:"Name"` + Description string `json:"Description"` + Quotas []*v1.Quota `json:"quotas"` +} + +func (w *WorkerManagerHandler) ModifyEnvoyFilterConfiguration(ctx *common.Context, wm *manager.WorkerManager, event string, trafficConfig *v1.TrafficConfig) error { + ctx.Log.Debug("modifyEnvoyFilterConfiguration running...") + if toBeDeleted(trafficConfig) { + err := deleteEnvoyFilter(ctx, wm, trafficConfig) + if err != nil { + return err + } + return nil + } + + err := createORUpdateEnvoyFilter(ctx, w, wm, event, trafficConfig) + if err != nil { + return err + } + ctx.Log.Info("ENVOY FILTER APPLIED SUCCESSFULLY..") + return nil +} + +func deleteEnvoyFilter(ctx *common.Context, rc *manager.WorkerManager, trafficConfig *v1.TrafficConfig) error { + ctx.Log.Info("deleting envoy filters as traffic config is disabled") + filterList, err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(common.NamespaceIstioSystem).List(context.TODO(), metaV1.ListOptions{LabelSelector: "createdFor=" + trafficConfig.Labels["asset"]}) + if err != nil { + ctx.Log.Errorf("could not list filter. error - %v ", err) + return err + } + if len(filterList.Items) > 0 { + for _, f := range filterList.Items { + err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(f.Namespace).Delete(context.TODO(), f.Name, metaV1.DeleteOptions{}) + if err != nil { + ctx.Log.Errorf("could not delete envoy filter. error - %v", err) + return err + } + } + ctx.Log.Info("envoy filters deleted successfully.") + } + ctx.Log.Info("no envoy filters found for deletion. Skipping..") + return nil +} + +func toBeDeleted(obj *v1.TrafficConfig) bool { + if obj.Annotations != nil { + if val, ok := obj.Annotations[common.IsDisabled]; ok { + if val == "true" { + return true + } + } + } + return false +} + +func checkIfPresent(filter *v1alpha3.EnvoyFilter, filterList []*v1alpha3.EnvoyFilter) bool { + for _, f := range filterList { + if f.Name == filter.Name { + return true + } + } + return false +} + +func createEnvoyFilters(ctx *common.Context, rc *manager.WorkerManager, filterList []*v1alpha3.EnvoyFilter) error { + for _, f := range filterList { + _, err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(f.Namespace).Create(context.TODO(), f, metaV1.CreateOptions{}) + if err != nil { + ctx.Log.Errorf("could not create envoy filter. error - %v", err) + return err + } + } + return nil +} + +func deleteEnvoyFilters(ctx *common.Context, rc *manager.WorkerManager, filterList []*v1alpha3.EnvoyFilter) error { + for _, f := range filterList { + err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(f.Namespace).Delete(context.TODO(), f.Name, metaV1.DeleteOptions{}) + if err != nil { + ctx.Log.Errorf("could not delete envoy filter. error - %v", err) + return err + } + } + return nil +} + +func updateEnvoyFilters(ctx *common.Context, rc *manager.WorkerManager, filterList []*v1alpha3.EnvoyFilter) error { + for _, f := range filterList { + _, err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(f.Namespace).Update(context.TODO(), f, metaV1.UpdateOptions{}) + if err != nil { + ctx.Log.Errorf("could not update envoy filter. error - %v", err) + return err + } + } + return nil +} + +func createORUpdateEnvoyFilter(ctx *common.Context, w *WorkerManagerHandler, rc *manager.WorkerManager, event string, trafficConfig *v1.TrafficConfig) error { + var err error + requestedEnvoyFilterList, err := constructEnvoyFilter(ctx, w, rc, trafficConfig, event) + if err != nil { + return err + } + existingEnvoyFilterList, err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(common.NamespaceIstioSystem).List(context.TODO(), metaV1.ListOptions{LabelSelector: "createdFor=" + trafficConfig.Labels["asset"]}) + if err != nil { + return err + } + filtersToBeDeleted := make([]*v1alpha3.EnvoyFilter, 0) + filtersToBeCreated := make([]*v1alpha3.EnvoyFilter, 0) + filtersToBeUpdated := make([]*v1alpha3.EnvoyFilter, 0) + + if len(requestedEnvoyFilterList) > 0 { + for _, requestedFilter := range requestedEnvoyFilterList { + if checkIfPresent(requestedFilter, existingEnvoyFilterList.Items) { + filtersToBeUpdated = append(filtersToBeUpdated, requestedFilter) + } else { + filtersToBeCreated = append(filtersToBeCreated, requestedFilter) + } + } + + for _, existingFilter := range existingEnvoyFilterList.Items { + if !checkIfPresent(existingFilter, requestedEnvoyFilterList) { + filtersToBeDeleted = append(filtersToBeDeleted, existingFilter) + } + } + } else { + filtersToBeDeleted = append(filtersToBeDeleted, existingEnvoyFilterList.Items...) + } + + if len(filtersToBeCreated) > 0 { + err = createEnvoyFilters(ctx, rc, filtersToBeCreated) + if err != nil { + return err + } + } + if len(filtersToBeUpdated) > 0 { + err = updateEnvoyFilters(ctx, rc, filtersToBeUpdated) + if err != nil { + return err + } + } + + if len(filtersToBeDeleted) > 0 { + err = deleteEnvoyFilters(ctx, rc, filtersToBeDeleted) + if err != nil { + return err + } + } + return nil +} + +func constructAdaptiveConcurrencyFilter(ctx *common.Context, tqg *v1.TotalQuotaGroup) *networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { + ctx.Log.Debug("constructAdaptiveConcurrencyFilter running....") + typedConfigValue := &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "gradient_controller_config": { + Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "sample_aggregate_percentile": { + Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "value": {Kind: &structPb.Value_NumberValue{NumberValue: float64(tqg.AdaptiveConcurrency.SampleAggregatePercentile)}}, + }, + }, + }, + }, + "concurrency_limit_params": { + Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "concurrency_update_interval": {Kind: &structPb.Value_StringValue{StringValue: tqg.AdaptiveConcurrency.ConcurrencyUpdateInterval}}, + }, + }, + }, + }, + "min_rtt_calc_params": {Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "interval": {Kind: &structPb.Value_StringValue{StringValue: tqg.AdaptiveConcurrency.MinRTTCalInterval}}, + "request_count": {Kind: &structPb.Value_NumberValue{NumberValue: float64(tqg.AdaptiveConcurrency.MinRTTCalRequestCount)}}, + "jitter": {Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{Fields: map[string]*structPb.Value{"value": {Kind: &structPb.Value_NumberValue{NumberValue: float64(tqg.AdaptiveConcurrency.MinRTTCalJitter)}}}}, + }}, + }, + }, + }, + }, + "enabled": {Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "default_value": {Kind: &structPb.Value_BoolValue{BoolValue: true}}, + "runtime_key": {Kind: &structPb.Value_StringValue{StringValue: "adaptive_concurrency.enabled"}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + typedConfig := &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "@type": {Kind: &structPb.Value_StringValue{StringValue: "type.googleapis.com/envoy.extensions.filters.http.adaptive_concurrency.v3.AdaptiveConcurrency"}}, + "value": {Kind: &structPb.Value_StructValue{StructValue: typedConfigValue}}, + }, + } + + envoyFilterPatch := getEnvoyFilterPatchValue(typedConfig, "intuit.go.app_throttle", "intuit.go.acropolis") + return envoyFilterPatch +} + +// constructScalableThrottleFilter returns scalable filter object. +func constructScalableThrottleFilter(ctx *common.Context, m map[string]*structPb.Value) *networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { + ctx.Log.Debug("constructScalableThrottleFilter running....") + m["APP_THROTTLE_CONFIG_VERSION"] = structpb.NewStringValue(common.AppThrottleConfigVersion) + m["LogLevel"] = structpb.NewStringValue(common.LogLevel) + typedConfigValue := structPb.Struct{ + Fields: map[string]*structPb.Value{ + "configmap": { + Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: m, + }, + }, + }, + }, + } + + typedConfig := &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "@type": {Kind: &structPb.Value_StringValue{StringValue: "type.googleapis.com/udpa.type.v1.TypedStruct"}}, + "value": {Kind: &structPb.Value_StructValue{StructValue: &typedConfigValue}}, + }, + } + envoyFilterPatch := getEnvoyFilterPatchValue(typedConfig, "intuit.go.app_throttle", "intuit.go.acropolis") + + return envoyFilterPatch +} + +// constructFastThrottleFilter returns fast throttle filter object. +func constructFastThrottleFilter(m map[string]*structPb.Value) *networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { + log.Debugln("constructFastThrottleFilter running....") + typedConfigValue := structPb.Struct{ + Fields: map[string]*structPb.Value{ + "configmap": { + Kind: &structPb.Value_StructValue{ + StructValue: &structPb.Struct{ + Fields: m, + }, + }, + }, + }, + } + typedConfig := &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "@type": {Kind: &structPb.Value_StringValue{StringValue: "type.googleapis.com/udpa.type.v1.TypedStruct"}}, + "value": {Kind: &structPb.Value_StructValue{StructValue: &typedConfigValue}}, + }, + } + envoyFilterPatch := getEnvoyFilterPatchValue(typedConfig, "intuit.go.fast_throttle", "intuit.go.acropolis") + return envoyFilterPatch +} + +// constructEnvoyFilter prepares EnvoyFilter CRD object to be applied. +func constructEnvoyFilter(ctx *common.Context, w *WorkerManagerHandler, rc *manager.WorkerManager, trafficConfig *v1.TrafficConfig, event string) ([]*v1alpha3.EnvoyFilter, error) { + ctx.Log.Debug("constructEnvoyFilter running....") + var err error + mapOfWorkLoadEnvAndFilterConfigPatches := make(map[string][]*networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch) // WorkloadEnv and List of all configPatches. Once all cases are checked - we will use this map to create envoy filter from for every key which is nothing but a workLoadEnv. + var RecordScalableMap = make(map[string]map[string]*structPb.Value) + var RecordFastMap = make(map[string]map[string]*structPb.Value) // This represents - map[WorkloadEnv](map[APP_THROTTLE_PLAN][envoyFilter Configuration]) + + if trafficConfig.Spec.QuotaGroup.AppQuotaGroups != nil { + ctx.Log.Debug("AppQG is not nil") + // var RecordMap = make(map[string]map[string]*structPb.Value) + for _, appQG := range trafficConfig.Spec.QuotaGroup.AppQuotaGroups { + for _, workLoadEnv := range appQG.WorkloadEnvSelectors { + // create a new envoyFilter CRD Object for every env. + var filter = ScalableThrottleFilterObj{} + filter.Name = appQG.Name + filter.Description = appQG.Description + filter.Quotas = *appQG.Quotas + filter.AssociatedApps = appQG.AssociatedApps + ConfigMapKey := "APP_THROTTLE_PLAN-" + filter.Name + filterJsonConfig, err := json.Marshal(filter) + if err != nil { + return nil, err + } + envoyFilterStringConfig := string(filterJsonConfig) + m := make(map[string]*structPb.Value) + m[ConfigMapKey] = structpb.NewStringValue(envoyFilterStringConfig) + m["MESH_SERVICE"] = structpb.NewStringValue(workLoadEnv + "." + strings.ToLower(trafficConfig.Labels["asset"]) + ".mesh") + if k, ok := RecordScalableMap[workLoadEnv]; ok { + for x, y := range k { + m[x] = y + } + } + RecordScalableMap[workLoadEnv] = m // We are building a map[WorkloadEnv](map[APP_THROTTLE_PLAN][envoyFilter Configuration]) + } + } + } + if trafficConfig.Spec.QuotaGroup.TotalQuotaGroup != nil { + log.Debugln("Total QG is not nil") + for _, tqg := range trafficConfig.Spec.QuotaGroup.TotalQuotaGroup { + for _, workLoadEnv := range tqg.WorkloadEnvSelectors { + slashStarRuleCount := 0 + var quota v1.Quota + // checking all quotas for every workload env to check if any of the quota has slash-star rule. + for _, quota = range *tqg.Quotas { + if quota.Rule == common.SlashSTARRule { + slashStarRuleCount += 1 + } + } + if slashStarRuleCount > 0 { + // Check for the workLoad, if it is exposed via Headless service. + // Assuming either deployment or rollout is already present in the namespace. Check if the Service is a Headless service. + isHeadlessSvc, err := CheckIFWorkloadExposedViaHeadlessService(ctx, w, trafficConfig.Labels[common.AssetLabel], workLoadEnv) + if err != nil { + log.Errorln(err) + } else { + if isHeadlessSvc { + log.Debugln("Matched service is headless. Creating Fast Throttle Filter") + m := make(map[string]*structPb.Value) + v1 := structpb.NewStringValue(workLoadEnv + ":" + strings.ToLower(trafficConfig.Labels["asset"]) + "," + strconv.Itoa(quota.MaxAmount) + "," + quota.TimePeriod) + v2 := structpb.NewStringValue("ROLLING_WINDOW") + m["TOTAL_QUOTA_RULE"] = v1 + m["FAST_THROTTLE_TYPE"] = v2 + RecordFastMap[workLoadEnv] = m + } else { + // create Scalable throttle filter. Matched service is not headless. + log.Debugln("Matched service is not headless.") + var filter = ScalableThrottleFilterObj{} + filter.Name = tqg.Name + filter.Description = tqg.Description + filter.Quotas = *tqg.Quotas + ConfigMapKey := "TOTAL_QUOTA_GROUP" + filterJsonConfig, err := json.Marshal(filter) + if err != nil { + return nil, err + } + envoyFilterStringConfig := string(filterJsonConfig) + m := make(map[string]*structPb.Value) + m[ConfigMapKey] = structpb.NewStringValue(envoyFilterStringConfig) + m["MESH_SERVICE"] = structpb.NewStringValue(workLoadEnv + "." + strings.ToLower(trafficConfig.Labels["asset"]) + ".mesh") + if k, ok := RecordScalableMap[workLoadEnv]; ok { + for x, y := range k { + m[x] = y + } + } + RecordScalableMap[workLoadEnv] = m + } + } + } else { + // create Scalable throttle filter. No "/*" rule is found. + log.Debugln("No Slash-Star rule found. Creating scalable throttle filter.") + var filter = ScalableThrottleFilterObj{} + filter.Name = tqg.Name + filter.Description = tqg.Description + filter.Quotas = *tqg.Quotas + ConfigMapKey := "TOTAL_QUOTA_GROUP" + filterJsonConfig, err := json.Marshal(filter) + if err != nil { + return nil, err + } + envoyFilterStringConfig := string(filterJsonConfig) + m := make(map[string]*structPb.Value) + m[ConfigMapKey] = structpb.NewStringValue(envoyFilterStringConfig) + m["MESH_SERVICE"] = structpb.NewStringValue(workLoadEnv + "." + strings.ToLower(trafficConfig.Labels["asset"]) + ".mesh") + if k, ok := RecordScalableMap[workLoadEnv]; ok { + for x, y := range k { + m[x] = y + } + } + RecordScalableMap[workLoadEnv] = m + } + + if tqg.AdaptiveConcurrency != nil { + ctx.Log.Debug("adaptive concurrency filter") + configPatch := constructAdaptiveConcurrencyFilter(ctx, tqg) + var ConfigPatchValues = make([]*networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch, 0) + ConfigPatchValues = append(ConfigPatchValues, configPatch) + mapOfWorkLoadEnvAndFilterConfigPatches[workLoadEnv] = ConfigPatchValues + } + } + } + } + + for _, env := range trafficConfig.Spec.WorkloadEnv { + configPatchArrayForEnv := make([]*networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch, 0) + if k, ok := mapOfWorkLoadEnvAndFilterConfigPatches[env]; ok { + configPatchArrayForEnv = append(configPatchArrayForEnv, k...) + } + + //for every i which is workLoadenv iterate over both scalable and fast and adaptive values and form config patch array. + if val, ok := RecordScalableMap[env]; ok { + if val != nil { + scalableConfigPatch := constructScalableThrottleFilter(ctx, val) + configPatchArrayForEnv = append(configPatchArrayForEnv, scalableConfigPatch) + } + } + // check in fast map + if val, ok := RecordFastMap[env]; ok { + // FastMap also has workload env entry. + // get the details for that and add into configPatchArrayForEnv array. + if val != nil { + fastConfigPatch := constructFastThrottleFilter(val) + configPatchArrayForEnv = append(configPatchArrayForEnv, fastConfigPatch) + } + } + mapOfWorkLoadEnvAndFilterConfigPatches[env] = configPatchArrayForEnv + } + + envoyFilterList := make([]*v1alpha3.EnvoyFilter, 0) + for env, configPatches := range mapOfWorkLoadEnvAndFilterConfigPatches { + if len(configPatches) > 0 { + m := make(map[string]string) + annotationMap := make(map[string]string) + annotationMap["createdBy"] = "admiral-unification" + annotationMap["createdFor"] = trafficConfig.Labels["asset"] + envoyFilterName := getEnvoyFilterName(trafficConfig, env) + envoyFilterNamespace := getEnvoyFilterNamespace() + workLoadLabels, err := getWorkLoadLabels(w, trafficConfig.Labels["asset"], env) + if err != nil { + return nil, err + } + for x, y := range *workLoadLabels { + m[x] = y + } + f, err := rc.IstioClient.NetworkingV1alpha3().EnvoyFilters(envoyFilterNamespace).Get(context.TODO(), envoyFilterName, metaV1.GetOptions{}) + if err != nil { + ctx.Log.Info("Filter does not exists.. Creating new filter") + } + envoyFilter := &v1alpha3.EnvoyFilter{ + TypeMeta: metaV1.TypeMeta{ + Kind: common.EnvoyKind, + APIVersion: common.EnvoyApiVersion, + }, + ObjectMeta: metaV1.ObjectMeta{ + Name: envoyFilterName, + Namespace: envoyFilterNamespace, + ResourceVersion: f.ResourceVersion, + Annotations: annotationMap, + Labels: map[string]string{ + "createdFor": trafficConfig.Labels[common.AssetLabel], + }, + }, + //nolint + Spec: networkingv1alpha3.EnvoyFilter{ + WorkloadSelector: &networkingv1alpha3.WorkloadSelector{Labels: m}, + ConfigPatches: configPatches, + Priority: 0, + }, + } + ctx.Log.Info("constructed required envoy filters") + envoyFilterList = append(envoyFilterList, envoyFilter) + } + } + return envoyFilterList, err +} + +func CheckIFWorkloadExposedViaHeadlessService(ctx *common.Context, w *WorkerManagerHandler, assetLabel string, workLoadEnv string) (bool, error) { + ctx.Log.Debug("checking if workload is exposed via headless service.") + if remoteControllers, ok := w.RemoteRegistry.remoteControllers[w.ClusterID]; ok { + var workloadNamespace string + deploy := remoteControllers.DeploymentController.Cache.Get(assetLabel, workLoadEnv) + if deploy != nil { + workloadNamespace = deploy.Namespace + services := remoteControllers.ServiceController.Cache.Get(workloadNamespace) + if services != nil { + for _, service := range services { + match := common.IsServiceMatch(service.Spec.Selector, deploy.Spec.Selector) + if match { + if service.Spec.ClusterIP == "None" { + ctx.Log.Debug("found headless service for the workload selector.") + return true, nil + } else { + // There should not be one service shared by multiple deploy/rollouts , if the matching deployment is found for a service and if it is not type headless service then it a scalable throttle filter + return false, nil + } + } + } + } + ctx.Log.Warn("service not found for the deployment.") + } else { + ctx.Log.Debug("There are no matching deployment found. Looking for rollouts in cache.") + if remoteControllers.RolloutController.Cache != nil { + rollout := remoteControllers.RolloutController.Cache.Get(assetLabel, workLoadEnv) + if rollout != nil { + workloadNamespace = rollout.Namespace + services := remoteControllers.ServiceController.Cache.Get(workloadNamespace) + if services != nil { + for _, service := range services { + match := common.IsServiceMatch(service.Spec.Selector, rollout.Spec.Selector) + if match { + if service.Spec.ClusterIP == "None" { + return true, nil + } else { + // There should not be one service shared by multiple deploy/rollouts , if the matching deployment is found for a service and if it is not type headless service then it a scalable throttle filter + return false, nil + } + } + } + } + } + ctx.Log.Warn("Service not found for the rollout.") + } + } + return false, errors.New("matching workload does not exist traffic config object") + } + err := errors.New("cluster not found for workload") + ctx.Log.Error("error - %v \n", err) + return false, err +} + +func getEnvoyFilterPatchValue(typedConfig *structPb.Struct, filterName string, subFilterName string) *networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch { + return &networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectPatch{ + ApplyTo: networkingv1alpha3.EnvoyFilter_HTTP_FILTER, + Patch: &networkingv1alpha3.EnvoyFilter_Patch{ + Operation: networkingv1alpha3.EnvoyFilter_Patch_INSERT_BEFORE, + Value: &structPb.Struct{ + Fields: map[string]*structPb.Value{ + "name": {Kind: &structPb.Value_StringValue{StringValue: filterName}}, + "typed_config": { + Kind: &structPb.Value_StructValue{ + StructValue: typedConfig, + }, + }, + }, + }, + FilterClass: 0, + }, + Match: &networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch{ + Context: networkingv1alpha3.EnvoyFilter_SIDECAR_INBOUND, + ObjectTypes: &networkingv1alpha3.EnvoyFilter_EnvoyConfigObjectMatch_Listener{ + Listener: &networkingv1alpha3.EnvoyFilter_ListenerMatch{ + FilterChain: &networkingv1alpha3.EnvoyFilter_ListenerMatch_FilterChainMatch{ + Filter: &networkingv1alpha3.EnvoyFilter_ListenerMatch_FilterMatch{ + Name: "envoy.filters.network.http_connection_manager", // envoy.filters.network.http_connection_manager | envoy.http_connection_manager + SubFilter: &networkingv1alpha3.EnvoyFilter_ListenerMatch_SubFilterMatch{ + Name: subFilterName}, + }, + }, + }, + }, + }, + } +} + +// getEnvoyFilterNamespace returns the user namespace where envoy filter needs to be created. +func getEnvoyFilterNamespace() string { + log.Debugln("getEnvoyFilterNamespace running...") + var namespace string + namespace = common.NamespaceIstioSystem + return namespace +} + +func getEnvoyFilterName(trafficConfig *v1.TrafficConfig, workLoadEnv string) string { + log.Debugln("getEnvoyFilterName running...") + envoyFilterName := trafficConfig.Labels[common.AssetLabel] + "-" + workLoadEnv + return strings.ToLower(envoyFilterName) +} + +func getWorkLoadLabels(w *WorkerManagerHandler, assetLabel string, workLoadEnv string) (*map[string]string, error) { + if remoteControllers, ok := w.RemoteRegistry.remoteControllers[w.ClusterID]; ok { + deploy := remoteControllers.DeploymentController.Cache.Get(assetLabel, workLoadEnv) + if deploy != nil { + return &deploy.Labels, nil + } else { + rollout := remoteControllers.RolloutController.Cache.Get(assetLabel, workLoadEnv) + if rollout != nil { + return &rollout.Labels, nil + } + } + log.Errorln("Workload not found for asset - %v and workload env - %v \n", assetLabel, workLoadEnv) + return nil, fmt.Errorf("Workload not found for asset - %v and workload env - %v \n", assetLabel, workLoadEnv) + } + log.Errorln("cluster not found in the cache") + return nil, fmt.Errorf("cluster not found in the cache") +} diff --git a/admiral/pkg/clusters/handler.go b/admiral/pkg/clusters/handler.go index 99d21410c..20e49fc57 100644 --- a/admiral/pkg/clusters/handler.go +++ b/admiral/pkg/clusters/handler.go @@ -317,6 +317,11 @@ func IgnoreIstioResource(exportTo []string, annotations map[string]string, names } } } + + if common.IsDefaultPersona() && len(annotations) > 0 && annotations[common.CreatedBy] == common.AdmiralUnification { + return true + } + return true } @@ -601,7 +606,7 @@ func skipDestructiveUpdate(rc *RemoteController, new *v1alpha3.ServiceEntry, old return skipDestructive, diff } -//Diffs only endpoints +// Diffs only endpoints func getServiceEntryDiff(new *v1alpha3.ServiceEntry, old *v1alpha3.ServiceEntry) (destructive bool, diff string) { //we diff only if both objects exist if old == nil || new == nil { @@ -703,17 +708,16 @@ func deleteDestinationRule(ctx context.Context, exist *v1alpha3.DestinationRule, } } -//nolint +// nolint func createServiceEntrySkeletion(se v1alpha32.ServiceEntry, name string, namespace string) *v1alpha3.ServiceEntry { return &v1alpha3.ServiceEntry{Spec: se, ObjectMeta: v12.ObjectMeta{Name: name, Namespace: namespace}} } -//nolint func createSidecarSkeleton(sidecar v1alpha32.Sidecar, name string, namespace string) *v1alpha3.Sidecar { return &v1alpha3.Sidecar{Spec: sidecar, ObjectMeta: v12.ObjectMeta{Name: name, Namespace: namespace}} } -//nolint +// nolint func createDestinationRuleSkeletion(dr v1alpha32.DestinationRule, name string, namespace string) *v1alpha3.DestinationRule { return &v1alpha3.DestinationRule{Spec: dr, ObjectMeta: v12.ObjectMeta{Name: name, Namespace: namespace}} } diff --git a/admiral/pkg/clusters/registry.go b/admiral/pkg/clusters/registry.go index 2ddbe2721..d6c145343 100644 --- a/admiral/pkg/clusters/registry.go +++ b/admiral/pkg/clusters/registry.go @@ -3,10 +3,11 @@ package clusters import ( "context" "fmt" + "github.com/istio-ecosystem/admiral/admiral/pkg/controller/istio" + "github.com/istio-ecosystem/admiral/admiral/pkg/manager" "os" "time" - "github.com/istio-ecosystem/admiral/admiral/pkg/controller/istio" "k8s.io/client-go/rest" "github.com/istio-ecosystem/admiral/admiral/pkg/controller/admiral" @@ -16,9 +17,10 @@ import ( ) const ( - LogFormat = "op=%s type=%v name=%v cluster=%s message=%s" - LogFormatAdv = "op=%s type=%v name=%v namespace=%s cluster=%s message=%s" - LogErrFormat = "op=%s type=%v name=%v cluster=%s, e=%v" + LogFormat = "op=%s type=%v Name=%v cluster=%s message=%s" + LogFormatAdv = "op=%s type=%v Name=%v namespace=%s cluster=%s message=%s" + LogFormatTID = "tid=%s op=%s type=%v Name=%v asset=%s revision=%v message=%v" + LogErrFormat = "op=%s type=%v Name=%v cluster=%s, e=%v" ) func InitAdmiral(ctx context.Context, params common.AdmiralParams) (*RemoteRegistry, error) { @@ -30,9 +32,7 @@ func InitAdmiral(ctx context.Context, params common.AdmiralParams) (*RemoteRegis // start admiral state checker for DR drStateChecker := initAdmiralStateChecker(ctx, params.AdmiralStateCheckerName, params.DRStateStoreConfigPath) RunAdmiralStateCheck(ctx, params.AdmiralStateCheckerName, drStateChecker) - pauseForAdmiralToInitializeState() - w := NewRemoteRegistry(ctx, params) wd := DependencyHandler{ @@ -53,17 +53,69 @@ func InitAdmiral(ctx context.Context, params common.AdmiralParams) (*RemoteRegis if err != nil { return nil, fmt.Errorf("error with configmap controller init: %v", err) } + w.AdmiralCache.ConfigMapController = configMapController loadServiceEntryCacheData(ctx, w.AdmiralCache.ConfigMapController, w.AdmiralCache) - err = createSecretController(ctx, w) - if err != nil { - return nil, fmt.Errorf("error with secret control init: %v", err) + if params.TrafficConfigPersona { + err = InitAdmiralWithTrafficConfigPersona(ctx, params, w) + } else { + err = InitAdmiralWithDefaultPersona(ctx, params, w) } go w.shutdown() - return w, nil + return w, err +} + +func InitAdmiralWithDefaultPersona(ctx context.Context, params common.AdmiralParams, w *RemoteRegistry) error { + log.Infof("Initializing Default Persona of Admiral") + + err := createSecretController(ctx, w) + if err != nil { + return fmt.Errorf("error with secret control init: %v", err) + } + + return nil +} + +func InitAdmiralWithTrafficConfigPersona(ctx context.Context, params common.AdmiralParams, w *RemoteRegistry) error { + log.Infof("Initializing Traffic Config Persona of Admiral") + + tc := TrafficConfigHandler{ + RemoteRegistry: w, + } + var err error + + tc.TrafficConfigController, err = admiral.NewTrafficConfigController(ctx.Done(), &tc, params.KubeconfigPath, params.TrafficConfigNamespace, params.CacheRefreshDuration) + if err != nil { + return fmt.Errorf("error with traffic config controller init: %v", err) + } + + var controller *secret.Controller + + w.secretClient, err = admiral.K8sClientFromPath(common.GetKubeconfigPath()) + if err != nil { + return fmt.Errorf("could not create K8s client: %v", err) + } + + controller, err = secret.StartSecretController(ctx, w.secretClient, + w.createWorkerManager, + w.updateWorkerManager, + w.deleteWorkerManager, + common.GetClusterRegistriesNamespace(), + common.GetAdmiralProfile(), common.GetAdmiralConfigPath()) + + if err != nil { + return fmt.Errorf("could not start secret controller: %v", err) + } + + w.SecretController = controller + if err != nil { + return fmt.Errorf("error with secret control init: %v", err) + } + + return nil } func pauseForAdmiralToInitializeState() { @@ -110,6 +162,84 @@ func createSecretController(ctx context.Context, w *RemoteRegistry) error { return nil } +func (r *RemoteRegistry) createWorkerManager(clientConfig *rest.Config, clusterID string, resyncPeriod time.Duration) error { + stop := make(chan struct{}) + + rwm := RemoteWorkerManager{ + stop: stop, + ClusterID: clusterID, + ApiServer: clientConfig.Host, + StartTime: time.Now(), + } + + rc := RemoteController{ + stop: stop, + ClusterID: clusterID, + ApiServer: clientConfig.Host, + StartTime: time.Now(), + } + + var err error + log.Infof("Starting NewWorkerManager for cluster - %+v", clusterID) + rwm.WorkerManager, err = manager.NewWorkerManager(stop, &WorkerManagerHandler{RemoteRegistry: r, ClusterID: clusterID}, clusterID, clientConfig, resyncPeriod) + if err != nil { + return fmt.Errorf("error with NewWorkerManager init: %v", err) + } + log.Infof("Created WorkerManger - %+v for - %s", rwm, clusterID) + + log.Infof("starting service controller clusterID: %v", clusterID) + rc.ServiceController, err = admiral.NewServiceController(stop, &ServiceHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, 0) + + if err != nil { + return fmt.Errorf("error with ServiceController controller init: %v", err) + } + + log.Infof("starting deployment controller clusterID: %v", clusterID) + rc.DeploymentController, err = admiral.NewDeploymentController(stop, &DeploymentHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, resyncPeriod) + + if err != nil { + return fmt.Errorf("error with DeploymentController controller init: %v", err) + } + + if r.AdmiralCache == nil { + log.Warn("admiral cache was nil!") + } else if r.AdmiralCache.argoRolloutsEnabled { + log.Infof("starting rollout controller clusterID: %v", clusterID) + rc.RolloutController, err = admiral.NewRolloutsController(stop, &RolloutHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, resyncPeriod) + + if err != nil { + return fmt.Errorf("error with Rollout controller init: %v", err) + } + } + + r.PutRemoteController(clusterID, &rc) + r.PutRemoteWorkerManager(clusterID, &rwm) + return nil +} + +func (r *RemoteRegistry) updateWorkerManager(clientConfig *rest.Config, clusterID string, resyncPeriod time.Duration) error { + workerManager := r.GetRemoteWorkerManager(clusterID) + if clientConfig.Host != workerManager.ApiServer { + log.Infof("Client mismatch, recreating worker manager for cluster=%v", clusterID) + if err := r.deleteWorkerManager(clusterID); err != nil { + return err + } + } + return r.createWorkerManager(clientConfig, clusterID, resyncPeriod) +} + +func (r *RemoteRegistry) deleteWorkerManager(clusterID string) error { + workerManager := r.GetRemoteWorkerManager(clusterID) + if workerManager.WorkerManager != nil { + close(workerManager.stop) + } + + r.DeleteRemoteWorkerManager(clusterID) + r.DeleteRemoteController(clusterID) + log.Infof(LogFormat, "Delete", "remote-worker-manager", clusterID, clusterID, "success") + return nil +} + func (r *RemoteRegistry) createCacheController(clientConfig *rest.Config, clusterID string, resyncPeriod time.Duration) error { stop := make(chan struct{}) @@ -123,6 +253,8 @@ func (r *RemoteRegistry) createCacheController(clientConfig *rest.Config, cluste var err error + log.Infof("Starting NewWorkerManager for cluster - %+v", clusterID) + log.Infof("starting service controller clusterID: %v", clusterID) rc.ServiceController, err = admiral.NewServiceController(stop, &ServiceHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, 0) @@ -179,6 +311,12 @@ func (r *RemoteRegistry) createCacheController(clientConfig *rest.Config, cluste return fmt.Errorf("error with DeploymentController controller init: %v", err) } + log.Infof("starting Routing Policies controller for custerID: %v", clusterID) + rc.RoutingPolicyController, err = admiral.NewRoutingPoliciesController(stop, &RoutingPolicyHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, 1*time.Minute) + + if err != nil { + return fmt.Errorf("error with virtualServiceController init: %v", err) + } if r.AdmiralCache == nil { log.Warn("admiral cache was nil!") } else if r.AdmiralCache.argoRolloutsEnabled { @@ -190,17 +328,7 @@ func (r *RemoteRegistry) createCacheController(clientConfig *rest.Config, cluste } } - log.Infof("starting Routing Policies controller for custerID: %v", clusterID) - rc.RoutingPolicyController, err = admiral.NewRoutingPoliciesController(stop, &RoutingPolicyHandler{RemoteRegistry: r, ClusterID: clusterID}, clientConfig, 1*time.Minute) - - if err != nil { - return fmt.Errorf("error with virtualServiceController init: %v", err) - } - r.PutRemoteController(clusterID, &rc) - - log.Infof("Create Controller %s", clusterID) - return nil } diff --git a/admiral/pkg/clusters/serviceentry.go b/admiral/pkg/clusters/serviceentry.go index c284ca404..c2cbe3c09 100644 --- a/admiral/pkg/clusters/serviceentry.go +++ b/admiral/pkg/clusters/serviceentry.go @@ -129,9 +129,25 @@ func modifyServiceEntryForNewServiceOrPod( cname = common.GetCname(deployment, common.GetWorkloadIdentifier(), common.GetHostnameSuffix()) sourceDeployments[rc.ClusterID] = deployment + + if common.IsPersonaTrafficConfig() { + continue + } + createServiceEntryForDeployment(ctx, event, rc, remoteRegistry.AdmiralCache, localMeshPorts, deployment, serviceEntries) } else if rollout != nil { remoteRegistry.AdmiralCache.IdentityClusterCache.Put(sourceIdentity, rc.ClusterID, rc.ClusterID) + + cname = common.GetCnameForRollout(rollout, common.GetWorkloadIdentifier(), common.GetHostnameSuffix()) + cnames[cname] = "1" + sourceRollouts[rc.ClusterID] = rollout + + namespace = rollout.Namespace + + if common.IsPersonaTrafficConfig() { + continue + } + weightedServices = getServiceForRollout(ctx, rc, rollout) if len(weightedServices) == 0 { log.Warnf(LogFormatAdv, "Get", "Service", rollout.Name, rollout.Namespace, rc.ClusterID, "No matching service instance found") @@ -143,16 +159,29 @@ func modifyServiceEntryForNewServiceOrPod( serviceInstance = sInstance.Service break } - namespace = rollout.Namespace - localMeshPorts := GetMeshPortsForRollout(rc.ClusterID, serviceInstance, rollout) - cname = common.GetCnameForRollout(rollout, common.GetWorkloadIdentifier(), common.GetHostnameSuffix()) - cnames[cname] = "1" - sourceRollouts[rc.ClusterID] = rollout + localMeshPorts := GetMeshPortsForRollout(rc.ClusterID, serviceInstance, rollout) createServiceEntryForRollout(ctx, event, rc, remoteRegistry.AdmiralCache, localMeshPorts, rollout, serviceEntries) } else { continue } + remoteRegistry.AdmiralCache.IdentityClusterCache.Put(sourceIdentity, rc.ClusterID, rc.ClusterID) + + remoteRegistry.AdmiralCache.CnameClusterCache.Put(cname, rc.ClusterID, rc.ClusterID) + remoteRegistry.AdmiralCache.CnameIdentityCache.Store(cname, sourceIdentity) + sourceServices[rc.ClusterID] = serviceInstance + sourceWeightedServices[rc.ClusterID] = weightedServices + + if common.IsPersonaTrafficConfig() { + continue + } + + // workload selector cache is needed for routingPolicy's envoyFilter to match the dependency and apply to the right POD + // using service labels + workloadSelectors := GetServiceSelector(rc.ClusterID, serviceInstance) + if workloadSelectors != nil { + remoteRegistry.AdmiralCache.WorkloadSelectorCache.PutMap(sourceIdentity+rc.ClusterID, workloadSelectors) + } gtpsInNamespace := rc.GlobalTraffic.Cache.Get(gtpKey, namespace) if len(gtpsInNamespace) > 0 { @@ -163,18 +192,20 @@ func modifyServiceEntryForNewServiceOrPod( } else { log.Debugf("No GTPs found for identity=%s in env=%s namespace=%s with key=%s", sourceIdentity, env, namespace, gtpKey) } + } - remoteRegistry.AdmiralCache.IdentityClusterCache.Put(sourceIdentity, rc.ClusterID, rc.ClusterID) - // workload selector cache is needed for routingPolicy's envoyFilter to match the dependency and apply to the right POD - // using service labels - workloadSelectors := GetServiceSelector(rc.ClusterID, serviceInstance) - if workloadSelectors != nil { - remoteRegistry.AdmiralCache.WorkloadSelectorCache.PutMap(sourceIdentity+rc.ClusterID, workloadSelectors) - } - remoteRegistry.AdmiralCache.CnameClusterCache.Put(cname, rc.ClusterID, rc.ClusterID) - remoteRegistry.AdmiralCache.CnameIdentityCache.Store(cname, sourceIdentity) - sourceServices[rc.ClusterID] = serviceInstance - sourceWeightedServices[rc.ClusterID] = weightedServices + dependents := remoteRegistry.AdmiralCache.IdentityDependencyCache.Get(sourceIdentity).Copy() + + dependentClusters := getDependentClusters(dependents, remoteRegistry.AdmiralCache.IdentityClusterCache, sourceServices) + + //update cname dependent cluster cache + for clusterId := range dependentClusters { + remoteRegistry.AdmiralCache.CnameDependentClusterCache.Put(cname, clusterId, clusterId) + } + + if common.IsPersonaTrafficConfig() { + log.Info("NOT Generating Service Entry in Traffic Config Persona") + return nil } util.LogElapsedTimeSince("BuildServiceEntry", sourceIdentity, env, "", start) @@ -182,8 +213,6 @@ func modifyServiceEntryForNewServiceOrPod( //cache the latest GTP in global cache to be reused during DR creation updateGlobalGtpCache(remoteRegistry.AdmiralCache, sourceIdentity, env, gtps) - dependents := remoteRegistry.AdmiralCache.IdentityDependencyCache.Get(sourceIdentity).Copy() - //handle local updates (source clusters first) //update the address to local fqdn for service entry in a cluster local to the service instance @@ -258,12 +287,6 @@ func modifyServiceEntryForNewServiceOrPod( //Write to dependent clusters start = time.Now() - dependentClusters := getDependentClusters(dependents, remoteRegistry.AdmiralCache.IdentityClusterCache, sourceServices) - - //update cname dependent cluster cache - for clusterId := range dependentClusters { - remoteRegistry.AdmiralCache.CnameDependentClusterCache.Put(cname, clusterId, clusterId) - } AddServiceEntriesWithDr(ctx, remoteRegistry, dependentClusters, serviceEntries) @@ -272,9 +295,9 @@ func modifyServiceEntryForNewServiceOrPod( return serviceEntries } -//Does two things; -//i) Picks the GTP that was created most recently from the passed in GTP list based on GTP priority label (GTPs from all clusters) -//ii) Updates the global GTP cache with the selected GTP in i) +// Does two things; +// i) Picks the GTP that was created most recently from the passed in GTP list based on GTP priority label (GTPs from all clusters) +// ii) Updates the global GTP cache with the selected GTP in i) func updateGlobalGtpCache(cache *AdmiralCache, identity, env string, gtps map[string][]*v1.GlobalTrafficPolicy) { defer util.LogElapsedTime("updateGlobalGtpCache", identity, env, "")() gtpsOrdered := make([]*v1.GlobalTrafficPolicy, 0) @@ -346,7 +369,7 @@ func updateEndpointsForBlueGreen(rollout *argo.Rollout, weightedServices map[str } } -//update endpoints for Argo rollouts specific Service Entries to account for traffic splitting (Canary strategy) +// update endpoints for Argo rollouts specific Service Entries to account for traffic splitting (Canary strategy) func updateEndpointsForWeightedServices(serviceEntry *networking.ServiceEntry, weightedServices map[string]*WeightedService, clusterIngress string, meshPorts map[string]uint32) { var endpoints = make([]*networking.WorkloadEntry, 0) var endpointToReplace *networking.WorkloadEntry @@ -421,8 +444,9 @@ func modifySidecarForLocalClusterCommunication( } } - //nolint - newSidecarConfig := createSidecarSkeleton(newSidecar.Spec, common.GetWorkloadSidecarName(), sidecarNamespace) + + //nolint + newSidecarConfig := createSidecarSkeleton(newSidecar.Spec, common.GetWorkloadSidecarName(), sidecarNamespace) //insert into cluster if newSidecarConfig != nil { @@ -457,7 +481,7 @@ func copySidecar(sidecar *v1alpha3.Sidecar) *v1alpha3.Sidecar { return newSidecarObj } -//AddServiceEntriesWithDr will create the default service entries and also additional ones specified in GTP +// AddServiceEntriesWithDr will create the default service entries and also additional ones specified in GTP func AddServiceEntriesWithDr(ctx context.Context, rr *RemoteRegistry, sourceClusters map[string]string, serviceEntries map[string]*networking.ServiceEntry) { cache := rr.AdmiralCache syncNamespace := common.GetSyncNamespace() @@ -654,8 +678,8 @@ func loadServiceEntryCacheData(ctx context.Context, c admiral.ConfigMapControlle } -//GetLocalAddressForSe gets a guarenteed unique local address for a serviceentry. Returns the address, True iff the configmap was updated false otherwise, and an error if any -//Any error coupled with an empty string address means the method should be retried +// GetLocalAddressForSe gets a guarenteed unique local address for a serviceentry. Returns the address, True iff the configmap was updated false otherwise, and an error if any +// Any error coupled with an empty string address means the method should be retried func GetLocalAddressForSe(ctx context.Context, seName string, seAddressCache *ServiceEntryAddressStore, configMapController admiral.ConfigMapControllerInterface) (string, bool, error) { var address = seAddressCache.EntryAddresses[seName] if len(address) == 0 { @@ -682,7 +706,7 @@ func GetServiceEntriesByCluster(ctx context.Context, clusterID string, remoteReg } } -//GenerateNewAddressAndAddToConfigMap an atomic fetch and update operation against the configmap (using K8s built in optimistic consistency mechanism via resource version) +// GenerateNewAddressAndAddToConfigMap an atomic fetch and update operation against the configmap (using K8s built in optimistic consistency mechanism via resource version) func GenerateNewAddressAndAddToConfigMap(ctx context.Context, seName string, configMapController admiral.ConfigMapControllerInterface) (string, error) { //1. get cm, see if there. 2. gen new uq address. 3. put configmap. RETURN SUCCESSFULLY IFF CONFIGMAP PUT SUCCEEDS cm, err := configMapController.GetConfigMap(ctx) @@ -724,7 +748,7 @@ func GenerateNewAddressAndAddToConfigMap(ctx context.Context, seName string, con return address, nil } -//puts new data into an existing configmap. Providing the original is necessary to prevent fetch and update race conditions +// puts new data into an existing configmap. Providing the original is necessary to prevent fetch and update race conditions func putServiceEntryStateFromConfigmap(ctx context.Context, c admiral.ConfigMapControllerInterface, originalConfigmap *k8sV1.ConfigMap, data *ServiceEntryAddressStore) error { if originalConfigmap == nil { return errors.New("configmap must not be nil") diff --git a/admiral/pkg/clusters/types.go b/admiral/pkg/clusters/types.go index 350c37c7a..7f548dfb8 100644 --- a/admiral/pkg/clusters/types.go +++ b/admiral/pkg/clusters/types.go @@ -1,9 +1,11 @@ package clusters import ( + "container/list" "context" "errors" "fmt" + "github.com/istio-ecosystem/admiral/admiral/pkg/manager" "sync" "time" @@ -20,6 +22,13 @@ import ( k8s "k8s.io/client-go/kubernetes" ) +const ( + ADD = "Add" + UPDATE = "Update" + DELETE = "Delete" + AdmiralIgnore = "admiral.io/ignore" +) + type ServiceEntrySuspender interface { SuspendUpdate(identity string, environment string) bool } @@ -32,6 +41,14 @@ type IgnoredIdentityCache struct { EnvironmentsByIdentity map[string][]string `json:"environmentsByIdentities"` } +type RemoteWorkerManager struct { + ClusterID string + ApiServer string + StartTime time.Time + WorkerManager *manager.WorkerManager + stop chan struct{} +} + type RemoteController struct { ClusterID string ApiServer string @@ -46,6 +63,7 @@ type RemoteController struct { SidecarController *istio.SidecarController RolloutController *admiral.RolloutController RoutingPolicyController *admiral.RoutingPolicyController + EnvoyFilterController *admiral.EnvoyFilterController stop chan struct{} //listener for normal types } @@ -72,14 +90,24 @@ type AdmiralCache struct { type RemoteRegistry struct { sync.Mutex remoteControllers map[string]*RemoteController + remoteWorkerManagers map[string]*RemoteWorkerManager SecretController *secret.Controller secretClient k8s.Interface ctx context.Context AdmiralCache *AdmiralCache StartTime time.Time ServiceEntrySuspender ServiceEntrySuspender + TrafficConfigRegistry sync.Map // Map[clusterID]Queue{TrafficConfig} + // TrafficConfigRegistry map[string]*WorkManagerObj +} + +type WorkManagerObj struct { + Queue *list.List + NotificationChannel chan bool } +// TODO - Write a new function to prepare a new Map. + func NewRemoteRegistry(ctx context.Context, params common.AdmiralParams) *RemoteRegistry { var serviceEntrySuspender ServiceEntrySuspender gtpCache := &globalTrafficCache{} @@ -115,12 +143,16 @@ func NewRemoteRegistry(ctx context.Context, params common.AdmiralParams) *Remote } else { serviceEntrySuspender = NewDummyServiceEntrySuspender() } + return &RemoteRegistry{ + remoteWorkerManagers: make(map[string]*RemoteWorkerManager), ctx: ctx, StartTime: time.Now(), remoteControllers: make(map[string]*RemoteController), AdmiralCache: admiralCache, ServiceEntrySuspender: serviceEntrySuspender, + TrafficConfigRegistry: sync.Map{}, + // TrafficConfigRegistry: make(map[string]*WorkManagerObj), // Adding trafficConfigRegistry - to share the trafficConfig map with all remote workManagers } } @@ -136,6 +168,28 @@ func (r *RemoteRegistry) PutRemoteController(clusterId string, rc *RemoteControl r.remoteControllers[clusterId] = rc } +func (r *RemoteRegistry) PutRemoteWorkerManager(clusterID string, wm *RemoteWorkerManager) { + r.Mutex.Lock() + defer r.Mutex.Unlock() + r.remoteWorkerManagers[clusterID] = wm +} + +func (r *RemoteRegistry) GetRemoteWorkerManager(clusterID string) *RemoteWorkerManager { + r.Mutex.Lock() + defer r.Mutex.Unlock() + if val, ok := r.remoteWorkerManagers[clusterID]; ok { + return val + } else { + return nil + } +} + +func (r *RemoteRegistry) DeleteRemoteWorkerManager(clusterId string) { + r.Mutex.Lock() + defer r.Mutex.Unlock() + delete(r.remoteWorkerManagers, clusterId) +} + func (r *RemoteRegistry) DeleteRemoteController(clusterId string) { r.Mutex.Lock() defer r.Mutex.Unlock() @@ -182,6 +236,11 @@ type DependencyHandler struct { DepController *admiral.DependencyController } +type TrafficConfigHandler struct { + RemoteRegistry *RemoteRegistry + TrafficConfigController *admiral.TrafficConfigController +} + type GlobalTrafficHandler struct { RemoteRegistry *RemoteRegistry ClusterID string @@ -454,6 +513,68 @@ type ServiceHandler struct { ClusterID string } +type WorkerManagerHandler struct { + RemoteRegistry *RemoteRegistry + ClusterID string +} + +// AddClusterEntry adds the clusterID into workerManager Map. +func (w *WorkerManagerHandler) AddClusterEntry(clusterID string) { + w.RemoteRegistry.TrafficConfigRegistry.LoadOrStore(clusterID, &WorkManagerObj{ + Queue: list.New(), + NotificationChannel: make(chan bool)}) +} + +// ProcessQueue process the queue for a corresponding value of clusterID in the map. +// We will have dedicated ProcessQueue goroutine running for each clusterID entry in the Map. Basically corresponding to every workerManager. +func (w *WorkerManagerHandler) ProcessQueue(stopCh <-chan struct{}) error { + val, ok := w.RemoteRegistry.TrafficConfigRegistry.Load(w.ClusterID) + if ok { + workMgrObj := val.(*WorkManagerObj) + for { + select { + case _ = <-workMgrObj.NotificationChannel: + obj := workMgrObj.Queue.Front() + log.Infof("total number of objects in the queue = %v \n", workMgrObj.Queue.Len()) + trafficConfigObj := obj.Value.(common.TrafficObject) + err := w.ProcessItem(&trafficConfigObj) + if err == nil { + log.Infof("object processed successfully, removing from the queue.") + workMgrObj.Queue.Remove(obj) + } + log.Infof("total number of objects in the queue after processing an Item = %v \n", workMgrObj.Queue.Len()) + case _ = <-stopCh: + // TODO Implement graceful shutdown + log.Infof("Shutting Down processQueue operation.") + } + } + } else { + err := fmt.Errorf("cluster not found in remoteworkermanager cache") + log.Errorf("error : %+v \n", err) + return err + } + return nil +} + +// ProcessItem TODO: Error handling is missing. +func (w *WorkerManagerHandler) ProcessItem(obj *common.TrafficObject) error { + // log.Debugf(LogFormatTID, obj.Ctx.Value("log").(*LogStruct).TID, obj.Ctx.Value("log").(*LogStruct).Event, obj.Ctx.Value("log").(*LogStruct).ObjectType, obj.Ctx.Value("log").(*LogStruct).ObjectName, obj.Ctx.Value("log").(*LogStruct).Asset, obj.Ctx.Value("log").(*LogStruct).Revision, "processing item...") + obj.Ctx.Log.Debug("processing item...") + workerManager := w.RemoteRegistry.remoteWorkerManagers[w.ClusterID] + err := w.ModifyEnvoyFilterConfiguration(obj.Ctx, workerManager.WorkerManager, obj.Event, obj.TrafficConfig) + if err != nil { + fmt.Errorf("Error creating Envoy Filter - %+v \n", err) + return err + } + + err = w.CreateOrUpdateVirtualServiceFromTrafficConfig(obj.Ctx, workerManager.WorkerManager, obj.TrafficConfig) + if err != nil { + fmt.Errorf("Error creating Virtual Service - %+v \n", err) + return err + } + return nil +} + func (sh *ServiceHandler) Added(ctx context.Context, obj *k8sV1.Service) { log.Infof(LogFormat, "Added", "service", obj.Name, sh.ClusterID, "received") err := HandleEventForService(ctx, obj, sh.RemoteRegistry, sh.ClusterID) @@ -642,3 +763,99 @@ func HandleEventForGlobalTrafficPolicy(ctx context.Context, event admiral.EventT modifyServiceEntryForNewServiceOrPod(ctx, admiral.Update, env, globalIdentifier, remoteRegistry) return nil } + +func (tc *TrafficConfigHandler) Added(ctx context.Context, obj *v1.TrafficConfig) { + + if CurrentAdmiralState.ReadOnly { + log.Infof(LogFormat, admiral.Add, "TrafficConfig", "", "", "skipping read-only mode") + return + } + log.Infof(LogFormat, admiral.Add, "TrafficConfig", obj.Name, "", "Received=true namespace="+obj.Namespace) + // customCtx := &v1.Context{} + err := HandleEventForTrafficConfig(&common.Context{}, admiral.Add, obj, tc.RemoteRegistry) + if err != nil { + log.Infof(err.Error()) + } +} + +func (tc *TrafficConfigHandler) Updated(ctx context.Context, obj *v1.TrafficConfig) { + if CurrentAdmiralState.ReadOnly { + log.Infof(LogFormat, admiral.Update, "TrafficConfig", "", "", "skipping read-only mode") + return + } + + log.Infof(LogFormat, admiral.Update, "TrafficConfig", obj.Name, "", "Received=true namespace="+obj.Namespace) + //customCtx := &v1.Context{} + err := HandleEventForTrafficConfig(&common.Context{}, admiral.Update, obj, tc.RemoteRegistry) + if err != nil { + log.Infof(err.Error()) + } +} + +func (tc *TrafficConfigHandler) Deleted(ctx context.Context, obj *v1.TrafficConfig) { + if CurrentAdmiralState.ReadOnly { + log.Infof(LogFormat, admiral.Delete, "TrafficConfig", "", "", "skipping read-only mode") + return + } + + log.Infof(LogFormat, admiral.Delete, "TrafficConfig", obj.Name, "", "Received=true namespace="+obj.Namespace) + // customCtx := &v1.Context{} + err := HandleEventForTrafficConfig(&common.Context{}, admiral.Delete, obj, tc.RemoteRegistry) + if err != nil { + log.Infof(err.Error()) + } +} + +func checkIFObjectNeedsToBeIgnored(obj *v1.TrafficConfig) bool { + if obj.Annotations != nil { + if val, ok := obj.Annotations[AdmiralIgnore]; ok { + if val == "true" { + return true + } + return false + } + return false + } + return false +} +func HandleEventForTrafficConfig(ctx *common.Context, event admiral.EventType, obj *v1.TrafficConfig, remoteRegistry *RemoteRegistry) error { + ctx.Log = log.WithFields(log.Fields{"tid": obj.Annotations["transactionID"], "event": event, "type": "TrafficConfig", "Name": obj.Name, "asset": obj.Labels["asset"], "revision": obj.Annotations["revisionNumber"]}) + + ctx.Log.Debug("Handling event for traffic config at time = " + time.Now().String()) + if !checkIFObjectNeedsToBeIgnored(obj) { + c := remoteRegistry.AdmiralCache.IdentityClusterCache.Get(obj.Labels["asset"]) + if c != nil { + for _, clusterID := range c.GetKeys() { + trafficObjQueue, clusterExists := remoteRegistry.TrafficConfigRegistry.Load(clusterID) + // TrafficConfigRegistry is a map of clusterID and Queue of Traffic Config Objects. + // If the map already has a clusterID , then add the newly arrived tc object into the corresponding queue. + if !clusterExists { + wmObj := &WorkManagerObj{ + Queue: list.New(), + NotificationChannel: make(chan bool, 0), + } + remoteRegistry.TrafficConfigRegistry.Store(clusterID, wmObj) + trafficObjQueue = wmObj + } + + w := trafficObjQueue.(*WorkManagerObj) + to := common.TrafficObject{ + TrafficConfig: obj, + Ctx: ctx, + Event: string(event), + } + w.Queue.PushBack(to) + w.NotificationChannel <- true + ctx.Log.Info("Traffic Config Object has been added to Cluster Queue: ", clusterID) + } + } else { + //TODO What to do when clusterID is not found in the cache? + logVal := fmt.Sprintf("clusterID for the asset - %+v not found in the IdentityClusterCache", obj.Labels["asset"]) + ctx.Log.Info(logVal) + return errors.New("clusterID not found in cache") + } + } else { + log.Infof(LogFormatTID, obj.Annotations["transactionID"], event, "TrafficConfig", obj.Name, obj.Labels["asset"], obj.Annotations["revisionNumber"], "ignoring as object has admiral.io/ignore annotation") + } + return nil +} diff --git a/admiral/pkg/clusters/virtualservice.go b/admiral/pkg/clusters/virtualservice.go new file mode 100644 index 000000000..039a0055f --- /dev/null +++ b/admiral/pkg/clusters/virtualservice.go @@ -0,0 +1,298 @@ +package clusters + +import ( + "context" + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + "github.com/istio-ecosystem/admiral/admiral/pkg/controller/common" + "github.com/istio-ecosystem/admiral/admiral/pkg/manager" + log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/durationpb" + networkingv1alpha3 "istio.io/api/networking/v1alpha3" + "istio.io/client-go/pkg/apis/networking/v1alpha3" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "strconv" + "strings" +) + +func (w *WorkerManagerHandler) CreateOrUpdateVirtualServiceFromTrafficConfig(ctx *common.Context, wm *manager.WorkerManager, trafficconfig *v1.TrafficConfig) error { + log.Debugln("CreateOrUpdateVirtualServiceFromTrafficConfig running.....") + vsMap, err := constructVirtualServices(trafficconfig) + if err != nil { + return err + } + + return w.CreateUpdateDeleteVirtualServices(ctx, wm, vsMap, trafficconfig) +} + +func constructVirtualServices(trafficConfig *v1.TrafficConfig) (map[string]*v1alpha3.VirtualService, error) { + + virtualServices := make(map[string]*v1alpha3.VirtualService, 0) + + for _, route := range trafficConfig.Spec.EdgeService.Routes { + for _, env := range route.WorkloadEnvSelectors { + // Check if it is already present in Map virtualServices + if _, ok := virtualServices[env]; !ok { + // Not Present. Create One. + vs := v1alpha3.VirtualService{} + assetAliasLowerCase := strings.ToLower(trafficConfig.Labels["asset"]) + vs.Name = env + "." + assetAliasLowerCase + "-unification-vs" + vs.Namespace = "admiral-sync" + vs.Spec.Hosts = append(vs.Spec.Hosts, env+"."+assetAliasLowerCase+".mesh") + virtualServices[env] = &vs + vsAnnotations := make(map[string]string) + vsAnnotations[common.RevisionNumber] = trafficConfig.ObjectMeta.Annotations[common.RevisionNumber] + vsAnnotations[common.TransactionID] = trafficConfig.ObjectMeta.Annotations[common.TransactionID] + vsAnnotations[common.CreatedBy] = common.AdmiralUnification + vsAnnotations[common.CreatedFor] = trafficConfig.Labels["asset"] + vsAnnotations[common.CreatedForEnv] = env + vs.ObjectMeta.SetAnnotations(vsAnnotations) + + vsLabels := make(map[string]string) + vsLabels[common.CreatedFor] = trafficConfig.Labels["asset"] + vs.ObjectMeta.SetLabels(vsLabels) + } + // Get the Virtual Service + vs := virtualServices[env] + if len(vs.Spec.Http) == 0 { + vs.Spec.Http = make([]*networkingv1alpha3.HTTPRoute, 0) + } + + // HTTP Route + httpRoute := networkingv1alpha3.HTTPRoute{} + httpRoute.Name = route.Name + httpRoute.Timeout = &durationpb.Duration{Seconds: int64(route.Timeout) / 1000} + + // URI Match + httpRoute.Match = make([]*networkingv1alpha3.HTTPMatchRequest, 0) + matchReq := networkingv1alpha3.HTTPMatchRequest{} + matchReq.Uri = &networkingv1alpha3.StringMatch{ + MatchType: &networkingv1alpha3.StringMatch_Prefix{Prefix: route.Inbound}, + } + + // Route + httpRoute.Route = make([]*networkingv1alpha3.HTTPRouteDestination, 0) + rd := networkingv1alpha3.HTTPRouteDestination{} + rd.Destination = &networkingv1alpha3.Destination{ + Host: vs.Spec.Hosts[0], + } + httpRoute.Route = append(httpRoute.Route, &rd) + + // Retries + /* + for _, filter := range trafficConfig.Spec.EdgeService.Filters { + if filter.Name == route.FilterSelector { + httpRoute.Retries = &networkingv1alpha3.HTTPRetry{} + httpRoute.Retries.PerTryTimeout = &durationpb.Duration{Seconds: getSeconds(filter.Retries.PerTryTimeout)} + httpRoute.Retries.RetryOn = "5xx,gateway-error" + httpRoute.Retries.Attempts = int32(filter.Retries.Attempts) + } + } + */ + + httpRoute.Match = append(httpRoute.Match, &matchReq) + vs.Spec.Http = append(vs.Spec.Http, &httpRoute) + } + } + + // Add Default Route to all + return virtualServices, nil +} + +func getSeconds(timeStr string) int64 { + timeNum, err := strconv.ParseInt(timeStr[0:len(timeStr)-1], 10, 0) + if err != nil { + return 0 + } + + switch timeStr[len(timeStr)-1:] { + case "s", "S": + return timeNum + case "m", "M": + return timeNum * 60 + case "h", "H": + return timeNum * 60 * 60 + default: + return 0 + } +} + +func isVsEnvExisting(env string, envList []string) bool { + for _, vsEnv := range envList { + if env == vsEnv { + return true + } + } + return false +} + +func (w *WorkerManagerHandler) CreateUpdateDeleteVirtualServices(ctx *common.Context, wm *manager.WorkerManager, confVs map[string]*v1alpha3.VirtualService, trafficconfig *v1.TrafficConfig) error { + + dependents := w.RemoteRegistry.AdmiralCache.IdentityDependencyCache.Get(trafficconfig.Labels["asset"]).Copy() + if dependents == nil { + // Nothing to Do. + ctx.Log.Infof("No Dependent Services Found For Asset: %v \n", trafficconfig.Labels["asset"]) + return nil + } + + var dependentClusters = make(map[string]string) + for depIdentity := range dependents { + clusters := w.RemoteRegistry.AdmiralCache.IdentityClusterCache.Get(depIdentity) + if clusters == nil { + continue + } + clusters.Range(func(k string, clusterID string) { + dependentClusters[clusterID] = clusterID + }) + } + + ctx.Log.Infof("Dependent Clusters for Asset: %v, are: %v \n", trafficconfig.Labels["asset"], dependentClusters) + + for cluster, _ := range dependentClusters { + rc := w.RemoteRegistry.GetRemoteWorkerManager(cluster) + ctx.Log.Infof("Create Update Delete Virtual Service in Cluster: %v \n", cluster) + if rc != nil { + addEnvs, updateEnvs, deleteEnvs, existingVS := w.getCreateUpdateDeleteEnvLists(ctx, rc, trafficconfig, confVs) + w.crudVirtualService(ctx, rc, addEnvs, updateEnvs, deleteEnvs, existingVS, confVs) + } else { + ctx.Log.Infof("Ignore Cluster %v. Remote Controller Is NULL \n", cluster) + } + } + + return nil +} + +func (w *WorkerManagerHandler) crudVirtualService(ctx *common.Context, rc *RemoteWorkerManager, addEnvs []string, updateEnvs []string, deleteEnvs []string, existingVS *v1alpha3.VirtualServiceList, confVs map[string]*v1alpha3.VirtualService) { + + // Create VS + for _, eachVSEnv := range addEnvs { + v := confVs[eachVSEnv] + _, err := rc.WorkerManager.IstioClient.NetworkingV1alpha3().VirtualServices(v.Namespace).Create(context.TODO(), v, metaV1.CreateOptions{}) + if err != nil { + ctx.Log.Errorf("Error Creating Virtual Service %v. error - %v \n", v.Name, err) + //return err + } else { + ctx.Log.Infof("Successfully Created Virtual Service %v \n", v.Name) + } + } + + // Update VS + for _, eachVSEnv := range updateEnvs { + v := confVs[eachVSEnv] + // Update Resource Version + for _, existingVS := range existingVS.Items { + if existingVS.Annotations[common.CreatedForEnv] == eachVSEnv { + v.ObjectMeta.SetResourceVersion(existingVS.ObjectMeta.GetResourceVersion()) + _, err := rc.WorkerManager.IstioClient.NetworkingV1alpha3().VirtualServices(v.Namespace).Update(context.TODO(), v, metaV1.UpdateOptions{}) + if err != nil { + ctx.Log.Errorf("Error Updating Virtual Service %v. error - %v \n", v.Name, err) + //return err + } else { + ctx.Log.Infof("Successfully Updated Virtual Service %v \n", v.Name) + } + break + } + } + } + + // Delete VS (Environment is not present in configured list, but is present in existing list) + for _, eachVSEnv := range deleteEnvs { + for _, existingVS := range existingVS.Items { + if eachVSEnv == existingVS.ObjectMeta.Annotations[common.CreatedForEnv] { + err := rc.WorkerManager.IstioClient.NetworkingV1alpha3().VirtualServices(existingVS.Namespace).Delete(context.TODO(), existingVS.Name, metaV1.DeleteOptions{}) + if err != nil { + ctx.Log.Errorf("Error Deleting Virtual Service %v error - %v \n", existingVS.Name, err) + } else { + ctx.Log.Infof("Successfully Deleted Virtual Service %v in Cluster %v \n", existingVS.Name) + } + } + } + } +} + +func (w *WorkerManagerHandler) getCreateUpdateDeleteEnvLists(ctx *common.Context, rc *RemoteWorkerManager, trafficconfig *v1.TrafficConfig, confVs map[string]*v1alpha3.VirtualService) ([]string, []string, []string, *v1alpha3.VirtualServiceList) { + + var addEnvs = make([]string, 0) + var updateEnvs = make([]string, 0) + var deleteEnvs = make([]string, 0) + + // Get a list of existing virtual services. IMPORTANT: Change to Cache + values, err := rc.WorkerManager.IstioClient.NetworkingV1alpha3().VirtualServices("admiral-sync").List(context.TODO(), metaV1.ListOptions{LabelSelector: "createdFor=" + trafficconfig.Labels["asset"]}) + + if err != nil { + // API Server not available!! + ctx.Log.Errorf("Error Fetching Existing Virtual Service %v \n", err) + } + + toBeDeleted := false + if trafficconfig.Annotations != nil { + if val, ok := trafficconfig.Annotations[common.IsDisabled]; ok { + if val == "true" { + toBeDeleted = true + } + } + } + + listOfExistingVSENVs := make([]string, 0) + listOfConfiguredVSENVs := make([]string, 0) + + for _, existingVS := range values.Items { + listOfExistingVSENVs = append(listOfExistingVSENVs, existingVS.ObjectMeta.Annotations[common.CreatedForEnv]) + } + + for _, confVS := range confVs { + listOfConfiguredVSENVs = append(listOfConfiguredVSENVs, confVS.ObjectMeta.Annotations[common.CreatedForEnv]) + } + + if toBeDeleted { + // Mark All Existing VS for deletion + for _, eachExistingEnv := range listOfExistingVSENVs { + deleteEnvs = append(deleteEnvs, eachExistingEnv) + } + } else { + /* + Use case-1 + Configured VS Envs : qal, qal-1, qal-2 + Existing: + Outcome: Create qal, qal-1, qal-2 + + Use case-2 + Configured VS Envs : qal, qal-1, qal-2 + Existing: qal, qal-1, qal-2 + Outcome: Update qal, qal-1, qal-2 + + Use case-3 + Configured VS Envs : qal-1, qal-2 + Existing: qal, qal-1, qal-2 + Outcome: Update qal-1, qal-2, Delete qal + + Use case-4 + Configured VS Envs : qal-1, qal-2, qal-0 + Existing: qal, qal-1, qal-2 + Outcome: Update qal-1, qal-2, Delete qal, Create qal-0 + + */ + // Mark Update & Delete Environments + for _, eachExistingEnv := range listOfExistingVSENVs { + // Existing ENV is Present in Configured List. + if isVsEnvExisting(eachExistingEnv, listOfConfiguredVSENVs) { + updateEnvs = append(updateEnvs, eachExistingEnv) + } else { + deleteEnvs = append(deleteEnvs, eachExistingEnv) + } + } + + // Mark Create Environments + for _, configuredEnv := range listOfConfiguredVSENVs { + // Configured ENV is NOT Present in Existing List. + if !isVsEnvExisting(configuredEnv, listOfExistingVSENVs) { + addEnvs = append(addEnvs, configuredEnv) + } + } + } + return addEnvs, updateEnvs, deleteEnvs, values +} + +// 1. For All Configured Virtual Services qal1 qal2 +// 2. get dependent clusters. cluster-c1, cluster-c2 +// 3. Get virtual services in cluster-c1 & cluster-c2 +// 4. Make a list of add update delete vs. diff --git a/admiral/pkg/controller/admiral/admiralclient.go b/admiral/pkg/controller/admiral/admiralclient.go index e3e973d2a..25ba228f3 100644 --- a/admiral/pkg/controller/admiral/admiralclient.go +++ b/admiral/pkg/controller/admiral/admiralclient.go @@ -2,6 +2,7 @@ package admiral import ( "fmt" + istioclientset "istio.io/client-go/pkg/clientset/versioned" log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" @@ -24,6 +25,19 @@ func AdmiralCrdClientFromConfig(config *rest.Config) (clientset.Interface, error return clientset.NewForConfig(config) } +// IstioKubeClientFromConfig returns istio client using InCluster kubeconfig. +func IstioKubeClientFromConfig(config *rest.Config) (istioclientset.Interface, error) { + return istioclientset.NewForConfig(config) +} + +func IstioKubeClientFromPath(kubeConfigPath string) (istioclientset.Interface, error) { + config, err := getConfig(kubeConfigPath) + if err != nil || config == nil { + return nil, err + } + return IstioKubeClientFromConfig(config) +} + func K8sClientFromConfig(config *rest.Config) (kubernetes.Interface, error) { return kubernetes.NewForConfig(config) } diff --git a/admiral/pkg/controller/admiral/envoyfilter.go b/admiral/pkg/controller/admiral/envoyfilter.go new file mode 100644 index 000000000..3b38295de --- /dev/null +++ b/admiral/pkg/controller/admiral/envoyfilter.go @@ -0,0 +1,71 @@ +package admiral + +import ( + "context" + "fmt" + clientset "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned" + log "github.com/sirupsen/logrus" + networking "istio.io/client-go/pkg/apis/networking/v1alpha3" + istioclientset "istio.io/client-go/pkg/clientset/versioned" + networkingv1alpha3 "istio.io/client-go/pkg/informers/externalversions/networking/v1alpha3" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "time" +) + +// EnvoyFilterHandler interface contains the methods that are required +type EnvoyFilterHandler interface { + Added(ctx context.Context, obj *networking.EnvoyFilter) + Updated(ctx context.Context, obj *networking.EnvoyFilter) + Deleted(ctx context.Context, obj *networking.EnvoyFilter) +} + +type EnvoyFilterController struct { + CrdClient clientset.Interface + IstioClient istioclientset.Interface + EnvoyFilterHandler EnvoyFilterHandler + informer cache.SharedIndexInformer +} + +func (e *EnvoyFilterController) Added(ctx context.Context, ojb interface{}) { + ef := ojb.(*networking.EnvoyFilter) + e.EnvoyFilterHandler.Added(ctx, ef) +} + +func (e *EnvoyFilterController) Updated(ctx context.Context, ojb interface{}, oldObj interface{}) { + ef := ojb.(*networking.EnvoyFilter) + e.EnvoyFilterHandler.Updated(ctx, ef) +} + +func (e *EnvoyFilterController) Deleted(ctx context.Context, ojb interface{}) { + ef := ojb.(*networking.EnvoyFilter) + e.EnvoyFilterHandler.Deleted(ctx, ef) +} + +func NewEnvoyFilterController(stopCh <-chan struct{}, handler EnvoyFilterHandler, config *rest.Config, resyncPeriod time.Duration) (*EnvoyFilterController, error) { + envoyFilterController := EnvoyFilterController{} + envoyFilterController.EnvoyFilterHandler = handler + + var err error + + envoyFilterController.CrdClient, err = AdmiralCrdClientFromConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create traffic config controller crd client: %v", err) + } + + envoyFilterController.IstioClient, err = IstioKubeClientFromConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create traffic config controller crd client: %v", err) + } + + envoyFilterController.informer = networkingv1alpha3.NewEnvoyFilterInformer( + envoyFilterController.IstioClient, + meta_v1.NamespaceAll, // TODO - change this to - admiral-sync namespace in future + resyncPeriod, + cache.Indexers{}, + ) + NewController("envoy-filter--ctrl-"+config.Host, stopCh, &envoyFilterController, envoyFilterController.informer) + log.Debugln("NewEnvoyFilterController created....") + return &envoyFilterController, nil +} diff --git a/admiral/pkg/controller/admiral/trafficconfig.go b/admiral/pkg/controller/admiral/trafficconfig.go new file mode 100644 index 000000000..39cb1f525 --- /dev/null +++ b/admiral/pkg/controller/admiral/trafficconfig.go @@ -0,0 +1,72 @@ +package admiral + +import ( + "context" + "fmt" + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + clientset "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned" + informerV1 "github.com/istio-ecosystem/admiral/admiral/pkg/client/informers/externalversions/admiral/v1" + log "github.com/sirupsen/logrus" + istioclientset "istio.io/client-go/pkg/clientset/versioned" + "k8s.io/client-go/tools/cache" + "sync" + "time" +) + +// TrafficConfigHandler interface contains the methods that are required +type TrafficConfigHandler interface { + Added(ctx context.Context, obj *v1.TrafficConfig) + Updated(ctx context.Context, obj *v1.TrafficConfig) + Deleted(ctx context.Context, obj *v1.TrafficConfig) +} + +type TrafficConfigController struct { + CrdClient clientset.Interface + // WorkerMap map[string]clusters.WorkManagerObj + WorkerMap sync.Map + IstioClient istioclientset.Interface + TrafficConfigHandler TrafficConfigHandler + informer cache.SharedIndexInformer +} + +// var TrafficConfigMap map[string]<-chan *v1.TrafficConfig // Creating new map for sharing details to remote clusters + +func (t *TrafficConfigController) Added(ctx context.Context, ojb interface{}) { + uc := ojb.(*v1.TrafficConfig) + t.TrafficConfigHandler.Added(ctx, uc) +} + +func (t *TrafficConfigController) Updated(ctx context.Context, ojb interface{}, oldObj interface{}) { + tc := ojb.(*v1.TrafficConfig) + t.TrafficConfigHandler.Updated(ctx, tc) +} + +func (t *TrafficConfigController) Deleted(ctx context.Context, ojb interface{}) { + tc := ojb.(*v1.TrafficConfig) + t.TrafficConfigHandler.Deleted(ctx, tc) +} + +func NewTrafficConfigController(stopCh <-chan struct{}, handler TrafficConfigHandler, configPath string, namespace string, resyncPeriod time.Duration) (*TrafficConfigController, error) { + trafficConfigController := TrafficConfigController{} + trafficConfigController.TrafficConfigHandler = handler + var err error + trafficConfigController.CrdClient, err = AdmiralCrdClientFromPath(configPath) + if err != nil { + return nil, fmt.Errorf("failed to create traffic config controller crd client: %v", err) + } + + trafficConfigController.IstioClient, err = IstioKubeClientFromPath(configPath) + if err != nil { + return nil, fmt.Errorf("failed to create traffic config controller crd client: %v", err) + } + + trafficConfigController.informer = informerV1.NewTrafficConfigInformer( + trafficConfigController.CrdClient, + namespace, + resyncPeriod, + cache.Indexers{}, + ) + NewController("traffic-config-ctrl-"+configPath, stopCh, &trafficConfigController, trafficConfigController.informer) + log.Debugln("NewTrafficConfigController created....") + return &trafficConfigController, nil +} diff --git a/admiral/pkg/controller/common/common.go b/admiral/pkg/controller/common/common.go index 048648e10..a753b3f73 100644 --- a/admiral/pkg/controller/common/common.go +++ b/admiral/pkg/controller/common/common.go @@ -46,6 +46,19 @@ const ( WASMPath = "wasmPath" AdmiralProfileIntuit = "intuit" AdmiralProfileDefault = "default" + AdmiralUnification = "admiral-unification" + CreatedBy = "createdBy" + CreatedFor = "createdFor" + CreatedForEnv = "createdForEnv" + IsDisabled = "isDisabled" + TransactionID = "transactionID" + RevisionNumber = "revisionNumber" + EnvoyKind = "EnvoyFilter" + EnvoyApiVersion = "networking.istio.io/v1alpha3" + SlashSTARRule = "/*" + AppThrottleConfigVersion = "v1" + LogLevel = "info" + AssetLabel = "asset" ) type Event int diff --git a/admiral/pkg/controller/common/config.go b/admiral/pkg/controller/common/config.go index ddbd6247d..1bd16e2fe 100644 --- a/admiral/pkg/controller/common/config.go +++ b/admiral/pkg/controller/common/config.go @@ -139,4 +139,12 @@ func SetEnablePrometheus(value bool) { func SetArgoRolloutsEnabled(value bool) { admiralParams.ArgoRolloutsEnabled = value -} \ No newline at end of file +} + +func IsPersonaTrafficConfig() bool { + return admiralParams.TrafficConfigPersona == true +} + +func IsDefaultPersona() bool { + return admiralParams.TrafficConfigPersona == false +} diff --git a/admiral/pkg/controller/common/types.go b/admiral/pkg/controller/common/types.go index 6bec16745..16c0f0575 100644 --- a/admiral/pkg/controller/common/types.go +++ b/admiral/pkg/controller/common/types.go @@ -2,6 +2,8 @@ package common import ( "fmt" + v1 "github.com/istio-ecosystem/admiral/admiral/pkg/apis/admiral/v1" + log "github.com/sirupsen/logrus" "sync" "time" ) @@ -22,7 +24,7 @@ type SidecarEgress struct { CNAMEs map[string]string } -//maintains a map from workload identity -> map[namespace]SidecarEgress +// maintains a map from workload identity -> map[namespace]SidecarEgress type SidecarEgressMap struct { cache map[string]map[string]SidecarEgress mutex *sync.Mutex @@ -34,6 +36,7 @@ type AdmiralParams struct { CacheRefreshDuration time.Duration ClusterRegistriesNamespace string DependenciesNamespace string + TrafficConfigNamespace string SyncNamespace string EnableSAN bool SANPrefix string @@ -53,6 +56,7 @@ type AdmiralParams struct { EnvoyFilterAdditionalConfig string EnableRoutingPolicy bool ExcludedIdentityList []string + TrafficConfigPersona bool } func (b AdmiralParams) String() string { @@ -69,7 +73,9 @@ func (b AdmiralParams) String() string { fmt.Sprintf("DRStateStoreConfigPath=%v ", b.DRStateStoreConfigPath) + fmt.Sprintf("ServiceEntryIPPrefix=%v ", b.ServiceEntryIPPrefix) + fmt.Sprintf("EnvoyFilterVersion=%v ", b.EnvoyFilterVersion) + - fmt.Sprintf("EnableRoutingPolicy=%v ", b.EnableRoutingPolicy) + fmt.Sprintf("EnableRoutingPolicy=%v ", b.EnableRoutingPolicy) + + fmt.Sprintf("TrafficConfigNamespace=%v ", b.TrafficConfigNamespace) + + fmt.Sprintf("TrafficConfigPersona=%v ", b.TrafficConfigPersona) } type LabelSet struct { @@ -85,6 +91,17 @@ type LabelSet struct { GatewayApp string //the value for `app` key that will be used to fetch the loadblancer for cross cluster calls, also referred to as east west gateway } +type TrafficObject struct { + TrafficConfig *v1.TrafficConfig + Ctx *Context + Event string +} + +type Context struct { + Log *log.Entry + Property map[string]string +} + func NewSidecarEgressMap() *SidecarEgressMap { n := new(SidecarEgressMap) n.cache = make(map[string]map[string]SidecarEgress) @@ -184,6 +201,16 @@ func (s *MapOfMaps) Range(fn func(k string, v *Map)) { s.mutex.Unlock() } +func (s *Map) GetKeys() []string { + defer s.mutex.Unlock() + s.mutex.Lock() + keys := make([]string, 0) + for _, val := range s.cache { + keys = append(keys, val) + } + return keys +} + func (s *SidecarEgressMap) Put(identity string, namespace string, fqdn string, cnames map[string]string) { defer s.mutex.Unlock() s.mutex.Lock() diff --git a/admiral/pkg/manager/workermanager.go b/admiral/pkg/manager/workermanager.go new file mode 100644 index 000000000..db1adc0ca --- /dev/null +++ b/admiral/pkg/manager/workermanager.go @@ -0,0 +1,59 @@ +package manager + +import ( + "fmt" + clientset "github.com/istio-ecosystem/admiral/admiral/pkg/client/clientset/versioned" + "github.com/istio-ecosystem/admiral/admiral/pkg/controller/admiral" + "github.com/istio-ecosystem/admiral/admiral/pkg/controller/common" + istioclientset "istio.io/client-go/pkg/clientset/versioned" + "k8s.io/client-go/rest" + "time" +) + +type WorkerManager struct { + CRDClient clientset.Interface + IstioClient istioclientset.Interface + WorkerHandler WorkerHandler + ClusterID string + ResyncPeriod time.Duration +} + +type WorkerHandler interface { + ProcessQueue(<-chan struct{}) error + ProcessItem(object *common.TrafficObject) error + AddClusterEntry(string) +} + +// TODO: 1. Propogate stopCh to gracefully terminate the workerManager. +// TODO: 2. Compare methods implemented here with controller.go +func NewWorkerManager(stopCh <-chan struct{}, handler WorkerHandler, clusterID string, config *rest.Config, resyncPeriod time.Duration) (*WorkerManager, error) { + m := &WorkerManager{} + crdClient, err := admiral.AdmiralCrdClientFromConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create worker manager crd-client: %v", err) + } + istioClient, err := admiral.IstioKubeClientFromConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create worker manager istio-client: %v", err) + } + m.CRDClient = crdClient + m.IstioClient = istioClient + m.WorkerHandler = handler + m.ClusterID = clusterID + m.ResyncPeriod = resyncPeriod + m.AddClusterEntry(clusterID) + go m.ProcessQueue(stopCh) // TODO : What will happen when this function will receive stop signal on stopCh channel. + return m, nil +} + +func (w *WorkerManager) ProcessQueue(stopCh <-chan struct{}) error { + go w.WorkerHandler.ProcessQueue(stopCh) + return nil +} +func (w *WorkerManager) AddClusterEntry(clusterID string) { + w.WorkerHandler.AddClusterEntry(clusterID) +} + +func (w *WorkerManager) ProcessItem(obj *common.TrafficObject) error { + return w.WorkerHandler.ProcessItem(obj) +} diff --git a/go.mod b/go.mod index 7b57abe4d..55e972f0d 100644 --- a/go.mod +++ b/go.mod @@ -5,19 +5,19 @@ go 1.18 require ( github.com/argoproj/argo-rollouts v1.2.1 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/golang/protobuf v1.5.2 - github.com/google/go-cmp v0.5.7 + github.com/google/go-cmp v0.5.9 github.com/gorilla/mux v1.8.0 github.com/imdario/mergo v0.3.12 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/onsi/gomega v1.19.0 github.com/prometheus/client_golang v1.12.2 github.com/prometheus/client_model v0.2.0 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 - github.com/stretchr/testify v1.7.1 - golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + github.com/stretchr/testify v1.8.1 + golang.org/x/net v0.6.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect google.golang.org/genproto v0.0.0-20220531134929-86cf59382f1b // indirect gopkg.in/yaml.v2 v2.4.0 @@ -26,7 +26,7 @@ require ( k8s.io/api v0.24.2 k8s.io/apimachinery v0.24.2 k8s.io/client-go v0.24.2 - sigs.k8s.io/yaml v1.2.0 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) require ( @@ -37,6 +37,8 @@ require ( google.golang.org/protobuf v1.28.1 ) +require github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect + require ( cloud.google.com/go/compute v1.6.1 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect @@ -44,17 +46,17 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-co-op/gocron v1.13.0 // indirect - github.com/go-logr/logr v1.2.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/gnostic v0.6.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.1.2 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/intuit/funnel v1.0.0 // indirect @@ -68,14 +70,13 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.3.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/tevino/abool v1.2.0 // indirect github.com/ugorji/go/codec v1.2.7 // indirect github.intuit.com/idps/device-grant-flow/go/dgfsdk v0.0.0-20220428022612-cf054cda65f7 // indirect @@ -84,22 +85,21 @@ require ( go.opencensus.io v0.23.0 // indirect golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.5.0 // indirect + golang.org/x/term v0.5.0 // indirect + golang.org/x/text v0.7.0 // indirect google.golang.org/api v0.76.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/grpc v1.46.2 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.60.1 // indirect - k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8 // indirect + k8s.io/klog/v2 v2.90.0 // indirect + k8s.io/kube-openapi v0.0.0-20230210211930-4b0756abdef5 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) replace ( diff --git a/go.sum b/go.sum index 1604d8c37..b2e26fb42 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,7 @@ github.com/aws/aws-sdk-go v1.44.105 h1:UUwoD1PRKIj3ltrDUYTDQj5fOTK3XsnqolLpRTMmS github.com/aws/aws-sdk-go v1.44.105/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -85,6 +86,8 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -110,8 +113,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -124,6 +127,7 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -139,21 +143,22 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -195,8 +200,9 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -209,11 +215,13 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -287,14 +295,17 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/resync v0.0.0-20161211202428-d39c09a11215 h1:hDa3vAq/Zo5gjfJ46XMsGFbH+hTizpR4fUzQCk2nxgk= github.com/matryer/resync v0.0.0-20161211202428-d39c09a11215/go.mod h1:LH+NgPY9AJpDfqAFtzyer01N9MYNsAKUf3DC9DV1xIY= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -316,18 +327,13 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -367,22 +373,29 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0= github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA= github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -487,13 +500,15 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -524,8 +539,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -565,7 +581,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -593,11 +608,13 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -606,8 +623,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -659,7 +677,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -672,7 +689,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -781,6 +797,7 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= @@ -848,13 +865,13 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -890,11 +907,12 @@ k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M= +k8s.io/klog/v2 v2.90.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8 h1:30P0UV8MQgg4f1khIUT09xHmpI5B5Wg0Vg6JNkUqsQ0= -k8s.io/kube-openapi v0.0.0-20220621154418-c39d0f63fac8/go.mod h1:PNbiP2hKArDh8cgJZTDL6Ss/z3wsbga8yjj/7VMB+I4= +k8s.io/kube-openapi v0.0.0-20230210211930-4b0756abdef5 h1:/zkKSeCtGRHYqRmrpa9uPYDWMpmQ5bZijBSoOpW384c= +k8s.io/kube-openapi v0.0.0-20230210211930-4b0756abdef5/go.mod h1:/BYxry62FuDzmI+i9B+X2pqfySRmSOW2ARmj5Zbqhj0= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -905,7 +923,9 @@ sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ= sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/install/admiralremote/base/remote.yaml b/install/admiralremote/base/remote.yaml index 94a852238..338d8c081 100644 --- a/install/admiralremote/base/remote.yaml +++ b/install/admiralremote/base/remote.yaml @@ -24,7 +24,7 @@ rules: resources: ['virtualservices', 'destinationrules', 'serviceentries', 'envoyfilters' ,'gateways', 'sidecars'] verbs: [ "get", "list", "watch"] - apiGroups: ["admiral.io"] - resources: ['globaltrafficpolicies', 'routingpolicies'] + resources: ['globaltrafficpolicies', 'routingpolicies',"trafficonfigs"] verbs: [ "get", "list", "watch"] - apiGroups: ["argoproj.io"] resources: ['rollouts']