mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 09:38:49 +01:00
Compare commits
43 Commits
crenshaw-d
...
v1.3.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f8608c9fc | ||
|
|
4c42c5fc70 | ||
|
|
1c01f9b7f5 | ||
|
|
24d43e45f7 | ||
|
|
22826baf46 | ||
|
|
58675b5266 | ||
|
|
786a94b03b | ||
|
|
79e364228a | ||
|
|
fba1c0d4f3 | ||
|
|
65e427eb4f | ||
|
|
a808fd2989 | ||
|
|
947b074d9a | ||
|
|
53252aa6a1 | ||
|
|
9df5e9560a | ||
|
|
7a9f7b01f8 | ||
|
|
52f7a66826 | ||
|
|
bcdaddcf69 | ||
|
|
593715038c | ||
|
|
4f84498265 | ||
|
|
8186ff0bb9 | ||
|
|
0432a85832 | ||
|
|
a0d37654b4 | ||
|
|
fe3b17322a | ||
|
|
59623b85fe | ||
|
|
905a8b0d75 | ||
|
|
30935e2019 | ||
|
|
f3e0e097de | ||
|
|
e1ff01cb56 | ||
|
|
e0de3300d2 | ||
|
|
40cb6fa9ce | ||
|
|
11de95cbac | ||
|
|
c7cd2e92bb | ||
|
|
a4f13f5f29 | ||
|
|
6460de9d03 | ||
|
|
6f6b03f74c | ||
|
|
36775ae1bb | ||
|
|
4a360cf9f4 | ||
|
|
6e56302fa4 | ||
|
|
3d82d5aab7 | ||
|
|
7df03b3c89 | ||
|
|
e059760906 | ||
|
|
8925b52bc8 | ||
|
|
8a43840f0b |
49
Dockerfile
49
Dockerfile
@@ -23,47 +23,16 @@ RUN apt-get update && apt-get install -y \
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
# Install dep
|
||||
ENV DEP_VERSION=0.5.0
|
||||
RUN wget https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -O /usr/local/bin/dep && \
|
||||
chmod +x /usr/local/bin/dep
|
||||
ADD hack/install.sh .
|
||||
ADD hack/installers installers
|
||||
|
||||
# Install packr
|
||||
ENV PACKR_VERSION=1.21.9
|
||||
RUN wget https://github.com/gobuffalo/packr/releases/download/v${PACKR_VERSION}/packr_${PACKR_VERSION}_linux_amd64.tar.gz && \
|
||||
tar -vxf packr*.tar.gz -C /tmp/ && \
|
||||
mv /tmp/packr /usr/local/bin/packr
|
||||
|
||||
# Install kubectl
|
||||
# NOTE: keep the version synced with https://storage.googleapis.com/kubernetes-release/release/stable.txt
|
||||
ENV KUBECTL_VERSION=1.14.0
|
||||
RUN curl -L -o /usr/local/bin/kubectl -LO https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl && \
|
||||
chmod +x /usr/local/bin/kubectl && \
|
||||
kubectl version --client
|
||||
|
||||
# Install ksonnet
|
||||
ENV KSONNET_VERSION=0.13.1
|
||||
RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION}/ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
|
||||
tar -C /tmp/ -xf ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
|
||||
mv /tmp/ks_${KSONNET_VERSION}_linux_amd64/ks /usr/local/bin/ks && \
|
||||
ks version
|
||||
|
||||
# Install helm
|
||||
ENV HELM_VERSION=2.12.1
|
||||
RUN wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
|
||||
tar -C /tmp/ -xf helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
|
||||
mv /tmp/linux-amd64/helm /usr/local/bin/helm && \
|
||||
helm version --client
|
||||
|
||||
ENV KUSTOMIZE_VERSION=3.1.0
|
||||
RUN curl -L -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 && \
|
||||
chmod +x /usr/local/bin/kustomize && \
|
||||
kustomize version
|
||||
|
||||
# Install AWS IAM Authenticator
|
||||
ENV AWS_IAM_AUTHENTICATOR_VERSION=0.4.0-alpha.1
|
||||
RUN curl -L -o /usr/local/bin/aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/${AWS_IAM_AUTHENTICATOR_VERSION}/aws-iam-authenticator_${AWS_IAM_AUTHENTICATOR_VERSION}_linux_amd64 && \
|
||||
chmod +x /usr/local/bin/aws-iam-authenticator
|
||||
RUN ./install.sh dep-linux
|
||||
RUN ./install.sh packr-linux
|
||||
RUN ./install.sh kubectl-linux
|
||||
RUN ./install.sh ksonnet-linux
|
||||
RUN ./install.sh helm-linux
|
||||
RUN ./install.sh kustomize-linux
|
||||
RUN ./install.sh aws-iam-authenticator-linux
|
||||
|
||||
####################################################################################################
|
||||
# Argo CD Base - used as the base for both the release and dev argocd images
|
||||
|
||||
@@ -77,7 +77,7 @@ func newCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
|
||||
kubectl := kube.KubectlCmd{}
|
||||
kubectl := &kube.KubectlCmd{}
|
||||
appController, err := controller.NewApplicationController(
|
||||
namespace,
|
||||
settingsMgr,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"syscall"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -108,7 +109,7 @@ func NewRunDexCommand() *cobra.Command {
|
||||
} else {
|
||||
err = ioutil.WriteFile("/tmp/dex.yaml", dexCfgBytes, 0644)
|
||||
errors.CheckError(err)
|
||||
log.Info(string(dexCfgBytes))
|
||||
log.Info(redactor(string(dexCfgBytes)))
|
||||
cmd = exec.Command("dex", "serve", "/tmp/dex.yaml")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -532,6 +533,11 @@ func NewClusterConfig() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
func redactor(dirtyString string) string {
|
||||
dirtyString = regexp.MustCompile("(clientSecret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
|
||||
return regexp.MustCompile("(secret: )[^ \n]*").ReplaceAllString(dirtyString, "$1********")
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := NewCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
73
cmd/argocd-util/main_test.go
Normal file
73
cmd/argocd-util/main_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var textToRedact = `
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: $dex.github.clientSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: Dis9M-GA11oTwZVQQWdDklPQw-sWXZkWJFyyEhMs
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
web:
|
||||
http: 0.0.0.0:5556`
|
||||
|
||||
var expectedRedaction = `
|
||||
- config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: ********
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
redirectURI: https://argocd.example.com/api/dex/callback
|
||||
id: github
|
||||
name: GitHub
|
||||
type: github
|
||||
grpc:
|
||||
addr: 0.0.0.0:5557
|
||||
issuer: https://argocd.example.com/api/dex
|
||||
oauth2:
|
||||
skipApprovalScreen: true
|
||||
staticClients:
|
||||
- id: argo-cd
|
||||
name: Argo CD
|
||||
redirectURIs:
|
||||
- https://argocd.example.com/auth/callback
|
||||
secret: ********
|
||||
- id: argo-cd-cli
|
||||
name: Argo CD CLI
|
||||
public: true
|
||||
redirectURIs:
|
||||
- http://localhost
|
||||
storage:
|
||||
type: memory
|
||||
web:
|
||||
http: 0.0.0.0:5556`
|
||||
|
||||
func TestSecretsRedactor(t *testing.T) {
|
||||
assert.Equal(t, expectedRedaction, redactor(textToRedact))
|
||||
}
|
||||
@@ -972,8 +972,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
}
|
||||
|
||||
foundDiffs = true
|
||||
err = diff.PrintDiff(item.key.Name, target, live)
|
||||
errors.CheckError(err)
|
||||
_ = diff.PrintDiff(item.key.Name, target, live)
|
||||
}
|
||||
}
|
||||
if foundDiffs {
|
||||
@@ -1962,7 +1961,7 @@ func filterResources(command *cobra.Command, resources []*argoappv1.ResourceDiff
|
||||
if resourceName != "" && resourceName != obj.GetName() {
|
||||
continue
|
||||
}
|
||||
if kind != "" && kind != gvk.Kind {
|
||||
if kind != gvk.Kind {
|
||||
continue
|
||||
}
|
||||
copy := obj.DeepCopy()
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -121,7 +120,8 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt
|
||||
func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var namespace string
|
||||
var resourceName string
|
||||
var kindArg string
|
||||
var kind string
|
||||
var group string
|
||||
var all bool
|
||||
var command = &cobra.Command{
|
||||
Use: "run APPNAME ACTION",
|
||||
@@ -130,7 +130,9 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
|
||||
|
||||
command.Flags().StringVar(&resourceName, "resource-name", "", "Name of resource")
|
||||
command.Flags().StringVar(&namespace, "namespace", "", "Namespace")
|
||||
command.Flags().StringVar(&kindArg, "kind", "", "Kind")
|
||||
command.Flags().StringVar(&kind, "kind", "", "Kind")
|
||||
command.Flags().StringVar(&group, "group", "", "Group")
|
||||
errors.CheckError(command.MarkFlagRequired("kind"))
|
||||
command.Flags().BoolVar(&all, "all", false, "Indicates whether to run the action on multiple matching resources")
|
||||
|
||||
command.Run = func(c *cobra.Command, args []string) {
|
||||
@@ -146,31 +148,14 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
|
||||
ctx := context.Background()
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
errors.CheckError(err)
|
||||
|
||||
var group string
|
||||
var kind string
|
||||
var actionNameOnly string
|
||||
// Backwards comparability for running resume actions
|
||||
if actionName == "resume" && kindArg == "Rollout" {
|
||||
group = "argoproj.io"
|
||||
kind = "Rollout"
|
||||
actionNameOnly = "resume"
|
||||
commandTail := ""
|
||||
if resourceName != "" {
|
||||
commandTail += " --resource-name " + resourceName
|
||||
filteredObjects := filterResources(command, resources.Items, group, kind, namespace, resourceName, all)
|
||||
var resGroup = filteredObjects[0].GroupVersionKind().Group
|
||||
for i := range filteredObjects[1:] {
|
||||
if filteredObjects[i].GroupVersionKind().Group != resGroup {
|
||||
log.Fatal("Ambiguous resource group. Use flag --group to specify resource group explicitly.")
|
||||
}
|
||||
if namespace != "" {
|
||||
commandTail += " --namespace " + namespace
|
||||
}
|
||||
if all {
|
||||
commandTail += " --all"
|
||||
}
|
||||
fmt.Printf("\nWarning: this syntax for running the \"resume\" action has been deprecated. Please run the action as\n\n\targocd app actions run %s argoproj.io/Rollout/resume%s\n\n", appName, commandTail)
|
||||
} else {
|
||||
group, kind, actionNameOnly = parseActionName(actionName)
|
||||
}
|
||||
|
||||
filteredObjects := filterResources(command, resources.Items, group, kind, namespace, resourceName, all)
|
||||
for i := range filteredObjects {
|
||||
obj := filteredObjects[i]
|
||||
gvk := obj.GroupVersionKind()
|
||||
@@ -181,18 +166,10 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
|
||||
ResourceName: objResourceName,
|
||||
Group: gvk.Group,
|
||||
Kind: gvk.Kind,
|
||||
Action: actionNameOnly,
|
||||
Action: actionName,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
return command
|
||||
}
|
||||
|
||||
func parseActionName(action string) (string, string, string) {
|
||||
actionSplit := strings.Split(action, "/")
|
||||
if len(actionSplit) != 3 {
|
||||
log.Fatal("Action name is malformed")
|
||||
}
|
||||
return actionSplit[0], actionSplit[1], actionSplit[2]
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
|
||||
@@ -50,13 +51,20 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
)
|
||||
|
||||
// For better readability and easier formatting
|
||||
var repoAddExamples = `
|
||||
Add a SSH repository using a private key for authentication, ignoring the server's host key:",
|
||||
$ argocd repo add git@git.example.com --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa",
|
||||
Add a HTTPS repository using username/password and TLS client certificates:",
|
||||
$ argocd repo add https://git.example.com --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key",
|
||||
Add a HTTPS repository using username/password without verifying the server's TLS certificate:",
|
||||
$ argocd repo add https://git.example.com --username git --password secret --insecure-skip-server-verification",
|
||||
var repoAddExamples = ` # Add a Git repository via SSH using a private key for authentication, ignoring the server's host key:
|
||||
argocd repo add git@git.example.com:repos/repo --insecure-ignore-host-key --ssh-private-key-path ~/id_rsa
|
||||
|
||||
# Add a private Git repository via HTTPS using username/password and TLS client certificates:
|
||||
argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key
|
||||
|
||||
# Add a private Git repository via HTTPS using username/password without verifying the server's TLS certificate
|
||||
argocd repo add https://git.example.com/repos/repo --username git --password secret --insecure-skip-server-verification
|
||||
|
||||
# Add a public Helm repository named 'stable' via HTTPS
|
||||
argocd repo add https://kubernetes-charts.storage.googleapis.com --type helm --name stable
|
||||
|
||||
# Add a private Helm repository named 'stable' via HTTPS
|
||||
argocd repo add https://kubernetes-charts.storage.googleapis.com --type helm --name stable --username test --password test
|
||||
`
|
||||
|
||||
var command = &cobra.Command{
|
||||
@@ -113,6 +121,10 @@ Add a HTTPS repository using username/password without verifying the server's TL
|
||||
repo.Insecure = insecureSkipServerVerification
|
||||
repo.EnableLFS = enableLfs
|
||||
|
||||
if repo.Type == "helm" && repo.Name == "" {
|
||||
errors.CheckError(fmt.Errorf("Must specify --name for repos of type 'helm'"))
|
||||
}
|
||||
|
||||
conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie()
|
||||
defer util.Close(conn)
|
||||
|
||||
@@ -148,8 +160,8 @@ Add a HTTPS repository using username/password without verifying the server's TL
|
||||
fmt.Printf("repository '%s' added\n", createdRepo.Repo)
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&repo.Type, "type", "", "type of the repository, \"git\" or \"helm\"")
|
||||
command.Flags().StringVar(&repo.Name, "name", "", "name of the repository")
|
||||
command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"")
|
||||
command.Flags().StringVar(&repo.Name, "name", "", "name of the repository, mandatory for repositories of type helm")
|
||||
command.Flags().StringVar(&repo.Username, "username", "", "username to the repository")
|
||||
command.Flags().StringVar(&repo.Password, "password", "", "password to the repository")
|
||||
command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")
|
||||
|
||||
@@ -21,9 +21,10 @@ const (
|
||||
ArgoCDTLSCertsConfigMapName = "argocd-tls-certs-cm"
|
||||
)
|
||||
|
||||
// Default system namespace
|
||||
// Some default configurables
|
||||
const (
|
||||
DefaultSystemNamespace = "kube-system"
|
||||
DefaultRepoType = "git"
|
||||
)
|
||||
|
||||
// Default listener ports for ArgoCD components
|
||||
|
||||
@@ -803,6 +803,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
revision = app.Status.Sync.Revision
|
||||
}
|
||||
|
||||
observedAt := metav1.Now()
|
||||
compareResult := ctrl.appStateManager.CompareAppState(app, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
|
||||
|
||||
ctrl.normalizeApplication(origApp, app)
|
||||
@@ -830,8 +831,10 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
}
|
||||
}
|
||||
|
||||
app.Status.ObservedAt = &compareResult.reconciledAt
|
||||
app.Status.ReconciledAt = &compareResult.reconciledAt
|
||||
if app.Status.ReconciledAt == nil || comparisonLevel == CompareWithLatest {
|
||||
app.Status.ReconciledAt = &observedAt
|
||||
}
|
||||
app.Status.ObservedAt = &observedAt
|
||||
app.Status.Sync = *compareResult.syncStatus
|
||||
app.Status.Health = *compareResult.healthStatus
|
||||
app.Status.Resources = compareResult.resources
|
||||
@@ -850,23 +853,22 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
|
||||
compareWith := CompareWithLatest
|
||||
refreshType := appv1.RefreshTypeNormal
|
||||
expired := app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusRefreshTimeout).Before(time.Now().UTC())
|
||||
if requestedType, ok := app.IsRefreshRequested(); ok || expired {
|
||||
if ok {
|
||||
refreshType = requestedType
|
||||
reason = fmt.Sprintf("%s refresh requested", refreshType)
|
||||
} else if expired {
|
||||
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
|
||||
}
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
|
||||
compareWith = level
|
||||
reason = fmt.Sprintf("controller refresh requested")
|
||||
} else if app.Status.Sync.Status == appv1.SyncStatusCodeUnknown && expired {
|
||||
reason = "comparison status unknown"
|
||||
|
||||
if requestedType, ok := app.IsRefreshRequested(); ok {
|
||||
// user requested app refresh.
|
||||
refreshType = requestedType
|
||||
reason = fmt.Sprintf("%s refresh requested", refreshType)
|
||||
} else if expired {
|
||||
reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout)
|
||||
} else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) {
|
||||
reason = "spec.source differs"
|
||||
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
|
||||
reason = "spec.destination differs"
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
|
||||
compareWith = level
|
||||
reason = fmt.Sprintf("controller refresh requested")
|
||||
}
|
||||
|
||||
if reason != "" {
|
||||
logCtx.Infof("Refreshing app status (%s), level (%d)", reason, compareWith)
|
||||
return true, refreshType, compareWith
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -597,6 +598,24 @@ func TestNeedRefreshAppStatus(t *testing.T) {
|
||||
assert.Equal(t, argoappv1.RefreshTypeHard, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
}
|
||||
|
||||
{
|
||||
app := app.DeepCopy()
|
||||
// ensure that CompareWithLatest level is used if application source has changed
|
||||
ctrl.requestAppRefresh(app.Name, ComparisonWithNothing)
|
||||
// sample app source change
|
||||
app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{
|
||||
Parameters: []argoappv1.HelmParameter{{
|
||||
Name: "foo",
|
||||
Value: "bar",
|
||||
}},
|
||||
}
|
||||
|
||||
needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour)
|
||||
assert.True(t, needRefresh)
|
||||
assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType)
|
||||
assert.Equal(t, CompareWithLatest, compareWith)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshAppConditions(t *testing.T) {
|
||||
@@ -651,3 +670,63 @@ func TestRefreshAppConditions(t *testing.T) {
|
||||
assert.Equal(t, "Application referencing project wrong project which does not exist", app.Status.Conditions[0].Message)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdateReconciledAt(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second))
|
||||
app.Status = argoappv1.ApplicationStatus{ReconciledAt: &reconciledAt}
|
||||
app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.Source, Destination: app.Spec.Destination}}
|
||||
ctrl := newFakeController(&fakeData{
|
||||
apps: []runtime.Object{app, &defaultProj},
|
||||
manifestResponse: &apiclient.ManifestResponse{
|
||||
Manifests: []string{},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "abc123",
|
||||
},
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
})
|
||||
key, _ := cache.MetaNamespaceKeyFunc(app)
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
fakeAppCs.ReactionChain = nil
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
t.Run("UpdatedOnFullReconciliation", func(t *testing.T) {
|
||||
receivedPatch = map[string]interface{}{}
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest)
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
|
||||
ctrl.processAppRefreshQueueItem()
|
||||
|
||||
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
|
||||
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
})
|
||||
|
||||
t.Run("NotUpdatedOnPartialReconciliation", func(t *testing.T) {
|
||||
receivedPatch = map[string]interface{}{}
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithRecent)
|
||||
|
||||
ctrl.processAppRefreshQueueItem()
|
||||
|
||||
_, updated, err := unstructured.NestedString(receivedPatch, "status", "reconciledAt")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, updated)
|
||||
|
||||
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, updated)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ type AppStateManager interface {
|
||||
}
|
||||
|
||||
type comparisonResult struct {
|
||||
reconciledAt metav1.Time
|
||||
syncStatus *v1alpha1.SyncStatus
|
||||
healthStatus *v1alpha1.HealthStatus
|
||||
resources []v1alpha1.ResourceStatus
|
||||
@@ -275,13 +274,11 @@ func (m *appStateManager) getComparisonSettings(app *appv1.Application) (string,
|
||||
// revision and supplied source. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, noCache bool, localManifests []string) *comparisonResult {
|
||||
reconciledAt := metav1.Now()
|
||||
appLabelKey, resourceOverrides, diffNormalizer, err := m.getComparisonSettings(app)
|
||||
|
||||
// return unknown comparison result if basic comparison settings cannot be loaded
|
||||
if err != nil {
|
||||
return &comparisonResult{
|
||||
reconciledAt: reconciledAt,
|
||||
syncStatus: &v1alpha1.SyncStatus{
|
||||
ComparedTo: appv1.ComparedTo{Source: source, Destination: app.Spec.Destination},
|
||||
Status: appv1.SyncStatusCodeUnknown,
|
||||
@@ -435,6 +432,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
} else {
|
||||
resState.Status = v1alpha1.SyncStatusCodeSynced
|
||||
}
|
||||
// we can't say anything about the status if we were unable to get the target objects
|
||||
if failedToLoadObjs {
|
||||
resState.Status = v1alpha1.SyncStatusCodeUnknown
|
||||
}
|
||||
managedResources[i] = managedResource{
|
||||
Name: resState.Name,
|
||||
Namespace: resState.Namespace,
|
||||
@@ -472,7 +473,6 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
}
|
||||
|
||||
compRes := comparisonResult{
|
||||
reconciledAt: reconciledAt,
|
||||
syncStatus: &syncStatus,
|
||||
healthStatus: healthStatus,
|
||||
resources: resourceSummaries,
|
||||
|
||||
@@ -354,7 +354,6 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
|
||||
|
||||
assert.Equal(t, argoappv1.HealthStatusUnknown, compRes.healthStatus.Status)
|
||||
assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status)
|
||||
assert.NotNil(t, compRes.reconciledAt)
|
||||
}
|
||||
|
||||
func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) {
|
||||
|
||||
8
hack/installers/install-aws-iam-authenticator-linux.sh
Executable file
8
hack/installers/install-aws-iam-authenticator-linux.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
AWS_IAM_AUTHENTICATOR_VERSION=0.4.0-alpha.1
|
||||
[ -e $DOWNLOADS/aws-iam-authenticator ] || curl -sLf --retry 3 -o $DOWNLOADS/aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/${AWS_IAM_AUTHENTICATOR_VERSION}/aws-iam-authenticator_${AWS_IAM_AUTHENTICATOR_VERSION}_linux_amd64
|
||||
cp $DOWNLOADS/aws-iam-authenticator $BIN/
|
||||
chmod +x $BIN/aws-iam-authenticator
|
||||
aws-iam-authenticator version
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
KUSTOMIZE_VERSION=2.0.3 "$(dirname $0)/../install.sh" helm-linux jq-linux kustomize-linux protoc-linux swagger-linux
|
||||
"$(dirname $0)/../install.sh" helm-linux jq-linux kustomize-linux protoc-linux swagger-linux
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz
|
||||
[ -e $DOWNLOADS/helm.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.15.2-linux-amd64.tar.gz
|
||||
tar -C /tmp/ -xf $DOWNLOADS/helm.tar.gz
|
||||
cp /tmp/linux-amd64/helm $BIN/helm
|
||||
helm version --client
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
set -eux -o pipefail
|
||||
|
||||
# TODO we use v2 for generating manifests, v3 for production - we should always use v3
|
||||
KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-3.1.0}
|
||||
KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-3.2.1}
|
||||
DL=$DOWNLOADS/kustomize-${KUSTOMIZE_VERSION}
|
||||
|
||||
[ -e $DL ] || curl -sLf --retry 3 -o $DL https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64
|
||||
# Note that kustomize release URIs have changed for v3.2.1. Then again for
|
||||
# v3.3.0. When upgrading to versions >= v3.3.0 please change the URI format. And
|
||||
# also note that as of version v3.3.0, assets are in .tar.gz form.
|
||||
# v3.2.0 = https://github.com/kubernetes-sigs/kustomize/releases/download/v3.2.0/kustomize_3.2.0_linux_amd64
|
||||
# v3.2.1 = https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.2.1/kustomize_kustomize.v3.2.1_linux_amd64
|
||||
# v3.3.0 = https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.3.0/kustomize_v3.3.0_linux_amd64.tar.gz
|
||||
[ -e $DL ] || curl -sLf --retry 3 -o $DL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v${KUSTOMIZE_VERSION}/kustomize_kustomize.v${KUSTOMIZE_VERSION}_linux_amd64
|
||||
cp $DL $BIN/kustomize
|
||||
chmod +x $BIN/kustomize
|
||||
kustomize version
|
||||
|
||||
9
hack/installers/install-packr-linux.sh
Executable file
9
hack/installers/install-packr-linux.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
PACKR_VERSION=1.21.9
|
||||
[ -e $DOWNLOADS/parkr.tar.gz ] || curl -sLf --retry 3 -o $DOWNLOADS/parkr.tar.gz https://github.com/gobuffalo/packr/releases/download/v${PACKR_VERSION}/packr_${PACKR_VERSION}_linux_amd64.tar.gz
|
||||
tar -vxf $DOWNLOADS/parkr.tar.gz -C /tmp/
|
||||
cp /tmp/packr $BIN/
|
||||
chmod +x $BIN/packr
|
||||
packr version
|
||||
@@ -1,18 +1,18 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
bases:
|
||||
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: v1.3.0
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: v1.3.0
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
- ./repo-server
|
||||
- ./server
|
||||
- ./config
|
||||
- ./redis
|
||||
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: latest
|
||||
|
||||
@@ -1032,6 +1032,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1509,6 +1511,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
|
||||
@@ -7,18 +7,18 @@ patchesStrategicMerge:
|
||||
- overlays/argocd-server-deployment.yaml
|
||||
- overlays/argocd-application-controller-deployment.yaml
|
||||
|
||||
bases:
|
||||
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: v1.3.0
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: v1.3.0
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/dex
|
||||
- ../../base/repo-server
|
||||
- ../../base/server
|
||||
- ../../base/config
|
||||
- ./redis-ha
|
||||
|
||||
images:
|
||||
- name: argoproj/argocd
|
||||
newName: argoproj/argocd
|
||||
newTag: latest
|
||||
- name: argoproj/argocd-ui
|
||||
newName: argoproj/argocd-ui
|
||||
newTag: latest
|
||||
|
||||
@@ -1033,6 +1033,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1510,6 +1512,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2785,6 +2789,30 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations: null
|
||||
labels:
|
||||
app.kubernetes.io/component: redis
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-redis-ha
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: server
|
||||
port: 6379
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: 26379
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
@@ -2863,30 +2891,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations: null
|
||||
labels:
|
||||
app.kubernetes.io/component: redis
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-redis-ha
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: server
|
||||
port: 6379
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: 26379
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: repo-server
|
||||
@@ -2908,23 +2912,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
@@ -2944,6 +2931,23 @@ spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -2978,7 +2982,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -3032,7 +3036,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -3088,7 +3092,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -3162,7 +3166,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1033,6 +1033,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1510,6 +1512,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2700,6 +2704,30 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations: null
|
||||
labels:
|
||||
app.kubernetes.io/component: redis
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-redis-ha
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: server
|
||||
port: 6379
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: 26379
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
@@ -2778,30 +2806,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
annotations: null
|
||||
labels:
|
||||
app.kubernetes.io/component: redis
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-redis-ha
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: server
|
||||
port: 6379
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: 26379
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-redis-ha
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: repo-server
|
||||
@@ -2823,23 +2827,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
@@ -2859,6 +2846,23 @@ spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -2893,7 +2897,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2947,7 +2951,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -3003,7 +3007,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -3077,7 +3081,7 @@ spec:
|
||||
- argocd-redis-ha-announce-2:26379
|
||||
- --sentinelmaster
|
||||
- argocd
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1033,6 +1033,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1510,6 +1512,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2680,23 +2684,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
@@ -2716,6 +2703,23 @@ spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -2742,7 +2746,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2796,7 +2800,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2860,7 +2864,7 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -2911,7 +2915,7 @@ spec:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -1033,6 +1033,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
observedAt:
|
||||
description: ObservedAt indicates when the application state was updated
|
||||
without querying latest git state
|
||||
format: date-time
|
||||
type: string
|
||||
operationState:
|
||||
@@ -1510,6 +1512,8 @@ spec:
|
||||
- startedAt
|
||||
type: object
|
||||
reconciledAt:
|
||||
description: ReconciledAt indicates when the application state was reconciled
|
||||
using the latest git version
|
||||
format: date-time
|
||||
type: string
|
||||
resources:
|
||||
@@ -2595,23 +2599,6 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
@@ -2631,6 +2618,23 @@ spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: server
|
||||
app.kubernetes.io/name: argocd-server-metrics
|
||||
app.kubernetes.io/part-of: argocd
|
||||
name: argocd-server-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 8083
|
||||
protocol: TCP
|
||||
targetPort: 8083
|
||||
selector:
|
||||
app.kubernetes.io/name: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -2657,7 +2661,7 @@ spec:
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2711,7 +2715,7 @@ spec:
|
||||
- cp
|
||||
- /usr/local/bin/argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -2775,7 +2779,7 @@ spec:
|
||||
- argocd-repo-server
|
||||
- --redis
|
||||
- argocd-redis:6379
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
@@ -2826,7 +2830,7 @@ spec:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
image: argoproj/argocd:latest
|
||||
image: argoproj/argocd:v1.3.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -33,7 +33,7 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
func (m *AWSAuthConfig) Reset() { *m = AWSAuthConfig{} }
|
||||
func (*AWSAuthConfig) ProtoMessage() {}
|
||||
func (*AWSAuthConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{0}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{0}
|
||||
}
|
||||
func (m *AWSAuthConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -61,7 +61,7 @@ var xxx_messageInfo_AWSAuthConfig proto.InternalMessageInfo
|
||||
func (m *AppProject) Reset() { *m = AppProject{} }
|
||||
func (*AppProject) ProtoMessage() {}
|
||||
func (*AppProject) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{1}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{1}
|
||||
}
|
||||
func (m *AppProject) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -89,7 +89,7 @@ var xxx_messageInfo_AppProject proto.InternalMessageInfo
|
||||
func (m *AppProjectList) Reset() { *m = AppProjectList{} }
|
||||
func (*AppProjectList) ProtoMessage() {}
|
||||
func (*AppProjectList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{2}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{2}
|
||||
}
|
||||
func (m *AppProjectList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -117,7 +117,7 @@ var xxx_messageInfo_AppProjectList proto.InternalMessageInfo
|
||||
func (m *AppProjectSpec) Reset() { *m = AppProjectSpec{} }
|
||||
func (*AppProjectSpec) ProtoMessage() {}
|
||||
func (*AppProjectSpec) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{3}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{3}
|
||||
}
|
||||
func (m *AppProjectSpec) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -145,7 +145,7 @@ var xxx_messageInfo_AppProjectSpec proto.InternalMessageInfo
|
||||
func (m *Application) Reset() { *m = Application{} }
|
||||
func (*Application) ProtoMessage() {}
|
||||
func (*Application) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{4}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{4}
|
||||
}
|
||||
func (m *Application) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -173,7 +173,7 @@ var xxx_messageInfo_Application proto.InternalMessageInfo
|
||||
func (m *ApplicationCondition) Reset() { *m = ApplicationCondition{} }
|
||||
func (*ApplicationCondition) ProtoMessage() {}
|
||||
func (*ApplicationCondition) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{5}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{5}
|
||||
}
|
||||
func (m *ApplicationCondition) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -201,7 +201,7 @@ var xxx_messageInfo_ApplicationCondition proto.InternalMessageInfo
|
||||
func (m *ApplicationDestination) Reset() { *m = ApplicationDestination{} }
|
||||
func (*ApplicationDestination) ProtoMessage() {}
|
||||
func (*ApplicationDestination) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{6}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{6}
|
||||
}
|
||||
func (m *ApplicationDestination) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -229,7 +229,7 @@ var xxx_messageInfo_ApplicationDestination proto.InternalMessageInfo
|
||||
func (m *ApplicationList) Reset() { *m = ApplicationList{} }
|
||||
func (*ApplicationList) ProtoMessage() {}
|
||||
func (*ApplicationList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{7}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{7}
|
||||
}
|
||||
func (m *ApplicationList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -257,7 +257,7 @@ var xxx_messageInfo_ApplicationList proto.InternalMessageInfo
|
||||
func (m *ApplicationSource) Reset() { *m = ApplicationSource{} }
|
||||
func (*ApplicationSource) ProtoMessage() {}
|
||||
func (*ApplicationSource) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{8}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{8}
|
||||
}
|
||||
func (m *ApplicationSource) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -285,7 +285,7 @@ var xxx_messageInfo_ApplicationSource proto.InternalMessageInfo
|
||||
func (m *ApplicationSourceDirectory) Reset() { *m = ApplicationSourceDirectory{} }
|
||||
func (*ApplicationSourceDirectory) ProtoMessage() {}
|
||||
func (*ApplicationSourceDirectory) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{9}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{9}
|
||||
}
|
||||
func (m *ApplicationSourceDirectory) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -313,7 +313,7 @@ var xxx_messageInfo_ApplicationSourceDirectory proto.InternalMessageInfo
|
||||
func (m *ApplicationSourceHelm) Reset() { *m = ApplicationSourceHelm{} }
|
||||
func (*ApplicationSourceHelm) ProtoMessage() {}
|
||||
func (*ApplicationSourceHelm) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{10}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{10}
|
||||
}
|
||||
func (m *ApplicationSourceHelm) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -341,7 +341,7 @@ var xxx_messageInfo_ApplicationSourceHelm proto.InternalMessageInfo
|
||||
func (m *ApplicationSourceJsonnet) Reset() { *m = ApplicationSourceJsonnet{} }
|
||||
func (*ApplicationSourceJsonnet) ProtoMessage() {}
|
||||
func (*ApplicationSourceJsonnet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{11}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{11}
|
||||
}
|
||||
func (m *ApplicationSourceJsonnet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -369,7 +369,7 @@ var xxx_messageInfo_ApplicationSourceJsonnet proto.InternalMessageInfo
|
||||
func (m *ApplicationSourceKsonnet) Reset() { *m = ApplicationSourceKsonnet{} }
|
||||
func (*ApplicationSourceKsonnet) ProtoMessage() {}
|
||||
func (*ApplicationSourceKsonnet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{12}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{12}
|
||||
}
|
||||
func (m *ApplicationSourceKsonnet) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -397,7 +397,7 @@ var xxx_messageInfo_ApplicationSourceKsonnet proto.InternalMessageInfo
|
||||
func (m *ApplicationSourceKustomize) Reset() { *m = ApplicationSourceKustomize{} }
|
||||
func (*ApplicationSourceKustomize) ProtoMessage() {}
|
||||
func (*ApplicationSourceKustomize) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{13}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{13}
|
||||
}
|
||||
func (m *ApplicationSourceKustomize) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -425,7 +425,7 @@ var xxx_messageInfo_ApplicationSourceKustomize proto.InternalMessageInfo
|
||||
func (m *ApplicationSourcePlugin) Reset() { *m = ApplicationSourcePlugin{} }
|
||||
func (*ApplicationSourcePlugin) ProtoMessage() {}
|
||||
func (*ApplicationSourcePlugin) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{14}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{14}
|
||||
}
|
||||
func (m *ApplicationSourcePlugin) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -453,7 +453,7 @@ var xxx_messageInfo_ApplicationSourcePlugin proto.InternalMessageInfo
|
||||
func (m *ApplicationSpec) Reset() { *m = ApplicationSpec{} }
|
||||
func (*ApplicationSpec) ProtoMessage() {}
|
||||
func (*ApplicationSpec) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{15}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{15}
|
||||
}
|
||||
func (m *ApplicationSpec) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -481,7 +481,7 @@ var xxx_messageInfo_ApplicationSpec proto.InternalMessageInfo
|
||||
func (m *ApplicationStatus) Reset() { *m = ApplicationStatus{} }
|
||||
func (*ApplicationStatus) ProtoMessage() {}
|
||||
func (*ApplicationStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{16}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{16}
|
||||
}
|
||||
func (m *ApplicationStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -509,7 +509,7 @@ var xxx_messageInfo_ApplicationStatus proto.InternalMessageInfo
|
||||
func (m *ApplicationSummary) Reset() { *m = ApplicationSummary{} }
|
||||
func (*ApplicationSummary) ProtoMessage() {}
|
||||
func (*ApplicationSummary) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{17}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{17}
|
||||
}
|
||||
func (m *ApplicationSummary) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -537,7 +537,7 @@ var xxx_messageInfo_ApplicationSummary proto.InternalMessageInfo
|
||||
func (m *ApplicationTree) Reset() { *m = ApplicationTree{} }
|
||||
func (*ApplicationTree) ProtoMessage() {}
|
||||
func (*ApplicationTree) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{18}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{18}
|
||||
}
|
||||
func (m *ApplicationTree) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -565,7 +565,7 @@ var xxx_messageInfo_ApplicationTree proto.InternalMessageInfo
|
||||
func (m *ApplicationWatchEvent) Reset() { *m = ApplicationWatchEvent{} }
|
||||
func (*ApplicationWatchEvent) ProtoMessage() {}
|
||||
func (*ApplicationWatchEvent) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{19}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{19}
|
||||
}
|
||||
func (m *ApplicationWatchEvent) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -593,7 +593,7 @@ var xxx_messageInfo_ApplicationWatchEvent proto.InternalMessageInfo
|
||||
func (m *Cluster) Reset() { *m = Cluster{} }
|
||||
func (*Cluster) ProtoMessage() {}
|
||||
func (*Cluster) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{20}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{20}
|
||||
}
|
||||
func (m *Cluster) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -621,7 +621,7 @@ var xxx_messageInfo_Cluster proto.InternalMessageInfo
|
||||
func (m *ClusterConfig) Reset() { *m = ClusterConfig{} }
|
||||
func (*ClusterConfig) ProtoMessage() {}
|
||||
func (*ClusterConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{21}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{21}
|
||||
}
|
||||
func (m *ClusterConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -649,7 +649,7 @@ var xxx_messageInfo_ClusterConfig proto.InternalMessageInfo
|
||||
func (m *ClusterList) Reset() { *m = ClusterList{} }
|
||||
func (*ClusterList) ProtoMessage() {}
|
||||
func (*ClusterList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{22}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{22}
|
||||
}
|
||||
func (m *ClusterList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -677,7 +677,7 @@ var xxx_messageInfo_ClusterList proto.InternalMessageInfo
|
||||
func (m *Command) Reset() { *m = Command{} }
|
||||
func (*Command) ProtoMessage() {}
|
||||
func (*Command) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{23}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{23}
|
||||
}
|
||||
func (m *Command) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -705,7 +705,7 @@ var xxx_messageInfo_Command proto.InternalMessageInfo
|
||||
func (m *ComparedTo) Reset() { *m = ComparedTo{} }
|
||||
func (*ComparedTo) ProtoMessage() {}
|
||||
func (*ComparedTo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{24}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{24}
|
||||
}
|
||||
func (m *ComparedTo) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -733,7 +733,7 @@ var xxx_messageInfo_ComparedTo proto.InternalMessageInfo
|
||||
func (m *ComponentParameter) Reset() { *m = ComponentParameter{} }
|
||||
func (*ComponentParameter) ProtoMessage() {}
|
||||
func (*ComponentParameter) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{25}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{25}
|
||||
}
|
||||
func (m *ComponentParameter) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -761,7 +761,7 @@ var xxx_messageInfo_ComponentParameter proto.InternalMessageInfo
|
||||
func (m *ConfigManagementPlugin) Reset() { *m = ConfigManagementPlugin{} }
|
||||
func (*ConfigManagementPlugin) ProtoMessage() {}
|
||||
func (*ConfigManagementPlugin) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{26}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{26}
|
||||
}
|
||||
func (m *ConfigManagementPlugin) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -789,7 +789,7 @@ var xxx_messageInfo_ConfigManagementPlugin proto.InternalMessageInfo
|
||||
func (m *ConnectionState) Reset() { *m = ConnectionState{} }
|
||||
func (*ConnectionState) ProtoMessage() {}
|
||||
func (*ConnectionState) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{27}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{27}
|
||||
}
|
||||
func (m *ConnectionState) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -817,7 +817,7 @@ var xxx_messageInfo_ConnectionState proto.InternalMessageInfo
|
||||
func (m *EnvEntry) Reset() { *m = EnvEntry{} }
|
||||
func (*EnvEntry) ProtoMessage() {}
|
||||
func (*EnvEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{28}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{28}
|
||||
}
|
||||
func (m *EnvEntry) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -845,7 +845,7 @@ var xxx_messageInfo_EnvEntry proto.InternalMessageInfo
|
||||
func (m *HealthStatus) Reset() { *m = HealthStatus{} }
|
||||
func (*HealthStatus) ProtoMessage() {}
|
||||
func (*HealthStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{29}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{29}
|
||||
}
|
||||
func (m *HealthStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -873,7 +873,7 @@ var xxx_messageInfo_HealthStatus proto.InternalMessageInfo
|
||||
func (m *HelmParameter) Reset() { *m = HelmParameter{} }
|
||||
func (*HelmParameter) ProtoMessage() {}
|
||||
func (*HelmParameter) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{30}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{30}
|
||||
}
|
||||
func (m *HelmParameter) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -901,7 +901,7 @@ var xxx_messageInfo_HelmParameter proto.InternalMessageInfo
|
||||
func (m *Info) Reset() { *m = Info{} }
|
||||
func (*Info) ProtoMessage() {}
|
||||
func (*Info) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{31}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{31}
|
||||
}
|
||||
func (m *Info) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -929,7 +929,7 @@ var xxx_messageInfo_Info proto.InternalMessageInfo
|
||||
func (m *InfoItem) Reset() { *m = InfoItem{} }
|
||||
func (*InfoItem) ProtoMessage() {}
|
||||
func (*InfoItem) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{32}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{32}
|
||||
}
|
||||
func (m *InfoItem) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -957,7 +957,7 @@ var xxx_messageInfo_InfoItem proto.InternalMessageInfo
|
||||
func (m *JWTToken) Reset() { *m = JWTToken{} }
|
||||
func (*JWTToken) ProtoMessage() {}
|
||||
func (*JWTToken) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{33}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{33}
|
||||
}
|
||||
func (m *JWTToken) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -985,7 +985,7 @@ var xxx_messageInfo_JWTToken proto.InternalMessageInfo
|
||||
func (m *JsonnetVar) Reset() { *m = JsonnetVar{} }
|
||||
func (*JsonnetVar) ProtoMessage() {}
|
||||
func (*JsonnetVar) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{34}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{34}
|
||||
}
|
||||
func (m *JsonnetVar) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1013,7 +1013,7 @@ var xxx_messageInfo_JsonnetVar proto.InternalMessageInfo
|
||||
func (m *KsonnetParameter) Reset() { *m = KsonnetParameter{} }
|
||||
func (*KsonnetParameter) ProtoMessage() {}
|
||||
func (*KsonnetParameter) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{35}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{35}
|
||||
}
|
||||
func (m *KsonnetParameter) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1041,7 +1041,7 @@ var xxx_messageInfo_KsonnetParameter proto.InternalMessageInfo
|
||||
func (m *KustomizeOptions) Reset() { *m = KustomizeOptions{} }
|
||||
func (*KustomizeOptions) ProtoMessage() {}
|
||||
func (*KustomizeOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{36}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{36}
|
||||
}
|
||||
func (m *KustomizeOptions) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1069,7 +1069,7 @@ var xxx_messageInfo_KustomizeOptions proto.InternalMessageInfo
|
||||
func (m *Operation) Reset() { *m = Operation{} }
|
||||
func (*Operation) ProtoMessage() {}
|
||||
func (*Operation) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{37}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{37}
|
||||
}
|
||||
func (m *Operation) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1097,7 +1097,7 @@ var xxx_messageInfo_Operation proto.InternalMessageInfo
|
||||
func (m *OperationState) Reset() { *m = OperationState{} }
|
||||
func (*OperationState) ProtoMessage() {}
|
||||
func (*OperationState) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{38}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{38}
|
||||
}
|
||||
func (m *OperationState) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1125,7 +1125,7 @@ var xxx_messageInfo_OperationState proto.InternalMessageInfo
|
||||
func (m *OrphanedResourcesMonitorSettings) Reset() { *m = OrphanedResourcesMonitorSettings{} }
|
||||
func (*OrphanedResourcesMonitorSettings) ProtoMessage() {}
|
||||
func (*OrphanedResourcesMonitorSettings) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{39}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{39}
|
||||
}
|
||||
func (m *OrphanedResourcesMonitorSettings) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1153,7 +1153,7 @@ var xxx_messageInfo_OrphanedResourcesMonitorSettings proto.InternalMessageInfo
|
||||
func (m *ProjectRole) Reset() { *m = ProjectRole{} }
|
||||
func (*ProjectRole) ProtoMessage() {}
|
||||
func (*ProjectRole) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{40}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{40}
|
||||
}
|
||||
func (m *ProjectRole) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1181,7 +1181,7 @@ var xxx_messageInfo_ProjectRole proto.InternalMessageInfo
|
||||
func (m *Repository) Reset() { *m = Repository{} }
|
||||
func (*Repository) ProtoMessage() {}
|
||||
func (*Repository) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{41}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{41}
|
||||
}
|
||||
func (m *Repository) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1209,7 +1209,7 @@ var xxx_messageInfo_Repository proto.InternalMessageInfo
|
||||
func (m *RepositoryCertificate) Reset() { *m = RepositoryCertificate{} }
|
||||
func (*RepositoryCertificate) ProtoMessage() {}
|
||||
func (*RepositoryCertificate) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{42}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{42}
|
||||
}
|
||||
func (m *RepositoryCertificate) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1237,7 +1237,7 @@ var xxx_messageInfo_RepositoryCertificate proto.InternalMessageInfo
|
||||
func (m *RepositoryCertificateList) Reset() { *m = RepositoryCertificateList{} }
|
||||
func (*RepositoryCertificateList) ProtoMessage() {}
|
||||
func (*RepositoryCertificateList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{43}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{43}
|
||||
}
|
||||
func (m *RepositoryCertificateList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1265,7 +1265,7 @@ var xxx_messageInfo_RepositoryCertificateList proto.InternalMessageInfo
|
||||
func (m *RepositoryList) Reset() { *m = RepositoryList{} }
|
||||
func (*RepositoryList) ProtoMessage() {}
|
||||
func (*RepositoryList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{44}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{44}
|
||||
}
|
||||
func (m *RepositoryList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1293,7 +1293,7 @@ var xxx_messageInfo_RepositoryList proto.InternalMessageInfo
|
||||
func (m *ResourceAction) Reset() { *m = ResourceAction{} }
|
||||
func (*ResourceAction) ProtoMessage() {}
|
||||
func (*ResourceAction) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{45}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{45}
|
||||
}
|
||||
func (m *ResourceAction) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1321,7 +1321,7 @@ var xxx_messageInfo_ResourceAction proto.InternalMessageInfo
|
||||
func (m *ResourceActionDefinition) Reset() { *m = ResourceActionDefinition{} }
|
||||
func (*ResourceActionDefinition) ProtoMessage() {}
|
||||
func (*ResourceActionDefinition) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{46}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{46}
|
||||
}
|
||||
func (m *ResourceActionDefinition) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1349,7 +1349,7 @@ var xxx_messageInfo_ResourceActionDefinition proto.InternalMessageInfo
|
||||
func (m *ResourceActionParam) Reset() { *m = ResourceActionParam{} }
|
||||
func (*ResourceActionParam) ProtoMessage() {}
|
||||
func (*ResourceActionParam) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{47}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{47}
|
||||
}
|
||||
func (m *ResourceActionParam) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1377,7 +1377,7 @@ var xxx_messageInfo_ResourceActionParam proto.InternalMessageInfo
|
||||
func (m *ResourceActions) Reset() { *m = ResourceActions{} }
|
||||
func (*ResourceActions) ProtoMessage() {}
|
||||
func (*ResourceActions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{48}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{48}
|
||||
}
|
||||
func (m *ResourceActions) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1405,7 +1405,7 @@ var xxx_messageInfo_ResourceActions proto.InternalMessageInfo
|
||||
func (m *ResourceDiff) Reset() { *m = ResourceDiff{} }
|
||||
func (*ResourceDiff) ProtoMessage() {}
|
||||
func (*ResourceDiff) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{49}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{49}
|
||||
}
|
||||
func (m *ResourceDiff) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1433,7 +1433,7 @@ var xxx_messageInfo_ResourceDiff proto.InternalMessageInfo
|
||||
func (m *ResourceIgnoreDifferences) Reset() { *m = ResourceIgnoreDifferences{} }
|
||||
func (*ResourceIgnoreDifferences) ProtoMessage() {}
|
||||
func (*ResourceIgnoreDifferences) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{50}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{50}
|
||||
}
|
||||
func (m *ResourceIgnoreDifferences) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1461,7 +1461,7 @@ var xxx_messageInfo_ResourceIgnoreDifferences proto.InternalMessageInfo
|
||||
func (m *ResourceNetworkingInfo) Reset() { *m = ResourceNetworkingInfo{} }
|
||||
func (*ResourceNetworkingInfo) ProtoMessage() {}
|
||||
func (*ResourceNetworkingInfo) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{51}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{51}
|
||||
}
|
||||
func (m *ResourceNetworkingInfo) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1489,7 +1489,7 @@ var xxx_messageInfo_ResourceNetworkingInfo proto.InternalMessageInfo
|
||||
func (m *ResourceNode) Reset() { *m = ResourceNode{} }
|
||||
func (*ResourceNode) ProtoMessage() {}
|
||||
func (*ResourceNode) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{52}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{52}
|
||||
}
|
||||
func (m *ResourceNode) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1517,7 +1517,7 @@ var xxx_messageInfo_ResourceNode proto.InternalMessageInfo
|
||||
func (m *ResourceOverride) Reset() { *m = ResourceOverride{} }
|
||||
func (*ResourceOverride) ProtoMessage() {}
|
||||
func (*ResourceOverride) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{53}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{53}
|
||||
}
|
||||
func (m *ResourceOverride) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1545,7 +1545,7 @@ var xxx_messageInfo_ResourceOverride proto.InternalMessageInfo
|
||||
func (m *ResourceRef) Reset() { *m = ResourceRef{} }
|
||||
func (*ResourceRef) ProtoMessage() {}
|
||||
func (*ResourceRef) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{54}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{54}
|
||||
}
|
||||
func (m *ResourceRef) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1573,7 +1573,7 @@ var xxx_messageInfo_ResourceRef proto.InternalMessageInfo
|
||||
func (m *ResourceResult) Reset() { *m = ResourceResult{} }
|
||||
func (*ResourceResult) ProtoMessage() {}
|
||||
func (*ResourceResult) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{55}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{55}
|
||||
}
|
||||
func (m *ResourceResult) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1601,7 +1601,7 @@ var xxx_messageInfo_ResourceResult proto.InternalMessageInfo
|
||||
func (m *ResourceStatus) Reset() { *m = ResourceStatus{} }
|
||||
func (*ResourceStatus) ProtoMessage() {}
|
||||
func (*ResourceStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{56}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{56}
|
||||
}
|
||||
func (m *ResourceStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1629,7 +1629,7 @@ var xxx_messageInfo_ResourceStatus proto.InternalMessageInfo
|
||||
func (m *RevisionHistory) Reset() { *m = RevisionHistory{} }
|
||||
func (*RevisionHistory) ProtoMessage() {}
|
||||
func (*RevisionHistory) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{57}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{57}
|
||||
}
|
||||
func (m *RevisionHistory) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1657,7 +1657,7 @@ var xxx_messageInfo_RevisionHistory proto.InternalMessageInfo
|
||||
func (m *RevisionMetadata) Reset() { *m = RevisionMetadata{} }
|
||||
func (*RevisionMetadata) ProtoMessage() {}
|
||||
func (*RevisionMetadata) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{58}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{58}
|
||||
}
|
||||
func (m *RevisionMetadata) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1685,7 +1685,7 @@ var xxx_messageInfo_RevisionMetadata proto.InternalMessageInfo
|
||||
func (m *SyncOperation) Reset() { *m = SyncOperation{} }
|
||||
func (*SyncOperation) ProtoMessage() {}
|
||||
func (*SyncOperation) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{59}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{59}
|
||||
}
|
||||
func (m *SyncOperation) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1713,7 +1713,7 @@ var xxx_messageInfo_SyncOperation proto.InternalMessageInfo
|
||||
func (m *SyncOperationResource) Reset() { *m = SyncOperationResource{} }
|
||||
func (*SyncOperationResource) ProtoMessage() {}
|
||||
func (*SyncOperationResource) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{60}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{60}
|
||||
}
|
||||
func (m *SyncOperationResource) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1741,7 +1741,7 @@ var xxx_messageInfo_SyncOperationResource proto.InternalMessageInfo
|
||||
func (m *SyncOperationResult) Reset() { *m = SyncOperationResult{} }
|
||||
func (*SyncOperationResult) ProtoMessage() {}
|
||||
func (*SyncOperationResult) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{61}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{61}
|
||||
}
|
||||
func (m *SyncOperationResult) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1769,7 +1769,7 @@ var xxx_messageInfo_SyncOperationResult proto.InternalMessageInfo
|
||||
func (m *SyncPolicy) Reset() { *m = SyncPolicy{} }
|
||||
func (*SyncPolicy) ProtoMessage() {}
|
||||
func (*SyncPolicy) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{62}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{62}
|
||||
}
|
||||
func (m *SyncPolicy) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1797,7 +1797,7 @@ var xxx_messageInfo_SyncPolicy proto.InternalMessageInfo
|
||||
func (m *SyncPolicyAutomated) Reset() { *m = SyncPolicyAutomated{} }
|
||||
func (*SyncPolicyAutomated) ProtoMessage() {}
|
||||
func (*SyncPolicyAutomated) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{63}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{63}
|
||||
}
|
||||
func (m *SyncPolicyAutomated) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1825,7 +1825,7 @@ var xxx_messageInfo_SyncPolicyAutomated proto.InternalMessageInfo
|
||||
func (m *SyncStatus) Reset() { *m = SyncStatus{} }
|
||||
func (*SyncStatus) ProtoMessage() {}
|
||||
func (*SyncStatus) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{64}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{64}
|
||||
}
|
||||
func (m *SyncStatus) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1853,7 +1853,7 @@ var xxx_messageInfo_SyncStatus proto.InternalMessageInfo
|
||||
func (m *SyncStrategy) Reset() { *m = SyncStrategy{} }
|
||||
func (*SyncStrategy) ProtoMessage() {}
|
||||
func (*SyncStrategy) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{65}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{65}
|
||||
}
|
||||
func (m *SyncStrategy) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1881,7 +1881,7 @@ var xxx_messageInfo_SyncStrategy proto.InternalMessageInfo
|
||||
func (m *SyncStrategyApply) Reset() { *m = SyncStrategyApply{} }
|
||||
func (*SyncStrategyApply) ProtoMessage() {}
|
||||
func (*SyncStrategyApply) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{66}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{66}
|
||||
}
|
||||
func (m *SyncStrategyApply) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1909,7 +1909,7 @@ var xxx_messageInfo_SyncStrategyApply proto.InternalMessageInfo
|
||||
func (m *SyncStrategyHook) Reset() { *m = SyncStrategyHook{} }
|
||||
func (*SyncStrategyHook) ProtoMessage() {}
|
||||
func (*SyncStrategyHook) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{67}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{67}
|
||||
}
|
||||
func (m *SyncStrategyHook) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1937,7 +1937,7 @@ var xxx_messageInfo_SyncStrategyHook proto.InternalMessageInfo
|
||||
func (m *SyncWindow) Reset() { *m = SyncWindow{} }
|
||||
func (*SyncWindow) ProtoMessage() {}
|
||||
func (*SyncWindow) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{68}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{68}
|
||||
}
|
||||
func (m *SyncWindow) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -1965,7 +1965,7 @@ var xxx_messageInfo_SyncWindow proto.InternalMessageInfo
|
||||
func (m *TLSClientConfig) Reset() { *m = TLSClientConfig{} }
|
||||
func (*TLSClientConfig) ProtoMessage() {}
|
||||
func (*TLSClientConfig) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_generated_622b11e42e23cc72, []int{69}
|
||||
return fileDescriptor_generated_b34c2064a02cfa33, []int{69}
|
||||
}
|
||||
func (m *TLSClientConfig) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
@@ -18635,10 +18635,10 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_622b11e42e23cc72)
|
||||
proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_b34c2064a02cfa33)
|
||||
}
|
||||
|
||||
var fileDescriptor_generated_622b11e42e23cc72 = []byte{
|
||||
var fileDescriptor_generated_b34c2064a02cfa33 = []byte{
|
||||
// 4679 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x3c, 0x5b, 0x8c, 0x1c, 0xd9,
|
||||
0x55, 0xae, 0x7e, 0xcf, 0x99, 0x87, 0x3d, 0x77, 0xd7, 0x9b, 0xce, 0x68, 0xe3, 0xb1, 0xca, 0x4a,
|
||||
|
||||
@@ -236,10 +236,12 @@ message ApplicationStatus {
|
||||
|
||||
repeated ApplicationCondition conditions = 5;
|
||||
|
||||
// ReconciledAt indicates when the application state was reconciled using the latest git version
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time reconciledAt = 6;
|
||||
|
||||
optional OperationState operationState = 7;
|
||||
|
||||
// ObservedAt indicates when the application state was updated without querying latest git state
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time observedAt = 8;
|
||||
|
||||
optional string sourceType = 9;
|
||||
|
||||
@@ -895,7 +895,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
|
||||
},
|
||||
"reconciledAt": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
Description: "ReconciledAt indicates when the application state was reconciled using the latest git version",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"operationState": {
|
||||
@@ -905,7 +906,8 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
|
||||
},
|
||||
"observedAt": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
Description: "ObservedAt indicates when the application state was updated without querying latest git state",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"sourceType": {
|
||||
|
||||
@@ -331,16 +331,18 @@ type ApplicationDestination struct {
|
||||
|
||||
// ApplicationStatus contains information about application sync, health status
|
||||
type ApplicationStatus struct {
|
||||
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
|
||||
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
|
||||
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
|
||||
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
|
||||
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
|
||||
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
|
||||
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
|
||||
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
|
||||
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
|
||||
Resources []ResourceStatus `json:"resources,omitempty" protobuf:"bytes,1,opt,name=resources"`
|
||||
Sync SyncStatus `json:"sync,omitempty" protobuf:"bytes,2,opt,name=sync"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,3,opt,name=health"`
|
||||
History []RevisionHistory `json:"history,omitempty" protobuf:"bytes,4,opt,name=history"`
|
||||
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,5,opt,name=conditions"`
|
||||
// ReconciledAt indicates when the application state was reconciled using the latest git version
|
||||
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
|
||||
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
|
||||
// ObservedAt indicates when the application state was updated without querying latest git state
|
||||
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
|
||||
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
|
||||
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
|
||||
}
|
||||
|
||||
// Operation contains requested operation parameters.
|
||||
@@ -1250,8 +1252,20 @@ var validActions = map[string]bool{
|
||||
"*": true,
|
||||
}
|
||||
|
||||
var validActionPatterns = []*regexp.Regexp{
|
||||
regexp.MustCompile("action/.*"),
|
||||
}
|
||||
|
||||
func isValidAction(action string) bool {
|
||||
return validActions[action]
|
||||
if validActions[action] {
|
||||
return true
|
||||
}
|
||||
for i := range validActionPatterns {
|
||||
if validActionPatterns[i].MatchString(action) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validatePolicy(proj string, role string, policy string) error {
|
||||
|
||||
@@ -257,8 +257,6 @@ func TestAppProject_InvalidPolicyRules(t *testing.T) {
|
||||
errmsg string
|
||||
}
|
||||
badPolicies := []badPolicy{
|
||||
// should have spaces
|
||||
{"p,proj:my-proj:my-role,applications,get,my-proj/*,allow", "syntax"},
|
||||
// incorrect form
|
||||
{"g, proj:my-proj:my-role, applications, get, my-proj/*, allow", "must be of the form: 'p, sub, res, act, obj, eft'"},
|
||||
{"p, not, enough, parts", "must be of the form: 'p, sub, res, act, obj, eft'"},
|
||||
@@ -310,6 +308,8 @@ func TestAppProject_ValidPolicyRules(t *testing.T) {
|
||||
"p, proj:my-proj:my-role, applications, update, my-proj/foo, allow",
|
||||
"p, proj:my-proj:my-role, applications, sync, my-proj/foo, allow",
|
||||
"p, proj:my-proj:my-role, applications, delete, my-proj/foo, allow",
|
||||
"p, proj:my-proj:my-role, applications, action/*, my-proj/foo, allow",
|
||||
"p, proj:my-proj:my-role, applications, action/apps/Deployment/restart, my-proj/foo, allow",
|
||||
}
|
||||
for _, good := range goodPolicies {
|
||||
p.Spec.Roles[0].Policies = []string{good}
|
||||
|
||||
@@ -8,8 +8,9 @@ import (
|
||||
)
|
||||
|
||||
type MetricsServer struct {
|
||||
handler http.Handler
|
||||
gitRequestCounter *prometheus.CounterVec
|
||||
handler http.Handler
|
||||
gitRequestCounter *prometheus.CounterVec
|
||||
repoPendingRequestsGauge *prometheus.GaugeVec
|
||||
}
|
||||
|
||||
type GitRequestType string
|
||||
@@ -34,9 +35,19 @@ func NewMetricsServer() *MetricsServer {
|
||||
)
|
||||
registry.MustRegister(gitRequestCounter)
|
||||
|
||||
repoPendingRequestsGauge := prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "argocd_repo_pending_request_total",
|
||||
Help: "Number of pending requests requiring repository lock",
|
||||
},
|
||||
[]string{"repo"},
|
||||
)
|
||||
registry.MustRegister(repoPendingRequestsGauge)
|
||||
|
||||
return &MetricsServer{
|
||||
handler: promhttp.HandlerFor(registry, promhttp.HandlerOpts{}),
|
||||
gitRequestCounter: gitRequestCounter,
|
||||
handler: promhttp.HandlerFor(registry, promhttp.HandlerOpts{}),
|
||||
gitRequestCounter: gitRequestCounter,
|
||||
repoPendingRequestsGauge: repoPendingRequestsGauge,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,3 +59,11 @@ func (m *MetricsServer) GetHandler() http.Handler {
|
||||
func (m *MetricsServer) IncGitRequest(repo string, requestType GitRequestType) {
|
||||
m.gitRequestCounter.WithLabelValues(repo, string(requestType)).Inc()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) IncPendingRepoRequest(repo string) {
|
||||
m.repoPendingRequestsGauge.WithLabelValues(repo).Inc()
|
||||
}
|
||||
|
||||
func (m *MetricsServer) DecPendingRepoRequest(repo string) {
|
||||
m.repoPendingRequestsGauge.WithLabelValues(repo).Dec()
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ type operationSettings struct {
|
||||
// runRepoOperation downloads either git folder or helm chart and executes specified operation
|
||||
func (s *Service) runRepoOperation(
|
||||
c context.Context,
|
||||
revision string,
|
||||
repo *v1alpha1.Repository,
|
||||
source *v1alpha1.ApplicationSource,
|
||||
getCached func(revision string) bool,
|
||||
@@ -119,9 +120,9 @@ func (s *Service) runRepoOperation(
|
||||
|
||||
var gitClient git.Client
|
||||
var err error
|
||||
revision := source.TargetRevision
|
||||
revision = util.FirstNonEmpty(revision, source.TargetRevision)
|
||||
if !source.IsHelm() {
|
||||
gitClient, revision, err = s.newClientResolveRevision(repo, source.TargetRevision)
|
||||
gitClient, revision, err = s.newClientResolveRevision(repo, revision)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -131,6 +132,9 @@ func (s *Service) runRepoOperation(
|
||||
return nil
|
||||
}
|
||||
|
||||
s.metricsServer.IncPendingRepoRequest(repo.Repo)
|
||||
defer s.metricsServer.DecPendingRepoRequest(repo.Repo)
|
||||
|
||||
if settings.sem != nil {
|
||||
err = settings.sem.Acquire(c, 1)
|
||||
if err != nil {
|
||||
@@ -188,7 +192,7 @@ func (s *Service) GenerateManifest(c context.Context, q *apiclient.ManifestReque
|
||||
}
|
||||
return false
|
||||
}
|
||||
err := s.runRepoOperation(c, q.Repo, q.ApplicationSource, getCached, func(appPath string, revision string) error {
|
||||
err := s.runRepoOperation(c, q.Revision, q.Repo, q.ApplicationSource, getCached, func(appPath string, revision string) error {
|
||||
var err error
|
||||
res, err = GenerateManifests(appPath, q)
|
||||
if err != nil {
|
||||
@@ -584,7 +588,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
|
||||
return false
|
||||
}
|
||||
|
||||
err := s.runRepoOperation(ctx, q.Repo, q.Source, getCached, func(appPath string, revision string) error {
|
||||
err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, getCached, func(appPath string, revision string) error {
|
||||
appSourceType, err := GetAppSourceType(q.Source, appPath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -88,6 +88,19 @@ func TestGenerateYamlManifestInDir(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateManifestsUseExactRevision(t *testing.T) {
|
||||
service, gitClient, _ := newServiceWithMocks(".")
|
||||
|
||||
src := argoappv1.ApplicationSource{Path: "./testdata/recurse", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}}
|
||||
|
||||
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Revision: "abc"}
|
||||
|
||||
res1, err := service.GenerateManifest(context.Background(), &q)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res1.Manifests))
|
||||
assert.Equal(t, gitClient.Calls[0].Arguments[0], "abc")
|
||||
}
|
||||
|
||||
func TestRecurseManifestsInDir(t *testing.T) {
|
||||
service := newService(".")
|
||||
|
||||
|
||||
32
resource_customizations/argoproj.io/AnalysisRun/health.lua
Normal file
32
resource_customizations/argoproj.io/AnalysisRun/health.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.phase == "Pending" then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Analysis run is running"
|
||||
end
|
||||
if obj.status.phase == "Running" then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Analysis run is running"
|
||||
end
|
||||
if obj.status.phase == "Successful" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "Analysis run completed successfully"
|
||||
end
|
||||
if obj.status.phase == "Failed" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = "Analysis run failed"
|
||||
end
|
||||
if obj.status.phase == "Error" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = "Analysis run had an error"
|
||||
end
|
||||
if obj.status.phase == "Inconclusive" then
|
||||
hs.status = "Unknown"
|
||||
hs.message = "Analysis run was inconclusive"
|
||||
end
|
||||
return hs
|
||||
end
|
||||
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for analysis run to finish: status has not been reconciled."
|
||||
return hs
|
||||
@@ -0,0 +1,29 @@
|
||||
tests:
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Analysis run is running"
|
||||
inputPath: testdata/pendingAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Waiting for analysis run to finish: status has not been reconciled."
|
||||
inputPath: testdata/noStatusAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Analysis run is running"
|
||||
inputPath: testdata/runningAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "Analysis run completed successfully"
|
||||
inputPath: testdata/successfulAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Analysis run failed"
|
||||
inputPath: testdata/failedAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Analysis run had an error"
|
||||
inputPath: testdata/errorAnalysisRun.yaml
|
||||
- healthStatus:
|
||||
status: Unknown
|
||||
message: "Analysis run was inconclusive"
|
||||
inputPath: testdata/inconclusiveAnalysisRun.yaml
|
||||
47
resource_customizations/argoproj.io/AnalysisRun/testdata/errorAnalysisRun.yaml
vendored
Normal file
47
resource_customizations/argoproj.io/AnalysisRun/testdata/errorAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-btpgc
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: result < 92
|
||||
interval: 10
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: result > 95
|
||||
status:
|
||||
metricResults:
|
||||
- consecutiveError: 5
|
||||
error: 5
|
||||
measurements:
|
||||
- finishedAt: '2019-10-28T18:13:01Z'
|
||||
startedAt: '2019-10-28T18:13:01Z'
|
||||
phase: Error
|
||||
value: '[0.9832775919732442]'
|
||||
- finishedAt: '2019-10-28T18:13:11Z'
|
||||
startedAt: '2019-10-28T18:13:11Z'
|
||||
phase: Error
|
||||
value: '[0.9832775919732442]'
|
||||
- finishedAt: '2019-10-28T18:13:21Z'
|
||||
startedAt: '2019-10-28T18:13:21Z'
|
||||
phase: Error
|
||||
value: '[0.9722530521642618]'
|
||||
- finishedAt: '2019-10-28T18:13:31Z'
|
||||
startedAt: '2019-10-28T18:13:31Z'
|
||||
phase: Error
|
||||
value: '[0.9722530521642618]'
|
||||
- finishedAt: '2019-10-28T18:13:41Z'
|
||||
startedAt: '2019-10-28T18:13:41Z'
|
||||
phase: Error
|
||||
value: '[0.9722530521642618]'
|
||||
name: memory-usage
|
||||
phase: Error
|
||||
phase: Error
|
||||
31
resource_customizations/argoproj.io/AnalysisRun/testdata/failedAnalysisRun.yaml
vendored
Normal file
31
resource_customizations/argoproj.io/AnalysisRun/testdata/failedAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-9k5rj
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: len(result) > 0
|
||||
interval: 10
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: len(result) > 0
|
||||
status:
|
||||
metricResults:
|
||||
- count: 1
|
||||
failed: 1
|
||||
measurements:
|
||||
- finishedAt: '2019-10-28T18:23:23Z'
|
||||
startedAt: '2019-10-28T18:23:23Z'
|
||||
phase: Failed
|
||||
value: '[0.9768211920529802]'
|
||||
name: memory-usage
|
||||
phase: Failed
|
||||
phase: Failed
|
||||
31
resource_customizations/argoproj.io/AnalysisRun/testdata/inconclusiveAnalysisRun.yaml
vendored
Normal file
31
resource_customizations/argoproj.io/AnalysisRun/testdata/inconclusiveAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-ddvn8
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: len(result) == 0
|
||||
interval: 10
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: len(result) == 0
|
||||
status:
|
||||
metricResults:
|
||||
- count: 1
|
||||
inconclusive: 1
|
||||
measurements:
|
||||
- finishedAt: '2019-10-28T18:24:31Z'
|
||||
startedAt: '2019-10-28T18:24:31Z'
|
||||
phase: Inconclusive
|
||||
value: '[0.9744444444444443]'
|
||||
name: memory-usage
|
||||
phase: Inconclusive
|
||||
phase: Inconclusive
|
||||
19
resource_customizations/argoproj.io/AnalysisRun/testdata/noStatusAnalysisRun.yaml
vendored
Normal file
19
resource_customizations/argoproj.io/AnalysisRun/testdata/noStatusAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-9k5rj
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: len(result) > 0
|
||||
interval: 10
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: len(result) > 0
|
||||
17
resource_customizations/argoproj.io/AnalysisRun/testdata/pendingAnalysisRun.yaml
vendored
Normal file
17
resource_customizations/argoproj.io/AnalysisRun/testdata/pendingAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: analysis-template
|
||||
spec:
|
||||
metrics:
|
||||
- name: memory-usage
|
||||
interval: 10
|
||||
successCondition: result > 95
|
||||
failureCondition: result < 92
|
||||
provider:
|
||||
prometheus:
|
||||
address: http://prometheus-operator-prometheus.prometheus-operator:9090
|
||||
query: |
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m])) / sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
status:
|
||||
phase: Pending
|
||||
35
resource_customizations/argoproj.io/AnalysisRun/testdata/runningAnalysisRun.yaml
vendored
Normal file
35
resource_customizations/argoproj.io/AnalysisRun/testdata/runningAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-5bpxj
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: len(result) == 0
|
||||
interval: 10
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: len(result) > 0
|
||||
status:
|
||||
metricResults:
|
||||
- count: 2
|
||||
measurements:
|
||||
- finishedAt: '2019-10-28T18:22:05Z'
|
||||
startedAt: '2019-10-28T18:22:05Z'
|
||||
phase: Successful
|
||||
value: '[0.9721293199554069]'
|
||||
- finishedAt: '2019-10-28T18:22:15Z'
|
||||
startedAt: '2019-10-28T18:22:15Z'
|
||||
phase: Successful
|
||||
value: '[0.9721293199554069]'
|
||||
name: memory-usage
|
||||
phase: Running
|
||||
successful: 2
|
||||
phase: Running
|
||||
30
resource_customizations/argoproj.io/AnalysisRun/testdata/successfulAnalysisRun.yaml
vendored
Normal file
30
resource_customizations/argoproj.io/AnalysisRun/testdata/successfulAnalysisRun.yaml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: AnalysisRun
|
||||
metadata:
|
||||
name: canary-demo-analysis-template-6c6bb7cf6f-zvcmx
|
||||
namespace: default
|
||||
spec:
|
||||
analysisSpec:
|
||||
metrics:
|
||||
- failureCondition: len(result) == 0
|
||||
name: memory-usage
|
||||
provider:
|
||||
prometheus:
|
||||
address: 'http://prometheus-operator-prometheus.prometheus-operator:9090'
|
||||
query: >
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview",status!~"[4-5].*"}[2m]))
|
||||
/
|
||||
sum(rate(nginx_ingress_controller_requests{ingress="canary-demo-preview"}[2m]))
|
||||
successCondition: len(result) > 0
|
||||
status:
|
||||
metricResults:
|
||||
- count: 1
|
||||
measurements:
|
||||
- finishedAt: '2019-10-28T18:20:37Z'
|
||||
startedAt: '2019-10-28T18:20:37Z'
|
||||
phase: Successful
|
||||
value: '[0.965324384787472]'
|
||||
name: memory-usage
|
||||
phase: Successful
|
||||
successful: 1
|
||||
phase: Successful
|
||||
28
resource_customizations/argoproj.io/Experiment/health.lua
Normal file
28
resource_customizations/argoproj.io/Experiment/health.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
hs = {}
|
||||
if obj.status ~= nil then
|
||||
if obj.status.phase == "Pending" then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Experiment is pending"
|
||||
end
|
||||
if obj.status.phase == "Running" then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Experiment is running"
|
||||
end
|
||||
if obj.status.phase == "Successful" then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "Experiment is successful"
|
||||
end
|
||||
if obj.status.phase == "Failed" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = "Experiment has failed"
|
||||
end
|
||||
if obj.status.phase == "Error" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = "Experiment had an error"
|
||||
end
|
||||
return hs
|
||||
end
|
||||
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for experiment to finish: status has not been reconciled."
|
||||
return hs
|
||||
@@ -0,0 +1,25 @@
|
||||
tests:
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Experiment is pending"
|
||||
inputPath: testdata/pendingExperiment.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Waiting for experiment to finish: status has not been reconciled."
|
||||
inputPath: testdata/noStatusExperiment.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Experiment is running"
|
||||
inputPath: testdata/runningExperiment.yaml
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
message: "Experiment is successful"
|
||||
inputPath: testdata/successfulExperiment.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Experiment has failed"
|
||||
inputPath: testdata/failedExperiment.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Experiment had an error"
|
||||
inputPath: testdata/errorExperiment.yaml
|
||||
49
resource_customizations/argoproj.io/Experiment/testdata/errorExperiment.yaml
vendored
Normal file
49
resource_customizations/argoproj.io/Experiment/testdata/errorExperiment.yaml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
name: experiment-error-template-missing
|
||||
namespace: jesse-test
|
||||
spec:
|
||||
analyses:
|
||||
- name: does-not-exist
|
||||
templateName: does-not-exist
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
spec:
|
||||
containers:
|
||||
- image: argoproj/rollouts-demo:blue
|
||||
name: rollouts-demo
|
||||
status:
|
||||
analysisRuns:
|
||||
- analysisRun: ""
|
||||
message: 'AnalysisTemplate verification failed for analysis ''does-not-exist'':
|
||||
analysistemplate.argoproj.io "does-not-exist" not found'
|
||||
name: does-not-exist
|
||||
phase: Error
|
||||
availableAt: "2019-10-27T23:13:10Z"
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-10-27T23:13:07Z"
|
||||
lastUpdateTime: "2019-10-28T05:59:33Z"
|
||||
message: Experiment "experiment-error-template-missing" is running.
|
||||
reason: NewReplicaSetAvailable
|
||||
phase: "True"
|
||||
type: Progressing
|
||||
message: 'AnalysisTemplate verification failed for analysis ''does-not-exist'':
|
||||
analysistemplate.argoproj.io "does-not-exist" not found'
|
||||
running: true
|
||||
phase: Error
|
||||
templateStatuses:
|
||||
- availableReplicas: 0
|
||||
lastTransitionTime: "2019-10-28T05:59:33Z"
|
||||
name: baseline
|
||||
readyReplicas: 0
|
||||
replicas: 0
|
||||
phase: Successful
|
||||
updatedReplicas: 0
|
||||
54
resource_customizations/argoproj.io/Experiment/testdata/failedExperiment.yaml
vendored
Normal file
54
resource_customizations/argoproj.io/Experiment/testdata/failedExperiment.yaml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
name: example-experiment
|
||||
namespace: default
|
||||
spec:
|
||||
analyses:
|
||||
- name: test
|
||||
templateName: analysis-template
|
||||
duration: 60
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
spec:
|
||||
containers:
|
||||
- image: 'argoproj/rollouts-demo:blue'
|
||||
name: guestbook
|
||||
status:
|
||||
analysisRuns:
|
||||
- analysisRun: example-experiment-test-57vl8
|
||||
name: test
|
||||
phase: Failed
|
||||
availableAt: '2019-10-28T20:58:00Z'
|
||||
conditions:
|
||||
- lastTransitionTime: '2019-10-28T20:57:58Z'
|
||||
lastUpdateTime: '2019-10-28T20:58:01Z'
|
||||
message: Experiment "example-experiment" is running.
|
||||
reason: NewReplicaSetAvailable
|
||||
phase: 'True'
|
||||
type: Progressing
|
||||
phase: Failed
|
||||
templateStatuses:
|
||||
- availableReplicas: 0
|
||||
lastTransitionTime: '2019-10-28T20:58:01Z'
|
||||
name: baseline
|
||||
readyReplicas: 0
|
||||
replicas: 0
|
||||
phase: Successful
|
||||
updatedReplicas: 0
|
||||
- availableReplicas: 0
|
||||
lastTransitionTime: '2019-10-28T20:58:01Z'
|
||||
name: canary
|
||||
readyReplicas: 0
|
||||
replicas: 0
|
||||
phase: Successful
|
||||
updatedReplicas: 0
|
||||
33
resource_customizations/argoproj.io/Experiment/testdata/noStatusExperiment.yaml
vendored
Normal file
33
resource_customizations/argoproj.io/Experiment/testdata/noStatusExperiment.yaml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: >
|
||||
{"apiVersion":"argoproj.io/v1alpha1","kind":"Experiment","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"rollouts-canary"},"name":"example-experiment","namespace":"argo-rollouts"},"spec":{"duration":60,"templates":[{"name":"baseline","selector":{"matchLabels":{"app":"rollouts-demo","color":"blue"}},"template":{"metadata":{"labels":{"app":"rollouts-demo","color":"blue"}},"spec":{"containers":[{"image":"argoproj/rollouts-demo:blue","name":"guestbook"}]}}},{"name":"canary","selector":{"matchLabels":{"app":"rollouts-demo","color":"yellow"}},"template":{"metadata":{"labels":{"app":"rollouts-demo","color":"yellow"}},"spec":{"containers":[{"image":"argoproj/rollouts-demo:yellow","name":"guestbook"}]}}}]}}
|
||||
creationTimestamp: '2019-10-28T20:13:28Z'
|
||||
generation: 1
|
||||
labels:
|
||||
app.kubernetes.io/instance: rollouts-canary
|
||||
name: example-experiment
|
||||
namespace: argo-rollouts
|
||||
resourceVersion: '28562006'
|
||||
selfLink: >-
|
||||
/apis/argoproj.io/v1alpha1/namespaces/argo-rollouts/experiments/example-experiment
|
||||
uid: 67792f8a-f9bf-11e9-a15b-42010aa80033
|
||||
spec:
|
||||
duration: 60
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
spec:
|
||||
containers:
|
||||
- image: 'argoproj/rollouts-demo:blue'
|
||||
name: guestbook
|
||||
47
resource_customizations/argoproj.io/Experiment/testdata/pendingExperiment.yaml
vendored
Normal file
47
resource_customizations/argoproj.io/Experiment/testdata/pendingExperiment.yaml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
name: experiment-with-analysis-5hm74
|
||||
namespace: default
|
||||
spec:
|
||||
analyses:
|
||||
- name: job
|
||||
templateName: job
|
||||
duration: 3600
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
spec:
|
||||
containers:
|
||||
- image: argoproj/rollouts-demo:blue
|
||||
name: rollouts-demo
|
||||
status:
|
||||
analysisRuns:
|
||||
- analysisRun: experiment-with-analysis-5hm74-job-h4bgb
|
||||
name: job
|
||||
phase: Running
|
||||
availableAt: "2019-10-21T03:40:28Z"
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-10-21T03:40:28Z"
|
||||
lastUpdateTime: "2019-10-21T03:40:28Z"
|
||||
message: Experiment "experiment-with-analysis-5hm74" has successfully ran and
|
||||
completed.
|
||||
reason: ExperimentCompleted
|
||||
phase: "False"
|
||||
type: Progressing
|
||||
running: false
|
||||
phase: Pending
|
||||
templateStatuses:
|
||||
- availableReplicas: 0
|
||||
lastTransitionTime: "2019-10-28T20:22:01Z"
|
||||
name: baseline
|
||||
readyReplicas: 0
|
||||
replicas: 0
|
||||
phase: Progressing
|
||||
updatedReplicas: 0
|
||||
40
resource_customizations/argoproj.io/Experiment/testdata/runningExperiment.yaml
vendored
Normal file
40
resource_customizations/argoproj.io/Experiment/testdata/runningExperiment.yaml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
name: example-experiment
|
||||
namespace: argo-rollouts
|
||||
spec:
|
||||
duration: 60
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
spec:
|
||||
containers:
|
||||
- image: 'argoproj/rollouts-demo:blue'
|
||||
name: guestbook
|
||||
status:
|
||||
availableAt: '2019-10-28T20:15:02Z'
|
||||
conditions:
|
||||
- lastTransitionTime: '2019-10-28T20:14:59Z'
|
||||
lastUpdateTime: '2019-10-28T20:15:02Z'
|
||||
message: Experiment "example-experiment" is running.
|
||||
reason: NewReplicaSetAvailable
|
||||
phase: 'True'
|
||||
type: Progressing
|
||||
phase: Running
|
||||
templateStatuses:
|
||||
- availableReplicas: 1
|
||||
lastTransitionTime: '2019-10-28T20:15:02Z'
|
||||
name: baseline
|
||||
readyReplicas: 1
|
||||
replicas: 1
|
||||
phase: Running
|
||||
updatedReplicas: 1
|
||||
61
resource_customizations/argoproj.io/Experiment/testdata/successfulExperiment.yaml
vendored
Normal file
61
resource_customizations/argoproj.io/Experiment/testdata/successfulExperiment.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Experiment
|
||||
metadata:
|
||||
name: example-experiment
|
||||
namespace: argo-rollouts
|
||||
spec:
|
||||
duration: 60
|
||||
templates:
|
||||
- name: baseline
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
color: blue
|
||||
spec:
|
||||
containers:
|
||||
- image: 'argoproj/rollouts-demo:blue'
|
||||
name: guestbook
|
||||
- name: canary
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rollouts-demo
|
||||
color: yellow
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rollouts-demo
|
||||
color: yellow
|
||||
spec:
|
||||
containers:
|
||||
- image: 'argoproj/rollouts-demo:yellow'
|
||||
name: guestbook
|
||||
status:
|
||||
availableAt: '2019-10-28T20:15:02Z'
|
||||
conditions:
|
||||
- lastTransitionTime: '2019-10-28T20:20:54Z'
|
||||
lastUpdateTime: '2019-10-28T20:20:54Z'
|
||||
message: Experiment "example-experiment" has successfully ran and completed.
|
||||
reason: ExperimentCompleted
|
||||
phase: 'False'
|
||||
type: Progressing
|
||||
phase: Successful
|
||||
templateStatuses:
|
||||
- availableReplicas: 1
|
||||
lastTransitionTime: '2019-10-28T20:15:02Z'
|
||||
name: baseline
|
||||
readyReplicas: 1
|
||||
replicas: 1
|
||||
phase: Successful
|
||||
updatedReplicas: 1
|
||||
- availableReplicas: 1
|
||||
lastTransitionTime: '2019-10-28T20:15:01Z'
|
||||
name: canary
|
||||
readyReplicas: 1
|
||||
replicas: 1
|
||||
phase: Successful
|
||||
updatedReplicas: 1
|
||||
@@ -1,24 +1,28 @@
|
||||
discoveryTests:
|
||||
- inputPath: testdata/paused_rollout.yaml
|
||||
- inputPath: testdata/pre_v0.6_paused_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: false
|
||||
- inputPath: testdata/v0.2_paused_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: false
|
||||
- inputPath: testdata/not_paused_rollout.yaml
|
||||
- inputPath: testdata/pre_v0.6_not_paused_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: true
|
||||
- inputPath: testdata/nil_paused_rollout.yaml
|
||||
- inputPath: testdata/pre_v0.6_nil_paused_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: true
|
||||
- inputPath: testdata/has_pause_condition_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: false
|
||||
- inputPath: testdata/no_pause_condition_rollout.yaml
|
||||
result:
|
||||
- name: resume
|
||||
disabled: true
|
||||
actionTests:
|
||||
- action: resume
|
||||
inputPath: testdata/paused_rollout.yaml
|
||||
expectedOutputPath: testdata/not_paused_rollout.yaml
|
||||
inputPath: testdata/pre_v0.6_paused_rollout.yaml
|
||||
expectedOutputPath: testdata/pre_v0.6_not_paused_rollout.yaml
|
||||
- action: resume
|
||||
inputPath: testdata/v0.2_paused_rollout.yaml
|
||||
expectedOutputPath: testdata/v0.2_not_paused_rollout.yaml
|
||||
inputPath: testdata/has_pause_condition_rollout.yaml
|
||||
expectedOutputPath: testdata/no_pause_condition_rollout.yaml
|
||||
@@ -3,8 +3,8 @@ actions["resume"] = {["disabled"] = false}
|
||||
|
||||
local paused = false
|
||||
|
||||
if obj.status ~= nil and obj.status.verifyingPreview ~= nil then
|
||||
paused = obj.status.verifyingPreview
|
||||
if obj.status ~= nil and obj.status.pauseConditions ~= nil then
|
||||
paused = table.getn(obj.status.pauseConditions) > 0
|
||||
elseif obj.spec.paused ~= nil then
|
||||
paused = obj.spec.paused
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if obj.status.verifyingPreview ~= nil and obj.status.verifyingPreview then
|
||||
obj.status.verifyingPreview = false
|
||||
if obj.status.pauseConditions ~= nil and table.getn(obj.status.pauseConditions) > 0 then
|
||||
obj.status.pauseConditions = nil
|
||||
end
|
||||
|
||||
if obj.spec.paused ~= nil and obj.spec.paused then
|
||||
|
||||
61
resource_customizations/argoproj.io/Rollout/actions/testdata/has_pause_condition_rollout.yaml
vendored
Normal file
61
resource_customizations/argoproj.io/Rollout/actions/testdata/has_pause_condition_rollout.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
name: canary-demo
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 5
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: canary-demo
|
||||
strategy:
|
||||
canary:
|
||||
analysis:
|
||||
name: analysis
|
||||
templateName: analysis-template
|
||||
canaryService: canary-demo-preview
|
||||
steps:
|
||||
- setWeight: 40
|
||||
- pause: {}
|
||||
- setWeight: 60
|
||||
- pause: {}
|
||||
- setWeight: 80
|
||||
- pause:
|
||||
duration: 10
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: canary-demo
|
||||
spec:
|
||||
containers:
|
||||
- image: argoproj/rollouts-demo:yellow
|
||||
imagePullPolicy: Always
|
||||
name: canary-demo
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
cpu: 5m
|
||||
memory: 32Mi
|
||||
status:
|
||||
HPAReplicas: 5
|
||||
availableReplicas: 5
|
||||
blueGreen: {}
|
||||
canary:
|
||||
currentBackgroundAnalysisRun: canary-demo-6758949f55-6-analysis
|
||||
stableRS: 645d5dbc4c
|
||||
controllerPause: true
|
||||
currentPodHash: 6758949f55
|
||||
currentStepHash: 59f8666948
|
||||
currentStepIndex: 1
|
||||
observedGeneration: 58b949649c
|
||||
pauseConditions:
|
||||
- reason: CanaryPauseStep
|
||||
startTime: "2019-11-05T18:10:29Z"
|
||||
readyReplicas: 5
|
||||
replicas: 5
|
||||
selector: app=canary-demo
|
||||
updatedReplicas: 2
|
||||
58
resource_customizations/argoproj.io/Rollout/actions/testdata/no_pause_condition_rollout.yaml
vendored
Normal file
58
resource_customizations/argoproj.io/Rollout/actions/testdata/no_pause_condition_rollout.yaml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
name: canary-demo
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 5
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: canary-demo
|
||||
strategy:
|
||||
canary:
|
||||
analysis:
|
||||
name: analysis
|
||||
templateName: analysis-template
|
||||
canaryService: canary-demo-preview
|
||||
steps:
|
||||
- setWeight: 40
|
||||
- pause: {}
|
||||
- setWeight: 60
|
||||
- pause: {}
|
||||
- setWeight: 80
|
||||
- pause:
|
||||
duration: 10
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: canary-demo
|
||||
spec:
|
||||
containers:
|
||||
- image: argoproj/rollouts-demo:yellow
|
||||
imagePullPolicy: Always
|
||||
name: canary-demo
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
cpu: 5m
|
||||
memory: 32Mi
|
||||
status:
|
||||
HPAReplicas: 5
|
||||
availableReplicas: 5
|
||||
blueGreen: {}
|
||||
canary:
|
||||
currentBackgroundAnalysisRun: canary-demo-6758949f55-6-analysis
|
||||
stableRS: 645d5dbc4c
|
||||
controllerPause: true
|
||||
currentPodHash: 6758949f55
|
||||
currentStepHash: 59f8666948
|
||||
currentStepIndex: 1
|
||||
observedGeneration: 58b949649c
|
||||
readyReplicas: 5
|
||||
replicas: 5
|
||||
selector: app=canary-demo
|
||||
updatedReplicas: 2
|
||||
@@ -1,55 +0,0 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
annotations:
|
||||
rollout.argoproj.io/revision: "7"
|
||||
clusterName: ""
|
||||
creationTimestamp: 2019-01-22T16:52:54Z
|
||||
generation: 1
|
||||
labels:
|
||||
app.kubernetes.io/instance: guestbook-default
|
||||
name: ks-guestbook-ui
|
||||
namespace: default
|
||||
resourceVersion: "164113"
|
||||
selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/rollouts/ks-guestbook-ui
|
||||
uid: 29802403-1e66-11e9-a6a4-025000000001
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ks-guestbook-ui
|
||||
strategy:
|
||||
blueGreen:
|
||||
activeService: ks-guestbook-ui-active
|
||||
previewService: ks-guestbook-ui-preview
|
||||
type: BlueGreenUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ks-guestbook-ui
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/heptio-images/ks-guestbook-demo:0.1
|
||||
name: ks-guestbook-ui
|
||||
ports:
|
||||
- containerPort: 83
|
||||
resources: {}
|
||||
status:
|
||||
blueGreen:
|
||||
activeSelector: 85f9884f5d
|
||||
previewSelector: 697fb9575c
|
||||
availableReplicas: 6
|
||||
conditions:
|
||||
- lastTransitionTime: 2019-01-25T07:44:26Z
|
||||
lastUpdateTime: 2019-01-25T07:44:26Z
|
||||
message: Rollout is serving traffic from the active service.
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Available
|
||||
currentPodHash: 697fb9575c
|
||||
observedGeneration: 767f98959f
|
||||
readyReplicas: 6
|
||||
replicas: 6
|
||||
updatedReplicas: 3
|
||||
verifyingPreview: false
|
||||
@@ -1,55 +0,0 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
annotations:
|
||||
rollout.argoproj.io/revision: "7"
|
||||
clusterName: ""
|
||||
creationTimestamp: 2019-01-22T16:52:54Z
|
||||
generation: 1
|
||||
labels:
|
||||
app.kubernetes.io/instance: guestbook-default
|
||||
name: ks-guestbook-ui
|
||||
namespace: default
|
||||
resourceVersion: "164113"
|
||||
selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/rollouts/ks-guestbook-ui
|
||||
uid: 29802403-1e66-11e9-a6a4-025000000001
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ks-guestbook-ui
|
||||
strategy:
|
||||
blueGreen:
|
||||
activeService: ks-guestbook-ui-active
|
||||
previewService: ks-guestbook-ui-preview
|
||||
type: BlueGreenUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ks-guestbook-ui
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/heptio-images/ks-guestbook-demo:0.1
|
||||
name: ks-guestbook-ui
|
||||
ports:
|
||||
- containerPort: 83
|
||||
resources: {}
|
||||
status:
|
||||
blueGreen:
|
||||
activeSelector: 85f9884f5d
|
||||
previewSelector: 697fb9575c
|
||||
availableReplicas: 6
|
||||
conditions:
|
||||
- lastTransitionTime: 2019-01-25T07:44:26Z
|
||||
lastUpdateTime: 2019-01-25T07:44:26Z
|
||||
message: Rollout is serving traffic from the active service.
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Available
|
||||
currentPodHash: 697fb9575c
|
||||
observedGeneration: 767f98959f
|
||||
readyReplicas: 6
|
||||
replicas: 6
|
||||
updatedReplicas: 3
|
||||
verifyingPreview: true
|
||||
@@ -10,22 +10,9 @@ function checkReplicasStatus(obj)
|
||||
hs.message = "Waiting for roll out to finish: More replicas need to be updated"
|
||||
return hs
|
||||
end
|
||||
if replicasStatus > updatedReplicas then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for roll out to finish: old replicas are pending termination"
|
||||
return hs
|
||||
end
|
||||
if availableReplicas < updatedReplicas then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for roll out to finish: updated replicas are still becoming available"
|
||||
return hs
|
||||
end
|
||||
if updatedReplicas < replicasCount then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for roll out to finish: More replicas need to be updated"
|
||||
return hs
|
||||
end
|
||||
if replicasStatus > updatedReplicas then
|
||||
-- Since the scale down delay can be very high, BlueGreen does not wait for all the old replicas to scale
|
||||
-- down before marking itself healthy. As a result, only evaluate this condition if the strategy is canary.
|
||||
if obj.spec.strategy.canary ~= nil and replicasStatus > updatedReplicas then
|
||||
hs.status = "Progressing"
|
||||
hs.message = "Waiting for roll out to finish: old replicas are pending termination"
|
||||
return hs
|
||||
@@ -71,6 +58,11 @@ if obj.status ~= nil then
|
||||
hs.message = condition.message
|
||||
return hs
|
||||
end
|
||||
if condition.type == "Progressing" and condition.reason == "RolloutAborted" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = condition.message
|
||||
return hs
|
||||
end
|
||||
if condition.type == "Progressing" and condition.reason == "ProgressDeadlineExceeded" then
|
||||
hs.status = "Degraded"
|
||||
hs.message = condition.message
|
||||
@@ -88,7 +80,7 @@ if obj.status ~= nil then
|
||||
if replicasHS ~= nil then
|
||||
return replicasHS
|
||||
end
|
||||
if obj.status.blueGreen ~= nil and obj.status.blueGreen.activeSelector ~= nil and obj.status.currentPodHash ~= nil and obj.status.blueGreen.activeSelector == obj.status.currentPodHash then
|
||||
if obj.status.blueGreen ~= nil and obj.status.blueGreen.activeSelector ~= nil and obj.status.blueGreen.activeSelector == obj.status.currentPodHash then
|
||||
hs.status = "Healthy"
|
||||
hs.message = "The active Service is serving traffic to the current pod spec"
|
||||
return hs
|
||||
|
||||
@@ -11,6 +11,10 @@ tests:
|
||||
status: Degraded
|
||||
message: ReplicaSet "guestbook-bluegreen-helm-guestbook-6b8cf6f7db" has timed out progressing.
|
||||
inputPath: testdata/degraded_rolloutTimeout.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: Rollout is aborted
|
||||
inputPath: testdata/degraded_abortedRollout.yaml
|
||||
#BlueGreen
|
||||
- healthStatus:
|
||||
status: Healthy
|
||||
@@ -28,10 +32,6 @@ tests:
|
||||
status: Progressing
|
||||
message: "Waiting for roll out to finish: More replicas need to be updated"
|
||||
inputPath: testdata/bluegreen/progressing_addingMoreReplicas.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Waiting for roll out to finish: old replicas are pending termination"
|
||||
inputPath: testdata/bluegreen/progressing_killingOldReplicas.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Waiting for roll out to finish: updated replicas are still becoming available"
|
||||
@@ -41,6 +41,10 @@ tests:
|
||||
status: Progressing
|
||||
message: Waiting for rollout to finish steps
|
||||
inputPath: testdata/canary/progressing_setWeightStep.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "Waiting for roll out to finish: old replicas are pending termination"
|
||||
inputPath: testdata/canary/progressing_killingOldReplicas.yaml
|
||||
- healthStatus:
|
||||
status: Suspended
|
||||
message: Rollout is paused
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"argoproj.io/v1alpha1","kind":"Rollout","metadata":{"annotations":{},"labels":{"app.kubernetes.io/instance":"guestbook-default","ksonnet.io/component":"guestbook-ui"},"name":"ks-guestbook-ui","namespace":"default"},"spec":{"minReadySeconds":30,"replicas":3,"selector":{"matchLabels":{"app":"ks-guestbook-ui"}},"strategy":{"blueGreen":{"activeService":"ks-guestbook-ui-active","previewService":"ks-guestbook-ui-preview"},"type":"BlueGreenUpdate"},"template":{"metadata":{"labels":{"app":"ks-guestbook-ui"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.1","name":"ks-guestbook-ui","ports":[{"containerPort":83}]}]}}}}
|
||||
rollout.argoproj.io/revision: "7"
|
||||
clusterName: ""
|
||||
creationTimestamp: 2019-01-22T16:52:54Z
|
||||
generation: 1
|
||||
labels:
|
||||
app.kubernetes.io/instance: guestbook-default
|
||||
ksonnet.io/component: guestbook-ui
|
||||
name: ks-guestbook-ui
|
||||
namespace: default
|
||||
resourceVersion: "164141"
|
||||
selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/rollouts/ks-guestbook-ui
|
||||
uid: 29802403-1e66-11e9-a6a4-025000000001
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ks-guestbook-ui
|
||||
strategy:
|
||||
blueGreen:
|
||||
activeService: ks-guestbook-ui-active
|
||||
previewService: ks-guestbook-ui-preview
|
||||
type: BlueGreenUpdate
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: ks-guestbook-ui
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/heptio-images/ks-guestbook-demo:0.1
|
||||
name: ks-guestbook-ui
|
||||
ports:
|
||||
- containerPort: 83
|
||||
resources: {}
|
||||
status:
|
||||
activeSelector: 697fb9575c
|
||||
availableReplicas: 6
|
||||
conditions:
|
||||
- lastTransitionTime: 2019-01-25T07:44:26Z
|
||||
lastUpdateTime: 2019-01-25T07:44:26Z
|
||||
message: Rollout is serving traffic from the active service.
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Available
|
||||
currentPodHash: 697fb9575c
|
||||
observedGeneration: 767f98959f
|
||||
previewSelector: ""
|
||||
readyReplicas: 6
|
||||
replicas: 6
|
||||
updatedReplicas: 3
|
||||
61
resource_customizations/argoproj.io/Rollout/testdata/canary/progressing_killingOldReplicas.yaml
vendored
Normal file
61
resource_customizations/argoproj.io/Rollout/testdata/canary/progressing_killingOldReplicas.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"argoproj.io/v1alpha1","kind":"Rollout","metadata":{"annotations":{},"name":"example-rollout-canary","namespace":"default"},"spec":{"minReadySeconds":30,"replicas":5,"revisionHistoryLimit":3,"selector":{"matchLabels":{"app":"guestbook"}},"strategy":{"canary":{"steps":[{"setWeight":20},{"pause":{"duration":20}},{"setWeight":40},{"pause":{}}]}},"template":{"metadata":{"labels":{"app":"guestbook"}},"spec":{"containers":[{"image":"gcr.io/heptio-images/ks-guestbook-demo:0.1","name":"guestbook","ports":[{"containerPort":80}]}]}}}}
|
||||
rollout.argoproj.io/revision: "3"
|
||||
creationTimestamp: "2019-10-20T15:42:26Z"
|
||||
generation: 101
|
||||
name: example-rollout-canary
|
||||
namespace: default
|
||||
resourceVersion: "1779901"
|
||||
selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/rollouts/example-rollout-canary
|
||||
uid: f8ebf794-8b4e-4a1f-a2d1-a85bc1d206ef
|
||||
spec:
|
||||
minReadySeconds: 30
|
||||
replicas: 5
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: guestbook
|
||||
strategy:
|
||||
canary: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: guestbook
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/heptio-images/ks-guestbook-demo:0.1
|
||||
name: guestbook
|
||||
ports:
|
||||
- containerPort: 80
|
||||
resources: {}
|
||||
status:
|
||||
HPAReplicas: 6
|
||||
availableReplicas: 5
|
||||
blueGreen: {}
|
||||
canary:
|
||||
stableRS: 74d6dc8544
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-10-25T16:08:02Z"
|
||||
lastUpdateTime: "2019-10-25T16:08:02Z"
|
||||
message: Rollout has minimum availability
|
||||
reason: AvailableReason
|
||||
status: "True"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-10-25T16:50:19Z"
|
||||
lastUpdateTime: "2019-11-07T18:19:25Z"
|
||||
message: ReplicaSet "example-rollout-canary-694fb7759c" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
currentPodHash: 694fb7759c
|
||||
currentStepHash: 5ffbfbbd64
|
||||
observedGeneration: 7fcc96c7b7
|
||||
readyReplicas: 6
|
||||
replicas: 6
|
||||
selector: app=guestbook
|
||||
updatedReplicas: 5
|
||||
70
resource_customizations/argoproj.io/Rollout/testdata/degraded_abortedRollout.yaml
vendored
Normal file
70
resource_customizations/argoproj.io/Rollout/testdata/degraded_abortedRollout.yaml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Rollout
|
||||
metadata:
|
||||
name: canary-demo
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 5
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: canary-demo
|
||||
strategy:
|
||||
canary:
|
||||
analysis:
|
||||
name: analysis
|
||||
templateName: analysis-template
|
||||
canaryService: canary-demo-preview
|
||||
steps:
|
||||
- setWeight: 40
|
||||
- pause: {}
|
||||
- setWeight: 60
|
||||
- pause: {}
|
||||
- setWeight: 80
|
||||
- pause:
|
||||
duration: 10
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: canary-demo
|
||||
spec:
|
||||
containers:
|
||||
- image: argoproj/rollouts-demo:yellow
|
||||
imagePullPolicy: Always
|
||||
name: canary-demo
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
protocol: TCP
|
||||
resources:
|
||||
requests:
|
||||
cpu: 5m
|
||||
memory: 32Mi
|
||||
status:
|
||||
HPAReplicas: 5
|
||||
abort: true
|
||||
availableReplicas: 5
|
||||
blueGreen: {}
|
||||
canary:
|
||||
stableRS: 645d5dbc4c
|
||||
conditions:
|
||||
- lastTransitionTime: "2019-11-03T01:32:46Z"
|
||||
lastUpdateTime: "2019-11-03T01:32:46Z"
|
||||
message: Rollout has minimum availability
|
||||
reason: AvailableReason
|
||||
status: "True"
|
||||
type: Available
|
||||
- lastTransitionTime: "2019-11-05T18:20:12Z"
|
||||
lastUpdateTime: "2019-11-05T18:20:12Z"
|
||||
message: Rollout is aborted
|
||||
reason: RolloutAborted
|
||||
status: "False"
|
||||
type: Progressing
|
||||
currentPodHash: 6758949f55
|
||||
currentStepHash: 59f8666948
|
||||
currentStepIndex: 0
|
||||
observedGeneration: 58b949649c
|
||||
readyReplicas: 5
|
||||
replicas: 5
|
||||
selector: app=canary-demo
|
||||
@@ -41,37 +41,38 @@ func NewServer(db db.ArgoDB, enf *rbac.Enforcer, cache *cache.Cache, kubectl kub
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) getConnectionState(cluster appv1.Cluster, errorMessage string) appv1.ConnectionState {
|
||||
if connectionState, err := s.cache.GetClusterConnectionState(cluster.Server); err == nil {
|
||||
return connectionState
|
||||
func (s *Server) getConnectionState(cluster appv1.Cluster, errorMessage string) (appv1.ConnectionState, string) {
|
||||
if clusterInfo, err := s.cache.GetClusterInfo(cluster.Server); err == nil {
|
||||
return clusterInfo.ConnectionState, clusterInfo.Version
|
||||
}
|
||||
now := v1.Now()
|
||||
connectionState := appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusSuccessful,
|
||||
ModifiedAt: &now,
|
||||
clusterInfo := cache.ClusterInfo{
|
||||
ConnectionState: appv1.ConnectionState{
|
||||
Status: appv1.ConnectionStatusSuccessful,
|
||||
ModifiedAt: &now,
|
||||
},
|
||||
}
|
||||
|
||||
config := cluster.RESTConfig()
|
||||
config.Timeout = time.Second
|
||||
kubeClientset, err := kubernetes.NewForConfig(config)
|
||||
if err == nil {
|
||||
_, err = kubeClientset.Discovery().ServerVersion()
|
||||
}
|
||||
version, err := s.kubectl.GetServerVersion(config)
|
||||
if err != nil {
|
||||
connectionState.Status = appv1.ConnectionStatusFailed
|
||||
connectionState.Message = fmt.Sprintf("Unable to connect to cluster: %v", err)
|
||||
clusterInfo.Status = appv1.ConnectionStatusFailed
|
||||
clusterInfo.Message = fmt.Sprintf("Unable to connect to cluster: %v", err)
|
||||
} else {
|
||||
clusterInfo.Version = version
|
||||
}
|
||||
|
||||
if errorMessage != "" {
|
||||
connectionState.Status = appv1.ConnectionStatusFailed
|
||||
connectionState.Message = fmt.Sprintf("%s %s", errorMessage, connectionState.Message)
|
||||
clusterInfo.Status = appv1.ConnectionStatusFailed
|
||||
clusterInfo.Message = fmt.Sprintf("%s %s", errorMessage, clusterInfo.Message)
|
||||
}
|
||||
|
||||
err = s.cache.SetClusterConnectionState(cluster.Server, &connectionState)
|
||||
err = s.cache.SetClusterInfo(cluster.Server, &clusterInfo)
|
||||
if err != nil {
|
||||
log.Warnf("getConnectionState cache set error %s: %v", cluster.Server, err)
|
||||
log.Warnf("getClusterInfo cache set error %s: %v", cluster.Server, err)
|
||||
}
|
||||
return connectionState
|
||||
return clusterInfo.ConnectionState, clusterInfo.Version
|
||||
}
|
||||
|
||||
// List returns list of clusters
|
||||
@@ -100,11 +101,9 @@ func (s *Server) List(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Clus
|
||||
warningMessage = fmt.Sprintf("There are %d credentials configured this cluster.", len(clusters))
|
||||
}
|
||||
if clust.ConnectionState.Status == "" {
|
||||
clust.ConnectionState = s.getConnectionState(clust, warningMessage)
|
||||
}
|
||||
clust.ServerVersion, err = s.kubectl.GetServerVersion(clust.RESTConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
state, serverVersion := s.getConnectionState(clust, warningMessage)
|
||||
clust.ConnectionState = state
|
||||
clust.ServerVersion = serverVersion
|
||||
}
|
||||
items[i] = *redact(&clust)
|
||||
return nil
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
|
||||
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
||||
@@ -82,10 +83,15 @@ func (s *Server) List(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1.
|
||||
items := appsv1.Repositories{}
|
||||
for _, repo := range repos {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, repo.Repo) {
|
||||
// For backwards compatibility, if we have no repo type set assume a default
|
||||
rType := repo.Type
|
||||
if rType == "" {
|
||||
rType = common.DefaultRepoType
|
||||
}
|
||||
// remove secrets
|
||||
items = append(items, &appsv1.Repository{
|
||||
Repo: repo.Repo,
|
||||
Type: repo.Type,
|
||||
Type: rType,
|
||||
Name: repo.Name,
|
||||
Username: repo.Username,
|
||||
Insecure: repo.IsInsecure(),
|
||||
@@ -222,7 +228,10 @@ func (s *Server) Create(ctx context.Context, q *repositorypkg.RepoCreateRequest)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "existing repository spec is different; use upsert flag to force update")
|
||||
}
|
||||
}
|
||||
return &appsv1.Repository{Repo: repo.Repo, Type: repo.Type, Name: repo.Name}, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &appsv1.Repository{Repo: repo.Repo, Type: repo.Type, Name: repo.Name}, nil
|
||||
}
|
||||
|
||||
// Update updates a repository
|
||||
|
||||
@@ -450,7 +450,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
)))
|
||||
grpcS := grpc.NewServer(sOpts...)
|
||||
db := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
|
||||
kubectl := kube.KubectlCmd{}
|
||||
kubectl := &kube.KubectlCmd{}
|
||||
clusterService := cluster.NewServer(db, a.enf, a.Cache, kubectl)
|
||||
repoService := repository.NewServer(a.RepoClientset, db, a.enf, a.Cache, a.settingsMgr)
|
||||
sessionService := session.NewServer(a.sessionMgr, a)
|
||||
@@ -478,22 +478,23 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
// TranslateGrpcCookieHeader conditionally sets a cookie on the response.
|
||||
func (a *ArgoCDServer) translateGrpcCookieHeader(ctx context.Context, w http.ResponseWriter, resp golang_proto.Message) error {
|
||||
if sessionResp, ok := resp.(*sessionpkg.SessionResponse); ok {
|
||||
flags := []string{"path=/"}
|
||||
flags := []string{"path=/", "SameSite=lax", "httpOnly"}
|
||||
if !a.Insecure {
|
||||
flags = append(flags, "Secure")
|
||||
}
|
||||
token := sessionResp.Token
|
||||
if token != "" {
|
||||
token, err := zjwt.ZJWT(token)
|
||||
var err error
|
||||
token, err = zjwt.ZJWT(token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, token, flags...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Set-Cookie", cookie)
|
||||
}
|
||||
cookie, err := httputil.MakeCookieMetadata(common.AuthCookieName, token, flags...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Set-Cookie", cookie)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apiclient/session"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
@@ -479,3 +482,31 @@ func Test_getToken(t *testing.T) {
|
||||
assert.Equal(t, token, getToken(metadata.New(map[string]string{"grpcgateway-cookie": "argocd.token=" + token})))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTranslateGrpcCookieHeader(t *testing.T) {
|
||||
argoCDOpts := ArgoCDServerOpts{
|
||||
Namespace: test.FakeArgoCDNamespace,
|
||||
KubeClientset: fake.NewSimpleClientset(test.NewFakeConfigMap(), test.NewFakeSecret()),
|
||||
AppClientset: apps.NewSimpleClientset(),
|
||||
}
|
||||
argocd := NewServer(context.Background(), argoCDOpts)
|
||||
|
||||
t.Run("TokenIsNotEmpty", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
err := argocd.translateGrpcCookieHeader(context.Background(), recorder, &session.SessionResponse{
|
||||
Token: "xyz",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "argocd.token=xyz; path=/; SameSite=lax; httpOnly; Secure", recorder.Result().Header.Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
t.Run("TokenIsEmpty", func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
err := argocd.translateGrpcCookieHeader(context.Background(), recorder, &session.SessionResponse{
|
||||
Token: "",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "argocd.token=; path=/; SameSite=lax; httpOnly; Secure", recorder.Result().Header.Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -25,31 +25,36 @@ func (s *Server) Version(context.Context, *empty.Empty) (*version.VersionMessage
|
||||
vers := common.GetVersion()
|
||||
if s.ksonnetVersion == "" {
|
||||
ksonnetVersion, err := ksutil.Version()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == nil {
|
||||
s.ksonnetVersion = ksonnetVersion
|
||||
} else {
|
||||
s.ksonnetVersion = err.Error()
|
||||
}
|
||||
s.ksonnetVersion = ksonnetVersion
|
||||
}
|
||||
if s.kustomizeVersion == "" {
|
||||
kustomizeVersion, err := kustomize.Version()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == nil {
|
||||
s.kustomizeVersion = kustomizeVersion
|
||||
} else {
|
||||
s.kustomizeVersion = err.Error()
|
||||
}
|
||||
s.kustomizeVersion = kustomizeVersion
|
||||
|
||||
}
|
||||
if s.helmVersion == "" {
|
||||
helmVersion, err := helm.Version()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == nil {
|
||||
s.helmVersion = helmVersion
|
||||
} else {
|
||||
s.helmVersion = err.Error()
|
||||
}
|
||||
s.helmVersion = helmVersion
|
||||
}
|
||||
if s.kubectlVersion == "" {
|
||||
kubectlVersion, err := kube.Version()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == nil {
|
||||
s.kubectlVersion = kubectlVersion
|
||||
} else {
|
||||
s.kubectlVersion = err.Error()
|
||||
}
|
||||
s.kubectlVersion = kubectlVersion
|
||||
}
|
||||
return &version.VersionMessage{
|
||||
Version: vers.Version,
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestDeclarativeHelmInvalidValuesFile(t *testing.T) {
|
||||
func TestHelmRepo(t *testing.T) {
|
||||
Given(t).
|
||||
CustomCACertAdded().
|
||||
HelmRepoAdded("").
|
||||
HelmRepoAdded("custom-repo").
|
||||
RepoURLType(RepoURLTypeHelm).
|
||||
Chart("helm").
|
||||
Revision("1.0.0").
|
||||
|
||||
@@ -16,7 +16,7 @@ func TestBuildManifests(t *testing.T) {
|
||||
|
||||
out, err := argoexec.RunCommand("kustomize", argoexec.CmdOpts{}, "version")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, Contains(out, "KustomizeVersion:3") || Contains(out, "KustomizeVersion:v3"), "kustomize should be version 3")
|
||||
assert.True(t, Contains(out, "Version:kustomize/v3"), "kustomize should be version 3")
|
||||
|
||||
err = filepath.Walk("../manifests", func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
|
||||
9
ui/.prettierrc
Normal file
9
ui/.prettierrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"bracketSpacing": false,
|
||||
"jsxSingleQuote": true,
|
||||
"printWidth": 180,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"jsxBracketSameLine": true,
|
||||
"quoteProps": "consistent"
|
||||
}
|
||||
@@ -72,15 +72,26 @@ async function isExpiredSSO() {
|
||||
|
||||
requests.onError.subscribe(async (err) => {
|
||||
if (err.status === 401) {
|
||||
if (!history.location.pathname.startsWith('/login')) {
|
||||
// Query for basehref and remove trailing /.
|
||||
// If basehref is the default `/` it will become an empty string.
|
||||
const basehref = document.querySelector('head > base').getAttribute('href').replace(/\/$/, '');
|
||||
if (await isExpiredSSO()) {
|
||||
window.location.href = `${basehref}/auth/login?return_url=${encodeURIComponent(location.href)}`;
|
||||
} else {
|
||||
history.push(`${basehref}/login?return_url=${encodeURIComponent(location.href)}`);
|
||||
}
|
||||
if (history.location.pathname.startsWith('/login')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isSSO = await isExpiredSSO();
|
||||
|
||||
// location might change after async method call, so we need to check again.
|
||||
if (history.location.pathname.startsWith('/login')) {
|
||||
return;
|
||||
}
|
||||
// Query for basehref and remove trailing /.
|
||||
// If basehref is the default `/` it will become an empty string.
|
||||
const basehref = document
|
||||
.querySelector('head > base')
|
||||
.getAttribute('href')
|
||||
.replace(/\/$/, '');
|
||||
if (isSSO) {
|
||||
window.location.href = `${basehref}/auth/login?return_url=${encodeURIComponent(location.href)}`;
|
||||
} else {
|
||||
history.push(`${basehref}/login?return_url=${encodeURIComponent(location.href)}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -522,7 +522,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{ na
|
||||
const resourceActions = services.applications.getResourceActions(application.metadata.name, resource)
|
||||
.then((actions) => items.concat(actions.map((action) => ({
|
||||
title: action.name,
|
||||
disabled: !action.available,
|
||||
disabled: !!action.disabled,
|
||||
action: async () => {
|
||||
try {
|
||||
const confirmed = await this.appContext.apis.popup.confirm(
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { ErrorNotification, MockupList, NotificationType, SlidingPanel } from 'argo-ui';
|
||||
import {ErrorNotification, MockupList, NotificationType, SlidingPanel} from 'argo-ui';
|
||||
import * as classNames from 'classnames';
|
||||
import * as minimatch from 'minimatch';
|
||||
import * as React from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Observable } from 'rxjs';
|
||||
import {RouteComponentProps} from 'react-router';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
import { Autocomplete, ClusterCtx, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query } from '../../../shared/components';
|
||||
import { Consumer } from '../../../shared/context';
|
||||
import {Autocomplete, ClusterCtx, DataLoader, EmptyState, ObservableQuery, Page, Paginate, Query} from '../../../shared/components';
|
||||
import {Consumer} from '../../../shared/context';
|
||||
import * as models from '../../../shared/models';
|
||||
import { AppsListPreferences, AppsListViewType, services } from '../../../shared/services';
|
||||
import { ApplicationCreatePanel } from '../application-create-panel/application-create-panel';
|
||||
import { ApplicationSyncPanel } from '../application-sync-panel/application-sync-panel';
|
||||
import {AppsListPreferences, AppsListViewType, services} from '../../../shared/services';
|
||||
import {ApplicationCreatePanel} from '../application-create-panel/application-create-panel';
|
||||
import {ApplicationSyncPanel} from '../application-sync-panel/application-sync-panel';
|
||||
import {ApplicationsSyncPanel} from '../applications-sync-panel/applications-sync-panel';
|
||||
import * as LabelSelector from '../label-selector';
|
||||
import * as AppUtils from '../utils';
|
||||
import { ApplicationsFilter } from './applications-filter';
|
||||
import { ApplicationsSummary } from './applications-summary';
|
||||
import { ApplicationsTable } from './applications-table';
|
||||
import { ApplicationTiles } from './applications-tiles';
|
||||
import {ApplicationsFilter} from './applications-filter';
|
||||
import {ApplicationsSummary} from './applications-summary';
|
||||
import {ApplicationsTable} from './applications-table';
|
||||
import {ApplicationTiles} from './applications-tiles';
|
||||
|
||||
require('./applications-list.scss');
|
||||
|
||||
@@ -25,93 +27,125 @@ const APP_FIELDS = [
|
||||
'metadata.labels',
|
||||
'metadata.resourceVersion',
|
||||
'metadata.creationTimestamp',
|
||||
'metadata.deletionTimestamp',
|
||||
'spec',
|
||||
'operation.sync',
|
||||
'status.sync.status',
|
||||
'status.health',
|
||||
'status.summary'];
|
||||
'status.operationState.phase',
|
||||
'status.operationState.operation.sync',
|
||||
'status.summary',
|
||||
];
|
||||
const APP_LIST_FIELDS = APP_FIELDS.map((field) => `items.${field}`);
|
||||
const APP_WATCH_FIELDS = ['result.type', ...APP_FIELDS.map((field) => `result.application.${field}`)];
|
||||
|
||||
function loadApplications(selector: string): Observable<models.Application[]> {
|
||||
return Observable.fromPromise(services.applications.list([], { fields: APP_LIST_FIELDS, selector })).flatMap((applications) =>
|
||||
function loadApplications(): Observable<models.Application[]> {
|
||||
return Observable.fromPromise(services.applications.list([], {fields: APP_LIST_FIELDS})).flatMap((applications) =>
|
||||
Observable.merge(
|
||||
Observable.from([applications]),
|
||||
services.applications.watch(null, { fields: APP_WATCH_FIELDS, selector }).map((appChange) => {
|
||||
const index = applications.findIndex((item) => item.metadata.name === appChange.application.metadata.name);
|
||||
if (index > -1 && appChange.application.metadata.resourceVersion === applications[index].metadata.resourceVersion) {
|
||||
return {applications, updated: false};
|
||||
}
|
||||
switch (appChange.type) {
|
||||
case 'DELETED':
|
||||
if (index > -1) {
|
||||
applications.splice(index, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (index > -1) {
|
||||
applications[index] = appChange.application;
|
||||
} else {
|
||||
applications.unshift(appChange.application);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return {applications, updated: true};
|
||||
}).filter((item) => item.updated).map((item) => item.applications),
|
||||
services.applications
|
||||
.watch(null, {fields: APP_WATCH_FIELDS})
|
||||
.map((appChange) => {
|
||||
const index = applications.findIndex((item) => item.metadata.name === appChange.application.metadata.name);
|
||||
if (index > -1 && appChange.application.metadata.resourceVersion === applications[index].metadata.resourceVersion) {
|
||||
return {applications, updated: false};
|
||||
}
|
||||
switch (appChange.type) {
|
||||
case 'DELETED':
|
||||
if (index > -1) {
|
||||
applications.splice(index, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (index > -1) {
|
||||
applications[index] = appChange.application;
|
||||
} else {
|
||||
applications.unshift(appChange.application);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return {applications, updated: true};
|
||||
})
|
||||
.filter((item) => item.updated)
|
||||
.map((item) => item.applications),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const ViewPref = ({children}: { children: (pref: AppsListPreferences & { page: number, search: string }) => React.ReactNode }) => (
|
||||
const ViewPref = ({children}: {children: (pref: AppsListPreferences & {page: number; search: string}) => React.ReactNode}) => (
|
||||
<ObservableQuery>
|
||||
{(q) => (
|
||||
<DataLoader load={() => Observable.combineLatest(
|
||||
services.viewPreferences.getPreferences().map((item) => item.appList), q).map((items) => {
|
||||
const params = items[1];
|
||||
const viewPref: AppsListPreferences = {...items[0]};
|
||||
if (params.get('proj') != null) {
|
||||
viewPref.projectsFilter = params.get('proj').split(',').filter((item) => !!item);
|
||||
}
|
||||
if (params.get('sync') != null) {
|
||||
viewPref.syncFilter = params.get('sync').split(',').filter((item) => !!item);
|
||||
}
|
||||
if (params.get('health') != null) {
|
||||
viewPref.healthFilter = params.get('health').split(',').filter((item) => !!item);
|
||||
}
|
||||
if (params.get('namespace') != null) {
|
||||
viewPref.namespacesFilter = params.get('namespace').split(',').filter((item) => !!item);
|
||||
}
|
||||
if (params.get('cluster') != null) {
|
||||
viewPref.clustersFilter = params.get('cluster').split(',').filter((item) => !!item);
|
||||
}
|
||||
if (params.get('view') != null) {
|
||||
viewPref.view = params.get('view') as AppsListViewType;
|
||||
}
|
||||
if (params.get('labels') != null) {
|
||||
viewPref.labelsFilter = params.get('labels').split(',').filter((item) => !!item);
|
||||
}
|
||||
return {...viewPref, page: parseInt(params.get('page') || '0', 10), search: params.get('search') || ''};
|
||||
})}>
|
||||
{(pref) => children(pref)}
|
||||
<DataLoader
|
||||
load={() =>
|
||||
Observable.combineLatest(services.viewPreferences.getPreferences().map((item) => item.appList), q).map((items) => {
|
||||
const params = items[1];
|
||||
const viewPref: AppsListPreferences = {...items[0]};
|
||||
if (params.get('proj') != null) {
|
||||
viewPref.projectsFilter = params
|
||||
.get('proj')
|
||||
.split(',')
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
if (params.get('sync') != null) {
|
||||
viewPref.syncFilter = params
|
||||
.get('sync')
|
||||
.split(',')
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
if (params.get('health') != null) {
|
||||
viewPref.healthFilter = params
|
||||
.get('health')
|
||||
.split(',')
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
if (params.get('namespace') != null) {
|
||||
viewPref.namespacesFilter = params
|
||||
.get('namespace')
|
||||
.split(',')
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
if (params.get('cluster') != null) {
|
||||
viewPref.clustersFilter = params
|
||||
.get('cluster')
|
||||
.split(',')
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
if (params.get('view') != null) {
|
||||
viewPref.view = params.get('view') as AppsListViewType;
|
||||
}
|
||||
if (params.get('labels') != null) {
|
||||
viewPref.labelsFilter = params
|
||||
.get('labels')
|
||||
.split(',')
|
||||
.map(decodeURIComponent)
|
||||
.filter((item) => !!item);
|
||||
}
|
||||
return {...viewPref, page: parseInt(params.get('page') || '0', 10), search: params.get('search') || ''};
|
||||
})
|
||||
}>
|
||||
{(pref) => children(pref)}
|
||||
</DataLoader>
|
||||
)}
|
||||
</ObservableQuery>
|
||||
);
|
||||
|
||||
function filterApps(applications: models.Application[], pref: AppsListPreferences, search: string) {
|
||||
return applications.filter((app) =>
|
||||
(search === '' || app.metadata.name.includes(search)) &&
|
||||
(pref.projectsFilter.length === 0 || pref.projectsFilter.includes(app.spec.project)) &&
|
||||
(pref.reposFilter.length === 0 || pref.reposFilter.includes(app.spec.source.repoURL)) &&
|
||||
(pref.syncFilter.length === 0 || pref.syncFilter.includes(app.status.sync.status)) &&
|
||||
(pref.healthFilter.length === 0 || pref.healthFilter.includes(app.status.health.status)) &&
|
||||
(pref.namespacesFilter.length === 0 || pref.namespacesFilter.some((ns) => minimatch(app.spec.destination.namespace, ns))) &&
|
||||
(pref.clustersFilter.length === 0 || pref.clustersFilter.some((server) => minimatch(app.spec.destination.server, server))),
|
||||
return applications.filter(
|
||||
(app) =>
|
||||
(search === '' || app.metadata.name.includes(search)) &&
|
||||
(pref.projectsFilter.length === 0 || pref.projectsFilter.includes(app.spec.project)) &&
|
||||
(pref.reposFilter.length === 0 || pref.reposFilter.includes(app.spec.source.repoURL)) &&
|
||||
(pref.syncFilter.length === 0 || pref.syncFilter.includes(app.status.sync.status)) &&
|
||||
(pref.healthFilter.length === 0 || pref.healthFilter.includes(app.status.health.status)) &&
|
||||
(pref.namespacesFilter.length === 0 || pref.namespacesFilter.some((ns) => minimatch(app.spec.destination.namespace, ns))) &&
|
||||
(pref.clustersFilter.length === 0 || pref.clustersFilter.some((server) => minimatch(app.spec.destination.server, server))) &&
|
||||
(pref.labelsFilter.length === 0 || pref.labelsFilter.every((selector) => LabelSelector.match(selector, app.metadata.labels))),
|
||||
);
|
||||
}
|
||||
|
||||
function tryJsonParse(input: string) {
|
||||
try {
|
||||
return input && JSON.parse(input) || null;
|
||||
return (input && JSON.parse(input)) || null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -120,179 +154,234 @@ function tryJsonParse(input: string) {
|
||||
export const ApplicationsList = (props: RouteComponentProps<{}>) => {
|
||||
const query = new URLSearchParams(props.location.search);
|
||||
const appInput = tryJsonParse(query.get('new'));
|
||||
const syncAppsInput = tryJsonParse(query.get('syncApps'));
|
||||
const [createApi, setCreateApi] = React.useState(null);
|
||||
const clusters = React.useMemo(() => services.clusters.list(), []);
|
||||
|
||||
return (
|
||||
<ClusterCtx.Provider value={clusters}>
|
||||
<Consumer>{
|
||||
(ctx) => (
|
||||
<Page title='Applications' toolbar={services.viewPreferences.getPreferences().map((pref) => ({
|
||||
breadcrumbs: [{ title: 'Applications', path: '/applications' }],
|
||||
tools: (
|
||||
<React.Fragment key='app-list-tools'>
|
||||
<span className='applications-list__view-type'>
|
||||
<i className={classNames('fa fa-th', {selected: pref.appList.view === 'tiles'})} onClick={() => {
|
||||
ctx.navigation.goto('.', { view: 'tiles'});
|
||||
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'tiles'} });
|
||||
}} />
|
||||
<i className={classNames('fa fa-th-list', {selected: pref.appList.view === 'list'})} onClick={() => {
|
||||
ctx.navigation.goto('.', { view: 'list'});
|
||||
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'list'} });
|
||||
}} />
|
||||
<i className={classNames('fa fa-chart-pie', {selected: pref.appList.view === 'summary'})} onClick={() => {
|
||||
ctx.navigation.goto('.', { view: 'summary'});
|
||||
services.viewPreferences.updatePreferences({ appList: {...pref.appList, view: 'summary'} });
|
||||
}} />
|
||||
</span>
|
||||
</React.Fragment>
|
||||
),
|
||||
actionMenu: {
|
||||
className: 'fa fa-plus',
|
||||
items: [{
|
||||
title: 'New Application',
|
||||
action: () => ctx.navigation.goto('.', { new: '{}' }),
|
||||
}],
|
||||
},
|
||||
}))}>
|
||||
<div className='applications-list'>
|
||||
<ViewPref>
|
||||
{(pref) =>
|
||||
<DataLoader
|
||||
input={(pref.labelsFilter || []).join(',')}
|
||||
load={(selector) => loadApplications(selector)}
|
||||
loadingRenderer={() => (<div className='argo-container'><MockupList height={100} marginTop={30}/></div>)}>
|
||||
{(applications: models.Application[]) => (
|
||||
applications.length === 0 && (pref.labelsFilter || []).length === 0 ? (
|
||||
<EmptyState icon='argo-icon-application'>
|
||||
<h4>No applications yet</h4>
|
||||
<h5>Create new application to start managing resources in your cluster</h5>
|
||||
<button className='argo-button argo-button--base' onClick={() => ctx.navigation.goto('.', { new: JSON.stringify({}) })}>Create application</button>
|
||||
</EmptyState>
|
||||
) : (
|
||||
<div className='row'>
|
||||
<div className='columns small-12 xxlarge-2'>
|
||||
<Query>
|
||||
{(q) => (
|
||||
<div className='applications-list__search'>
|
||||
<i className='fa fa-search'/>
|
||||
{q.get('search') && (
|
||||
<i className='fa fa-times' onClick={() => ctx.navigation.goto('.', { search: null }, { replace: true })}/>
|
||||
)}
|
||||
<Autocomplete
|
||||
filterSuggestions={true}
|
||||
renderInput={(inputProps) => (
|
||||
<input {...inputProps} onFocus={(e) => {
|
||||
e.target.select();
|
||||
if (inputProps.onFocus) {
|
||||
inputProps.onFocus(e);
|
||||
}
|
||||
}} className='argo-field' />
|
||||
)}
|
||||
renderItem={(item) => (
|
||||
<React.Fragment>
|
||||
<i className='icon argo-icon-application'/> {item.label}
|
||||
</React.Fragment>
|
||||
)}
|
||||
onSelect={(val) => {
|
||||
ctx.navigation.goto(`./${val}`);
|
||||
<ClusterCtx.Provider value={clusters}>
|
||||
<Consumer>
|
||||
{(ctx) => (
|
||||
<Page
|
||||
title='Applications'
|
||||
toolbar={services.viewPreferences.getPreferences().map((pref) => ({
|
||||
breadcrumbs: [{title: 'Applications', path: '/applications'}],
|
||||
tools: (
|
||||
<React.Fragment key='app-list-tools'>
|
||||
<span className='applications-list__view-type'>
|
||||
<i
|
||||
className={classNames('fa fa-th', {selected: pref.appList.view === 'tiles'})}
|
||||
onClick={() => {
|
||||
ctx.navigation.goto('.', {view: 'tiles'});
|
||||
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'tiles'}});
|
||||
}}
|
||||
onChange={(e) => ctx.navigation.goto('.', { search: e.target.value }, { replace: true })}
|
||||
value={q.get('search') || ''} items={applications.map((app) => app.metadata.name)}/>
|
||||
</div>
|
||||
)}
|
||||
</Query>
|
||||
<ApplicationsFilter applications={applications} pref={pref} onChange={(newPref) => {
|
||||
services.viewPreferences.updatePreferences({appList: newPref});
|
||||
ctx.navigation.goto('.', {
|
||||
proj: newPref.projectsFilter.join(','),
|
||||
sync: newPref.syncFilter.join(','),
|
||||
health: newPref.healthFilter.join(','),
|
||||
namespace: newPref.namespacesFilter.join(','),
|
||||
cluster: newPref.clustersFilter.join(','),
|
||||
labels: newPref.labelsFilter.join(','),
|
||||
});
|
||||
}} />
|
||||
</div>
|
||||
<div className='columns small-12 xxlarge-10'>
|
||||
{pref.view === 'summary' && (
|
||||
<ApplicationsSummary applications={filterApps(applications, pref, pref.search)} />
|
||||
) || (
|
||||
<Paginate
|
||||
preferencesKey='applications-list'
|
||||
page={pref.page}
|
||||
emptyState={() => (
|
||||
<EmptyState icon='fa fa-search'>
|
||||
<h4>No applications found</h4>
|
||||
<h5>Try to change filter criteria</h5>
|
||||
</EmptyState>
|
||||
)}
|
||||
data={filterApps(applications, pref, pref.search)} onPageChange={(page) => ctx.navigation.goto('.', { page })} >
|
||||
{(data) => (
|
||||
pref.view === 'tiles' && (
|
||||
<ApplicationTiles
|
||||
applications={data}
|
||||
syncApplication={(appName) => ctx.navigation.goto('.', { syncApp: appName })}
|
||||
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
|
||||
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
|
||||
/>
|
||||
) || (
|
||||
<ApplicationsTable applications={data}
|
||||
syncApplication={(appName) => ctx.navigation.goto('.', { syncApp: appName })}
|
||||
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
|
||||
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
|
||||
<i
|
||||
className={classNames('fa fa-th-list', {selected: pref.appList.view === 'list'})}
|
||||
onClick={() => {
|
||||
ctx.navigation.goto('.', {view: 'list'});
|
||||
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'list'}});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
<i
|
||||
className={classNames('fa fa-chart-pie', {selected: pref.appList.view === 'summary'})}
|
||||
onClick={() => {
|
||||
ctx.navigation.goto('.', {view: 'summary'});
|
||||
services.viewPreferences.updatePreferences({appList: {...pref.appList, view: 'summary'}});
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</React.Fragment>
|
||||
),
|
||||
actionMenu: {
|
||||
items: [
|
||||
{
|
||||
title: 'New App',
|
||||
iconClassName: 'fa fa-plus',
|
||||
action: () => ctx.navigation.goto('.', {new: '{}'}),
|
||||
},
|
||||
{
|
||||
title: 'Sync Apps',
|
||||
iconClassName: 'fa fa-sync',
|
||||
action: () => ctx.navigation.goto('.', {syncApps: true}),
|
||||
},
|
||||
],
|
||||
},
|
||||
}))}>
|
||||
<div className='applications-list'>
|
||||
<ViewPref>
|
||||
{(pref) => (
|
||||
<DataLoader
|
||||
load={() => loadApplications()}
|
||||
loadingRenderer={() => (
|
||||
<div className='argo-container'>
|
||||
<MockupList height={100} marginTop={30} />
|
||||
</div>
|
||||
)}>
|
||||
{(applications: models.Application[]) =>
|
||||
applications.length === 0 && (pref.labelsFilter || []).length === 0 ? (
|
||||
<EmptyState icon='argo-icon-application'>
|
||||
<h4>No applications yet</h4>
|
||||
<h5>Create new application to start managing resources in your cluster</h5>
|
||||
<button className='argo-button argo-button--base' onClick={() => ctx.navigation.goto('.', {new: JSON.stringify({})})}>
|
||||
Create application
|
||||
</button>
|
||||
</EmptyState>
|
||||
) : (
|
||||
<div className='row'>
|
||||
<div className='columns small-12 xxlarge-2'>
|
||||
<Query>
|
||||
{(q) => (
|
||||
<div className='applications-list__search'>
|
||||
<i className='fa fa-search' />
|
||||
{q.get('search') && (
|
||||
<i className='fa fa-times' onClick={() => ctx.navigation.goto('.', {search: null}, {replace: true})} />
|
||||
)}
|
||||
<Autocomplete
|
||||
filterSuggestions={true}
|
||||
renderInput={(inputProps) => (
|
||||
<input
|
||||
{...inputProps}
|
||||
onFocus={(e) => {
|
||||
e.target.select();
|
||||
if (inputProps.onFocus) {
|
||||
inputProps.onFocus(e);
|
||||
}
|
||||
}}
|
||||
className='argo-field'
|
||||
/>
|
||||
)}
|
||||
renderItem={(item) => (
|
||||
<React.Fragment>
|
||||
<i className='icon argo-icon-application' /> {item.label}
|
||||
</React.Fragment>
|
||||
)}
|
||||
onSelect={(val) => {
|
||||
ctx.navigation.goto(`./${val}`);
|
||||
}}
|
||||
onChange={(e) => ctx.navigation.goto('.', {search: e.target.value}, {replace: true})}
|
||||
value={q.get('search') || ''}
|
||||
items={applications.map((app) => app.metadata.name)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Query>
|
||||
<ApplicationsFilter
|
||||
applications={applications}
|
||||
pref={pref}
|
||||
onChange={(newPref) => {
|
||||
services.viewPreferences.updatePreferences({appList: newPref});
|
||||
ctx.navigation.goto('.', {
|
||||
proj: newPref.projectsFilter.join(','),
|
||||
sync: newPref.syncFilter.join(','),
|
||||
health: newPref.healthFilter.join(','),
|
||||
namespace: newPref.namespacesFilter.join(','),
|
||||
cluster: newPref.clustersFilter.join(','),
|
||||
labels: newPref.labelsFilter.map(encodeURIComponent).join(','),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{syncAppsInput && (
|
||||
<ApplicationsSyncPanel
|
||||
key='syncsPanel'
|
||||
show={syncAppsInput}
|
||||
hide={() => ctx.navigation.goto('.', {syncApps: null})}
|
||||
apps={filterApps(applications, pref, pref.search)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className='columns small-12 xxlarge-10'>
|
||||
{(pref.view === 'summary' && <ApplicationsSummary applications={filterApps(applications, pref, pref.search)} />) || (
|
||||
<Paginate
|
||||
preferencesKey='applications-list'
|
||||
page={pref.page}
|
||||
emptyState={() => (
|
||||
<EmptyState icon='fa fa-search'>
|
||||
<h4>No applications found</h4>
|
||||
<h5>Try to change filter criteria</h5>
|
||||
</EmptyState>
|
||||
)}
|
||||
data={filterApps(applications, pref, pref.search)}
|
||||
onPageChange={(page) => ctx.navigation.goto('.', {page})}>
|
||||
{(data) =>
|
||||
(pref.view === 'tiles' && (
|
||||
<ApplicationTiles
|
||||
applications={data}
|
||||
syncApplication={(appName) => ctx.navigation.goto('.', {syncApp: appName})}
|
||||
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
|
||||
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
|
||||
/>
|
||||
)) || (
|
||||
<ApplicationsTable
|
||||
applications={data}
|
||||
syncApplication={(appName) => ctx.navigation.goto('.', {syncApp: appName})}
|
||||
refreshApplication={(appName) => services.applications.get(appName, 'normal')}
|
||||
deleteApplication={(appName) => AppUtils.deleteApplication(appName, ctx)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Paginate>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</DataLoader>
|
||||
)}
|
||||
</Paginate>
|
||||
)}
|
||||
</div>
|
||||
</ViewPref>
|
||||
</div>
|
||||
)
|
||||
<ObservableQuery>
|
||||
{(q) => (
|
||||
<DataLoader
|
||||
load={() =>
|
||||
q.flatMap((params) => {
|
||||
const syncApp = params.get('syncApp');
|
||||
return (syncApp && Observable.fromPromise(services.applications.get(syncApp))) || Observable.from([null]);
|
||||
})
|
||||
}>
|
||||
{(app) => (
|
||||
<ApplicationSyncPanel key='syncPanel' application={app} selectedResource={'all'} hide={() => ctx.navigation.goto('.', {syncApp: null})} />
|
||||
)}
|
||||
</DataLoader>
|
||||
)}
|
||||
</ObservableQuery>
|
||||
<SlidingPanel
|
||||
isShown={!!appInput}
|
||||
onClose={() => ctx.navigation.goto('.', {new: null})}
|
||||
header={
|
||||
<div>
|
||||
<button className='argo-button argo-button--base' onClick={() => createApi && createApi.submitForm(null)}>
|
||||
Create
|
||||
</button>{' '}
|
||||
<button onClick={() => ctx.navigation.goto('.', {new: null})} className='argo-button argo-button--base-o'>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
}>
|
||||
{appInput && (
|
||||
<ApplicationCreatePanel
|
||||
getFormApi={(api) => {
|
||||
setCreateApi(api);
|
||||
}}
|
||||
createApp={async (app) => {
|
||||
try {
|
||||
await services.applications.create(app);
|
||||
ctx.navigation.goto('.', {new: null});
|
||||
} catch (e) {
|
||||
ctx.notifications.show({
|
||||
content: <ErrorNotification title='Unable to create application' e={e} />,
|
||||
type: NotificationType.Error,
|
||||
});
|
||||
}
|
||||
}}
|
||||
app={appInput}
|
||||
onAppChanged={(app) => ctx.navigation.goto('.', {new: JSON.stringify(app)}, {replace: true})}
|
||||
/>
|
||||
)}
|
||||
</SlidingPanel>
|
||||
</Page>
|
||||
)}
|
||||
</DataLoader>
|
||||
}</ViewPref>
|
||||
</div>
|
||||
<ObservableQuery>
|
||||
{(q) => (
|
||||
<DataLoader load={() => q.flatMap((params) => {
|
||||
const syncApp = params.get('syncApp');
|
||||
return syncApp && Observable.fromPromise(services.applications.get(syncApp)) || Observable.from([null]);
|
||||
}) }>
|
||||
{(app) => (
|
||||
<ApplicationSyncPanel key='syncPanel' application={app} selectedResource={'all'} hide={() => ctx.navigation.goto('.', { syncApp: null })} />
|
||||
)}
|
||||
</DataLoader>
|
||||
)}
|
||||
</ObservableQuery>
|
||||
<SlidingPanel isShown={!!appInput} onClose={() => ctx.navigation.goto('.', { new: null })} header={
|
||||
<div>
|
||||
<button className='argo-button argo-button--base'
|
||||
onClick={() => createApi && createApi.submitForm(null)}>
|
||||
Create
|
||||
</button> <button onClick={() => ctx.navigation.goto('.', { new: null })} className='argo-button argo-button--base-o'>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
}>
|
||||
{appInput && <ApplicationCreatePanel getFormApi={(api) => {
|
||||
setCreateApi(api);
|
||||
}} createApp={ async (app) => {
|
||||
try {
|
||||
await services.applications.create(app);
|
||||
ctx.navigation.goto('.', { new: null });
|
||||
} catch (e) {
|
||||
ctx.notifications.show({
|
||||
content: <ErrorNotification title='Unable to create application' e={e}/>,
|
||||
type: NotificationType.Error,
|
||||
});
|
||||
}
|
||||
}}
|
||||
app={appInput}
|
||||
onAppChanged={(app) => ctx.navigation.goto('.', { new: JSON.stringify(app) }, { replace: true })} />}
|
||||
</SlidingPanel>
|
||||
</Page>
|
||||
)}
|
||||
</Consumer>
|
||||
</ClusterCtx.Provider>);
|
||||
</Consumer>
|
||||
</ClusterCtx.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import {ErrorNotification, NotificationType, SlidingPanel} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {Checkbox, Form, FormApi} from 'react-form';
|
||||
import {Consumer} from '../../../shared/context';
|
||||
import * as models from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {ComparisonStatusIcon, HealthStatusIcon} from '../utils';
|
||||
|
||||
export const ApplicationsSyncPanel = ({show, apps, hide}: {show: boolean; apps: models.Application[]; hide: () => void}) => {
|
||||
const [form, setForm] = React.useState<FormApi>(null);
|
||||
const getSelectedApps = (params: any) => apps.filter((app) => params['app/' + app.metadata.name]);
|
||||
return (
|
||||
<Consumer>
|
||||
{(ctx) => (
|
||||
<SlidingPanel
|
||||
isMiddle={true}
|
||||
isShown={show}
|
||||
onClose={() => hide()}
|
||||
header={
|
||||
<div>
|
||||
<button className='argo-button argo-button--base' onClick={() => form.submitForm(null)}>
|
||||
Sync
|
||||
</button>{' '}
|
||||
<button onClick={() => hide()} className='argo-button argo-button--base-o'>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
}>
|
||||
<Form
|
||||
onSubmit={async (params: any) => {
|
||||
const selectedApps = getSelectedApps(params);
|
||||
if (selectedApps.length === 0) {
|
||||
ctx.notifications.show({content: `No apps selected`, type: NotificationType.Error});
|
||||
return;
|
||||
}
|
||||
ctx.notifications.show({
|
||||
content: `Syncing ${selectedApps.length} app(s)`,
|
||||
type: NotificationType.Success,
|
||||
});
|
||||
const syncStrategy = (params.applyOnly ? {apply: {force: params.force}} : {hook: {force: params.force}}) as models.SyncStrategy;
|
||||
for (const app of selectedApps) {
|
||||
await services.applications.sync(app.metadata.name, app.spec.source.targetRevision, params.prune, params.dryRun, syncStrategy, null).catch((e) => {
|
||||
ctx.notifications.show({
|
||||
content: <ErrorNotification title={`Unable to sync ${app.metadata.name}`} e={e} />,
|
||||
type: NotificationType.Error,
|
||||
});
|
||||
});
|
||||
}
|
||||
hide();
|
||||
}}
|
||||
getApi={setForm}>
|
||||
{(formApi) => (
|
||||
<React.Fragment>
|
||||
<div className='argo-form-row'>
|
||||
<h4>Sync app(s)</h4>
|
||||
<label>Options:</label>
|
||||
<div style={{paddingLeft: '1em'}}>
|
||||
<label>
|
||||
<Checkbox field='prune' /> Prune
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<Checkbox field='dryRun' /> Dry Run
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<Checkbox field='applyOnly' /> Apply Only
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<Checkbox field='force' /> Force
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
Apps (<a
|
||||
onClick={() => apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, true))}>all</a>/
|
||||
<a
|
||||
onClick={() =>
|
||||
apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, app.status.sync.status === models.SyncStatuses.OutOfSync))
|
||||
}>
|
||||
out of sync
|
||||
</a>
|
||||
/<a
|
||||
onClick={() => apps.forEach((app) => formApi.setValue('app/' + app.metadata.name, false))}>none</a>
|
||||
):
|
||||
</label>
|
||||
<div style={{paddingLeft: '1em'}}>
|
||||
{apps.map((app) => (
|
||||
<label key={app.metadata.name}>
|
||||
<Checkbox field={`app/${app.metadata.name}`} />
|
||||
|
||||
{app.metadata.name}
|
||||
|
||||
<ComparisonStatusIcon status={app.status.sync.status} />
|
||||
|
||||
<HealthStatusIcon state={app.status.health} />
|
||||
<br />
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Form>
|
||||
</SlidingPanel>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
45
ui/src/app/applications/components/label-selector.test.ts
Normal file
45
ui/src/app/applications/components/label-selector.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as LabelSelector from './label-selector';
|
||||
|
||||
test('exists', () => {
|
||||
expect(LabelSelector.match('test', {test: 'hello'})).toBeTruthy();
|
||||
expect(LabelSelector.match('test1', {test: 'hello'})).toBeFalsy();
|
||||
expect(LabelSelector.match('app.kubernetes.io/instance', {'app.kubernetes.io/instance': 'hello'})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('not exists', () => {
|
||||
expect(LabelSelector.match('!test', {test: 'hello'})).toBeFalsy();
|
||||
expect(LabelSelector.match('!test1', {test: 'hello'})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('in', () => {
|
||||
expect(LabelSelector.match('test in 1, 2, 3', {test: '1'})).toBeTruthy();
|
||||
expect(LabelSelector.match('test in 1, 2, 3', {test: '4'})).toBeFalsy();
|
||||
expect(LabelSelector.match('test in 1, 2, 3', {test1: '1'})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('notIn', () => {
|
||||
expect(LabelSelector.match('test notin 1, 2, 3', {test: '1'})).toBeFalsy();
|
||||
expect(LabelSelector.match('test notin 1, 2, 3', {test: '4'})).toBeTruthy();
|
||||
expect(LabelSelector.match('test notin 1, 2, 3', {test1: '1'})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('equal', () => {
|
||||
expect(LabelSelector.match('test=hello', {test: 'hello'})).toBeTruthy();
|
||||
expect(LabelSelector.match('test=world', {test: 'hello'})).toBeFalsy();
|
||||
expect(LabelSelector.match('test==hello', {test: 'hello'})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('notEqual', () => {
|
||||
expect(LabelSelector.match('test!=hello', {test: 'hello'})).toBeFalsy();
|
||||
expect(LabelSelector.match('test!=world', {test: 'hello'})).toBeTruthy();
|
||||
});
|
||||
|
||||
test('greaterThen', () => {
|
||||
expect(LabelSelector.match('test gt 1', {test: '2'})).toBeTruthy();
|
||||
expect(LabelSelector.match('test gt 3', {test: '2'})).toBeFalsy();
|
||||
});
|
||||
|
||||
test('lessThen', () => {
|
||||
expect(LabelSelector.match('test lt 1', {test: '2'})).toBeFalsy();
|
||||
expect(LabelSelector.match('test lt 3', {test: '2'})).toBeTruthy();
|
||||
});
|
||||
39
ui/src/app/applications/components/label-selector.ts
Normal file
39
ui/src/app/applications/components/label-selector.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
type operatorFn = (labels: {[name: string]: string}, key: string, values: string[]) => boolean;
|
||||
|
||||
const operators: {[type: string]: operatorFn} = {
|
||||
'!=': (labels, key, values) => labels[key] !== values[0],
|
||||
'==': (labels, key, values) => labels[key] === values[0],
|
||||
'=': (labels, key, values) => labels[key] === values[0],
|
||||
'[\\W]notin[\\W]': (labels, key, values) => !values.includes(labels[key]),
|
||||
'[\\W]in[\\W]': (labels, key, values) => values.includes(labels[key]),
|
||||
'[\\W]gt[\\W]': (labels, key, values) => parseFloat(labels[key]) > parseFloat(values[0]),
|
||||
'[\\W]lt[\\W]': (labels, key, values) => parseFloat(labels[key]) < parseFloat(values[0]),
|
||||
};
|
||||
|
||||
function split(input: string, delimiter: string | RegExp): string[] {
|
||||
return input
|
||||
.split(delimiter)
|
||||
.map((part) => part.trim())
|
||||
.filter((part) => part !== '');
|
||||
}
|
||||
|
||||
export type LabelSelector = (labels: {[name: string]: string}) => boolean;
|
||||
|
||||
export function parse(selector: string): LabelSelector {
|
||||
for (const type of Object.keys(operators)) {
|
||||
const operator = operators[type];
|
||||
const parts = split(selector, new RegExp(type));
|
||||
if (parts.length > 1) {
|
||||
const values = split(parts[1], ',');
|
||||
return (labels) => operator(labels, parts[0], values);
|
||||
}
|
||||
}
|
||||
if (selector.startsWith('!')) {
|
||||
return (labels) => !labels.hasOwnProperty(selector.slice(1));
|
||||
}
|
||||
return (labels) => labels.hasOwnProperty(selector);
|
||||
}
|
||||
|
||||
export function match(selector: string, labels: {[name: string]: string}): boolean {
|
||||
return parse(selector)(labels || {});
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
import {DataLoader, Page as ArgoPage, Toolbar, Utils} from 'argo-ui';
|
||||
import { parse } from 'cookie';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
import {Observable} from 'rxjs';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {AppContext} from '../context';
|
||||
import {services} from '../services';
|
||||
|
||||
const mostRecentLoggedIn = new BehaviorSubject<boolean>(false);
|
||||
|
||||
function isLoggedIn(): Observable<boolean> {
|
||||
services.users.get().then((info) => mostRecentLoggedIn.next(info.loggedIn));
|
||||
return mostRecentLoggedIn;
|
||||
}
|
||||
|
||||
export class Page extends React.Component<{ title: string, toolbar?: Toolbar | Observable<Toolbar> }> {
|
||||
public static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -14,20 +20,31 @@ export class Page extends React.Component<{ title: string, toolbar?: Toolbar | O
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<DataLoader input={new Date()} load={() => Utils.toObservable(this.props.toolbar).map((toolbar) => {
|
||||
toolbar = toolbar || {};
|
||||
toolbar.tools = [
|
||||
toolbar.tools,
|
||||
// this is a crummy check, as the token maybe expired, but it is better than flashing user interface
|
||||
parse(document.cookie)['argocd.token'] ?
|
||||
<a key='logout' onClick={() => this.goToLogin(true)}>Logout</a> :
|
||||
<a key='login' onClick={() => this.goToLogin(false)}>Login</a>,
|
||||
];
|
||||
return toolbar;
|
||||
})}>
|
||||
{(toolbar) => (
|
||||
<ArgoPage title={this.props.title} children={this.props.children} toolbar={toolbar} />
|
||||
)}
|
||||
<DataLoader
|
||||
input={new Date()}
|
||||
load={() =>
|
||||
Utils.toObservable(this.props.toolbar).map((toolbar) => {
|
||||
toolbar = toolbar || {};
|
||||
toolbar.tools = [
|
||||
toolbar.tools,
|
||||
<DataLoader key='loginPanel' load={() => isLoggedIn()}>
|
||||
{(loggedIn) =>
|
||||
loggedIn ? (
|
||||
<a key='logout' onClick={() => this.goToLogin(true)}>
|
||||
Logout
|
||||
</a>
|
||||
) : (
|
||||
<a key='login' onClick={() => this.goToLogin(false)}>
|
||||
Login
|
||||
</a>
|
||||
)
|
||||
}
|
||||
</DataLoader>,
|
||||
];
|
||||
return toolbar;
|
||||
})
|
||||
}>
|
||||
{(toolbar) => <ArgoPage title={this.props.title} children={this.props.children} toolbar={toolbar} />}
|
||||
</DataLoader>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ export interface ResourceActionParam {
|
||||
export interface ResourceAction {
|
||||
name: string;
|
||||
params: ResourceActionParam[];
|
||||
available: boolean;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export interface SyncWindowsState {
|
||||
|
||||
@@ -12,7 +12,7 @@ interface QueryOptions {
|
||||
|
||||
function optionsToSearch(options?: QueryOptions) {
|
||||
if (options) {
|
||||
return { fields: (options.exclude ? '-' : '') + options.fields.join(','), selector: options.selector };
|
||||
return { fields: (options.exclude ? '-' : '') + options.fields.join(','), selector: options.selector || '' };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export interface ViewPreferences {
|
||||
|
||||
const VIEW_PREFERENCES_KEY = 'view_preferences';
|
||||
|
||||
const minVer = 3;
|
||||
const minVer = 4;
|
||||
|
||||
const DEFAULT_PREFERENCES: ViewPreferences = {
|
||||
version: 1,
|
||||
|
||||
11
util/cache/cache.go
vendored
11
util/cache/cache.go
vendored
@@ -30,6 +30,11 @@ type OIDCState struct {
|
||||
ReturnURL string `json:"returnURL"`
|
||||
}
|
||||
|
||||
type ClusterInfo struct {
|
||||
appv1.ConnectionState
|
||||
Version string
|
||||
}
|
||||
|
||||
// NewCache creates new instance of Cache
|
||||
func NewCache(cacheClient CacheClient) *Cache {
|
||||
return &Cache{client: cacheClient}
|
||||
@@ -153,13 +158,13 @@ func (c *Cache) SetAppResourcesTree(appName string, resourcesTree *appv1.Applica
|
||||
return c.setItem(appResourcesTreeKey(appName), resourcesTree, appStateCacheExpiration, resourcesTree == nil)
|
||||
}
|
||||
|
||||
func (c *Cache) GetClusterConnectionState(server string) (appv1.ConnectionState, error) {
|
||||
res := appv1.ConnectionState{}
|
||||
func (c *Cache) GetClusterInfo(server string) (ClusterInfo, error) {
|
||||
res := ClusterInfo{}
|
||||
err := c.getItem(clusterConnectionStateKey(server), &res)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (c *Cache) SetClusterConnectionState(server string, state *appv1.ConnectionState) error {
|
||||
func (c *Cache) SetClusterInfo(server string, state *ClusterInfo) error {
|
||||
return c.setItem(clusterConnectionStateKey(server), &state, connectionStatusCacheExpiration, state == nil)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ func ignoreLiveObjectHealth(liveObj *unstructured.Unstructured, resHealth appv1.
|
||||
return true
|
||||
}
|
||||
gvk := liveObj.GroupVersionKind()
|
||||
if gvk.Group == "argoproj.io" && gvk.Kind == "Application" && resHealth.Status == appv1.HealthStatusMissing {
|
||||
if gvk.Group == "argoproj.io" && gvk.Kind == "Application" && (resHealth.Status == appv1.HealthStatusMissing || resHealth.Status == appv1.HealthStatusUnknown) {
|
||||
// Covers the app-of-apps corner case where child app is deployed but that app itself
|
||||
// has a status of 'Missing', which we don't want to cause the parent's health status
|
||||
// to also be Missing
|
||||
|
||||
@@ -115,6 +115,7 @@ func TestAppOfAppsHealth(t *testing.T) {
|
||||
}
|
||||
|
||||
missingApp, missingStatus := newAppLiveObj("foo", appv1.HealthStatusMissing)
|
||||
unknownApp, unknownStatus := newAppLiveObj("fooz", appv1.HealthStatusUnknown)
|
||||
healthyApp, healthyStatus := newAppLiveObj("bar", appv1.HealthStatusHealthy)
|
||||
degradedApp, degradedStatus := newAppLiveObj("baz", appv1.HealthStatusDegraded)
|
||||
|
||||
@@ -127,6 +128,15 @@ func TestAppOfAppsHealth(t *testing.T) {
|
||||
assert.Equal(t, appv1.HealthStatusHealthy, healthStatus.Status)
|
||||
}
|
||||
|
||||
// verify unknown child app does not affect app health
|
||||
{
|
||||
unknownAndHealthyStatuses := []appv1.ResourceStatus{unknownStatus, healthyStatus}
|
||||
unknownAndHealthyLiveObjects := []*unstructured.Unstructured{unknownApp, healthyApp}
|
||||
healthStatus, err := SetApplicationHealth(unknownAndHealthyStatuses, unknownAndHealthyLiveObjects, nil, noFilter)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, appv1.HealthStatusHealthy, healthStatus.Status)
|
||||
}
|
||||
|
||||
// verify degraded does affect
|
||||
{
|
||||
degradedAndHealthyStatuses := []appv1.ResourceStatus{degradedStatus, healthyStatus}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/config"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -128,22 +129,41 @@ func (c *nativeHelmChart) ExtractChart(chart string, version string) (string, ut
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
// download chart tar file into persistent helm repository directory
|
||||
_, err = helmCmd.Fetch(c.repoURL, chart, version, c.creds)
|
||||
// (1) because `helm fetch` downloads an arbitrary file name, we download to an empty temp directory
|
||||
tempDest, err := ioutil.TempDir("", "helm")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
defer func() { _ = os.RemoveAll(tempDest) }()
|
||||
_, err = helmCmd.Fetch(c.repoURL, chart, version, tempDest, c.creds)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
// (2) then we assume that the only file downloaded into the directory is the tgz file
|
||||
// and we move that to where we want it
|
||||
infos, err := ioutil.ReadDir(tempDest)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return "", nil, fmt.Errorf("expected 1 file, found %v", len(infos))
|
||||
}
|
||||
err = os.Rename(filepath.Join(tempDest, infos[0].Name()), chartPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
// untar helm chart into throw away temp directory which should be deleted as soon as no longer needed
|
||||
tempDir, err := ioutil.TempDir("", "")
|
||||
tempDir, err := ioutil.TempDir("", "helm")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmd := exec.Command("tar", "-zxvf", chartPath)
|
||||
cmd.Dir = tempDir
|
||||
_, err = argoexec.RunCommandExt(cmd, argoexec.CmdOpts{})
|
||||
_, err = argoexec.RunCommandExt(cmd, config.CmdOpts())
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
return "", nil, err
|
||||
}
|
||||
return path.Join(tempDir, chart), util.NewCloser(func() error {
|
||||
return os.RemoveAll(tempDir)
|
||||
|
||||
@@ -1,27 +1,43 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
)
|
||||
|
||||
func TestIndex(t *testing.T) {
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
_, err := NewClient("", Creds{}).GetIndex()
|
||||
client := NewClient("", Creds{})
|
||||
_, err := client.GetIndex()
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("Stable", func(t *testing.T) {
|
||||
index, err := NewClient("https://kubernetes-charts.storage.googleapis.com", Creds{}).GetIndex()
|
||||
client := NewClient("https://argoproj.github.io/argo-helm", Creds{})
|
||||
index, err := client.GetIndex()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, index)
|
||||
})
|
||||
t.Run("BasicAuth", func(t *testing.T) {
|
||||
index, err := NewClient("https://kubernetes-charts.storage.googleapis.com", Creds{
|
||||
client := NewClient("https://argoproj.github.io/argo-helm", Creds{
|
||||
Username: "my-password",
|
||||
Password: "my-username",
|
||||
}).GetIndex()
|
||||
})
|
||||
index, err := client.GetIndex()
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, index)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_nativeHelmChart_ExtractChart(t *testing.T) {
|
||||
client := NewClient("https://argoproj.github.io/argo-helm", Creds{})
|
||||
path, closer, err := client.ExtractChart("argo-cd", "0.7.1")
|
||||
defer util.Close(closer)
|
||||
assert.NoError(t, err)
|
||||
info, err := os.Stat(path)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, info.IsDir())
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
argoexec "github.com/argoproj/pkg/exec"
|
||||
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/config"
|
||||
"github.com/argoproj/argo-cd/util/security"
|
||||
)
|
||||
|
||||
@@ -39,6 +40,7 @@ func (c Cmd) run(args ...string) (string, error) {
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("HELM_HOME=%s", c.helmHome))
|
||||
return argoexec.RunCommandExt(cmd, argoexec.CmdOpts{
|
||||
Timeout: config.CmdOpts().Timeout,
|
||||
Redactor: redactor,
|
||||
})
|
||||
}
|
||||
@@ -117,31 +119,31 @@ func writeToTmp(data []byte) (string, io.Closer, error) {
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (c *Cmd) Fetch(repo, chartName string, version string, opts Creds) (string, error) {
|
||||
args := []string{"fetch"}
|
||||
func (c *Cmd) Fetch(repo, chartName, version, destination string, creds Creds) (string, error) {
|
||||
args := []string{"fetch", "--destination", destination}
|
||||
|
||||
if version != "" {
|
||||
args = append(args, "--version", version)
|
||||
}
|
||||
if opts.Username != "" {
|
||||
args = append(args, "--username", opts.Username)
|
||||
if creds.Username != "" {
|
||||
args = append(args, "--username", creds.Username)
|
||||
}
|
||||
if opts.Password != "" {
|
||||
args = append(args, "--password", opts.Password)
|
||||
if creds.Password != "" {
|
||||
args = append(args, "--password", creds.Password)
|
||||
}
|
||||
if opts.CAPath != "" {
|
||||
args = append(args, "--ca-file", opts.CAPath)
|
||||
if creds.CAPath != "" {
|
||||
args = append(args, "--ca-file", creds.CAPath)
|
||||
}
|
||||
if len(opts.CertData) > 0 {
|
||||
filePath, closer, err := writeToTmp(opts.CertData)
|
||||
if len(creds.CertData) > 0 {
|
||||
filePath, closer, err := writeToTmp(creds.CertData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer util.Close(closer)
|
||||
args = append(args, "--cert-file", filePath)
|
||||
}
|
||||
if len(opts.KeyData) > 0 {
|
||||
filePath, closer, err := writeToTmp(opts.KeyData)
|
||||
if len(creds.KeyData) > 0 {
|
||||
filePath, closer, err := writeToTmp(creds.KeyData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
argoexec "github.com/argoproj/pkg/exec"
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/argoproj/argo-cd/util/config"
|
||||
)
|
||||
@@ -89,6 +88,7 @@ func (h *helm) Dispose() {
|
||||
func Version() (string, error) {
|
||||
cmd := exec.Command("helm", "version", "--client")
|
||||
out, err := argoexec.RunCommandExt(cmd, argoexec.CmdOpts{
|
||||
Timeout: config.CmdOpts().Timeout,
|
||||
Redactor: redactor,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -138,12 +138,17 @@ func (h *helm) GetParameters(valuesFiles []string) (map[string]string, error) {
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func flatVals(input map[string]interface{}, output map[string]string, prefixes ...string) {
|
||||
for key, val := range input {
|
||||
if subMap, ok := val.(map[string]interface{}); ok {
|
||||
flatVals(subMap, output, append(prefixes, fmt.Sprintf("%v", key))...)
|
||||
} else {
|
||||
output[strings.Join(append(prefixes, fmt.Sprintf("%v", key)), ".")] = fmt.Sprintf("%v", val)
|
||||
func flatVals(input interface{}, output map[string]string, prefixes ...string) {
|
||||
switch i := input.(type) {
|
||||
case map[string]interface{}:
|
||||
for k, v := range i {
|
||||
flatVals(v, output, append(prefixes, k)...)
|
||||
}
|
||||
case []interface{}:
|
||||
for j, v := range i {
|
||||
flatVals(v, output, append(prefixes[0:len(prefixes)-1], fmt.Sprintf("%s[%v]", prefixes[len(prefixes)-1], j))...)
|
||||
}
|
||||
default:
|
||||
output[strings.Join(prefixes, ".")] = fmt.Sprintf("%v", i)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,3 +164,27 @@ func TestVersion(t *testing.T) {
|
||||
re := regexp.MustCompile(SemverRegexValidation)
|
||||
assert.True(t, re.MatchString(ver))
|
||||
}
|
||||
|
||||
func Test_flatVals(t *testing.T) {
|
||||
t.Run("Map", func(t *testing.T) {
|
||||
output := map[string]string{}
|
||||
|
||||
flatVals(map[string]interface{}{"foo": map[string]interface{}{"bar": "baz"}}, output)
|
||||
|
||||
assert.Equal(t, map[string]string{"foo.bar": "baz"}, output)
|
||||
})
|
||||
t.Run("Array", func(t *testing.T) {
|
||||
output := map[string]string{}
|
||||
|
||||
flatVals(map[string]interface{}{"foo": []interface{}{"bar"}}, output)
|
||||
|
||||
assert.Equal(t, map[string]string{"foo[0]": "bar"}, output)
|
||||
})
|
||||
t.Run("Val", func(t *testing.T) {
|
||||
output := map[string]string{}
|
||||
|
||||
flatVals(map[string]interface{}{"foo": 1}, output)
|
||||
|
||||
assert.Equal(t, map[string]string{"foo": "1"}, output)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func isSupportedVerb(apiResource *metav1.APIResource, verb string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (k KubectlCmd) GetAPIResources(config *rest.Config, resourceFilter ResourceFilter) ([]APIResourceInfo, error) {
|
||||
func (k *KubectlCmd) GetAPIResources(config *rest.Config, resourceFilter ResourceFilter) ([]APIResourceInfo, error) {
|
||||
apiResIfs, err := filterAPIResources(config, resourceFilter, func(apiResource *metav1.APIResource) bool {
|
||||
return isSupportedVerb(apiResource, listVerb) && isSupportedVerb(apiResource, watchVerb)
|
||||
}, "")
|
||||
@@ -119,7 +119,7 @@ func (k KubectlCmd) GetAPIResources(config *rest.Config, resourceFilter Resource
|
||||
}
|
||||
|
||||
// GetResource returns resource
|
||||
func (k KubectlCmd) GetResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) {
|
||||
func (k *KubectlCmd) GetResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) {
|
||||
dynamicIf, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -138,7 +138,7 @@ func (k KubectlCmd) GetResource(config *rest.Config, gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
// PatchResource patches resource
|
||||
func (k KubectlCmd) PatchResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, patchType types.PatchType, patchBytes []byte) (*unstructured.Unstructured, error) {
|
||||
func (k *KubectlCmd) PatchResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, patchType types.PatchType, patchBytes []byte) (*unstructured.Unstructured, error) {
|
||||
dynamicIf, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -157,7 +157,7 @@ func (k KubectlCmd) PatchResource(config *rest.Config, gvk schema.GroupVersionKi
|
||||
}
|
||||
|
||||
// DeleteResource deletes resource
|
||||
func (k KubectlCmd) DeleteResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, forceDelete bool) error {
|
||||
func (k *KubectlCmd) DeleteResource(config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, forceDelete bool) error {
|
||||
dynamicIf, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -184,7 +184,7 @@ func (k KubectlCmd) DeleteResource(config *rest.Config, gvk schema.GroupVersionK
|
||||
}
|
||||
|
||||
// ApplyResource performs an apply of a unstructured resource
|
||||
func (k KubectlCmd) ApplyResource(config *rest.Config, obj *unstructured.Unstructured, namespace string, dryRun, force, validate bool) (string, error) {
|
||||
func (k *KubectlCmd) ApplyResource(config *rest.Config, obj *unstructured.Unstructured, namespace string, dryRun, force, validate bool) (string, error) {
|
||||
log.Infof("Applying resource %s/%s in cluster: %s, namespace: %s", obj.GetKind(), obj.GetName(), config.Host, namespace)
|
||||
f, err := ioutil.TempFile(util.TempDir, "")
|
||||
if err != nil {
|
||||
@@ -329,7 +329,7 @@ func Version() (string, error) {
|
||||
}
|
||||
|
||||
// ConvertToVersion converts an unstructured object into the specified group/version
|
||||
func (k KubectlCmd) ConvertToVersion(obj *unstructured.Unstructured, group string, version string) (*unstructured.Unstructured, error) {
|
||||
func (k *KubectlCmd) ConvertToVersion(obj *unstructured.Unstructured, group string, version string) (*unstructured.Unstructured, error) {
|
||||
gvk := obj.GroupVersionKind()
|
||||
if gvk.Group == group && gvk.Version == version {
|
||||
return obj.DeepCopy(), nil
|
||||
@@ -375,7 +375,7 @@ func (k KubectlCmd) ConvertToVersion(obj *unstructured.Unstructured, group strin
|
||||
return &convertedObj, nil
|
||||
}
|
||||
|
||||
func (k KubectlCmd) GetServerVersion(config *rest.Config) (string, error) {
|
||||
func (k *KubectlCmd) GetServerVersion(config *rest.Config) (string, error) {
|
||||
client, err := discovery.NewDiscoveryClientForConfig(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -387,6 +387,6 @@ func (k KubectlCmd) GetServerVersion(config *rest.Config) (string, error) {
|
||||
return fmt.Sprintf("%s.%s", v.Major, v.Minor), nil
|
||||
}
|
||||
|
||||
func (k KubectlCmd) SetOnKubectlRun(onKubectlRun func(command string) (util.Closer, error)) {
|
||||
func (k *KubectlCmd) SetOnKubectlRun(onKubectlRun func(command string) (util.Closer, error)) {
|
||||
k.OnKubectlRun = onKubectlRun
|
||||
}
|
||||
|
||||
@@ -15,15 +15,14 @@ import (
|
||||
func TestConvertToVersion(t *testing.T) {
|
||||
callbackExecuted := false
|
||||
closerExecuted := false
|
||||
kubectl := KubectlCmd{
|
||||
func(command string) (util.Closer, error) {
|
||||
callbackExecuted = true
|
||||
return util.NewCloser(func() error {
|
||||
closerExecuted = true
|
||||
return nil
|
||||
}), nil
|
||||
},
|
||||
}
|
||||
kubectl := KubectlCmd{}
|
||||
kubectl.SetOnKubectlRun(func(command string) (util.Closer, error) {
|
||||
callbackExecuted = true
|
||||
return util.NewCloser(func() error {
|
||||
closerExecuted = true
|
||||
return nil
|
||||
}), nil
|
||||
})
|
||||
|
||||
yamlBytes, err := ioutil.ReadFile("testdata/nginx.yaml")
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -178,16 +177,7 @@ func Version() (string, error) {
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not get kustomize version: %s", err)
|
||||
}
|
||||
re := regexp.MustCompile(`KustomizeVersion:([a-zA-Z0-9\.]+)`)
|
||||
matches := re.FindStringSubmatch(out)
|
||||
if len(matches) != 2 {
|
||||
return "", errors.New("could not get kustomize version")
|
||||
}
|
||||
version := matches[1]
|
||||
if version[0] != 'v' {
|
||||
version = "v" + version
|
||||
}
|
||||
return strings.TrimSpace(version), nil
|
||||
return strings.TrimSpace(out), nil
|
||||
}
|
||||
|
||||
func getImageParameters(objs []*unstructured.Unstructured) []Image {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/argoproj/pkg/exec"
|
||||
@@ -102,7 +101,5 @@ func TestParseKustomizeBuildOptions(t *testing.T) {
|
||||
func TestVersion(t *testing.T) {
|
||||
ver, err := Version()
|
||||
assert.NoError(t, err)
|
||||
SemverRegexValidation := `^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$`
|
||||
re := regexp.MustCompile(SemverRegexValidation)
|
||||
assert.True(t, re.MatchString(ver))
|
||||
assert.NotEmpty(t, ver)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user