mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-11 02:48:47 +01:00
Compare commits
3 Commits
release-0.
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08c63ec234 | ||
|
|
41f950fd43 | ||
|
|
826ee0dfa0 |
@@ -29,13 +29,7 @@ spec:
|
||||
- name: cmd
|
||||
value: "{{item}}"
|
||||
withItems:
|
||||
- dep ensure && make cli lint test
|
||||
- name: test-e2e
|
||||
template: ci-builder
|
||||
arguments:
|
||||
parameters:
|
||||
- name: cmd
|
||||
value: "dep ensure && make test-e2e"
|
||||
- dep ensure && make cli lint test test-e2e
|
||||
|
||||
- name: ci-builder
|
||||
inputs:
|
||||
|
||||
147
CHANGELOG.md
147
CHANGELOG.md
@@ -1,119 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## v0.7.2 (2018-08-21)
|
||||
- API discovery becomes best effort when partial resource list is returned (issue #524)
|
||||
|
||||
## v0.7.1 (2018-08-03)
|
||||
+ Surface helm parameters to the application level (#485)
|
||||
+ [UI] Improve application creation wizard (#459)
|
||||
+ [UI] Show indicator when refresh is still in progress (#493)
|
||||
* [UI] Improve data loading error notification (#446)
|
||||
* Infer username from claims during an `argocd relogin` (#475)
|
||||
* Expand RBAC role to be able to create application events. Fix username claims extraction
|
||||
- Fix scalability issues with the ListApps API (#494)
|
||||
- Fix issue where application server was retrieving events from incorrect cluster (#478)
|
||||
- Fix failure in identifying app source type when path was '.'
|
||||
- AppProjectSpec SourceRepos mislabeled (#490)
|
||||
- Failed e2e test was not failing CI workflow
|
||||
* Fix linux download link in getting_started.md (#487) (@chocopowwwa)
|
||||
|
||||
## v0.7.0 (2018-07-27)
|
||||
+ Support helm charts and yaml directories as an application source
|
||||
+ Audit trails in the form of API call logs
|
||||
+ Generate kubernetes events for application state changes
|
||||
+ Add ksonnet version to version endpoint (#433)
|
||||
+ Show CLI progress for sync and rollback
|
||||
+ Make use of dex refresh tokens and store them into local config
|
||||
+ Expire local superuser tokens when their password changes
|
||||
+ Add `argocd relogin` command as a convenience around login to current context
|
||||
- Fix saving default connection status for repos and clusters
|
||||
- Fix undesired fail-fast behavior of health check
|
||||
- Fix memory leak in the cluster resource watch
|
||||
- Health check for StatefulSets, DaemonSet, and ReplicaSets were failing due to use of wrong converters
|
||||
|
||||
## v0.6.2 (2018-07-23)
|
||||
- Health check for StatefulSets, DaemonSet, and ReplicaSets were failing due to use of wrong converters
|
||||
|
||||
## v0.6.1 (2018-07-18)
|
||||
- Fix regression where deployment health check incorrectly reported Healthy
|
||||
+ Intercept dex SSO errors and present them in Argo login page
|
||||
|
||||
## v0.6.0 (2018-07-16)
|
||||
+ Support PreSync, Sync, PostSync resource hooks
|
||||
+ Introduce Application Projects for finer grain RBAC controls
|
||||
+ Swagger Docs & UI
|
||||
+ Support in-cluster deployments internal kubernetes service name
|
||||
+ Refactoring & Improvements
|
||||
* Improved error handling, status and condition reporting
|
||||
* Remove installer in favor of kubectl apply instructions
|
||||
* Add validation when setting application parameters
|
||||
* Cascade deletion is decided during app deletion, instead of app creation
|
||||
- Fix git authentication implementation when using using SSH key
|
||||
- app-name label was inadvertently injected into spec.selector if selector was omitted from v1beta1 specs
|
||||
|
||||
## v0.5.4 (2018-06-27)
|
||||
- Refresh flag to sync should be optional, not required
|
||||
|
||||
## v0.5.3 (2018-06-20)
|
||||
+ Support cluster management using the internal k8s API address https://kubernetes.default.svc (#307)
|
||||
+ Support diffing a local ksonnet app to the live application state (resolves #239) (#298)
|
||||
+ Add ability to show last operation result in app get. Show path in app list -o wide (#297)
|
||||
+ Update dependencies: ksonnet v0.11, golang v1.10, debian v9.4 (#296)
|
||||
+ Add ability to force a refresh of an app during get (resolves #269) (#293)
|
||||
+ Automatically restart API server upon certificate changes (#292)
|
||||
|
||||
## v0.5.2 (2018-06-14)
|
||||
+ Resource events tab on application details page (#286)
|
||||
+ Display pod status on application details page (#231)
|
||||
|
||||
## v0.5.1 (2018-06-13)
|
||||
- API server incorrectly compose application fully qualified name for RBAC check (#283)
|
||||
- UI crash while rendering application operation info if operation failed
|
||||
|
||||
## v0.5.0 (2018-06-12)
|
||||
+ RBAC access control
|
||||
+ Repository/Cluster state monitoring
|
||||
+ ArgoCD settings import/export
|
||||
+ Application creation UI wizard
|
||||
+ argocd app manifests for printing the application manifests
|
||||
+ argocd app unset command to unset parameter overrides
|
||||
+ Fail app sync if prune flag is required (#276)
|
||||
+ Take into account number of unavailable replicas to decided if deployment is healthy or not #270
|
||||
+ Add ability to show parameters and overrides in CLI (resolves #240)
|
||||
- Repo names containing underscores were not being accepted (#258)
|
||||
- Cookie token was not parsed properly when mixed with other site cookies
|
||||
|
||||
## v0.4.7 (2018-06-07)
|
||||
- Fix argocd app wait health checking logic
|
||||
|
||||
## v0.4.6 (2018-06-06)
|
||||
- Retry argocd app wait connection errors from EOF watch. Show detailed state changes
|
||||
|
||||
## v0.4.5 (2018-05-31)
|
||||
+ Add argocd app unset command to unset parameter overrides
|
||||
- Cookie token was not parsed properly when mixed with other site cookies
|
||||
|
||||
## v0.4.4 (2018-05-30)
|
||||
+ Add ability to show parameters and overrides in CLI (resolves #240)
|
||||
+ Add Events API endpoint
|
||||
+ Issue #238 - add upsert flag to 'argocd app create' command
|
||||
+ Add repo browsing endpoint (#229)
|
||||
+ Support subscribing to settings updates and auto-restart of dex and API server
|
||||
- Issue #233 - Controller does not persist rollback operation result
|
||||
- App sync frequently fails due to concurrent app modification
|
||||
|
||||
## v0.4.3 (2018-05-21)
|
||||
- Move local branch deletion as part of git Reset() (resolves #185) (#222)
|
||||
- Fix exit code for app wait (#219)
|
||||
|
||||
## v0.4.2 (2018-05-21)
|
||||
+ Show URL in argocd app get
|
||||
- Remove interactive context name prompt during login which broke login automation
|
||||
* Rename force flag to cascade in argocd app delete
|
||||
|
||||
## v0.4.1 (2018-05-18)
|
||||
+ Implemented argocd app wait command
|
||||
|
||||
## v0.4.0 (2018-05-17)
|
||||
+ SSO Integration
|
||||
+ GitHub Webhook
|
||||
@@ -126,36 +12,3 @@
|
||||
* Manifests are memoized in repo server
|
||||
- Fix connection timeouts to SSH repos
|
||||
|
||||
## v0.3.2 (2018-05-03)
|
||||
+ Application sync should delete 'unexpected' resources #139
|
||||
+ Update ksonnet to v0.10.1
|
||||
+ Detect unexpected resources
|
||||
- Fix: App sync frequently fails due to concurrent app modification #147
|
||||
- Fix: improve app state comparator: #136, #132
|
||||
|
||||
## v0.3.1 (2018-04-24)
|
||||
+ Add new rollback RPC with numeric identifiers
|
||||
+ New argo app history and argo app rollback command
|
||||
+ Switch to gogo/protobuf for golang code generation
|
||||
- Fix: create .argocd directory during argo login (issue #123)
|
||||
- Fix: Allow overriding server or namespace separately (issue #110)
|
||||
|
||||
## v0.3.0 (2018-04-23)
|
||||
+ Auth support
|
||||
+ TLS support
|
||||
+ DAG-based application view
|
||||
+ Bulk watch
|
||||
+ ksonnet v0.10.0-alpha.3
|
||||
+ kubectl apply deployment strategy
|
||||
+ CLI improvements for app management
|
||||
|
||||
## v0.2.0 (2018-04-03)
|
||||
+ Rollback UI
|
||||
+ Override parameters
|
||||
|
||||
## v0.1.0 (2018-03-12)
|
||||
+ Define app in Github with dev and preprod environment using KSonnet
|
||||
+ Add cluster Diff App with a cluster Deploy app in a cluster
|
||||
+ Deploy a new version of the app in the cluster
|
||||
+ App sync based on Github app config change - polling only
|
||||
+ Basic UI: App diff between Git and k8s cluster for all environments Basic GUI
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
## Requirements
|
||||
Make sure you have following tools installed
|
||||
* [docker](https://docs.docker.com/install/#supported-platforms)
|
||||
* [golang](https://golang.org/)
|
||||
* [dep](https://github.com/golang/dep)
|
||||
* [protobuf](https://developers.google.com/protocol-buffers/)
|
||||
* [ksonnet](https://github.com/ksonnet/ksonnet#install)
|
||||
* [helm](https://github.com/helm/helm/releases)
|
||||
* [go-swagger](https://github.com/go-swagger/go-swagger/blob/master/docs/install.md)
|
||||
* [jq](https://stedolan.github.io/jq/)
|
||||
* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
|
||||
Make sure you have following tools installed [docker](https://docs.docker.com/install/#supported-platforms), [golang](https://golang.org/), [dep](https://github.com/golang/dep), [protobuf](https://developers.google.com/protocol-buffers/), [ksonnet](https://github.com/ksonnet/ksonnet#install), [go-swagger](https://github.com/go-swagger/go-swagger/blob/master/docs/install.md), and [jq](https://stedolan.github.io/jq/)
|
||||
[kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
|
||||
|
||||
```
|
||||
$ brew tap go-swagger/go-swagger
|
||||
$ brew install go dep protobuf kubectl ksonnet/tap/ks kubernetes-helm jq go-swagger
|
||||
$ brew install go dep protobuf kubectl ksonnet/tap/ks jq go-swagger
|
||||
$ go get -u github.com/golang/protobuf/protoc-gen-go
|
||||
$ go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
|
||||
@@ -38,18 +30,6 @@ NOTE: The make command can take a while, and we recommend building the specific
|
||||
* `make codegen` - Builds protobuf and swagger files
|
||||
* `make argocd-util` - Make the administrator's utility, used for certain tasks such as import/export
|
||||
|
||||
## Generating ArgoCD manifests for a specific image repository/tag
|
||||
|
||||
During development, the `update-manifests.sh` script, can be used to conveniently regenerate the
|
||||
ArgoCD installation manifests with a customized image namespace and tag. This enables developers
|
||||
to easily apply manifests which are using the images that they pushed into their personal container
|
||||
repository.
|
||||
|
||||
```
|
||||
$ IMAGE_NAMESPACE=jessesuen IMAGE_TAG=latest ./hack/update-manifests.sh
|
||||
$ kubectl apply -n argocd -f ./manifests/install.yaml
|
||||
```
|
||||
|
||||
## Running locally
|
||||
|
||||
You need to have access to kubernetes cluster (including [minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) or [docker edge](https://docs.docker.com/docker-for-mac/install/) ) in order to run Argo CD on your laptop:
|
||||
|
||||
@@ -66,10 +66,6 @@ RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION
|
||||
RUN curl -o /kubectl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
|
||||
chmod +x /kubectl
|
||||
|
||||
env HELM_VERSION=2.9.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 /helm
|
||||
|
||||
##############################################################
|
||||
FROM debian:9.3
|
||||
@@ -78,7 +74,6 @@ RUN apt-get update && apt-get install -y git && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
COPY --from=cli-tooling /ks /usr/local/bin/ks
|
||||
COPY --from=cli-tooling /helm /usr/local/bin/helm
|
||||
COPY --from=cli-tooling /kubectl /usr/local/bin/kubectl
|
||||
# workaround ksonnet issue https://github.com/ksonnet/ksonnet/issues/298
|
||||
ENV USER=root
|
||||
|
||||
@@ -20,9 +20,3 @@ RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION
|
||||
tar -C /tmp/ -xf ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
|
||||
mv /tmp/ks_${KSONNET_VERSION}_linux_amd64/ks /usr/local/bin/ks && \
|
||||
rm -rf /tmp/ks_${KSONNET_VERSION}
|
||||
|
||||
# Install helm
|
||||
env HELM_VERSION=2.9.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
|
||||
|
||||
370
Gopkg.lock
generated
370
Gopkg.lock
generated
File diff suppressed because it is too large
Load Diff
7
Makefile
7
Makefile
@@ -81,7 +81,8 @@ argocd-util: clean-debug
|
||||
.PHONY: install-manifest
|
||||
install-manifest:
|
||||
if [ "${IMAGE_NAMESPACE}" = "" ] ; then echo "IMAGE_NAMESPACE must be set to build install manifest" ; exit 1 ; fi
|
||||
./hack/update-manifests.sh
|
||||
echo "# This is an auto-generated file. DO NOT EDIT" > manifests/install.yaml
|
||||
cat manifests/components/*.yaml | sed 's@\( image: argoproj/\(.*\):latest\)@ image: '"${IMAGE_NAMESPACE}"'/\2:'"${IMAGE_TAG}"'@g' >> manifests/install.yaml
|
||||
|
||||
.PHONY: server
|
||||
server: clean-debug
|
||||
@@ -125,11 +126,11 @@ lint:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -v `go list ./... | grep -v "github.com/argoproj/argo-cd/test/e2e"`
|
||||
go test `go list ./... | grep -v "github.com/argoproj/argo-cd/test/e2e"`
|
||||
|
||||
.PHONY: test-e2e
|
||||
test-e2e:
|
||||
go test -v -failfast -timeout 20m ./test/e2e
|
||||
go test ./test/e2e
|
||||
|
||||
# Cleans VSCode debug.test files from sub-dirs to prevent them from being included in packr boxes
|
||||
.PHONY: clean-debug
|
||||
|
||||
64
README.md
64
README.md
@@ -3,7 +3,7 @@
|
||||
|
||||
## What is Argo CD?
|
||||
|
||||
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
|
||||
Argo CD is a declarative, continuous delivery service based on **ksonnet** for Kubernetes.
|
||||
|
||||

|
||||
|
||||
@@ -19,25 +19,21 @@ is provided for additional features.
|
||||
|
||||
## How it works
|
||||
|
||||
Argo CD follows the **GitOps** pattern of using git repositories as the source of truth for defining
|
||||
the desired application state. Kubernetes manifests can be specified in several ways:
|
||||
* [ksonnet](https://ksonnet.io) applications
|
||||
* [helm](https://helm.sh) charts
|
||||
* Simple directory of YAML/json manifests
|
||||
Argo CD follows the **GitOps** pattern of using git repositories as the source of truth for defining the
|
||||
desired application state. Kubernetes manifests are specified as [ksonnet](https://ksonnet.io)
|
||||
applications. Argo CD automates the deployment of the desired
|
||||
application states in the specified target environments.
|
||||
|
||||

|
||||
|
||||
Argo CD automates the deployment of the desired application states in the specified target environments.
|
||||
Application deployments can track updates to branches, tags, or pinned to a specific version of
|
||||
manifests at a git commit. See [tracking strategies](docs/tracking_strategies.md) for additional
|
||||
details about the different tracking strategies available.
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
|
||||
Argo CD is implemented as a kubernetes controller which continuously monitors running applications
|
||||
and compares the current, live state against the desired target state (as specified in the git repo).
|
||||
A deployed application whose live state deviates from the target state is considered `OutOfSync`.
|
||||
Argo CD reports & visualizes the differences, while providing facilities to automatically or
|
||||
A deployed application whose live state deviates from the target state is considered out-of-sync.
|
||||
Argo CD reports & visualizes the differences as well as providing facilities to automatically or
|
||||
manually sync the live state back to the desired target state. Any modifications made to the desired
|
||||
target state in the git repo can be automatically applied and reflected in the specified target
|
||||
environments.
|
||||
@@ -55,15 +51,47 @@ For additional details, see [architecture overview](docs/architecture.md).
|
||||
* SSO Integration (OIDC, OAuth2, LDAP, SAML 2.0, GitLab, Microsoft, LinkedIn)
|
||||
* Webhook Integration (GitHub, BitBucket, GitLab)
|
||||
* PreSync, Sync, PostSync hooks to support complex application rollouts (e.g.blue/green & canary upgrades)
|
||||
* Audit trails for application events and API calls
|
||||
* Parameter overrides for overriding ksonnet/helm parameters in git
|
||||
|
||||
## What is ksonnet?
|
||||
|
||||
* [Jsonnet](http://jsonnet.org), the basis for ksonnet, is a domain specific configuration language,
|
||||
which provides extreme flexibility for composing and manipulating JSON/YAML specifications.
|
||||
* [Ksonnet](http://ksonnet.io) goes one step further by applying Jsonnet principles to Kubernetes
|
||||
manifests. It provides an opinionated file & directory structure to organize applications into
|
||||
reusable components, parameters, and environments. Environments can be hierarchical, which promotes
|
||||
both re-use and granular customization of application and environment specifications.
|
||||
|
||||
## Why ksonnet?
|
||||
|
||||
Application configuration management is a hard problem and grows rapidly in complexity as you deploy
|
||||
more applications, against more and more environments. Current templating systems, such as Jinja,
|
||||
and Golang templating, are unnatural ways to maintain kubernetes manifests, and are not well suited to
|
||||
capture subtle configuration differences between environments. Its ability to compose and re-use
|
||||
application and environment configurations is also very limited.
|
||||
|
||||
Imagine we have a single guestbook application deployed in following environments:
|
||||
|
||||
| Environment | K8s Version | Application Image | DB Connection String | Environment Vars | Sidecars |
|
||||
|---------------|-------------|------------------------|-----------------------|------------------|---------------|
|
||||
| minikube | 1.10.0 | jesse/guestbook:latest | sql://locahost/db | DEBUG=true | |
|
||||
| dev | 1.11.0 | app/guestbook:latest | sql://dev-test/db | DEBUG=true | |
|
||||
| staging | 1.10.0 | app/guestbook:e3c0263 | sql://staging/db | | istio,dnsmasq |
|
||||
| us-west-1 | 1.9.0 | app/guestbook:abc1234 | sql://prod/db | FOO_FEATURE=true | istio,dnsmasq |
|
||||
| us-west-2 | 1.10.0 | app/guestbook:abc1234 | sql://prod/db | | istio,dnsmasq |
|
||||
| us-east-1 | 1.9.0 | app/guestbook:abc1234 | sql://prod/db | BAR_FEATURE=true | istio,dnsmasq |
|
||||
|
||||
Ksonnet:
|
||||
* Enables composition and re-use of common YAML specifications
|
||||
* Allows overrides, additions, and subtractions of YAML sub-components specific to each environment
|
||||
* Guarantees proper generation of K8s manifests suitable for the corresponding Kubernetes API version
|
||||
* Provides [kubernetes-specific jsonnet libraries](https://github.com/ksonnet/ksonnet-lib) to enable
|
||||
concise definition of kubernetes manifests
|
||||
|
||||
## Development Status
|
||||
* Argo CD is being used in production to deploy SaaS services at Intuit
|
||||
|
||||
## Roadmap
|
||||
* Auto-sync toggle to directly apply git state changes to live state
|
||||
* Audit trails for application events and API calls
|
||||
* Service account/access key management for CI pipelines
|
||||
* Support for additional config management tools (Kustomize?)
|
||||
* Revamped UI, and feature parity with CLI
|
||||
* Revamped UI
|
||||
* Customizable application actions
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/argo"
|
||||
"github.com/argoproj/argo-cd/util/config"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/ksonnet"
|
||||
kubeutil "github.com/argoproj/argo-cd/util/kube"
|
||||
@@ -71,27 +71,29 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
||||
upsert bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "create APPNAME",
|
||||
Use: "create",
|
||||
Short: "Create an application from a git location",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
var app argoappv1.Application
|
||||
if fileURL != "" {
|
||||
parsedURL, err := url.ParseRequestURI(fileURL)
|
||||
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
|
||||
err = config.UnmarshalLocalFile(fileURL, &app)
|
||||
err = cli.UnmarshalLocalFile(fileURL, &app)
|
||||
} else {
|
||||
err = config.UnmarshalRemoteFile(fileURL, &app)
|
||||
err = cli.UnmarshalRemoteFile(fileURL, &app)
|
||||
}
|
||||
errors.CheckError(err)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
} else {
|
||||
if len(args) == 1 {
|
||||
if appName != "" && appName != args[0] {
|
||||
log.Fatalf("--name argument '%s' does not match app name %s", appName, args[0])
|
||||
}
|
||||
appName = args[0]
|
||||
}
|
||||
if appOpts.repoURL == "" || appOpts.appPath == "" || appName == "" {
|
||||
log.Fatal("name, repo, path are required")
|
||||
if appOpts.repoURL == "" || appOpts.appPath == "" || appOpts.env == "" || appName == "" {
|
||||
log.Fatal("name, repo, path, env are required")
|
||||
os.Exit(1)
|
||||
}
|
||||
app = argoappv1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -115,9 +117,6 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
||||
app.Spec.Destination.Namespace = appOpts.destNamespace
|
||||
}
|
||||
setParameterOverrides(&app, appOpts.parameters)
|
||||
if len(appOpts.valuesFiles) > 0 {
|
||||
app.Spec.Source.ValuesFiles = appOpts.valuesFiles
|
||||
}
|
||||
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
appCreateRequest := application.ApplicationCreateRequest{
|
||||
@@ -130,7 +129,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
||||
},
|
||||
}
|
||||
command.Flags().StringVarP(&fileURL, "file", "f", "", "Filename or URL to Kubernetes manifests for the app")
|
||||
command.Flags().StringVar(&appName, "name", "", "A name for the app, ignored if a file is set (DEPRECATED)")
|
||||
command.Flags().StringVar(&appName, "name", "", "A name for the app, ignored if a file is set")
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Allows to override application with the same name even if supplied application spec is different from existing spec")
|
||||
addAppFlags(command, &appOpts)
|
||||
return command
|
||||
@@ -172,15 +171,10 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
fmt.Printf(printOpFmtStr, "Server:", app.Spec.Destination.Server)
|
||||
fmt.Printf(printOpFmtStr, "Namespace:", app.Spec.Destination.Namespace)
|
||||
fmt.Printf(printOpFmtStr, "URL:", appURL(acdClient, app))
|
||||
fmt.Printf(printOpFmtStr, "Environment:", app.Spec.Source.Environment)
|
||||
fmt.Printf(printOpFmtStr, "Repo:", app.Spec.Source.RepoURL)
|
||||
fmt.Printf(printOpFmtStr, "Target:", app.Spec.Source.TargetRevision)
|
||||
fmt.Printf(printOpFmtStr, "Path:", app.Spec.Source.Path)
|
||||
if app.Spec.Source.Environment != "" {
|
||||
fmt.Printf(printOpFmtStr, "Environment:", app.Spec.Source.Environment)
|
||||
}
|
||||
if len(app.Spec.Source.ValuesFiles) > 0 {
|
||||
fmt.Printf(printOpFmtStr, "Helm Values:", strings.Join(app.Spec.Source.ValuesFiles, ","))
|
||||
}
|
||||
fmt.Printf(printOpFmtStr, "Target:", app.Spec.Source.TargetRevision)
|
||||
|
||||
if len(app.Status.Conditions) > 0 {
|
||||
fmt.Println()
|
||||
@@ -257,19 +251,10 @@ func printParams(app *argoappv1.Application) {
|
||||
}
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
isKsonnet := app.Spec.Source.Environment != ""
|
||||
if isKsonnet {
|
||||
fmt.Fprintf(w, "COMPONENT\tNAME\tVALUE\tOVERRIDE\n")
|
||||
for _, p := range app.Status.Parameters {
|
||||
overrideValue := overrides[fmt.Sprintf("%s/%s", p.Component, p.Name)]
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", p.Component, p.Name, truncateString(p.Value, paramLenLimit), truncateString(overrideValue, paramLenLimit))
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "NAME\tVALUE\n")
|
||||
for _, p := range app.Spec.Source.ComponentParameterOverrides {
|
||||
fmt.Fprintf(w, "%s\t%s\n", p.Name, truncateString(p.Value, paramLenLimit))
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "COMPONENT\tNAME\tVALUE\tOVERRIDE\n")
|
||||
for _, p := range app.Status.Parameters {
|
||||
overrideValue := overrides[fmt.Sprintf("%s/%s", p.Component, p.Name)]
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", p.Component, p.Name, truncateString(p.Value, paramLenLimit), truncateString(overrideValue, paramLenLimit))
|
||||
}
|
||||
_ = w.Flush()
|
||||
}
|
||||
@@ -304,8 +289,6 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
app.Spec.Source.Environment = appOpts.env
|
||||
case "revision":
|
||||
app.Spec.Source.TargetRevision = appOpts.revision
|
||||
case "values":
|
||||
app.Spec.Source.ValuesFiles = appOpts.valuesFiles
|
||||
case "dest-server":
|
||||
app.Spec.Destination.Server = appOpts.destServer
|
||||
case "dest-namespace":
|
||||
@@ -355,7 +338,6 @@ type appOptions struct {
|
||||
destServer string
|
||||
destNamespace string
|
||||
parameters []string
|
||||
valuesFiles []string
|
||||
project string
|
||||
}
|
||||
|
||||
@@ -367,21 +349,19 @@ func addAppFlags(command *cobra.Command, opts *appOptions) {
|
||||
command.Flags().StringVar(&opts.destServer, "dest-server", "", "K8s cluster URL (overrides the server URL specified in the ksonnet app.yaml)")
|
||||
command.Flags().StringVar(&opts.destNamespace, "dest-namespace", "", "K8s target namespace (overrides the namespace specified in the ksonnet app.yaml)")
|
||||
command.Flags().StringArrayVarP(&opts.parameters, "parameter", "p", []string{}, "set a parameter override (e.g. -p guestbook=image=example/guestbook:latest)")
|
||||
command.Flags().StringArrayVar(&opts.valuesFiles, "values", []string{}, "Helm values file(s) to use")
|
||||
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
|
||||
}
|
||||
|
||||
// NewApplicationUnsetCommand returns a new instance of an `argocd app unset` command
|
||||
func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
parameters []string
|
||||
valuesFiles []string
|
||||
parameters []string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "unset APPNAME -p COMPONENT=PARAM",
|
||||
Short: "Unset application parameters",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 1 || (len(parameters) == 0 && len(valuesFiles) == 0) {
|
||||
if len(args) != 1 || len(parameters) == 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -390,44 +370,22 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
||||
defer util.Close(conn)
|
||||
app, err := appIf.Get(context.Background(), &application.ApplicationQuery{Name: &appName})
|
||||
errors.CheckError(err)
|
||||
isKsonnetApp := app.Spec.Source.Environment != ""
|
||||
|
||||
updated := false
|
||||
for _, paramStr := range parameters {
|
||||
if isKsonnetApp {
|
||||
parts := strings.SplitN(paramStr, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
log.Fatalf("Expected parameter of the form: component=param. Received: %s", paramStr)
|
||||
}
|
||||
overrides := app.Spec.Source.ComponentParameterOverrides
|
||||
for i, override := range overrides {
|
||||
if override.Component == parts[0] && override.Name == parts[1] {
|
||||
app.Spec.Source.ComponentParameterOverrides = append(overrides[0:i], overrides[i+1:]...)
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
overrides := app.Spec.Source.ComponentParameterOverrides
|
||||
for i, override := range overrides {
|
||||
if override.Name == paramStr {
|
||||
app.Spec.Source.ComponentParameterOverrides = append(overrides[0:i], overrides[i+1:]...)
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
parts := strings.SplitN(paramStr, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
log.Fatalf("Expected parameter of the form: component=param. Received: %s", paramStr)
|
||||
}
|
||||
}
|
||||
for _, valuesFile := range valuesFiles {
|
||||
for i, vf := range app.Spec.Source.ValuesFiles {
|
||||
if vf == valuesFile {
|
||||
app.Spec.Source.ValuesFiles = append(app.Spec.Source.ValuesFiles[0:i], app.Spec.Source.ValuesFiles[i+1:]...)
|
||||
overrides := app.Spec.Source.ComponentParameterOverrides
|
||||
for i, override := range overrides {
|
||||
if override.Component == parts[0] && override.Name == parts[1] {
|
||||
app.Spec.Source.ComponentParameterOverrides = append(overrides[0:i], overrides[i+1:]...)
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !updated {
|
||||
return
|
||||
}
|
||||
@@ -439,7 +397,6 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
||||
},
|
||||
}
|
||||
command.Flags().StringArrayVarP(¶meters, "parameter", "p", []string{}, "unset a parameter override (e.g. -p guestbook=image)")
|
||||
command.Flags().StringArrayVar(&valuesFiles, "values", []string{}, "unset one or more helm values files")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -635,10 +592,9 @@ func formatConditionsSummary(app argoappv1.Application) string {
|
||||
// NewApplicationWaitCommand returns a new instance of an `argocd app wait` command
|
||||
func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
watchSync bool
|
||||
watchHealth bool
|
||||
watchOperations bool
|
||||
timeout uint
|
||||
syncOnly bool
|
||||
healthOnly bool
|
||||
timeout uint
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "wait APPNAME",
|
||||
@@ -648,22 +604,49 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
if !watchSync && !watchHealth && !watchOperations {
|
||||
watchSync = true
|
||||
watchHealth = true
|
||||
watchOperations = true
|
||||
if syncOnly && healthOnly {
|
||||
log.Fatalln("Please specify at most one of --sync-only or --health-only.")
|
||||
}
|
||||
appName := args[0]
|
||||
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
_, err := waitOnApplicationStatus(appIf, appName, timeout, watchSync, watchHealth, watchOperations)
|
||||
if timeout != 0 {
|
||||
time.AfterFunc(time.Duration(timeout)*time.Second, func() {
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
|
||||
// print the initial components to format the tabwriter columns
|
||||
app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &appName})
|
||||
errors.CheckError(err)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
printAppResources(w, app, false)
|
||||
_ = w.Flush()
|
||||
prevCompRes := &app.Status.ComparisonResult
|
||||
|
||||
appEventCh := watchApp(ctx, appIf, appName)
|
||||
for appEvent := range appEventCh {
|
||||
app := appEvent.Application
|
||||
printAppStateChange(w, prevCompRes, &app)
|
||||
_ = w.Flush()
|
||||
prevCompRes = &app.Status.ComparisonResult
|
||||
|
||||
synced := app.Status.ComparisonResult.Status == argoappv1.ComparisonStatusSynced
|
||||
healthy := app.Status.Health.Status == argoappv1.HealthStatusHealthy
|
||||
if len(app.Status.GetErrorConditions()) == 0 && ((synced && healthy) || (synced && syncOnly) || (healthy && healthOnly)) {
|
||||
log.Printf("App %q matches desired state", appName)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Fatalf("Timed out (%ds) waiting for app %q match desired state", timeout, appName)
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVar(&watchSync, "sync", false, "Wait for sync")
|
||||
command.Flags().BoolVar(&watchHealth, "health", false, "Wait for health")
|
||||
command.Flags().BoolVar(&watchOperations, "operation", false, "Wait for pending operations")
|
||||
command.Flags().BoolVar(&syncOnly, "sync-only", false, "Wait only for sync")
|
||||
command.Flags().BoolVar(&healthOnly, "health-only", false, "Wait only for health")
|
||||
command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds")
|
||||
return command
|
||||
}
|
||||
@@ -775,6 +758,38 @@ func printAppResources(w io.Writer, app *argoappv1.Application, showOperation bo
|
||||
}
|
||||
}
|
||||
|
||||
// printAppStateChange prints a component state change if it was different from the last time we saw it
|
||||
func printAppStateChange(w io.Writer, prevComp *argoappv1.ComparisonResult, app *argoappv1.Application) {
|
||||
getPrevResState := func(kind, name string) (argoappv1.ComparisonStatus, argoappv1.HealthStatusCode) {
|
||||
for _, res := range prevComp.Resources {
|
||||
obj, err := argoappv1.UnmarshalToUnstructured(res.TargetState)
|
||||
errors.CheckError(err)
|
||||
if obj == nil {
|
||||
obj, err = argoappv1.UnmarshalToUnstructured(res.LiveState)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
if obj.GetKind() == kind && obj.GetName() == name {
|
||||
return res.Status, res.Health.Status
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
if len(app.Status.ComparisonResult.Resources) > 0 {
|
||||
for _, res := range app.Status.ComparisonResult.Resources {
|
||||
obj, err := argoappv1.UnmarshalToUnstructured(res.TargetState)
|
||||
errors.CheckError(err)
|
||||
if obj == nil {
|
||||
obj, err = argoappv1.UnmarshalToUnstructured(res.LiveState)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
prevSync, prevHealth := getPrevResState(obj.GetKind(), obj.GetName())
|
||||
if prevSync != res.Status || prevHealth != res.Health.Status {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", obj.GetKind(), obj.GetName(), res.Status, res.Health.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewApplicationSyncCommand returns a new instance of an `argocd app sync` command
|
||||
func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
@@ -815,10 +830,23 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
ctx := context.Background()
|
||||
_, err := appIf.Sync(ctx, &syncReq)
|
||||
errors.CheckError(err)
|
||||
|
||||
app, err := waitOnApplicationStatus(appIf, appName, timeout, false, false, true)
|
||||
app, err := waitUntilOperationCompleted(appIf, appName, timeout)
|
||||
errors.CheckError(err)
|
||||
|
||||
// get refreshed app before printing to show accurate sync/health status
|
||||
app, err = appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, Refresh: true})
|
||||
errors.CheckError(err)
|
||||
|
||||
fmt.Printf(printOpFmtStr, "Application:", appName)
|
||||
printOperationResult(app.Status.OperationState)
|
||||
|
||||
if len(app.Status.ComparisonResult.Resources) > 0 {
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
printAppResources(w, app, true)
|
||||
_ = w.Flush()
|
||||
}
|
||||
|
||||
pruningRequired := 0
|
||||
for _, resDetails := range app.Status.OperationState.SyncResult.Resources {
|
||||
if resDetails.Status == argoappv1.ResourceDetailsPruningRequired {
|
||||
@@ -843,171 +871,26 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
return command
|
||||
}
|
||||
|
||||
// ResourceState tracks the state of a resource when waiting on an application status.
|
||||
type resourceState struct {
|
||||
Kind string
|
||||
Name string
|
||||
PrevState string
|
||||
Fields map[string]string
|
||||
Updated bool
|
||||
}
|
||||
|
||||
func newResourceState(kind, name, status, healthStatus, resType, message string) *resourceState {
|
||||
return &resourceState{
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
Fields: map[string]string{
|
||||
"status": status,
|
||||
"healthStatus": healthStatus,
|
||||
"type": resType,
|
||||
"message": message,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns a unique-ish key for the resource.
|
||||
func (rs *resourceState) Key() string {
|
||||
return fmt.Sprintf("%s/%s", rs.Kind, rs.Name)
|
||||
}
|
||||
|
||||
// Merge merges the new state into the previous state, returning whether the
|
||||
// new state contains any additional keys or different values from the old state.
|
||||
func (rs *resourceState) Merge() bool {
|
||||
if out := rs.String(); out != rs.PrevState {
|
||||
rs.PrevState = out
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (rs *resourceState) String() string {
|
||||
return fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", rs.Kind, rs.Name, rs.Fields["status"], rs.Fields["healthStatus"], rs.Fields["type"], rs.Fields["message"])
|
||||
}
|
||||
|
||||
// Update a resourceState with any different contents from another resourceState.
|
||||
// Blank fields in the receiver state will be updated to non-blank.
|
||||
// Non-blank fields in the receiver state will never be updated to blank.
|
||||
func (rs *resourceState) Update(newState *resourceState) {
|
||||
for k, v := range newState.Fields {
|
||||
if v != "" {
|
||||
rs.Fields[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitOnApplicationStatus(appClient application.ApplicationServiceClient, appName string, timeout uint, watchSync, watchHealth, watchOperations bool) (*argoappv1.Application, error) {
|
||||
func waitUntilOperationCompleted(appClient application.ApplicationServiceClient, appName string, timeout uint) (*argoappv1.Application, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
printFinalStatus := func() {
|
||||
// get refreshed app before printing to show accurate sync/health status
|
||||
app, err := appClient.Get(ctx, &application.ApplicationQuery{Name: &appName, Refresh: true})
|
||||
errors.CheckError(err)
|
||||
|
||||
fmt.Printf(printOpFmtStr, "Application:", appName)
|
||||
printOperationResult(app.Status.OperationState)
|
||||
|
||||
if len(app.Status.ComparisonResult.Resources) > 0 {
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
printAppResources(w, app, true)
|
||||
_ = w.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
if timeout != 0 {
|
||||
time.AfterFunc(time.Duration(timeout)*time.Second, func() {
|
||||
cancel()
|
||||
printFinalStatus()
|
||||
})
|
||||
}
|
||||
|
||||
// print the initial components to format the tabwriter columns
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "KIND\tNAME\tSTATUS\tHEALTH\tHOOK\tOPERATIONMSG")
|
||||
_ = w.Flush()
|
||||
|
||||
prevStates := make(map[string]*resourceState)
|
||||
conditionallyPrintOutput := func(w io.Writer, newState *resourceState) {
|
||||
stateKey := newState.Key()
|
||||
if prevState, found := prevStates[stateKey]; found {
|
||||
prevState.Update(newState)
|
||||
} else {
|
||||
prevStates[stateKey] = newState
|
||||
}
|
||||
}
|
||||
|
||||
printCompResults := func(compResult *argoappv1.ComparisonResult) {
|
||||
if compResult != nil {
|
||||
for _, res := range compResult.Resources {
|
||||
obj, err := argoappv1.UnmarshalToUnstructured(res.TargetState)
|
||||
errors.CheckError(err)
|
||||
if obj == nil {
|
||||
obj, err = argoappv1.UnmarshalToUnstructured(res.LiveState)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
newState := newResourceState(obj.GetKind(), obj.GetName(), string(res.Status), res.Health.Status, "", "")
|
||||
conditionallyPrintOutput(w, newState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printOpResults := func(opResult *argoappv1.SyncOperationResult) {
|
||||
if opResult != nil {
|
||||
if opResult.Hooks != nil {
|
||||
for _, hook := range opResult.Hooks {
|
||||
newState := newResourceState(hook.Kind, hook.Name, string(hook.Status), "", string(hook.Type), hook.Message)
|
||||
conditionallyPrintOutput(w, newState)
|
||||
}
|
||||
}
|
||||
|
||||
if opResult.Resources != nil {
|
||||
for _, res := range opResult.Resources {
|
||||
newState := newResourceState(res.Kind, res.Name, string(res.Status), "", "", res.Message)
|
||||
conditionallyPrintOutput(w, newState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appEventCh := watchApp(ctx, appClient, appName)
|
||||
for appEvent := range appEventCh {
|
||||
app := appEvent.Application
|
||||
|
||||
printCompResults(&app.Status.ComparisonResult)
|
||||
|
||||
if opState := app.Status.OperationState; opState != nil {
|
||||
printOpResults(opState.SyncResult)
|
||||
printOpResults(opState.RollbackResult)
|
||||
}
|
||||
|
||||
for _, v := range prevStates {
|
||||
if v.Merge() {
|
||||
fmt.Fprintln(w, v)
|
||||
}
|
||||
}
|
||||
|
||||
_ = w.Flush()
|
||||
|
||||
// consider skipped checks successful
|
||||
synced := !watchSync || app.Status.ComparisonResult.Status == argoappv1.ComparisonStatusSynced
|
||||
healthy := !watchHealth || app.Status.Health.Status == argoappv1.HealthStatusHealthy
|
||||
operational := !watchOperations || appEvent.Application.Operation == nil
|
||||
if len(app.Status.GetErrorConditions()) == 0 && synced && healthy && operational {
|
||||
log.Printf("App %q matches desired state", appName)
|
||||
printFinalStatus()
|
||||
return &app, nil
|
||||
if appEvent.Application.Status.OperationState != nil && appEvent.Application.Status.OperationState.Phase.Completed() {
|
||||
return &appEvent.Application, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Timed out (%ds) waiting for app %q match desired state", timeout, appName)
|
||||
}
|
||||
|
||||
// setParameterOverrides updates an existing or appends a new parameter override in the application
|
||||
// If the app is a ksonnet app, then parameters are expected to be in the form: component=param=value
|
||||
// Otherwise, the app is assumed to be a helm app and is expected to be in the form:
|
||||
// param=value
|
||||
func setParameterOverrides(app *argoappv1.Application, parameters []string) {
|
||||
if len(parameters) == 0 {
|
||||
return
|
||||
@@ -1018,28 +901,15 @@ func setParameterOverrides(app *argoappv1.Application, parameters []string) {
|
||||
} else {
|
||||
newParams = make([]argoappv1.ComponentParameter, 0)
|
||||
}
|
||||
isKsonnetApp := app.Spec.Source.Environment != ""
|
||||
for _, paramStr := range parameters {
|
||||
var newParam argoappv1.ComponentParameter
|
||||
if isKsonnetApp {
|
||||
parts := strings.SplitN(paramStr, "=", 3)
|
||||
if len(parts) != 3 {
|
||||
log.Fatalf("Expected ksonnet parameter of the form: component=param=value. Received: %s", paramStr)
|
||||
}
|
||||
newParam = argoappv1.ComponentParameter{
|
||||
Component: parts[0],
|
||||
Name: parts[1],
|
||||
Value: parts[2],
|
||||
}
|
||||
} else {
|
||||
parts := strings.SplitN(paramStr, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
log.Fatalf("Expected helm parameter of the form: param=value. Received: %s", paramStr)
|
||||
}
|
||||
newParam = argoappv1.ComponentParameter{
|
||||
Name: parts[0],
|
||||
Value: parts[1],
|
||||
}
|
||||
parts := strings.SplitN(paramStr, "=", 3)
|
||||
if len(parts) != 3 {
|
||||
log.Fatalf("Expected parameter of the form: component=param=value. Received: %s", paramStr)
|
||||
}
|
||||
newParam := argoappv1.ComponentParameter{
|
||||
Component: parts[0],
|
||||
Name: parts[1],
|
||||
Value: parts[2],
|
||||
}
|
||||
index := -1
|
||||
for i, cp := range newParams {
|
||||
@@ -1149,8 +1019,18 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
_, err = waitOnApplicationStatus(appIf, appName, timeout, false, false, true)
|
||||
app, err = waitUntilOperationCompleted(appIf, appName, timeout)
|
||||
errors.CheckError(err)
|
||||
|
||||
// get refreshed app before printing to show accurate sync/health status
|
||||
app, err = appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, Refresh: true})
|
||||
errors.CheckError(err)
|
||||
|
||||
fmt.Printf(printOpFmtStr, "Application:", appName)
|
||||
printOperationResult(app.Status.OperationState)
|
||||
if !app.Status.OperationState.Phase.Successful() {
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVar(&prune, "prune", false, "Allow deleting unexpected resources")
|
||||
|
||||
@@ -77,7 +77,6 @@ func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
|
||||
// Perform the login
|
||||
var tokenString string
|
||||
var refreshToken string
|
||||
if !sso {
|
||||
tokenString = passwordLogin(acdClient, username, password)
|
||||
} else {
|
||||
@@ -86,7 +85,15 @@ func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
if !ssoConfigured(acdSet) {
|
||||
log.Fatalf("ArgoCD instance is not configured with SSO")
|
||||
}
|
||||
tokenString, refreshToken = oauth2Login(server, clientOpts.PlainText)
|
||||
tokenString = oauth2Login(server, clientOpts.PlainText)
|
||||
// The token which we just received from the OAuth2 flow, was from dex. ArgoCD
|
||||
// currently does not back dex with any kind of persistent storage (it is run
|
||||
// in-memory). As a result, this token cannot be used in any permanent capacity.
|
||||
// Restarts of dex will result in a different signing key, and sessions becoming
|
||||
// invalid. Instead we turn-around and ask ArgoCD to re-sign the token (who *does*
|
||||
// have persistence of signing keys), and is what we store in the config. Should we
|
||||
// ever decide to have a database layer for dex, the next line can be removed.
|
||||
tokenString = tokenLogin(acdClient, tokenString)
|
||||
}
|
||||
|
||||
parser := &jwt.Parser{
|
||||
@@ -109,9 +116,8 @@ func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
Insecure: globalClientOpts.Insecure,
|
||||
})
|
||||
localCfg.UpsertUser(localconfig.User{
|
||||
Name: ctxName,
|
||||
AuthToken: tokenString,
|
||||
RefreshToken: refreshToken,
|
||||
Name: ctxName,
|
||||
AuthToken: tokenString,
|
||||
})
|
||||
if ctxName == "" {
|
||||
ctxName = server
|
||||
@@ -157,9 +163,8 @@ func getFreePort() (int, error) {
|
||||
return ln.Addr().(*net.TCPAddr).Port, ln.Close()
|
||||
}
|
||||
|
||||
// oauth2Login opens a browser, runs a temporary HTTP server to delegate OAuth2 login flow and
|
||||
// returns the JWT token and a refresh token (if supported)
|
||||
func oauth2Login(host string, plaintext bool) (string, string) {
|
||||
// oauth2Login opens a browser, runs a temporary HTTP server to delegate OAuth2 login flow and returns the JWT token
|
||||
func oauth2Login(host string, plaintext bool) string {
|
||||
ctx := context.Background()
|
||||
port, err := getFreePort()
|
||||
errors.CheckError(err)
|
||||
@@ -178,7 +183,6 @@ func oauth2Login(host string, plaintext bool) (string, string) {
|
||||
}
|
||||
srv := &http.Server{Addr: ":" + strconv.Itoa(port)}
|
||||
var tokenString string
|
||||
var refreshToken string
|
||||
loginCompleted := make(chan struct{})
|
||||
|
||||
callbackHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -211,9 +215,8 @@ func oauth2Login(host string, plaintext bool) (string, string) {
|
||||
log.Fatal(errMsg)
|
||||
return
|
||||
}
|
||||
refreshToken, _ = tok.Extra("refresh_token").(string)
|
||||
|
||||
log.Debugf("Token: %s", tokenString)
|
||||
log.Debugf("Refresh Token: %s", tokenString)
|
||||
successPage := `
|
||||
<div style="height:100px; width:100%!; display:flex; flex-direction: column; justify-content: center; align-items:center; background-color:#2ecc71; color:white; font-size:22"><div>Authentication successful!</div></div>
|
||||
<p style="margin-top:20px; font-size:18; text-align:center">Authentication was successful, you can now return to CLI. This page will close automatically</p>
|
||||
@@ -245,7 +248,7 @@ func oauth2Login(host string, plaintext bool) (string, string) {
|
||||
}()
|
||||
<-loginCompleted
|
||||
_ = srv.Shutdown(ctx)
|
||||
return tokenString, refreshToken
|
||||
return tokenString
|
||||
}
|
||||
|
||||
func passwordLogin(acdClient argocdclient.Client, username, password string) string {
|
||||
@@ -260,3 +263,14 @@ func passwordLogin(acdClient argocdclient.Client, username, password string) str
|
||||
errors.CheckError(err)
|
||||
return createdSession.Token
|
||||
}
|
||||
|
||||
func tokenLogin(acdClient argocdclient.Client, token string) string {
|
||||
sessConn, sessionIf := acdClient.NewSessionClientOrDie()
|
||||
defer util.Close(sessConn)
|
||||
sessionRequest := session.SessionCreateRequest{
|
||||
Token: token,
|
||||
}
|
||||
createdSession, err := sessionIf.Create(context.Background(), &sessionRequest)
|
||||
errors.CheckError(err)
|
||||
return createdSession.Token
|
||||
}
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
)
|
||||
|
||||
// NewReloginCommand returns a new instance of `argocd relogin` command
|
||||
func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
password string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "relogin",
|
||||
Short: "Refresh an expired authenticate token",
|
||||
Long: "Refresh an expired authenticate token",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
localCfg, err := localconfig.ReadLocalConfig(globalClientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
if localCfg == nil {
|
||||
log.Fatalf("No context found. Login using `argocd login`")
|
||||
}
|
||||
configCtx, err := localCfg.ResolveContext(localCfg.CurrentContext)
|
||||
errors.CheckError(err)
|
||||
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
}
|
||||
claims := jwt.StandardClaims{}
|
||||
_, _, err = parser.ParseUnverified(configCtx.User.AuthToken, &claims)
|
||||
errors.CheckError(err)
|
||||
|
||||
var tokenString string
|
||||
var refreshToken string
|
||||
if claims.Issuer == session.SessionManagerClaimsIssuer {
|
||||
clientOpts := argocdclient.ClientOptions{
|
||||
ConfigPath: "",
|
||||
ServerAddr: configCtx.Server.Server,
|
||||
Insecure: configCtx.Server.Insecure,
|
||||
PlainText: configCtx.Server.PlainText,
|
||||
}
|
||||
acdClient := argocdclient.NewClientOrDie(&clientOpts)
|
||||
fmt.Printf("Relogging in as '%s'\n", claims.Subject)
|
||||
tokenString = passwordLogin(acdClient, claims.Subject, password)
|
||||
} else {
|
||||
fmt.Println("Reinitiating SSO login")
|
||||
tokenString, refreshToken = oauth2Login(configCtx.Server.Server, configCtx.Server.PlainText)
|
||||
}
|
||||
|
||||
localCfg.UpsertUser(localconfig.User{
|
||||
Name: localCfg.CurrentContext,
|
||||
AuthToken: tokenString,
|
||||
RefreshToken: refreshToken,
|
||||
})
|
||||
err = localconfig.WriteLocalConfig(*localCfg, globalClientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Context '%s' updated\n", localCfg.CurrentContext)
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&password, "password", "", "the password of an account to authenticate")
|
||||
return command
|
||||
}
|
||||
@@ -27,7 +27,6 @@ func NewCommand() *cobra.Command {
|
||||
command.AddCommand(NewClusterCommand(&clientOpts, pathOpts))
|
||||
command.AddCommand(NewApplicationCommand(&clientOpts))
|
||||
command.AddCommand(NewLoginCommand(&clientOpts))
|
||||
command.AddCommand(NewReloginCommand(&clientOpts))
|
||||
command.AddCommand(NewRepoCommand(&clientOpts))
|
||||
command.AddCommand(NewContextCommand(&clientOpts))
|
||||
command.AddCommand(NewProjectCommand(&clientOpts))
|
||||
|
||||
@@ -54,7 +54,6 @@ func NewVersionCmd(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
fmt.Printf(" GoVersion: %s\n", serverVers.GoVersion)
|
||||
fmt.Printf(" Compiler: %s\n", serverVers.Compiler)
|
||||
fmt.Printf(" Platform: %s\n", serverVers.Platform)
|
||||
fmt.Printf(" Ksonnet Version: %s\n", serverVers.KsonnetVersion)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
@@ -73,8 +73,6 @@ var (
|
||||
AnnotationHook = MetadataPrefix + "/hook"
|
||||
// AnnotationHookDeletePolicy is the policy of deleting a hook
|
||||
AnnotationHookDeletePolicy = MetadataPrefix + "/hook-delete-policy"
|
||||
// AnnotationHelmHook is the helm hook annotation
|
||||
AnnotationHelmHook = "helm.sh/hook"
|
||||
|
||||
// LabelKeyApplicationControllerInstanceID is the label which allows to separate application among multiple running application controllers.
|
||||
LabelKeyApplicationControllerInstanceID = application.ApplicationFullName + "/controller-instanceid"
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@@ -47,7 +46,6 @@ type ApplicationController struct {
|
||||
namespace string
|
||||
kubeClientset kubernetes.Interface
|
||||
applicationClientset appclientset.Interface
|
||||
auditLogger *argo.AuditLogger
|
||||
appRefreshQueue workqueue.RateLimitingInterface
|
||||
appOperationQueue workqueue.RateLimitingInterface
|
||||
appInformer cache.SharedIndexInformer
|
||||
@@ -90,7 +88,6 @@ func NewApplicationController(
|
||||
statusRefreshTimeout: appResyncPeriod,
|
||||
forceRefreshApps: make(map[string]bool),
|
||||
forceRefreshAppsMutex: &sync.Mutex{},
|
||||
auditLogger: argo.NewAuditLogger(namespace, kubeClientset, "application-controller"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +201,7 @@ func retryUntilSucceed(action func() error, desc string, ctx context.Context, ti
|
||||
log.Infof("Stop retrying %s", desc)
|
||||
return
|
||||
} else {
|
||||
log.Warnf("Failed to %s: %+v, retrying in %v", desc, err, timeout)
|
||||
log.Warnf("Failed to %s: %v, retrying in %v", desc, err, timeout)
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
}
|
||||
@@ -286,7 +283,6 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
|
||||
Type: appv1.ApplicationConditionDeletionError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonStatusRefreshed, Action: "refresh_status"}, v1.EventTypeWarning)
|
||||
} else {
|
||||
log.Infof("Successfully deleted resources for application %s", app.Name)
|
||||
}
|
||||
@@ -400,7 +396,6 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
// If operation is completed, clear the operation field to indicate no operation is
|
||||
// in progress.
|
||||
patch["operation"] = nil
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Action: "refresh_status"}, v1.EventTypeNormal)
|
||||
}
|
||||
if reflect.DeepEqual(app.Status.OperationState, state) {
|
||||
log.Infof("No operation updates necessary to '%s'. Skipping patch", app.Name)
|
||||
@@ -558,7 +553,6 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
|
||||
|
||||
// setApplicationHealth updates the health statuses of all resources performed in the comparison
|
||||
func setApplicationHealth(comparisonResult *appv1.ComparisonResult) (*appv1.HealthStatus, error) {
|
||||
var savedErr error
|
||||
appHealth := appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
if comparisonResult.Status == appv1.ComparisonStatusUnknown {
|
||||
appHealth.Status = appv1.HealthStatusUnknown
|
||||
@@ -573,8 +567,8 @@ func setApplicationHealth(comparisonResult *appv1.ComparisonResult) (*appv1.Heal
|
||||
return nil, err
|
||||
}
|
||||
healthState, err := health.GetAppHealth(&obj)
|
||||
if err != nil && savedErr == nil {
|
||||
savedErr = err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resource.Health = *healthState
|
||||
}
|
||||
@@ -583,7 +577,7 @@ func setApplicationHealth(comparisonResult *appv1.ComparisonResult) (*appv1.Heal
|
||||
appHealth.Status = resource.Health.Status
|
||||
}
|
||||
}
|
||||
return &appHealth, savedErr
|
||||
return &appHealth, nil
|
||||
}
|
||||
|
||||
// updateAppStatus persists updates to application status. Detects if there patch
|
||||
|
||||
@@ -120,7 +120,6 @@ func (s *ksonnetAppStateManager) getTargetObjs(app *v1alpha1.Application, revisi
|
||||
Revision: revision,
|
||||
ComponentParameterOverrides: mfReqOverrides,
|
||||
AppLabel: app.Name,
|
||||
ValueFiles: app.Spec.Source.ValuesFiles,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -431,7 +431,7 @@ func (sc *syncContext) doHookSync(syncTasks []syncTask, hooks []*unstructured.Un
|
||||
sc.setOperationPhase(appv1.OperationSucceeded, "successfully synced")
|
||||
}
|
||||
|
||||
// getHooks returns all ArgoCD hooks, optionally filtered by ones of the specific type(s)
|
||||
// getHooks returns all hooks, or ones of the specific type(s)
|
||||
func (sc *syncContext) getHooks(hookTypes ...appv1.HookType) ([]*unstructured.Unstructured, error) {
|
||||
var hooks []*unstructured.Unstructured
|
||||
for _, manifest := range sc.manifestInfo.Manifests {
|
||||
@@ -440,9 +440,7 @@ func (sc *syncContext) getHooks(hookTypes ...appv1.HookType) ([]*unstructured.Un
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isArgoHook(&hook) {
|
||||
// TODO: in the future, if we want to map helm hooks to ArgoCD lifecycles, we should
|
||||
// include helm hooks in the returned list
|
||||
if !isHook(&hook) {
|
||||
continue
|
||||
}
|
||||
if len(hookTypes) > 0 {
|
||||
@@ -616,24 +614,9 @@ func isHookType(hook *unstructured.Unstructured, hookType appv1.HookType) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isHook indicates if the object is either a ArgoCD or Helm hook
|
||||
// isHook tells whether or not the supplied object is a application lifecycle hook, or a normal,
|
||||
// synced application resource
|
||||
func isHook(obj *unstructured.Unstructured) bool {
|
||||
return isArgoHook(obj) || isHelmHook(obj)
|
||||
}
|
||||
|
||||
// isHelmHook indicates if the supplied object is a helm hook
|
||||
func isHelmHook(obj *unstructured.Unstructured) bool {
|
||||
annotations := obj.GetAnnotations()
|
||||
if annotations == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := annotations[common.AnnotationHook]
|
||||
return ok
|
||||
}
|
||||
|
||||
// isArgoHook indicates if the supplied object is an ArgoCD application lifecycle hook
|
||||
// (vs. a normal, synced application resource)
|
||||
func isArgoHook(obj *unstructured.Unstructured) bool {
|
||||
annotations := obj.GetAnnotations()
|
||||
if annotations == nil {
|
||||
return false
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
* [Tracking Strategies](tracking_strategies.md)
|
||||
|
||||
## Features
|
||||
* [Application Sources](application_sources.md)
|
||||
* [Application Parameters](parameters.md)
|
||||
* [Resource Health](health.md)
|
||||
* [Resource Hooks](resource_hooks.md)
|
||||
* [Single Sign On](sso.md)
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
# Application Source Types
|
||||
|
||||
ArgoCD supports several different ways in which kubernetes manifests can be defined:
|
||||
|
||||
* [ksonnet](https://ksonnet.io) applications
|
||||
* [helm](https://helm.sh) charts
|
||||
* Simple directory of YAML/json manifests
|
||||
|
||||
Some additional considerations should be made when deploying apps of a particular type:
|
||||
|
||||
## Ksonnet
|
||||
|
||||
### Environments
|
||||
Ksonnet has a first class concept of an "environment." To create an application from a ksonnet
|
||||
app directory, an environment must be specified. For example, the following command creates the
|
||||
"guestbook-default" app, which points to the `default` environment:
|
||||
|
||||
```
|
||||
argocd app create guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --env default
|
||||
```
|
||||
|
||||
### Parameters
|
||||
Ksonnet parameters all belong to a component. For example, the following are the parameters
|
||||
available in the guestbook app, all of which belong to the `guestbook-ui` component:
|
||||
|
||||
```
|
||||
$ ks param list
|
||||
COMPONENT PARAM VALUE
|
||||
========= ===== =====
|
||||
guestbook-ui containerPort 80
|
||||
guestbook-ui image "gcr.io/heptio-images/ks-guestbook-demo:0.1"
|
||||
guestbook-ui name "guestbook-ui"
|
||||
guestbook-ui replicas 1
|
||||
guestbook-ui servicePort 80
|
||||
guestbook-ui type "LoadBalancer"
|
||||
```
|
||||
|
||||
When overriding ksonnet parameters in ArgoCD, the component name should also be specified in the
|
||||
`argocd app set` command, in the form of `-p COMPONENT=PARAM=VALUE`. For example:
|
||||
```
|
||||
argocd app set guestbook-default -p guestbook-ui=image=gcr.io/heptio-images/ks-guestbook-demo:0.1
|
||||
```
|
||||
|
||||
## Helm
|
||||
|
||||
### Values Files
|
||||
|
||||
Helm has the ability to use a different, or even multiple "values.yaml" files to derive its
|
||||
parameters from. Alternate or multiple values file(s), can be specified using the `--values`
|
||||
flag. The flag can be repeated to support multiple values files:
|
||||
|
||||
```
|
||||
argocd app set helm-guestbook --values values-production.yaml
|
||||
```
|
||||
|
||||
### Helm Parameters
|
||||
|
||||
Helm has the ability to set parameter values, which override any values in
|
||||
a `values.yaml`. For example, `service.type` is a common parameter which is exposed in a Helm chart:
|
||||
```
|
||||
helm template . --set service.type=LoadBalancer
|
||||
```
|
||||
Similarly ArgoCD can override values in the `values.yaml` parameters using `argo app set` command,
|
||||
in the form of `-p PARAM=VALUE`. For example:
|
||||
```
|
||||
argocd app set helm-guestbook -p service.type=LoadBalancer
|
||||
```
|
||||
|
||||
### Helm Hooks
|
||||
|
||||
Helm hooks are equivalent in concept to [ArgoCD resource hooks](resource_hooks.md). In helm, a hook
|
||||
is any normal kubernetes resource annotated with the `helm.sh/hook` annotation. When ArgoCD deploys
|
||||
helm application which contains helm hooks, all helm hook resources are currently ignored during
|
||||
the `kubectl apply` of the manifests. There is an
|
||||
[open issue](https://github.com/argoproj/argo-cd/issues/355) to map Helm hooks to ArgoCD's concept
|
||||
of Pre/Post/Sync hooks.
|
||||
|
||||
### Random Data
|
||||
|
||||
Helm templating has the ability to generate random data during chart rendering via the
|
||||
`randAlphaNum` function. Many helm charts from the [charts repository](https://github.com/helm/charts)
|
||||
make use of this feature. For example, the following is the secret for the
|
||||
[redis helm chart](https://github.com/helm/charts/blob/master/stable/redis/templates/secrets.yaml):
|
||||
|
||||
```
|
||||
data:
|
||||
{{- if .Values.password }}
|
||||
redis-password: {{ .Values.password | b64enc | quote }}
|
||||
{{- else }}
|
||||
redis-password: {{ randAlphaNum 10 | b64enc | quote }}
|
||||
{{- end }}
|
||||
```
|
||||
|
||||
The ArgoCD application controller periodically compares git state against the live state, running
|
||||
the `helm template <CHART>` command to generate the helm manifests. Because the random value is
|
||||
regenerated every time the comparison is made, any application which makes use of the `randAlphaNum`
|
||||
function will always be in an `OutOfSync` state. This can be mitigated by explicitly setting a
|
||||
value, in the values.yaml such that the value is stable between each comparison. For example:
|
||||
|
||||
```
|
||||
argocd app set redis -p password=abc123
|
||||
```
|
||||
@@ -22,31 +22,15 @@ manifests when provided the following inputs:
|
||||
* repository URL
|
||||
* git revision (commit, tag, branch)
|
||||
* application path
|
||||
* template specific settings: parameters, ksonnet environments, helm values.yaml
|
||||
* application environment
|
||||
|
||||
### Application Controller
|
||||
The application controller is a Kubernetes controller which continuously monitors running
|
||||
applications and compares the current, live state against the desired target state (as specified in
|
||||
the git repo). It detects `OutOfSync` application state and optionally takes corrective action. It
|
||||
is responsible for invoking any user-defined hooks for lifcecycle events (PreSync, Sync, PostSync)
|
||||
the git repo). It detects out-of-sync application state and optionally takes corrective action. It
|
||||
is responsible for invoking any user-defined handlers (argo workflows) for Sync, OutOfSync events
|
||||
|
||||
### Application CRD (Custom Resource Definition)
|
||||
The Application CRD is the Kubernetes resource object representing a deployed application instance
|
||||
in an environment. It is defined by two key pieces of information:
|
||||
* `source` reference to the desired state in git (repository, revision, path, environment)
|
||||
* `destination` reference to the target cluster and namespace.
|
||||
|
||||
An example spec is as follows:
|
||||
|
||||
```
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
targetRevision: HEAD
|
||||
path: guestbook
|
||||
environment: default
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: default
|
||||
```
|
||||
in an environment. It holds a reference to the desired target state (repo, revision, app, environment)
|
||||
of which the application controller will enforce state against.
|
||||
|
||||
@@ -1,37 +1,30 @@
|
||||
# ArgoCD Getting Started
|
||||
|
||||
An example guestbook application is provided to demonstrate how ArgoCD works.
|
||||
An example Ksonnet guestbook application is provided to demonstrates how ArgoCD works.
|
||||
|
||||
## Requirements
|
||||
* Installed [minikube](https://github.com/kubernetes/minikube#installation)
|
||||
* Installed [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) command-line tool
|
||||
* Have a [kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) file (default location is `~/.kube/config`).
|
||||
|
||||
## 1. Install ArgoCD
|
||||
```
|
||||
kubectl create namespace argocd
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.7.1/manifests/install.yaml
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml
|
||||
```
|
||||
This will create a new namespace, `argocd`, where ArgoCD services and application resources will live.
|
||||
|
||||
NOTE:
|
||||
* On GKE with RBAC enabled, you may need to grant your account the ability to create new cluster roles
|
||||
```
|
||||
kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
|
||||
$ kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
|
||||
```
|
||||
|
||||
## 2. Download ArgoCD CLI
|
||||
|
||||
Download the latest ArgoCD version:
|
||||
|
||||
On Mac:
|
||||
```
|
||||
brew install argoproj/tap/argocd
|
||||
```
|
||||
|
||||
On Linux:
|
||||
|
||||
```
|
||||
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.7.1/argocd-linux-amd64
|
||||
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.6.0/argocd-darwin-amd64
|
||||
chmod +x /usr/local/bin/argocd
|
||||
```
|
||||
|
||||
@@ -60,14 +53,13 @@ argocd login $(minikube service argocd-server -n argocd --url | cut -d'/' -f 3)
|
||||
```
|
||||
Other clusters:
|
||||
```
|
||||
kubectl get svc -n argocd argocd-server
|
||||
kubectl get svc argocd-server
|
||||
argocd login <EXTERNAL-IP>
|
||||
```
|
||||
|
||||
After logging in, change the password using the command:
|
||||
```
|
||||
argocd account update-password
|
||||
argocd relogin
|
||||
```
|
||||
|
||||
|
||||
@@ -123,7 +115,7 @@ After connecting a git repository, select the guestbook application for creation
|
||||
Applications can be also be created using the ArgoCD CLI:
|
||||
|
||||
```
|
||||
argocd app create guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --env default
|
||||
argocd app create --name guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --env default
|
||||
```
|
||||
|
||||
## 7. Sync (deploy) the application
|
||||
@@ -165,13 +157,17 @@ Service guestbook-ui service "guestbook-ui" created
|
||||
Deployment guestbook-ui deployment.apps "guestbook-ui" created
|
||||
```
|
||||
|
||||
This command retrieves the manifests from git repository and performs a `kubectl apply` of the
|
||||
manifests. The guestbook app is now running and you can now view its resource
|
||||
This command retrieves the manifests from the ksonnet app in the git repository and performs a
|
||||
`kubectl apply` of the manifests. The guestbook app is now running and you can now view its resource
|
||||
components, logs, events, and assessed health:
|
||||
|
||||

|
||||
|
||||
|
||||
## 8. Next Steps
|
||||
|
||||
ArgoCD supports additional features such as SSO, WebHooks, RBAC, Projects. See the rest of
|
||||
the [documentation](./) for details.
|
||||
ArgoCD supports additional features such as SSO, WebHooks, RBAC. See the following guides on setting
|
||||
these up:
|
||||
* [Configuring SSO](sso.md)
|
||||
* [Configuring RBAC](rbac.md)
|
||||
* [Configuring WebHooks](webhook.md)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Parameter Overrides
|
||||
|
||||
ArgoCD provides a mechanism to override the parameters of a ksonnet/helm app. This gives some extra
|
||||
flexibility in having most of the application manifests defined in git, while leaving room for
|
||||
*some* parts of the k8s manifests determined dynamically, or outside of git. It also serves as an
|
||||
alternative way of redeploying an application by changing application parameters via ArgoCD, instead
|
||||
of making the changes to the manifests in git.
|
||||
|
||||
**NOTE:** many consider this mode of operation as an anti-pattern to GitOps, since the source of
|
||||
truth becomes a union of the git repository, and the application overrides. The ArgoCD parameter
|
||||
overrides feature is provided mainly convenience to developers and is intended to be used more for
|
||||
dev/test environments, vs. production environments.
|
||||
|
||||
To use parameter overrides, run the `argocd app set -p (COMPONENT=)PARAM=VALUE` command:
|
||||
```
|
||||
argocd app set guestbook -p guestbook=image=example/guestbook:abcd123
|
||||
argocd app sync guestbook
|
||||
```
|
||||
|
||||
The following are situations where parameter overrides would be useful:
|
||||
|
||||
1. A team maintains a "dev" environment, which needs to be continually updated with the latest
|
||||
version of their guestbook application after every build in the tip of master. To address this use
|
||||
case, the application would expose an parameter named `image`, whose value used in the `dev`
|
||||
environment contains a placeholder value (e.g. `example/guestbook:replaceme`). The placeholder value
|
||||
would be determined externally (outside of git) such as a build systems. Then, as part of the build
|
||||
pipeline, the parameter value of the `image` would be continually updated to the freshly built image
|
||||
(e.g. `argocd app set guestbook -p guestbook=image=example/guestbook:abcd123`). A sync operation
|
||||
would result in the application being redeployed with the new image.
|
||||
|
||||
2. A repository of helm manifests is already publicly available (e.g. https://github.com/helm/charts).
|
||||
Since commit access to the repository is unavailable, it is useful to be able to install charts from
|
||||
the public repository, customizing the deployment with different parameters, without resorting to
|
||||
forking the repository to make the changes. For example, to install redis from the helm chart
|
||||
repository and customize the the database password, you would run:
|
||||
|
||||
```
|
||||
argocd app create redis --repo https://github.com/helm/charts.git --path stable/redis --dest-server https://kubernetes.default.svc --dest-namespace default -p password=abc123
|
||||
```
|
||||
12
docs/rbac.md
12
docs/rbac.md
@@ -44,19 +44,15 @@ Kubernetes clusters which can be used by applications belonging to the project.
|
||||
|
||||
### 1. Create new project
|
||||
|
||||
Following command creates project `myproject` which can deploy applications to namespace `default` of cluster `https://kubernetes.default.svc`. The valid application source is defined in the `https://github.com/argoproj/argocd-example-apps.git` repository.
|
||||
Following command creates project `myproject` which can deploy applications to namespace `default` of cluster `https://kubernetes.default.svc`. The source ksonnet application
|
||||
should be defined in `https://github.com/argoproj/argocd-example-apps.git` repository.
|
||||
|
||||
```
|
||||
argocd proj create myproject -d https://kubernetes.default.svc,default -s https://github.com/argoproj/argocd-example-apps.git
|
||||
```
|
||||
|
||||
Project sources and destinations can be managed using commands
|
||||
```
|
||||
argocd project add-destination
|
||||
argocd project remove-destination
|
||||
argocd project add-source
|
||||
argocd project remove-source
|
||||
```
|
||||
Project sources and destinations can be managed using commands `argocd project add-destination`, `argocd project remove-destination`, `argocd project add-source`
|
||||
and `argocd project remove-source`.
|
||||
|
||||
### 2. Assign application to a project
|
||||
|
||||
|
||||
@@ -1,45 +1,41 @@
|
||||
# Tracking and Deployment Strategies
|
||||
|
||||
An ArgoCD application spec provides several different ways of track kubernetes resource manifests in
|
||||
git. This document describes the different techniques and the means of deploying those manifests to
|
||||
the target environment.
|
||||
An ArgoCD application spec provides several different ways of track kubernetes resource manifests in git. This document describes the different techniques and the means of deploying those manifests to the target environment.
|
||||
|
||||
## Branch Tracking
|
||||
|
||||
If a branch name is specified, ArgoCD will continually compare live state against the resource
|
||||
manifests defined at the tip of the specified branch.
|
||||
If a branch name is specified, ArgoCD will continually compare live state against the resource manifests defined at the tip of the specified branch.
|
||||
|
||||
To redeploy an application, a user makes changes to the manifests, and commit/pushes those the
|
||||
changes to the tracked branch, which will then be detected by ArgoCD controller.
|
||||
To redeploy an application, a user makes changes to the manifests, and commit/pushes those the changes to the tracked branch, which will then be detected by ArgoCD controller.
|
||||
|
||||
## Tag Tracking
|
||||
|
||||
If a tag is specified, the manifests at the specified git tag will be used to perform the sync
|
||||
comparison. This provides some advantages over branch tracking in that a tag is generally considered
|
||||
more stable, and less frequently updated, with some manual judgement of what constitutes a tag.
|
||||
If a tag is specified, the manifests at the specified git tag will be used to perform the sync comparison. This provides some advantages over branch tracking in that a tag is generally considered more stable, and less frequently updated, with some manual judgement of what constitutes a tag.
|
||||
|
||||
To redeploy an application, the user uses git to change the meaning of a tag by retagging it to a
|
||||
different commit SHA. ArgoCD will detect the new meaning of the tag when performing the
|
||||
comparison/sync.
|
||||
To redeploy an application, the user uses git to change the meaning of a tag by retagging it to a different commit SHA. ArgoCD will detect the new meaning of the tag when performing the comparison/sync.
|
||||
|
||||
## Commit Pinning
|
||||
|
||||
If a git commit SHA is specified, the application is effectively pinned to the manifests defined at
|
||||
the specified commit. This is the most restrictive of the techniques and is typically used to
|
||||
control production environments.
|
||||
If a git commit SHA is specified, the application is effectively pinned to the manifests defined at the specified commit. This is the most restrictive of the techniques and is typically used to control production environments.
|
||||
|
||||
Since commit SHAs cannot change meaning, the only way to change the live state of an application
|
||||
which is pinned to a commit, is by updating the tracking revision in the application to a different
|
||||
commit containing the new manifests. Note that [parameter overrides](parameters.md) can still be set
|
||||
on an application which is pinned to a revision.
|
||||
|
||||
## Auto-Sync [(Not Yet Implemented)]((https://github.com/argoproj/argo-cd/issues/79))
|
||||
|
||||
In all tracking strategies, the application will have the option to sync automatically. If auto-sync
|
||||
is configured, the new resources manifests will be applied automatically -- as soon as a difference
|
||||
is detected between the target state (git) and live state. If auto-sync is disabled, a manual sync
|
||||
will be needed using the Argo UI, CLI, or API.
|
||||
Since commit SHAs cannot change meaning, the only way to change the live state of an application which is pinned to a commit, is by updating the tracking revision in the application to a different commit containing the new manifests.
|
||||
Note that parameter overrides can still be made against a application which is pinned to a revision.
|
||||
|
||||
## Parameter Overrides
|
||||
Note that in all tracking strategies, any [parameter overrides](parameters.md) set in the
|
||||
application instance take precedence over the git state.
|
||||
|
||||
ArgoCD provides means to override the parameters of a ksonnet app. This gives some extra flexibility in having *some* parts of the k8s manifests determined dynamically. It also serves as an alternative way of redeploying an application by changing application parameters via ArgoCD, instead of making the changes to the manifests in git.
|
||||
|
||||
The following is an example of where this would be useful: A team maintains a "dev" environment, which needs to be continually updated with the latest version of their guestbook application after every build in the tip of master. To address this use case, the ksonnet application should expose an parameter named `image`, whose value used in the `dev` environment contains a placeholder value (e.g. `example/guestbook:replaceme`), intended to be set externally (outside of git) such as a build systems. As part of the build pipeline, the parameter value of the `image` would be continually updated to the freshly built image (e.g. `example/guestbook:abcd123`). A sync operation would result in the application being redeployed with the new image.
|
||||
|
||||
ArgoCD provides these operations conveniently via the CLI, or alternatively via the gRPC/REST API.
|
||||
```
|
||||
$ argocd app set guestbook -p guestbook=image=example/guestbook:abcd123
|
||||
$ argocd app sync guestbook
|
||||
```
|
||||
|
||||
Note that in all tracking strategies, any parameter overrides set in the application instance will be honored.
|
||||
|
||||
|
||||
## [Auto-Sync](https://github.com/argoproj/argo-cd/issues/79) (Not Yet Implemented)
|
||||
|
||||
In all tracking strategies, the application will have the option to sync automatically. If auto-sync is configured, the new resources manifests will be applied automatically -- as soon as a difference is detected between the target state (git) and live state. If auto-sync is disabled, a manual sync will be needed using the Argo UI, CLI, or API.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
IMAGE_NAMESPACE=${IMAGE_NAMESPACE:='argoproj'}
|
||||
IMAGE_TAG=${IMAGE_TAG:='latest'}
|
||||
|
||||
for i in "$(ls manifests/components/*.yaml)"; do
|
||||
sed -i '' 's@\( image: \(.*\)/\(argocd-.*\):.*\)@ image: '"${IMAGE_NAMESPACE}"'/\3:'"${IMAGE_TAG}"'@g' $i
|
||||
done
|
||||
|
||||
echo "# This is an auto-generated file. DO NOT EDIT" > manifests/install.yaml
|
||||
cat manifests/components/*.yaml >> manifests/install.yaml
|
||||
@@ -27,11 +27,3 @@ rules:
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
|
||||
image: argoproj/argocd-application-controller:v0.7.2
|
||||
image: argoproj/argocd-application-controller:latest
|
||||
name: application-controller
|
||||
serviceAccountName: application-controller
|
||||
|
||||
@@ -30,10 +30,3 @@ rules:
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
|
||||
@@ -15,20 +15,20 @@ spec:
|
||||
serviceAccountName: argocd-server
|
||||
initContainers:
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
image: argoproj/argocd-server:latest
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: ui
|
||||
image: argoproj/argocd-ui:v0.7.2
|
||||
image: argoproj/argocd-ui:latest
|
||||
command: [cp, -r, /app, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- name: argocd-server
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
image: argoproj/argocd-server:latest
|
||||
command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
|
||||
@@ -14,7 +14,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:v0.7.2
|
||||
image: argoproj/argocd-repo-server:latest
|
||||
command: [/argocd-repo-server]
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
|
||||
@@ -126,14 +126,6 @@ rules:
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
@@ -162,7 +154,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
|
||||
image: argoproj/argocd-application-controller:v0.7.2
|
||||
image: argoproj/argocd-application-controller:v0.6.2
|
||||
name: application-controller
|
||||
serviceAccountName: application-controller
|
||||
---
|
||||
@@ -202,13 +194,6 @@ rules:
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
@@ -238,20 +223,20 @@ spec:
|
||||
serviceAccountName: argocd-server
|
||||
initContainers:
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
image: argoproj/argocd-server:v0.6.2
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: ui
|
||||
image: argoproj/argocd-ui:v0.7.2
|
||||
image: argoproj/argocd-ui:v0.6.2
|
||||
command: [cp, -r, /app, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- name: argocd-server
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
image: argoproj/argocd-server:v0.6.2
|
||||
command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
@@ -298,7 +283,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:v0.7.2
|
||||
image: argoproj/argocd-repo-server:v0.6.2
|
||||
command: [/argocd-repo-server]
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
|
||||
@@ -8,20 +8,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/oauth2"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/server/account"
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
@@ -32,6 +21,9 @@ import (
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -76,12 +68,11 @@ type ClientOptions struct {
|
||||
}
|
||||
|
||||
type client struct {
|
||||
ServerAddr string
|
||||
PlainText bool
|
||||
Insecure bool
|
||||
CertPEMData []byte
|
||||
AuthToken string
|
||||
RefreshToken string
|
||||
ServerAddr string
|
||||
PlainText bool
|
||||
Insecure bool
|
||||
CertPEMData []byte
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
// NewClient creates a new API client from a set of config options.
|
||||
@@ -91,7 +82,6 @@ func NewClient(opts *ClientOptions) (Client, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ctxName string
|
||||
if localCfg != nil {
|
||||
configCtx, err := localCfg.ResolveContext(opts.Context)
|
||||
if err != nil {
|
||||
@@ -108,8 +98,6 @@ func NewClient(opts *ClientOptions) (Client, error) {
|
||||
c.PlainText = configCtx.Server.PlainText
|
||||
c.Insecure = configCtx.Server.Insecure
|
||||
c.AuthToken = configCtx.User.AuthToken
|
||||
c.RefreshToken = configCtx.User.RefreshToken
|
||||
ctxName = configCtx.Name
|
||||
}
|
||||
}
|
||||
// Override server address if specified in env or CLI flag
|
||||
@@ -149,97 +137,9 @@ func NewClient(opts *ClientOptions) (Client, error) {
|
||||
if opts.Insecure {
|
||||
c.Insecure = true
|
||||
}
|
||||
if localCfg != nil {
|
||||
err = c.refreshAuthToken(localCfg, ctxName, opts.ConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// refreshAuthToken refreshes a JWT auth token if it is invalid (e.g. expired)
|
||||
func (c *client) refreshAuthToken(localCfg *localconfig.LocalConfig, ctxName, configPath string) error {
|
||||
configCtx, err := localCfg.ResolveContext(ctxName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.RefreshToken == "" {
|
||||
// If we have no refresh token, there's no point in doing anything
|
||||
return nil
|
||||
}
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
}
|
||||
var claims jwt.StandardClaims
|
||||
_, _, err = parser.ParseUnverified(configCtx.User.AuthToken, &claims)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if claims.Valid() == nil {
|
||||
// token is still valid
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("Auth token no longer valid. Refreshing")
|
||||
tlsConfig, err := c.tlsConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
},
|
||||
}
|
||||
ctx := oidc.ClientContext(context.Background(), httpClient)
|
||||
var scheme string
|
||||
if c.PlainText {
|
||||
scheme = "http"
|
||||
} else {
|
||||
scheme = "https"
|
||||
}
|
||||
conf := &oauth2.Config{
|
||||
ClientID: common.ArgoCDCLIClientAppID,
|
||||
Scopes: []string{"openid", "profile", "email", "groups", "offline_access"},
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s://%s%s/auth", scheme, c.ServerAddr, common.DexAPIEndpoint),
|
||||
TokenURL: fmt.Sprintf("%s://%s%s/token", scheme, c.ServerAddr, common.DexAPIEndpoint),
|
||||
},
|
||||
RedirectURL: fmt.Sprintf("%s://%s/auth/callback", scheme, c.ServerAddr),
|
||||
}
|
||||
t := &oauth2.Token{
|
||||
RefreshToken: c.RefreshToken,
|
||||
}
|
||||
token, err := conf.TokenSource(ctx, t).Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawIDToken, ok := token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
return errors.New("no id_token in token response")
|
||||
}
|
||||
refreshToken, _ := token.Extra("refresh_token").(string)
|
||||
c.AuthToken = rawIDToken
|
||||
c.RefreshToken = refreshToken
|
||||
localCfg.UpsertUser(localconfig.User{
|
||||
Name: ctxName,
|
||||
AuthToken: c.AuthToken,
|
||||
RefreshToken: c.RefreshToken,
|
||||
})
|
||||
err = localconfig.WriteLocalConfig(*localCfg, configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClientOrDie creates a new API client from a set of config options, or fails fatally if the new client creation fails.
|
||||
func NewClientOrDie(opts *ClientOptions) Client {
|
||||
client, err := NewClient(opts)
|
||||
@@ -262,17 +162,25 @@ func (c jwtCredentials) RequireTransportSecurity() bool {
|
||||
func (c jwtCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
MetaDataTokenKey: c.Token,
|
||||
"tokens": c.Token, // legacy key. delete eventually
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *client) NewConn() (*grpc.ClientConn, error) {
|
||||
var creds credentials.TransportCredentials
|
||||
if !c.PlainText {
|
||||
tlsConfig, err := c.tlsConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var tlsConfig tls.Config
|
||||
if len(c.CertPEMData) > 0 {
|
||||
cp := x509.NewCertPool()
|
||||
if !cp.AppendCertsFromPEM(c.CertPEMData) {
|
||||
return nil, fmt.Errorf("credentials: failed to append certificates")
|
||||
}
|
||||
tlsConfig.RootCAs = cp
|
||||
}
|
||||
creds = credentials.NewTLS(tlsConfig)
|
||||
if c.Insecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
creds = credentials.NewTLS(&tlsConfig)
|
||||
}
|
||||
endpointCredentials := jwtCredentials{
|
||||
Token: c.AuthToken,
|
||||
@@ -280,21 +188,6 @@ func (c *client) NewConn() (*grpc.ClientConn, error) {
|
||||
return grpc_util.BlockingDial(context.Background(), "tcp", c.ServerAddr, creds, grpc.WithPerRPCCredentials(endpointCredentials))
|
||||
}
|
||||
|
||||
func (c *client) tlsConfig() (*tls.Config, error) {
|
||||
var tlsConfig tls.Config
|
||||
if len(c.CertPEMData) > 0 {
|
||||
cp := x509.NewCertPool()
|
||||
if !cp.AppendCertsFromPEM(c.CertPEMData) {
|
||||
return nil, fmt.Errorf("credentials: failed to append certificates")
|
||||
}
|
||||
tlsConfig.RootCAs = cp
|
||||
}
|
||||
if c.Insecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
return &tlsConfig, nil
|
||||
}
|
||||
|
||||
func (c *client) ClientOptions() ClientOptions {
|
||||
return ClientOptions{
|
||||
ServerAddr: c.ServerAddr,
|
||||
|
||||
@@ -547,21 +547,6 @@ func (m *ApplicationSource) MarshalTo(dAtA []byte) (int, error) {
|
||||
i += n
|
||||
}
|
||||
}
|
||||
if len(m.ValuesFiles) > 0 {
|
||||
for _, s := range m.ValuesFiles {
|
||||
dAtA[i] = 0x32
|
||||
i++
|
||||
l = len(s)
|
||||
for l >= 1<<7 {
|
||||
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||
l >>= 7
|
||||
i++
|
||||
}
|
||||
dAtA[i] = uint8(l)
|
||||
i++
|
||||
i += copy(dAtA[i:], s)
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -1773,12 +1758,6 @@ func (m *ApplicationSource) Size() (n int) {
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
if len(m.ValuesFiles) > 0 {
|
||||
for _, s := range m.ValuesFiles {
|
||||
l = len(s)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -2289,7 +2268,6 @@ func (this *ApplicationSource) String() string {
|
||||
`Environment:` + fmt.Sprintf("%v", this.Environment) + `,`,
|
||||
`TargetRevision:` + fmt.Sprintf("%v", this.TargetRevision) + `,`,
|
||||
`ComponentParameterOverrides:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ComponentParameterOverrides), "ComponentParameter", "ComponentParameter", 1), `&`, ``, 1) + `,`,
|
||||
`ValuesFiles:` + fmt.Sprintf("%v", this.ValuesFiles) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@@ -3663,35 +3641,6 @@ func (m *ApplicationSource) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 6:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ValuesFiles", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ValuesFiles = append(m.ValuesFiles, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
@@ -7776,158 +7725,157 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptorGenerated = []byte{
|
||||
// 2446 bytes of a gzipped FileDescriptorProto
|
||||
// 2425 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0x4b, 0x8c, 0x1c, 0x47,
|
||||
0x19, 0x76, 0xcf, 0x6b, 0x67, 0xfe, 0xd9, 0x87, 0x5d, 0x79, 0x30, 0x38, 0xd2, 0xee, 0xaa, 0xc3,
|
||||
0xc3, 0xa0, 0x64, 0x06, 0x1b, 0x02, 0xe6, 0x21, 0x24, 0xcf, 0xae, 0x1d, 0x6f, 0xd6, 0x8f, 0xa5,
|
||||
0x66, 0x13, 0xa4, 0x10, 0x05, 0xda, 0x3d, 0xb5, 0x33, 0xed, 0x99, 0xe9, 0xee, 0x74, 0xd5, 0x8c,
|
||||
0x35, 0x12, 0x41, 0x41, 0x08, 0x29, 0xbc, 0x24, 0x10, 0x42, 0x5c, 0x39, 0x70, 0x42, 0x48, 0x48,
|
||||
0x88, 0x13, 0x12, 0x07, 0x38, 0x20, 0x1f, 0x73, 0x00, 0x11, 0x05, 0xb4, 0xc2, 0x9b, 0x4b, 0x24,
|
||||
0x0e, 0xdc, 0x73, 0x42, 0xf5, 0xe8, 0xae, 0xea, 0x9e, 0x5d, 0x76, 0xed, 0x69, 0x1b, 0x72, 0xeb,
|
||||
0xfe, 0xff, 0xbf, 0xff, 0xef, 0xaf, 0xbf, 0xfe, 0xfa, 0x1f, 0xd5, 0xb0, 0xd5, 0xf3, 0x58, 0x7f,
|
||||
0x7c, 0xab, 0xe9, 0x06, 0xa3, 0x96, 0x13, 0xf5, 0x82, 0x30, 0x0a, 0x6e, 0x8b, 0x87, 0x67, 0xdd,
|
||||
0x6e, 0x2b, 0x1c, 0xf4, 0x5a, 0x4e, 0xe8, 0xd1, 0x96, 0x13, 0x86, 0x43, 0xcf, 0x75, 0x98, 0x17,
|
||||
0xf8, 0xad, 0xc9, 0x79, 0x67, 0x18, 0xf6, 0x9d, 0xf3, 0xad, 0x1e, 0xf1, 0x49, 0xe4, 0x30, 0xd2,
|
||||
0x6d, 0x86, 0x51, 0xc0, 0x02, 0xf4, 0x79, 0xad, 0xaa, 0x19, 0xab, 0x12, 0x0f, 0x5f, 0x77, 0xbb,
|
||||
0xcd, 0x70, 0xd0, 0x6b, 0x72, 0x55, 0x4d, 0x43, 0x55, 0x33, 0x56, 0x75, 0xf6, 0x59, 0xc3, 0x8a,
|
||||
0x5e, 0xd0, 0x0b, 0x5a, 0x42, 0xe3, 0xad, 0xf1, 0x9e, 0x78, 0x13, 0x2f, 0xe2, 0x49, 0x22, 0x9d,
|
||||
0xfd, 0xcc, 0xe0, 0x22, 0x6d, 0x7a, 0x01, 0xb7, 0x6d, 0xe4, 0xb8, 0x7d, 0xcf, 0x27, 0xd1, 0x54,
|
||||
0x1b, 0x3b, 0x22, 0xcc, 0x69, 0x4d, 0x66, 0xec, 0x3b, 0xdb, 0x3a, 0xea, 0xab, 0x68, 0xec, 0x33,
|
||||
0x6f, 0x44, 0x66, 0x3e, 0xf8, 0xec, 0x71, 0x1f, 0x50, 0xb7, 0x4f, 0x46, 0xce, 0xcc, 0x77, 0x9f,
|
||||
0x3e, 0xea, 0xbb, 0x31, 0xf3, 0x86, 0x2d, 0xcf, 0x67, 0x94, 0x45, 0xd9, 0x8f, 0xec, 0xbf, 0x5b,
|
||||
0x00, 0x97, 0xc2, 0x70, 0x27, 0x0a, 0x6e, 0x13, 0x97, 0xa1, 0x6f, 0x40, 0x95, 0xaf, 0xa3, 0xeb,
|
||||
0x30, 0xa7, 0x61, 0xad, 0x5b, 0xe7, 0xea, 0x17, 0x3e, 0xd5, 0x94, 0x6a, 0x9b, 0xa6, 0x5a, 0xed,
|
||||
0x57, 0x2e, 0xdd, 0x9c, 0x9c, 0x6f, 0xde, 0xbc, 0xc5, 0xbf, 0xbf, 0x4e, 0x98, 0xd3, 0x46, 0x77,
|
||||
0xf7, 0xd7, 0x4e, 0x1d, 0xec, 0xaf, 0x81, 0xa6, 0xe1, 0x44, 0x2b, 0x1a, 0x40, 0x89, 0x86, 0xc4,
|
||||
0x6d, 0x14, 0x84, 0xf6, 0xad, 0xe6, 0x03, 0xef, 0x5e, 0x53, 0x9b, 0xdd, 0x09, 0x89, 0xdb, 0x5e,
|
||||
0x54, 0xb0, 0x25, 0xfe, 0x86, 0x05, 0x88, 0xfd, 0x8e, 0x05, 0xcb, 0x5a, 0xec, 0x9a, 0x47, 0x19,
|
||||
0x7a, 0x65, 0x66, 0x85, 0xcd, 0x93, 0xad, 0x90, 0x7f, 0x2d, 0xd6, 0x77, 0x5a, 0x01, 0x55, 0x63,
|
||||
0x8a, 0xb1, 0xba, 0xdb, 0x50, 0xf6, 0x18, 0x19, 0xd1, 0x46, 0x61, 0xbd, 0x78, 0xae, 0x7e, 0xe1,
|
||||
0x72, 0x2e, 0xcb, 0x6b, 0x2f, 0x29, 0xc4, 0xf2, 0x16, 0xd7, 0x8d, 0x25, 0x84, 0xfd, 0x66, 0xc1,
|
||||
0x5c, 0x1c, 0x5f, 0x35, 0x3a, 0x0f, 0x75, 0x1a, 0x8c, 0x23, 0x97, 0x60, 0x12, 0x06, 0xb4, 0x61,
|
||||
0xad, 0x17, 0xcf, 0xd5, 0xda, 0x2b, 0x07, 0xfb, 0x6b, 0xf5, 0x8e, 0x26, 0x63, 0x53, 0x06, 0xfd,
|
||||
0xc0, 0x82, 0xc5, 0x2e, 0xa1, 0xcc, 0xf3, 0x05, 0x7e, 0x6c, 0xf9, 0x57, 0xe6, 0xb3, 0x3c, 0x26,
|
||||
0x6e, 0x6a, 0xcd, 0xed, 0xc7, 0xd5, 0x2a, 0x16, 0x0d, 0x22, 0xc5, 0x29, 0x70, 0xf4, 0x1c, 0xd4,
|
||||
0xbb, 0x84, 0xba, 0x91, 0x17, 0xf2, 0xf7, 0x46, 0x71, 0xdd, 0x3a, 0x57, 0x6b, 0x3f, 0xa6, 0x3e,
|
||||
0xac, 0x6f, 0x6a, 0x16, 0x36, 0xe5, 0xec, 0x3f, 0x17, 0xa1, 0x6e, 0xa0, 0x3e, 0x82, 0x30, 0x1e,
|
||||
0xa6, 0xc2, 0xf8, 0x85, 0x7c, 0xbc, 0x75, 0x54, 0x1c, 0x23, 0x06, 0x15, 0xca, 0x1c, 0x36, 0xa6,
|
||||
0xc2, 0x23, 0xf5, 0x0b, 0xd7, 0x72, 0xc2, 0x13, 0x3a, 0xdb, 0xcb, 0x0a, 0xb1, 0x22, 0xdf, 0xb1,
|
||||
0xc2, 0x42, 0xaf, 0x41, 0x2d, 0x08, 0x79, 0xb6, 0xe0, 0x5b, 0x51, 0x12, 0xc0, 0x9b, 0x73, 0x00,
|
||||
0xdf, 0x8c, 0x75, 0xb5, 0x97, 0x0e, 0xf6, 0xd7, 0x6a, 0xc9, 0x2b, 0xd6, 0x28, 0xb6, 0x0b, 0x8f,
|
||||
0x1b, 0xf6, 0x6d, 0x04, 0x7e, 0xd7, 0x13, 0x1b, 0xba, 0x0e, 0x25, 0x36, 0x0d, 0x89, 0xd8, 0xcc,
|
||||
0x9a, 0x76, 0xd1, 0xee, 0x34, 0x24, 0x58, 0x70, 0xd0, 0x27, 0x60, 0x61, 0x44, 0x28, 0x75, 0x7a,
|
||||
0x44, 0xec, 0x49, 0xad, 0xbd, 0xa2, 0x84, 0x16, 0xae, 0x4b, 0x32, 0x8e, 0xf9, 0xf6, 0x6b, 0xf0,
|
||||
0xe4, 0xe1, 0x21, 0x8a, 0x3e, 0x06, 0x15, 0x4a, 0xa2, 0x09, 0x89, 0x14, 0x90, 0xf6, 0x8c, 0xa0,
|
||||
0x62, 0xc5, 0x45, 0x2d, 0xa8, 0xf9, 0xce, 0x88, 0xd0, 0xd0, 0x71, 0x63, 0xb8, 0x33, 0x4a, 0xb4,
|
||||
0x76, 0x23, 0x66, 0x60, 0x2d, 0x63, 0xff, 0xc3, 0x82, 0x15, 0x03, 0xf3, 0x11, 0x64, 0xa2, 0x41,
|
||||
0x3a, 0x13, 0x5d, 0xc9, 0x27, 0x62, 0x8e, 0x48, 0x45, 0x7f, 0x2c, 0xc2, 0x19, 0x33, 0xae, 0x44,
|
||||
0x7e, 0xe1, 0x5b, 0x12, 0x91, 0x30, 0x78, 0x11, 0x5f, 0x53, 0xee, 0x4c, 0xb6, 0x04, 0x4b, 0x32,
|
||||
0x8e, 0xf9, 0x7c, 0x7f, 0x43, 0x87, 0xf5, 0x95, 0x2f, 0x93, 0xfd, 0xdd, 0x71, 0x58, 0x1f, 0x0b,
|
||||
0x0e, 0xcf, 0x0c, 0xc4, 0x9f, 0x78, 0x51, 0xe0, 0x8f, 0x88, 0xcf, 0xb2, 0x99, 0xe1, 0xb2, 0x66,
|
||||
0x61, 0x53, 0x0e, 0x7d, 0x19, 0x96, 0x99, 0x13, 0xf5, 0x08, 0xc3, 0x64, 0xe2, 0xd1, 0x38, 0x90,
|
||||
0x6b, 0xed, 0x27, 0xd5, 0x97, 0xcb, 0xbb, 0x29, 0x2e, 0xce, 0x48, 0xa3, 0xdf, 0x59, 0xf0, 0x94,
|
||||
0x1b, 0x8c, 0xc2, 0xc0, 0x27, 0x3e, 0xdb, 0x71, 0x22, 0x67, 0x44, 0x18, 0x89, 0x6e, 0x4e, 0x48,
|
||||
0x14, 0x79, 0x5d, 0x42, 0x1b, 0x65, 0xe1, 0xdd, 0xeb, 0x73, 0x78, 0x77, 0x63, 0x46, 0x7b, 0xfb,
|
||||
0x69, 0x65, 0xdc, 0x53, 0x1b, 0x47, 0x23, 0xe3, 0xff, 0x66, 0x16, 0x2f, 0x04, 0x13, 0x67, 0x38,
|
||||
0x26, 0xf4, 0x8a, 0x37, 0x24, 0xb4, 0x51, 0xd1, 0x85, 0xe0, 0x25, 0x4d, 0xc6, 0xa6, 0x8c, 0xfd,
|
||||
0x87, 0x42, 0x2a, 0x44, 0x3b, 0x71, 0xde, 0x11, 0x7b, 0xa9, 0x02, 0x34, 0xaf, 0xbc, 0x23, 0x74,
|
||||
0x1a, 0xa7, 0x4b, 0xd6, 0x23, 0x85, 0x85, 0xde, 0xb4, 0x44, 0x15, 0x88, 0x4f, 0xa5, 0xca, 0xb1,
|
||||
0x0f, 0xa1, 0x22, 0x99, 0x85, 0x25, 0x26, 0x62, 0x13, 0x9a, 0x87, 0x70, 0x28, 0xeb, 0xab, 0x8a,
|
||||
0xb8, 0x24, 0x84, 0x55, 0xd9, 0xc5, 0x31, 0xdf, 0xfe, 0x45, 0x25, 0x7d, 0x06, 0x64, 0x0e, 0xfd,
|
||||
0x89, 0x05, 0xa7, 0xf9, 0x46, 0x39, 0x91, 0x47, 0x03, 0x1f, 0x13, 0x3a, 0x1e, 0x32, 0xe5, 0xcc,
|
||||
0xed, 0x39, 0x83, 0xc6, 0x54, 0xd9, 0x6e, 0x28, 0xbb, 0x4e, 0x67, 0x39, 0x78, 0x06, 0x1e, 0x31,
|
||||
0x58, 0xe8, 0x7b, 0x94, 0x05, 0xd1, 0x54, 0x25, 0x87, 0x79, 0xba, 0xb0, 0x4d, 0x12, 0x0e, 0x83,
|
||||
0x29, 0x3f, 0x6b, 0x5b, 0xfe, 0x5e, 0xa0, 0xfd, 0x73, 0x55, 0x22, 0xe0, 0x18, 0x0a, 0x7d, 0xdb,
|
||||
0x02, 0x08, 0xe3, 0x48, 0xe5, 0x85, 0xec, 0x21, 0x1c, 0x9c, 0xa4, 0x66, 0x27, 0x24, 0x8a, 0x0d,
|
||||
0x50, 0x14, 0x40, 0xa5, 0x4f, 0x9c, 0x21, 0xeb, 0xab, 0x72, 0xf6, 0xfc, 0x1c, 0xf0, 0x57, 0x85,
|
||||
0xa2, 0x6c, 0x09, 0x95, 0x54, 0xac, 0x60, 0xd0, 0x77, 0x2d, 0x58, 0x4e, 0xaa, 0x1b, 0x97, 0x25,
|
||||
0x8d, 0xf2, 0xdc, 0x8d, 0xef, 0xcd, 0x94, 0xc2, 0x36, 0xe2, 0x69, 0x2c, 0x4d, 0xc3, 0x19, 0x50,
|
||||
0xf4, 0x1d, 0x0b, 0xc0, 0x8d, 0xab, 0xa9, 0xcc, 0x07, 0xf5, 0x0b, 0x37, 0xf3, 0x39, 0x51, 0x49,
|
||||
0x95, 0xd6, 0xee, 0x4f, 0x48, 0x14, 0x1b, 0xb0, 0xf6, 0xbb, 0x16, 0x3c, 0x61, 0x7c, 0xf8, 0x55,
|
||||
0x87, 0xb9, 0xfd, 0xcb, 0x13, 0x9e, 0xa6, 0xb7, 0x53, 0xf5, 0xfd, 0x73, 0x66, 0x7d, 0x7f, 0x7f,
|
||||
0x7f, 0xed, 0xe3, 0x47, 0x4d, 0x36, 0x77, 0xb8, 0x86, 0xa6, 0x50, 0x61, 0xb4, 0x02, 0xaf, 0x43,
|
||||
0xdd, 0xb0, 0x59, 0xa5, 0x8f, 0xbc, 0x0a, 0x60, 0x92, 0x33, 0x0c, 0x22, 0x36, 0xf1, 0xec, 0xbf,
|
||||
0x16, 0x60, 0x61, 0x63, 0x38, 0xa6, 0x8c, 0x44, 0x27, 0x6e, 0x28, 0xd6, 0xa1, 0xc4, 0x9b, 0x85,
|
||||
0x6c, 0xfd, 0xe3, 0xbd, 0x04, 0x16, 0x1c, 0x14, 0x42, 0xc5, 0x0d, 0xfc, 0x3d, 0xaf, 0xa7, 0x5a,
|
||||
0xc0, 0xab, 0xf3, 0x9c, 0x1c, 0x69, 0xdd, 0x86, 0xd0, 0xa7, 0x6d, 0x92, 0xef, 0x58, 0xe1, 0xa0,
|
||||
0x1f, 0x59, 0xb0, 0xe2, 0x06, 0xbe, 0x4f, 0x5c, 0x1d, 0xbc, 0xa5, 0xb9, 0xdb, 0xdd, 0x8d, 0xb4,
|
||||
0xc6, 0xf6, 0x87, 0x14, 0xfa, 0x4a, 0x86, 0x81, 0xb3, 0xd8, 0xf6, 0x6f, 0x0b, 0xb0, 0x94, 0xb2,
|
||||
0x1c, 0x3d, 0x03, 0xd5, 0x31, 0x25, 0x91, 0xf0, 0x9c, 0xf4, 0x6f, 0xd2, 0x11, 0xbd, 0xa8, 0xe8,
|
||||
0x38, 0x91, 0xe0, 0xd2, 0xa1, 0x43, 0xe9, 0x9d, 0x20, 0xea, 0x2a, 0x3f, 0x27, 0xd2, 0x3b, 0x8a,
|
||||
0x8e, 0x13, 0x09, 0xde, 0x6f, 0xdc, 0x22, 0x4e, 0x44, 0xa2, 0xdd, 0x60, 0x40, 0x66, 0x26, 0x91,
|
||||
0xb6, 0x66, 0x61, 0x53, 0x4e, 0x38, 0x8d, 0x0d, 0xe9, 0xc6, 0xd0, 0x23, 0x3e, 0x93, 0x66, 0xe6,
|
||||
0xe0, 0xb4, 0xdd, 0x6b, 0x1d, 0x53, 0xa3, 0x76, 0x5a, 0x86, 0x81, 0xb3, 0xd8, 0xf6, 0x5f, 0x2c,
|
||||
0xa8, 0x2b, 0xa7, 0x3d, 0x82, 0xa6, 0xb3, 0x97, 0x6e, 0x3a, 0xdb, 0xf3, 0xc7, 0xe8, 0x11, 0x0d,
|
||||
0xe7, 0xaf, 0x8b, 0x30, 0x53, 0xe9, 0xd0, 0xab, 0x3c, 0xc7, 0x71, 0x1a, 0xe9, 0x5e, 0x8a, 0x8b,
|
||||
0xec, 0x27, 0x4f, 0xb6, 0xba, 0x5d, 0x6f, 0x44, 0xcc, 0xf4, 0x15, 0x6b, 0xc1, 0x86, 0x46, 0xf4,
|
||||
0x86, 0xa5, 0x01, 0x76, 0x03, 0x95, 0x57, 0xf2, 0x6d, 0x89, 0x66, 0x4c, 0xd8, 0x0d, 0xb0, 0x81,
|
||||
0x89, 0xbe, 0x90, 0x0c, 0x82, 0x65, 0x11, 0x90, 0x76, 0x7a, 0x74, 0x7b, 0x3f, 0xd5, 0x00, 0x64,
|
||||
0xc6, 0xb9, 0x29, 0xd4, 0x22, 0x22, 0x5b, 0xac, 0xb8, 0x02, 0xcc, 0x93, 0x44, 0xb0, 0xd2, 0x25,
|
||||
0x8f, 0x71, 0x32, 0xfe, 0xc4, 0x64, 0x8a, 0x35, 0x9a, 0xfd, 0x43, 0x0b, 0xd0, 0x6c, 0xb9, 0xe6,
|
||||
0x63, 0x54, 0xd2, 0xc4, 0xaa, 0x03, 0x9c, 0xe8, 0x49, 0xc4, 0xb1, 0x96, 0x39, 0x41, 0x9a, 0x7c,
|
||||
0x1a, 0xca, 0xa2, 0xa9, 0x55, 0x07, 0x36, 0x89, 0x1e, 0xd1, 0xf6, 0x62, 0xc9, 0xb3, 0xff, 0x64,
|
||||
0x41, 0x36, 0xdd, 0x88, 0x4c, 0x2d, 0x3d, 0x9b, 0xcd, 0xd4, 0x69, 0x2f, 0x9e, 0x7c, 0xce, 0x44,
|
||||
0xaf, 0x40, 0xdd, 0x61, 0x8c, 0x8c, 0x42, 0x26, 0x02, 0xb2, 0x78, 0xdf, 0x01, 0xb9, 0xcc, 0x23,
|
||||
0xe1, 0x7a, 0xd0, 0xf5, 0xf6, 0x3c, 0x11, 0x8c, 0xa6, 0x3a, 0xfb, 0xbd, 0x22, 0x2c, 0xa7, 0x9b,
|
||||
0x2f, 0x34, 0x86, 0x8a, 0x68, 0x76, 0xe4, 0xcd, 0x4f, 0xee, 0xdd, 0x55, 0xe2, 0x12, 0x41, 0xa2,
|
||||
0x58, 0x81, 0xf1, 0xc4, 0x1a, 0xc5, 0xd3, 0x55, 0x26, 0xb1, 0x26, 0x73, 0x55, 0x22, 0x71, 0xec,
|
||||
0x44, 0x55, 0xfc, 0xff, 0x9c, 0xa8, 0x5e, 0x05, 0xe8, 0x0a, 0x6f, 0x8b, 0xbd, 0x2c, 0x3d, 0x78,
|
||||
0x72, 0xd9, 0x4c, 0xb4, 0x60, 0x43, 0x23, 0x3a, 0x0b, 0x05, 0xaf, 0x2b, 0x4e, 0x75, 0xb1, 0x0d,
|
||||
0x4a, 0xb6, 0xb0, 0xb5, 0x89, 0x0b, 0x5e, 0xd7, 0xa6, 0xb0, 0x68, 0x76, 0x9b, 0x27, 0x8e, 0xd5,
|
||||
0x2f, 0xc2, 0x92, 0x7c, 0xda, 0x24, 0xcc, 0xf1, 0x86, 0x54, 0xed, 0xce, 0x13, 0x4a, 0x7c, 0xa9,
|
||||
0x63, 0x32, 0x71, 0x5a, 0xd6, 0xfe, 0x79, 0x01, 0xe0, 0x6a, 0x10, 0x0c, 0x14, 0x66, 0x7c, 0xf4,
|
||||
0xac, 0x23, 0x8f, 0xde, 0x3a, 0x94, 0x06, 0x9e, 0xdf, 0xcd, 0x1e, 0xce, 0x6d, 0xcf, 0xef, 0x62,
|
||||
0xc1, 0x41, 0x17, 0x00, 0x9c, 0xd0, 0x7b, 0x89, 0x44, 0x54, 0x5f, 0xee, 0x25, 0x7e, 0xb9, 0xb4,
|
||||
0xb3, 0xa5, 0x38, 0xd8, 0x90, 0x42, 0xcf, 0xa8, 0xce, 0x50, 0x8e, 0xed, 0x8d, 0x4c, 0x67, 0x58,
|
||||
0xe5, 0x16, 0x1a, 0xad, 0xdf, 0xc5, 0x4c, 0x7e, 0x5c, 0x9f, 0xc9, 0x8f, 0xba, 0x53, 0xde, 0xe9,
|
||||
0x3b, 0x94, 0x1c, 0x76, 0xae, 0x2b, 0xc7, 0xdc, 0x1f, 0xfd, 0xcb, 0x02, 0x7d, 0x7b, 0x85, 0xf6,
|
||||
0xa0, 0x44, 0xa7, 0xbe, 0xab, 0xea, 0xcd, 0x3c, 0x19, 0xb5, 0x33, 0xf5, 0x5d, 0x7d, 0x49, 0x56,
|
||||
0x15, 0x77, 0x80, 0x53, 0xdf, 0xc5, 0x42, 0x3f, 0x9a, 0x40, 0x35, 0x0a, 0x86, 0xc3, 0x5b, 0x8e,
|
||||
0x3b, 0xc8, 0xa1, 0xf4, 0x60, 0xa5, 0x4a, 0xe3, 0x2d, 0x8a, 0xf3, 0xaa, 0xc8, 0x38, 0xc1, 0xb2,
|
||||
0x7f, 0x53, 0x86, 0xcc, 0x74, 0x81, 0xc6, 0xe6, 0xc5, 0xa0, 0x95, 0xe3, 0xc5, 0x60, 0x92, 0xfd,
|
||||
0x0f, 0xbb, 0x1c, 0x44, 0xcf, 0x41, 0x39, 0xe4, 0x7b, 0xa6, 0x22, 0x6c, 0x2d, 0xce, 0xed, 0x62,
|
||||
0x23, 0x0f, 0xd9, 0x5a, 0x29, 0x6d, 0xee, 0x6c, 0xf1, 0x98, 0x8c, 0xfd, 0x2d, 0x00, 0xee, 0x6b,
|
||||
0x35, 0xa6, 0xcb, 0x43, 0x7e, 0x23, 0xaf, 0x1d, 0x55, 0x93, 0xba, 0x48, 0xea, 0x9d, 0x04, 0x05,
|
||||
0x1b, 0x88, 0xe8, 0xfb, 0x16, 0x2c, 0xc7, 0x8e, 0x57, 0x46, 0x94, 0x1f, 0x8a, 0x11, 0x62, 0x66,
|
||||
0xc4, 0x29, 0x24, 0x9c, 0x41, 0x46, 0x5f, 0x83, 0x1a, 0x65, 0x4e, 0x24, 0x8b, 0x57, 0xe5, 0xbe,
|
||||
0x13, 0x5e, 0xb2, 0x97, 0x9d, 0x58, 0x09, 0xd6, 0xfa, 0xd0, 0xcb, 0x00, 0x7b, 0x9e, 0xef, 0xd1,
|
||||
0xbe, 0xd0, 0xbe, 0xf0, 0x60, 0xa5, 0xf1, 0x4a, 0xa2, 0x01, 0x1b, 0xda, 0xec, 0xbf, 0x15, 0x00,
|
||||
0xc4, 0xcf, 0x0d, 0x4f, 0x5c, 0x3c, 0xac, 0x43, 0x29, 0x22, 0x61, 0x90, 0xcd, 0x5c, 0x5c, 0x02,
|
||||
0x0b, 0x4e, 0x6a, 0x8e, 0x28, 0xdc, 0xd7, 0x1c, 0x51, 0x3c, 0x76, 0x8e, 0xe0, 0x39, 0x98, 0xf6,
|
||||
0x77, 0x22, 0x6f, 0xe2, 0x30, 0xb2, 0x4d, 0xa6, 0x2a, 0x91, 0xe9, 0x1c, 0xdc, 0xb9, 0xaa, 0x99,
|
||||
0x38, 0x2d, 0x7b, 0xe8, 0x08, 0x56, 0xfe, 0x1f, 0x8e, 0x60, 0xef, 0x58, 0xb0, 0xac, 0x3d, 0xfb,
|
||||
0xc1, 0xfa, 0x9f, 0xa6, 0xed, 0x3e, 0x62, 0xa6, 0xf8, 0xb7, 0x05, 0x2b, 0x71, 0xf7, 0xaa, 0x8a,
|
||||
0x60, 0x2e, 0x55, 0x2f, 0xf5, 0xb3, 0xa0, 0x78, 0xfc, 0xcf, 0x02, 0x33, 0x61, 0x95, 0x8e, 0x49,
|
||||
0x58, 0x5f, 0xca, 0xd4, 0xbb, 0x8f, 0xcc, 0xd4, 0x3b, 0x94, 0xf4, 0xe9, 0x53, 0xdf, 0x4d, 0xf7,
|
||||
0x07, 0xf6, 0xaf, 0x2c, 0x58, 0x8c, 0xd9, 0x37, 0x82, 0xae, 0xe8, 0x9e, 0xa9, 0x08, 0x32, 0x2b,
|
||||
0xdd, 0x3d, 0xcb, 0x70, 0x90, 0x3c, 0x34, 0x86, 0xaa, 0xdb, 0xf7, 0x86, 0xdd, 0x88, 0xf8, 0x6a,
|
||||
0x5b, 0x9e, 0xcf, 0x61, 0x8c, 0xe0, 0xf8, 0x3a, 0x14, 0x36, 0x14, 0x00, 0x4e, 0xa0, 0xec, 0xdf,
|
||||
0x17, 0x61, 0x29, 0x35, 0x73, 0xf0, 0x11, 0x5d, 0xde, 0xd6, 0x77, 0x0c, 0x9b, 0x93, 0x11, 0x7d,
|
||||
0x57, 0xb3, 0xb0, 0x29, 0xc7, 0xf7, 0x63, 0xe8, 0x4d, 0xa4, 0x8e, 0xec, 0xcf, 0x9b, 0x6b, 0x31,
|
||||
0x03, 0x6b, 0x19, 0x63, 0xe8, 0x2a, 0xde, 0xf7, 0xd0, 0xf5, 0x53, 0x0b, 0x90, 0x58, 0x02, 0xd7,
|
||||
0x9c, 0xcc, 0x46, 0x8d, 0x52, 0xbe, 0x7e, 0x3b, 0xab, 0x2c, 0x42, 0x1b, 0x33, 0x50, 0xf8, 0x10,
|
||||
0x78, 0xe3, 0x1e, 0xb4, 0xfc, 0x48, 0xee, 0x41, 0xed, 0x6f, 0xc2, 0x99, 0x99, 0x8e, 0x43, 0xb5,
|
||||
0xbc, 0xd6, 0x61, 0x2d, 0x2f, 0x8f, 0xc4, 0x30, 0x1a, 0xfb, 0x72, 0x83, 0xaa, 0x3a, 0x12, 0x77,
|
||||
0x38, 0x11, 0x4b, 0x1e, 0xef, 0x83, 0xbb, 0xd1, 0x14, 0x8f, 0x65, 0x2f, 0x59, 0xd5, 0xe8, 0x9b,
|
||||
0x82, 0x8a, 0x15, 0xd7, 0xfe, 0x5e, 0x01, 0x96, 0x52, 0x55, 0x30, 0x35, 0xb2, 0x58, 0xc7, 0x8e,
|
||||
0x2c, 0x79, 0x1a, 0x83, 0x5e, 0x87, 0x45, 0x2a, 0x8e, 0x62, 0xe4, 0x30, 0xd2, 0x9b, 0xe6, 0x70,
|
||||
0x13, 0xdd, 0x31, 0xd4, 0xb5, 0x4f, 0x1f, 0xec, 0xaf, 0x2d, 0x9a, 0x14, 0x9c, 0x82, 0xb3, 0x7f,
|
||||
0x59, 0x80, 0xc7, 0x0e, 0xe9, 0x08, 0xd0, 0x1d, 0xf3, 0x76, 0x40, 0x8e, 0x8f, 0x2f, 0xe4, 0x10,
|
||||
0x9e, 0x2a, 0x91, 0xca, 0x5f, 0xbe, 0x87, 0xdd, 0x0d, 0xdc, 0xe7, 0xf4, 0xb8, 0x07, 0xe5, 0x7e,
|
||||
0x10, 0x0c, 0xe2, 0x31, 0x71, 0x9e, 0x82, 0xa0, 0x87, 0x9b, 0x76, 0x8d, 0xef, 0x26, 0x7f, 0xa7,
|
||||
0x58, 0xaa, 0xb7, 0xdf, 0xb3, 0x20, 0xe5, 0x45, 0x34, 0x82, 0x32, 0xd7, 0x32, 0xcd, 0xe1, 0x4f,
|
||||
0x98, 0xa9, 0xf7, 0x12, 0xd7, 0x29, 0xf1, 0xc5, 0x23, 0x96, 0x28, 0xc8, 0x83, 0x12, 0x37, 0x44,
|
||||
0x75, 0xfa, 0xdb, 0x39, 0xa1, 0xf1, 0x25, 0xca, 0xc1, 0x82, 0x3f, 0x61, 0x01, 0x61, 0x5f, 0x84,
|
||||
0x33, 0x33, 0x16, 0xf1, 0x90, 0xdf, 0x0b, 0xe2, 0x1f, 0x7f, 0x46, 0xc8, 0x5f, 0xe1, 0x44, 0x2c,
|
||||
0x79, 0xbc, 0x7e, 0x9c, 0xce, 0xaa, 0x47, 0x3f, 0xb3, 0xe0, 0x0c, 0xcd, 0xea, 0x7b, 0x28, 0x5e,
|
||||
0xfb, 0xb0, 0x32, 0x6a, 0xd6, 0x7c, 0x3c, 0x6b, 0x01, 0xdf, 0xd1, 0xec, 0x75, 0x29, 0x8f, 0x3d,
|
||||
0xcf, 0xa7, 0xc4, 0x1d, 0x47, 0xf1, 0x42, 0x93, 0xd8, 0xdb, 0x52, 0x74, 0x9c, 0x48, 0xf0, 0xf1,
|
||||
0x55, 0x5e, 0xd7, 0xdf, 0xd0, 0x8d, 0x62, 0x32, 0xbe, 0x76, 0x12, 0x0e, 0x36, 0xa4, 0xd0, 0x39,
|
||||
0xa8, 0xba, 0x24, 0x62, 0x9b, 0xbc, 0x3d, 0xe2, 0x79, 0x61, 0x51, 0xce, 0x59, 0x1b, 0x8a, 0x86,
|
||||
0x13, 0x2e, 0xfa, 0x28, 0x2c, 0x0c, 0xc8, 0x54, 0x08, 0x96, 0x84, 0x60, 0x9d, 0x57, 0xfc, 0x6d,
|
||||
0x49, 0xc2, 0x31, 0x0f, 0xd9, 0x50, 0x71, 0x1d, 0x21, 0x55, 0x16, 0x52, 0x20, 0x6e, 0xee, 0x2f,
|
||||
0x09, 0x21, 0xc5, 0x69, 0x37, 0xef, 0xde, 0x5b, 0x3d, 0xf5, 0xd6, 0xbd, 0xd5, 0x53, 0x6f, 0xdf,
|
||||
0x5b, 0x3d, 0xf5, 0xc6, 0xc1, 0xaa, 0x75, 0xf7, 0x60, 0xd5, 0x7a, 0xeb, 0x60, 0xd5, 0x7a, 0xfb,
|
||||
0x60, 0xd5, 0xfa, 0xe7, 0xc1, 0xaa, 0xf5, 0xe3, 0x77, 0x57, 0x4f, 0xbd, 0x5c, 0x8d, 0x5d, 0xfb,
|
||||
0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf5, 0xd2, 0xa5, 0x7e, 0x8e, 0x27, 0x00, 0x00,
|
||||
0x66, 0x13, 0xa4, 0x10, 0x01, 0xed, 0x9e, 0xda, 0x99, 0xf6, 0xcc, 0x74, 0x77, 0xba, 0x6a, 0xc6,
|
||||
0x1a, 0x89, 0x20, 0x23, 0x84, 0xc4, 0x5b, 0x20, 0x84, 0xb8, 0x72, 0xe0, 0x84, 0x90, 0x90, 0x10,
|
||||
0x27, 0x24, 0x2e, 0x1c, 0x90, 0x8f, 0x39, 0x80, 0x88, 0x02, 0x5a, 0xe1, 0xcd, 0x25, 0x12, 0x07,
|
||||
0xee, 0x39, 0xa1, 0x7a, 0x74, 0x75, 0x75, 0xcf, 0x2e, 0xbb, 0xf6, 0xb4, 0x0d, 0xb9, 0x75, 0xff,
|
||||
0xff, 0xdf, 0xff, 0xf7, 0xd7, 0x5f, 0x7f, 0xfd, 0x8f, 0x6a, 0xd8, 0xea, 0x79, 0xac, 0x3f, 0xbe,
|
||||
0xd5, 0x74, 0x83, 0x51, 0xcb, 0x89, 0x7a, 0x41, 0x18, 0x05, 0xb7, 0xc5, 0xc3, 0xf3, 0x6e, 0xb7,
|
||||
0x15, 0x0e, 0x7a, 0x2d, 0x27, 0xf4, 0x68, 0xcb, 0x09, 0xc3, 0xa1, 0xe7, 0x3a, 0xcc, 0x0b, 0xfc,
|
||||
0xd6, 0xe4, 0xbc, 0x33, 0x0c, 0xfb, 0xce, 0xf9, 0x56, 0x8f, 0xf8, 0x24, 0x72, 0x18, 0xe9, 0x36,
|
||||
0xc3, 0x28, 0x60, 0x01, 0xfa, 0x6c, 0xa2, 0xaa, 0x19, 0xab, 0x12, 0x0f, 0x5f, 0x73, 0xbb, 0xcd,
|
||||
0x70, 0xd0, 0x6b, 0x72, 0x55, 0x4d, 0x43, 0x55, 0x33, 0x56, 0x75, 0xf6, 0x79, 0xc3, 0x8a, 0x5e,
|
||||
0xd0, 0x0b, 0x5a, 0x42, 0xe3, 0xad, 0xf1, 0x9e, 0x78, 0x13, 0x2f, 0xe2, 0x49, 0x22, 0x9d, 0xfd,
|
||||
0xd4, 0xe0, 0x22, 0x6d, 0x7a, 0x01, 0xb7, 0x6d, 0xe4, 0xb8, 0x7d, 0xcf, 0x27, 0xd1, 0x34, 0x31,
|
||||
0x76, 0x44, 0x98, 0xd3, 0x9a, 0xcc, 0xd8, 0x77, 0xb6, 0x75, 0xd4, 0x57, 0xd1, 0xd8, 0x67, 0xde,
|
||||
0x88, 0xcc, 0x7c, 0xf0, 0xe9, 0xe3, 0x3e, 0xa0, 0x6e, 0x9f, 0x8c, 0x9c, 0x99, 0xef, 0x3e, 0x79,
|
||||
0xd4, 0x77, 0x63, 0xe6, 0x0d, 0x5b, 0x9e, 0xcf, 0x28, 0x8b, 0xb2, 0x1f, 0xd9, 0x7f, 0xb7, 0x00,
|
||||
0x2e, 0x85, 0xe1, 0x4e, 0x14, 0xdc, 0x26, 0x2e, 0x43, 0x5f, 0x87, 0x2a, 0x5f, 0x47, 0xd7, 0x61,
|
||||
0x4e, 0xc3, 0x5a, 0xb7, 0xce, 0xd5, 0x2f, 0x7c, 0xa2, 0x29, 0xd5, 0x36, 0x4d, 0xb5, 0x89, 0x5f,
|
||||
0xb9, 0x74, 0x73, 0x72, 0xbe, 0x79, 0xf3, 0x16, 0xff, 0xfe, 0x3a, 0x61, 0x4e, 0x1b, 0xdd, 0xdb,
|
||||
0x5f, 0x3b, 0x75, 0xb0, 0xbf, 0x06, 0x09, 0x0d, 0x6b, 0xad, 0x68, 0x00, 0x25, 0x1a, 0x12, 0xb7,
|
||||
0x51, 0x10, 0xda, 0xb7, 0x9a, 0x0f, 0xbd, 0x7b, 0xcd, 0xc4, 0xec, 0x4e, 0x48, 0xdc, 0xf6, 0xa2,
|
||||
0x82, 0x2d, 0xf1, 0x37, 0x2c, 0x40, 0xec, 0xb7, 0x2d, 0x58, 0x4e, 0xc4, 0xae, 0x79, 0x94, 0xa1,
|
||||
0xd7, 0x66, 0x56, 0xd8, 0x3c, 0xd9, 0x0a, 0xf9, 0xd7, 0x62, 0x7d, 0xa7, 0x15, 0x50, 0x35, 0xa6,
|
||||
0x18, 0xab, 0xbb, 0x0d, 0x65, 0x8f, 0x91, 0x11, 0x6d, 0x14, 0xd6, 0x8b, 0xe7, 0xea, 0x17, 0x2e,
|
||||
0xe7, 0xb2, 0xbc, 0xf6, 0x92, 0x42, 0x2c, 0x6f, 0x71, 0xdd, 0x58, 0x42, 0xd8, 0x77, 0x0b, 0xe6,
|
||||
0xe2, 0xf8, 0xaa, 0xd1, 0xc7, 0x60, 0x81, 0x06, 0xe3, 0xc8, 0x25, 0xb4, 0x61, 0xad, 0x17, 0xcf,
|
||||
0xd5, 0xda, 0x2b, 0x07, 0xfb, 0x6b, 0xf5, 0x8e, 0x20, 0x61, 0x12, 0x06, 0x14, 0xc7, 0x7c, 0xf4,
|
||||
0x03, 0x0b, 0x16, 0xbb, 0x84, 0x32, 0xcf, 0x17, 0xb8, 0xb1, 0xc5, 0x5f, 0x9a, 0xcf, 0xe2, 0x98,
|
||||
0xb8, 0x99, 0x68, 0x6e, 0x3f, 0xa9, 0xac, 0x5f, 0x34, 0x88, 0x14, 0xa7, 0xc0, 0xd1, 0x0b, 0x50,
|
||||
0xef, 0x12, 0xea, 0x46, 0x5e, 0xc8, 0xdf, 0x1b, 0xc5, 0x75, 0xeb, 0x5c, 0xad, 0xfd, 0x84, 0xfa,
|
||||
0xb0, 0xbe, 0x99, 0xb0, 0xb0, 0x29, 0x67, 0xff, 0xb9, 0x08, 0x75, 0x03, 0xf5, 0x31, 0x84, 0xef,
|
||||
0x30, 0x15, 0xbe, 0x2f, 0xe5, 0xe3, 0xad, 0xa3, 0xe2, 0x17, 0x31, 0xa8, 0x50, 0xe6, 0xb0, 0x31,
|
||||
0x15, 0x1e, 0xa9, 0x5f, 0xb8, 0x96, 0x13, 0x9e, 0xd0, 0xd9, 0x5e, 0x56, 0x88, 0x15, 0xf9, 0x8e,
|
||||
0x15, 0x16, 0x7a, 0x1d, 0x6a, 0x41, 0xc8, 0xb3, 0x04, 0xdf, 0x8a, 0x92, 0x00, 0xde, 0x9c, 0x03,
|
||||
0xf8, 0x66, 0xac, 0xab, 0xbd, 0x74, 0xb0, 0xbf, 0x56, 0xd3, 0xaf, 0x38, 0x41, 0xb1, 0x5d, 0x78,
|
||||
0xd2, 0xb0, 0x6f, 0x23, 0xf0, 0xbb, 0x9e, 0xd8, 0xd0, 0x75, 0x28, 0xb1, 0x69, 0x48, 0xc4, 0x66,
|
||||
0xd6, 0x12, 0x17, 0xed, 0x4e, 0x43, 0x82, 0x05, 0x87, 0x87, 0xfc, 0x88, 0x50, 0xea, 0xf4, 0x88,
|
||||
0xd8, 0x93, 0x5a, 0x7b, 0x45, 0x09, 0x2d, 0x5c, 0x97, 0x64, 0x1c, 0xf3, 0xed, 0xd7, 0xe1, 0xe9,
|
||||
0xc3, 0x43, 0x14, 0x7d, 0x04, 0x2a, 0x94, 0x44, 0x13, 0x12, 0x29, 0xa0, 0xc4, 0x33, 0x82, 0x8a,
|
||||
0x15, 0x17, 0xb5, 0xa0, 0xe6, 0x3b, 0x23, 0x42, 0x43, 0xc7, 0x8d, 0xe1, 0xce, 0x28, 0xd1, 0xda,
|
||||
0x8d, 0x98, 0x81, 0x13, 0x19, 0xfb, 0x1f, 0x16, 0xac, 0x18, 0x98, 0x8f, 0x21, 0x03, 0x0d, 0xd2,
|
||||
0x19, 0xe8, 0x4a, 0x3e, 0x11, 0x73, 0x44, 0x0a, 0xfa, 0x71, 0x11, 0xce, 0x98, 0x71, 0x25, 0x72,
|
||||
0x0b, 0xdf, 0x92, 0x88, 0x84, 0xc1, 0xcb, 0xf8, 0x9a, 0x72, 0xa7, 0xde, 0x12, 0x2c, 0xc9, 0x38,
|
||||
0xe6, 0xf3, 0xfd, 0x0d, 0x1d, 0xd6, 0x57, 0xbe, 0xd4, 0xfb, 0xbb, 0xe3, 0xb0, 0x3e, 0x16, 0x1c,
|
||||
0x9e, 0x19, 0x88, 0x3f, 0xf1, 0xa2, 0xc0, 0x1f, 0x11, 0x9f, 0x65, 0x33, 0xc3, 0xe5, 0x84, 0x85,
|
||||
0x4d, 0x39, 0xf4, 0x45, 0x58, 0x66, 0x4e, 0xd4, 0x23, 0x0c, 0x93, 0x89, 0x47, 0xe3, 0x40, 0xae,
|
||||
0xb5, 0x9f, 0x56, 0x5f, 0x2e, 0xef, 0xa6, 0xb8, 0x38, 0x23, 0x8d, 0x7e, 0x6f, 0xc1, 0x33, 0x6e,
|
||||
0x30, 0x0a, 0x03, 0x9f, 0xf8, 0x6c, 0xc7, 0x89, 0x9c, 0x11, 0x61, 0x24, 0xba, 0x39, 0x21, 0x51,
|
||||
0xe4, 0x75, 0x09, 0x6d, 0x94, 0x85, 0x77, 0xaf, 0xcf, 0xe1, 0xdd, 0x8d, 0x19, 0xed, 0xed, 0x67,
|
||||
0x95, 0x71, 0xcf, 0x6c, 0x1c, 0x8d, 0x8c, 0xff, 0x9b, 0x59, 0xf6, 0x1f, 0x0b, 0xa9, 0x78, 0xeb,
|
||||
0xc4, 0x49, 0x44, 0x6c, 0x8c, 0x8a, 0xb6, 0xbc, 0x92, 0x88, 0xd0, 0x69, 0x1c, 0x15, 0x59, 0x65,
|
||||
0x14, 0x16, 0xfa, 0xae, 0x25, 0x52, 0x7a, 0x7c, 0xc4, 0x54, 0xc2, 0x7c, 0x04, 0xe5, 0xc5, 0xac,
|
||||
0x12, 0x31, 0x11, 0x9b, 0xd0, 0x3c, 0x1e, 0x43, 0x59, 0x24, 0x55, 0xf8, 0xe8, 0x78, 0x54, 0xb5,
|
||||
0x13, 0xc7, 0x7c, 0xfb, 0x97, 0x95, 0x74, 0x40, 0xcb, 0x84, 0xf8, 0x53, 0x0b, 0x4e, 0x73, 0xaf,
|
||||
0x3b, 0x91, 0x47, 0x03, 0x1f, 0x13, 0x3a, 0x1e, 0x32, 0xe5, 0xcc, 0xed, 0x39, 0x23, 0xc0, 0x54,
|
||||
0xd9, 0x6e, 0x28, 0xbb, 0x4e, 0x67, 0x39, 0x78, 0x06, 0x1e, 0x31, 0x58, 0xe8, 0x7b, 0x94, 0x05,
|
||||
0xd1, 0x54, 0x9d, 0xf4, 0x79, 0x5a, 0xa9, 0x4d, 0x12, 0x0e, 0x83, 0x29, 0x3f, 0x38, 0x5b, 0xfe,
|
||||
0x5e, 0x90, 0xf8, 0xe7, 0xaa, 0x44, 0xc0, 0x31, 0x14, 0xfa, 0x96, 0x05, 0x10, 0xc6, 0x61, 0xc7,
|
||||
0xab, 0xd2, 0x23, 0x38, 0x05, 0xba, 0x00, 0x6b, 0x12, 0xc5, 0x06, 0x28, 0x0a, 0xa0, 0xd2, 0x27,
|
||||
0xce, 0x90, 0xf5, 0x55, 0x6d, 0x7a, 0x71, 0x0e, 0xf8, 0xab, 0x42, 0x51, 0xb6, 0x1e, 0x4a, 0x2a,
|
||||
0x56, 0x30, 0xe8, 0x3b, 0x16, 0x2c, 0xeb, 0x52, 0xc5, 0x65, 0x49, 0xa3, 0x3c, 0x77, 0xf7, 0x7a,
|
||||
0x33, 0xa5, 0xb0, 0x8d, 0x78, 0x4e, 0x4a, 0xd3, 0x70, 0x06, 0x14, 0x7d, 0xdb, 0x02, 0x70, 0xe3,
|
||||
0xd2, 0x48, 0x1b, 0x15, 0xe1, 0xfc, 0x9b, 0xf9, 0x9c, 0x28, 0x5d, 0x72, 0x13, 0xf7, 0x6b, 0x12,
|
||||
0xc5, 0x06, 0xac, 0xfd, 0x8e, 0x05, 0x4f, 0x19, 0x1f, 0x7e, 0xd9, 0x61, 0x6e, 0xff, 0xf2, 0x84,
|
||||
0xe7, 0xdc, 0xed, 0x54, 0xb1, 0xfe, 0x8c, 0x59, 0xac, 0xdf, 0xdb, 0x5f, 0xfb, 0xe8, 0x51, 0xe3,
|
||||
0xc9, 0x1d, 0xae, 0xa1, 0x29, 0x54, 0x18, 0x75, 0xfd, 0x0d, 0xa8, 0x1b, 0x36, 0xab, 0xf4, 0x91,
|
||||
0x57, 0x35, 0xd3, 0x39, 0xc3, 0x20, 0x62, 0x13, 0xcf, 0xfe, 0x6b, 0x01, 0x16, 0x36, 0x86, 0x63,
|
||||
0xca, 0x48, 0x74, 0xe2, 0xee, 0x60, 0x1d, 0x4a, 0xbc, 0xf2, 0x67, 0x8b, 0x19, 0x6f, 0x0c, 0xb0,
|
||||
0xe0, 0xa0, 0x10, 0x2a, 0x6e, 0xe0, 0xef, 0x79, 0x3d, 0xd5, 0xcf, 0x5d, 0x9d, 0xe7, 0xe4, 0x48,
|
||||
0xeb, 0x36, 0x84, 0xbe, 0xc4, 0x26, 0xf9, 0x8e, 0x15, 0x0e, 0xfa, 0x91, 0x05, 0x2b, 0x6e, 0xe0,
|
||||
0xfb, 0xc4, 0x4d, 0x82, 0xb7, 0x34, 0x77, 0xef, 0xba, 0x91, 0xd6, 0xd8, 0xfe, 0x80, 0x42, 0x5f,
|
||||
0xc9, 0x30, 0x70, 0x16, 0xdb, 0xfe, 0x5d, 0x01, 0x96, 0x52, 0x96, 0xa3, 0xe7, 0xa0, 0x3a, 0xa6,
|
||||
0x24, 0x12, 0x9e, 0x93, 0xfe, 0xd5, 0xed, 0xcd, 0xcb, 0x8a, 0x8e, 0xb5, 0x04, 0x97, 0x0e, 0x1d,
|
||||
0x4a, 0xef, 0x04, 0x51, 0x57, 0xf9, 0x59, 0x4b, 0xef, 0x28, 0x3a, 0xd6, 0x12, 0xbc, 0x79, 0xb8,
|
||||
0x45, 0x9c, 0x88, 0x44, 0xbb, 0xc1, 0x80, 0xcc, 0x8c, 0x15, 0xed, 0x84, 0x85, 0x4d, 0x39, 0xe1,
|
||||
0x34, 0x36, 0xa4, 0x1b, 0x43, 0x8f, 0xf8, 0x4c, 0x9a, 0x99, 0x83, 0xd3, 0x76, 0xaf, 0x75, 0x4c,
|
||||
0x8d, 0x89, 0xd3, 0x32, 0x0c, 0x9c, 0xc5, 0xb6, 0xff, 0x62, 0x41, 0x5d, 0x39, 0xed, 0x31, 0x74,
|
||||
0x90, 0xbd, 0x74, 0x07, 0xd9, 0x9e, 0x3f, 0x46, 0x8f, 0xe8, 0x1e, 0x7f, 0x53, 0x84, 0x99, 0x4a,
|
||||
0x87, 0xbe, 0xca, 0x73, 0x1c, 0xa7, 0x91, 0xee, 0xa5, 0xb8, 0xc8, 0x7e, 0xfc, 0x64, 0xab, 0xdb,
|
||||
0xf5, 0x46, 0xc4, 0x4c, 0x5f, 0xb1, 0x16, 0x6c, 0x68, 0x44, 0x77, 0xad, 0x04, 0x60, 0x37, 0x50,
|
||||
0x79, 0x25, 0xdf, 0x96, 0x68, 0xc6, 0x84, 0xdd, 0x00, 0x1b, 0x98, 0xe8, 0x73, 0x7a, 0xaa, 0x2b,
|
||||
0x8b, 0x80, 0xb4, 0xd3, 0x73, 0xd8, 0x7b, 0xa9, 0x06, 0x20, 0x33, 0x9b, 0x4d, 0xa1, 0x16, 0x91,
|
||||
0x78, 0xc6, 0x97, 0x15, 0x60, 0x9e, 0x24, 0x82, 0x95, 0x2e, 0x79, 0x8c, 0xf5, 0x2c, 0x13, 0x93,
|
||||
0x29, 0x4e, 0xd0, 0xec, 0x1f, 0x5a, 0x80, 0x66, 0xcb, 0x35, 0x9f, 0x89, 0x74, 0x47, 0xaa, 0x0e,
|
||||
0xb0, 0xd6, 0xa3, 0xc5, 0x71, 0x22, 0x73, 0x82, 0x34, 0xf9, 0x2c, 0x94, 0x27, 0xce, 0x70, 0x4c,
|
||||
0xd4, 0x81, 0xd5, 0xd1, 0xf3, 0x0a, 0x27, 0x62, 0xc9, 0xb3, 0xff, 0x64, 0x41, 0x36, 0xdd, 0x88,
|
||||
0x4c, 0x2d, 0x3d, 0x9b, 0xcd, 0xd4, 0x69, 0x2f, 0x9e, 0x7c, 0x68, 0x44, 0xaf, 0x41, 0xdd, 0x61,
|
||||
0x8c, 0x8c, 0x42, 0x26, 0x02, 0xb2, 0xf8, 0xc0, 0x01, 0xb9, 0xcc, 0x23, 0xe1, 0x7a, 0xd0, 0xf5,
|
||||
0xf6, 0x3c, 0x11, 0x8c, 0xa6, 0x3a, 0xfb, 0xdd, 0x22, 0x2c, 0xa7, 0x9b, 0x2f, 0x34, 0x86, 0x8a,
|
||||
0x68, 0x76, 0xe4, 0x15, 0x4e, 0xee, 0xdd, 0x95, 0x76, 0x89, 0x20, 0x51, 0xac, 0xc0, 0x78, 0x62,
|
||||
0x8d, 0xe2, 0x51, 0x29, 0x93, 0x58, 0xf5, 0x90, 0xa4, 0x25, 0x8e, 0x1d, 0x8f, 0x8a, 0xff, 0x97,
|
||||
0xe3, 0x11, 0x4f, 0x2e, 0x5d, 0xe1, 0x6d, 0xb1, 0x97, 0xa5, 0x87, 0x4f, 0x2e, 0x9b, 0x5a, 0x0b,
|
||||
0x36, 0x34, 0xa2, 0xb3, 0x50, 0xf0, 0xba, 0xe2, 0x54, 0x17, 0xdb, 0xa0, 0x64, 0x0b, 0x5b, 0x9b,
|
||||
0xb8, 0xe0, 0x75, 0x6d, 0x0a, 0x8b, 0x66, 0xb7, 0x79, 0xe2, 0x58, 0xfd, 0x3c, 0x2c, 0xc9, 0xa7,
|
||||
0x4d, 0xc2, 0x1c, 0x6f, 0x48, 0xd5, 0xee, 0x3c, 0xa5, 0xc4, 0x97, 0x3a, 0x26, 0x13, 0xa7, 0x65,
|
||||
0xed, 0x5f, 0x14, 0x00, 0xae, 0x06, 0xc1, 0x40, 0x61, 0xc6, 0x47, 0xcf, 0x3a, 0xf2, 0xe8, 0xad,
|
||||
0x43, 0x69, 0xe0, 0xf9, 0xdd, 0xec, 0xe1, 0xdc, 0xf6, 0xfc, 0x2e, 0x16, 0x1c, 0x74, 0x01, 0xc0,
|
||||
0x09, 0xbd, 0x57, 0x48, 0x44, 0x93, 0x9b, 0x3a, 0xed, 0x97, 0x4b, 0x3b, 0x5b, 0x8a, 0x83, 0x0d,
|
||||
0x29, 0xf4, 0x9c, 0xea, 0x0c, 0xe5, 0x0c, 0xde, 0xc8, 0x74, 0x86, 0x55, 0x6e, 0xa1, 0xd1, 0xfa,
|
||||
0x5d, 0xcc, 0xe4, 0xc7, 0xf5, 0x99, 0xfc, 0x98, 0x74, 0xca, 0x3b, 0x7d, 0x87, 0x92, 0xc3, 0xce,
|
||||
0x75, 0xe5, 0x98, 0xcb, 0xa0, 0x7f, 0x59, 0x90, 0x5c, 0x45, 0xa1, 0x3d, 0x28, 0xd1, 0xa9, 0xef,
|
||||
0xaa, 0x7a, 0x33, 0x4f, 0x46, 0xed, 0x4c, 0x7d, 0x37, 0xb9, 0xf1, 0xaa, 0x8a, 0x0b, 0xbd, 0xa9,
|
||||
0xef, 0x62, 0xa1, 0x1f, 0x4d, 0xa0, 0x1a, 0x05, 0xc3, 0xe1, 0x2d, 0xc7, 0x1d, 0xe4, 0x50, 0x7a,
|
||||
0xb0, 0x52, 0x95, 0xe0, 0x2d, 0x8a, 0xf3, 0xaa, 0xc8, 0x58, 0x63, 0xd9, 0xbf, 0x2d, 0x43, 0x66,
|
||||
0xba, 0x40, 0x63, 0xf3, 0x96, 0xcf, 0xca, 0xf1, 0x96, 0x4f, 0x67, 0xff, 0xc3, 0x6e, 0xfa, 0xd0,
|
||||
0x0b, 0x50, 0x0e, 0xf9, 0x9e, 0xa9, 0x08, 0x5b, 0x8b, 0x73, 0xbb, 0xd8, 0xc8, 0x43, 0xb6, 0x56,
|
||||
0x4a, 0x9b, 0x3b, 0x5b, 0x3c, 0x26, 0x63, 0x7f, 0x13, 0x80, 0xfb, 0x5a, 0x8d, 0xe9, 0xf2, 0x90,
|
||||
0xdf, 0xc8, 0x6b, 0x47, 0xd5, 0xa4, 0x2e, 0x92, 0x7a, 0x47, 0xa3, 0x60, 0x03, 0x11, 0x7d, 0xdf,
|
||||
0x82, 0xe5, 0xd8, 0xf1, 0xca, 0x88, 0xf2, 0x23, 0x31, 0x42, 0xcc, 0x8c, 0x38, 0x85, 0x84, 0x33,
|
||||
0xc8, 0xe8, 0x2b, 0x50, 0xa3, 0xcc, 0x89, 0x64, 0xf1, 0xaa, 0x3c, 0x70, 0xc2, 0xd3, 0x7b, 0xd9,
|
||||
0x89, 0x95, 0xe0, 0x44, 0x1f, 0x7a, 0x15, 0x60, 0xcf, 0xf3, 0x3d, 0xda, 0x17, 0xda, 0x17, 0x1e,
|
||||
0xae, 0x34, 0x5e, 0xd1, 0x1a, 0xb0, 0xa1, 0xcd, 0xfe, 0x5b, 0x01, 0x40, 0xfc, 0xb2, 0xf0, 0xc4,
|
||||
0xc5, 0xc3, 0x3a, 0x94, 0x22, 0x12, 0x06, 0xd9, 0xcc, 0xc5, 0x25, 0xb0, 0xe0, 0xa4, 0xe6, 0x88,
|
||||
0xc2, 0x03, 0xcd, 0x11, 0xc5, 0x63, 0xe7, 0x08, 0x9e, 0x83, 0x69, 0x7f, 0x27, 0xf2, 0x26, 0x0e,
|
||||
0x23, 0xdb, 0x64, 0xaa, 0x12, 0x59, 0x92, 0x83, 0x3b, 0x57, 0x13, 0x26, 0x4e, 0xcb, 0x1e, 0x3a,
|
||||
0x82, 0x95, 0xff, 0x87, 0x23, 0xd8, 0xdb, 0x16, 0x2c, 0x27, 0x9e, 0x7d, 0x7f, 0xfd, 0x14, 0x4b,
|
||||
0xec, 0x3e, 0x62, 0xa6, 0xf8, 0xb7, 0x05, 0x2b, 0x71, 0xf7, 0xaa, 0x8a, 0x60, 0x2e, 0x55, 0x2f,
|
||||
0x75, 0xf3, 0x5f, 0x3c, 0xfe, 0xe6, 0xdf, 0x4c, 0x58, 0xa5, 0x63, 0x12, 0xd6, 0x17, 0x32, 0xf5,
|
||||
0xee, 0x43, 0x33, 0xf5, 0x0e, 0xe9, 0x3e, 0x7d, 0xea, 0xbb, 0xe9, 0xfe, 0xc0, 0xfe, 0xb5, 0x05,
|
||||
0x8b, 0x31, 0xfb, 0x46, 0xd0, 0x15, 0xdd, 0x33, 0x15, 0x41, 0x66, 0xa5, 0xbb, 0x67, 0x19, 0x0e,
|
||||
0x92, 0x87, 0xc6, 0x50, 0x75, 0xfb, 0xde, 0xb0, 0x1b, 0x11, 0x5f, 0x6d, 0xcb, 0x8b, 0x39, 0x8c,
|
||||
0x11, 0x1c, 0x3f, 0x09, 0x85, 0x0d, 0x05, 0x80, 0x35, 0x94, 0xfd, 0x87, 0x22, 0x2c, 0xa5, 0x66,
|
||||
0x0e, 0x3e, 0xa2, 0xcb, 0xab, 0xf7, 0x8e, 0x61, 0xb3, 0x1e, 0xd1, 0x77, 0x13, 0x16, 0x36, 0xe5,
|
||||
0xf8, 0x7e, 0x0c, 0xbd, 0x89, 0xd4, 0x91, 0xfd, 0x13, 0x73, 0x2d, 0x66, 0xe0, 0x44, 0xc6, 0x18,
|
||||
0xba, 0x8a, 0x0f, 0x3c, 0x74, 0xfd, 0xcc, 0x02, 0x24, 0x96, 0xc0, 0x35, 0xeb, 0xd9, 0xa8, 0x51,
|
||||
0xca, 0xd7, 0x6f, 0x67, 0x95, 0x45, 0x68, 0x63, 0x06, 0x0a, 0x1f, 0x02, 0x6f, 0xdc, 0x83, 0x96,
|
||||
0x1f, 0xcb, 0x3d, 0xa8, 0xfd, 0x0d, 0x38, 0x33, 0xd3, 0x71, 0xa8, 0x96, 0xd7, 0x3a, 0xac, 0xe5,
|
||||
0xe5, 0x91, 0x18, 0x46, 0x63, 0x5f, 0x6e, 0x50, 0x35, 0x89, 0xc4, 0x1d, 0x4e, 0xc4, 0x92, 0xc7,
|
||||
0xfb, 0xe0, 0x6e, 0x34, 0xc5, 0x63, 0xd9, 0x4b, 0x56, 0x13, 0xf4, 0x4d, 0x41, 0xc5, 0x8a, 0x6b,
|
||||
0x7f, 0xaf, 0x00, 0x4b, 0xa9, 0x2a, 0x98, 0x1a, 0x59, 0xac, 0x63, 0x47, 0x96, 0x3c, 0x8d, 0x41,
|
||||
0x6f, 0xc0, 0x22, 0x15, 0x47, 0x31, 0x72, 0x18, 0xe9, 0x4d, 0x73, 0xb8, 0x89, 0xee, 0x18, 0xea,
|
||||
0xda, 0xa7, 0x0f, 0xf6, 0xd7, 0x16, 0x4d, 0x0a, 0x4e, 0xc1, 0xd9, 0xbf, 0x2a, 0xc0, 0x13, 0x87,
|
||||
0x74, 0x04, 0xe8, 0x8e, 0x79, 0x3b, 0x20, 0xc7, 0xc7, 0x97, 0x72, 0x08, 0x4f, 0x95, 0x48, 0xe5,
|
||||
0xff, 0xdb, 0xc3, 0xee, 0x06, 0x1e, 0x70, 0x7a, 0xdc, 0x83, 0x72, 0x3f, 0x08, 0x06, 0xf1, 0x98,
|
||||
0x38, 0x4f, 0x41, 0x48, 0x86, 0x9b, 0x76, 0x8d, 0xef, 0x26, 0x7f, 0xa7, 0x58, 0xaa, 0xb7, 0xdf,
|
||||
0xb5, 0x20, 0xe5, 0x45, 0x34, 0x82, 0x32, 0xd7, 0x32, 0xcd, 0xe1, 0x4f, 0x98, 0xa9, 0xf7, 0x12,
|
||||
0xd7, 0x29, 0xf1, 0xc5, 0x23, 0x96, 0x28, 0xc8, 0x83, 0x12, 0x37, 0x44, 0x75, 0xfa, 0xdb, 0x39,
|
||||
0xa1, 0xf1, 0x25, 0xca, 0xc1, 0x82, 0x3f, 0x61, 0x01, 0x61, 0x5f, 0x84, 0x33, 0x33, 0x16, 0xf1,
|
||||
0x90, 0xdf, 0x0b, 0xe2, 0x1f, 0x7f, 0x46, 0xc8, 0x5f, 0xe1, 0x44, 0x2c, 0x79, 0xbc, 0x7e, 0x9c,
|
||||
0xce, 0xaa, 0x47, 0x3f, 0xb7, 0xe0, 0x0c, 0xcd, 0xea, 0x7b, 0x24, 0x5e, 0xfb, 0xa0, 0x32, 0x6a,
|
||||
0xd6, 0x7c, 0x3c, 0x6b, 0x01, 0xdf, 0xd1, 0xec, 0x75, 0x29, 0x8f, 0x3d, 0xcf, 0xa7, 0xc4, 0x1d,
|
||||
0x47, 0xf1, 0x42, 0x75, 0xec, 0x6d, 0x29, 0x3a, 0xd6, 0x12, 0x7c, 0x7c, 0x95, 0xd7, 0xf5, 0x37,
|
||||
0x92, 0x46, 0x51, 0x8f, 0xaf, 0x1d, 0xcd, 0xc1, 0x86, 0x14, 0x3a, 0x07, 0x55, 0x97, 0x44, 0x6c,
|
||||
0x93, 0xb7, 0x47, 0x3c, 0x2f, 0x2c, 0xca, 0x39, 0x6b, 0x43, 0xd1, 0xb0, 0xe6, 0xa2, 0x0f, 0xc3,
|
||||
0xc2, 0x80, 0x4c, 0x85, 0x60, 0x49, 0x08, 0xd6, 0x79, 0xc5, 0xdf, 0x96, 0x24, 0x1c, 0xf3, 0x90,
|
||||
0x0d, 0x15, 0xd7, 0x11, 0x52, 0x65, 0x21, 0x05, 0xe2, 0xe6, 0xfe, 0x92, 0x10, 0x52, 0x9c, 0x76,
|
||||
0xf3, 0xde, 0xfd, 0xd5, 0x53, 0x6f, 0xde, 0x5f, 0x3d, 0xf5, 0xd6, 0xfd, 0xd5, 0x53, 0x77, 0x0f,
|
||||
0x56, 0xad, 0x7b, 0x07, 0xab, 0xd6, 0x9b, 0x07, 0xab, 0xd6, 0x5b, 0x07, 0xab, 0xd6, 0x3f, 0x0f,
|
||||
0x56, 0xad, 0x9f, 0xbc, 0xb3, 0x7a, 0xea, 0xd5, 0x6a, 0xec, 0xda, 0xff, 0x04, 0x00, 0x00, 0xff,
|
||||
0xff, 0xb1, 0x18, 0x0d, 0xa9, 0x53, 0x27, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ message AppProjectList {
|
||||
// AppProjectSpec represents
|
||||
message AppProjectSpec {
|
||||
// SourceRepos contains list of git repository URLs which can be used for deployment
|
||||
repeated string sourceRepos = 1;
|
||||
repeated string sources = 1;
|
||||
|
||||
// Destinations contains list of destinations available for deployment
|
||||
repeated ApplicationDestination destinations = 2;
|
||||
@@ -85,24 +85,21 @@ message ApplicationList {
|
||||
|
||||
// ApplicationSource contains information about github repository, path within repository and target application environment.
|
||||
message ApplicationSource {
|
||||
// RepoURL is the git repository URL of the application manifests
|
||||
// RepoURL is the repository URL containing the ksonnet application.
|
||||
optional string repoURL = 1;
|
||||
|
||||
// Path is a directory path within the repository containing a
|
||||
// Path is a directory path within repository which contains ksonnet application.
|
||||
optional string path = 2;
|
||||
|
||||
// Environment is a ksonnet application environment name
|
||||
// Environment is a ksonnet application environment name.
|
||||
optional string environment = 3;
|
||||
|
||||
// TargetRevision defines the commit, tag, or branch in which to sync the application to.
|
||||
// If omitted, will sync to HEAD
|
||||
optional string targetRevision = 4;
|
||||
|
||||
// ComponentParameterOverrides are a list of parameter override values
|
||||
// Environment parameter override values
|
||||
repeated ComponentParameter componentParameterOverrides = 5;
|
||||
|
||||
// ValuesFiles is a list of Helm values files to use when generating a template
|
||||
repeated string valuesFiles = 6;
|
||||
}
|
||||
|
||||
// ApplicationSpec represents desired application state. Contains link to repository with application definition and additional parameters link definition revision.
|
||||
|
||||
@@ -2,7 +2,6 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -222,26 +221,24 @@ type ApplicationSpec struct {
|
||||
|
||||
// ComponentParameter contains information about component parameter value
|
||||
type ComponentParameter struct {
|
||||
Component string `json:"component,omitempty" protobuf:"bytes,1,opt,name=component"`
|
||||
Component string `json:"component" protobuf:"bytes,1,opt,name=component"`
|
||||
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
|
||||
Value string `json:"value" protobuf:"bytes,3,opt,name=value"`
|
||||
}
|
||||
|
||||
// ApplicationSource contains information about github repository, path within repository and target application environment.
|
||||
type ApplicationSource struct {
|
||||
// RepoURL is the git repository URL of the application manifests
|
||||
// RepoURL is the repository URL containing the ksonnet application.
|
||||
RepoURL string `json:"repoURL" protobuf:"bytes,1,opt,name=repoURL"`
|
||||
// Path is a directory path within the repository containing a
|
||||
// Path is a directory path within repository which contains ksonnet application.
|
||||
Path string `json:"path" protobuf:"bytes,2,opt,name=path"`
|
||||
// Environment is a ksonnet application environment name
|
||||
Environment string `json:"environment,omitempty" protobuf:"bytes,3,opt,name=environment"`
|
||||
// Environment is a ksonnet application environment name.
|
||||
Environment string `json:"environment" protobuf:"bytes,3,opt,name=environment"`
|
||||
// TargetRevision defines the commit, tag, or branch in which to sync the application to.
|
||||
// If omitted, will sync to HEAD
|
||||
TargetRevision string `json:"targetRevision,omitempty" protobuf:"bytes,4,opt,name=targetRevision"`
|
||||
// ComponentParameterOverrides are a list of parameter override values
|
||||
// Environment parameter override values
|
||||
ComponentParameterOverrides []ComponentParameter `json:"componentParameterOverrides,omitempty" protobuf:"bytes,5,opt,name=componentParameterOverrides"`
|
||||
// ValuesFiles is a list of Helm values files to use when generating a template
|
||||
ValuesFiles []string `json:"valuesFiles,omitempty" protobuf:"bytes,6,opt,name=valuesFiles"`
|
||||
}
|
||||
|
||||
// ApplicationDestination contains deployment destination information
|
||||
@@ -446,7 +443,7 @@ type AppProject struct {
|
||||
// AppProjectSpec represents
|
||||
type AppProjectSpec struct {
|
||||
// SourceRepos contains list of git repository URLs which can be used for deployment
|
||||
SourceRepos []string `json:"sourceRepos" protobuf:"bytes,1,name=sourceRepos"`
|
||||
SourceRepos []string `json:"sources" protobuf:"bytes,1,name=destination"`
|
||||
|
||||
// Destinations contains list of destinations available for deployment
|
||||
Destinations []ApplicationDestination `json:"destinations" protobuf:"bytes,2,name=destination"`
|
||||
@@ -510,7 +507,10 @@ func (condition *ApplicationCondition) IsError() bool {
|
||||
|
||||
// Equals compares two instances of ApplicationSource and return true if instances are equal.
|
||||
func (source ApplicationSource) Equals(other ApplicationSource) bool {
|
||||
return reflect.DeepEqual(source, other)
|
||||
return source.TargetRevision == other.TargetRevision &&
|
||||
source.RepoURL == other.RepoURL &&
|
||||
source.Path == other.Path &&
|
||||
source.Environment == other.Environment
|
||||
}
|
||||
|
||||
func (spec ApplicationSpec) BelongsToDefaultProject() bool {
|
||||
|
||||
@@ -205,11 +205,6 @@ func (in *ApplicationSource) DeepCopyInto(out *ApplicationSource) {
|
||||
*out = make([]ComponentParameter, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ValuesFiles != nil {
|
||||
in, out := &in.ValuesFiles, &out.ValuesFiles
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -7,20 +7,15 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ksonnet/ksonnet/pkg/app"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/cache"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/helm"
|
||||
ksutil "github.com/argoproj/argo-cd/util/ksonnet"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
)
|
||||
@@ -30,14 +25,6 @@ const (
|
||||
DefaultRepoCacheExpiration = 24 * time.Hour
|
||||
)
|
||||
|
||||
type AppSourceType string
|
||||
|
||||
const (
|
||||
AppSourceKsonnet AppSourceType = "ksonnet"
|
||||
AppSourceHelm AppSourceType = "helm"
|
||||
AppSourceDirectory AppSourceType = "directory"
|
||||
)
|
||||
|
||||
// Service implements ManifestService interface
|
||||
type Service struct {
|
||||
repoLock *util.KeyLock
|
||||
@@ -130,7 +117,7 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
var res ManifestResponse
|
||||
if git.IsCommitSHA(q.Revision) {
|
||||
cacheKey := manifestCacheKey(q.Revision, q)
|
||||
err := s.cache.Get(cacheKey, res)
|
||||
err := s.cache.Get(cacheKey, &res)
|
||||
if err == nil {
|
||||
log.Infof("manifest cache hit: %s", cacheKey)
|
||||
return &res, nil
|
||||
@@ -166,53 +153,35 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
return nil, err
|
||||
}
|
||||
appPath := path.Join(appRepoPath, q.Path)
|
||||
ksApp, err := ksutil.NewKsonnetApp(appPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load application from %s: %v", appPath, err)
|
||||
}
|
||||
|
||||
genRes, err := generateManifests(appPath, q)
|
||||
params, err := ksApp.ListEnvParams(q.Environment)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to list ksonnet app params: %v", err)
|
||||
}
|
||||
|
||||
if q.ComponentParameterOverrides != nil {
|
||||
for _, override := range q.ComponentParameterOverrides {
|
||||
err = ksApp.SetComponentParams(q.Environment, override.Component, override.Name, override.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appSpec := ksApp.App()
|
||||
env, err := appSpec.Environment(q.Environment)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("environment '%s' does not exist in ksonnet app", q.Environment)
|
||||
}
|
||||
|
||||
targetObjs, err := ksApp.Show(q.Environment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = *genRes
|
||||
res.Revision = commitSHA
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: cacheKey,
|
||||
Object: res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("manifest cache set error %s: %v", cacheKey, err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
// generateManifests generates manifests from a path
|
||||
func generateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, error) {
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
var params []*v1alpha1.ComponentParameter
|
||||
var env *app.EnvironmentSpec
|
||||
var err error
|
||||
|
||||
appSourceType := IdentifyAppSourceTypeByAppDir(appPath)
|
||||
switch appSourceType {
|
||||
case AppSourceKsonnet:
|
||||
targetObjs, params, env, err = ksShow(appPath, q.Environment, q.ComponentParameterOverrides)
|
||||
case AppSourceHelm:
|
||||
h := helm.NewHelmApp(appPath)
|
||||
targetObjs, err = h.Template(q.AppLabel, q.ValueFiles, q.ComponentParameterOverrides)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params, err = h.GetParameters(q.ValueFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case AppSourceDirectory:
|
||||
targetObjs, err = findManifests(appPath)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(jessesuen): we need to sort objects based on their dependency order of creation
|
||||
|
||||
manifests := make([]string, len(targetObjs))
|
||||
for i, target := range targetObjs {
|
||||
if q.AppLabel != "" {
|
||||
@@ -228,13 +197,20 @@ func generateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, e
|
||||
manifests[i] = string(manifestStr)
|
||||
}
|
||||
|
||||
res := ManifestResponse{
|
||||
res = ManifestResponse{
|
||||
Revision: commitSHA,
|
||||
Manifests: manifests,
|
||||
Namespace: env.Destination.Namespace,
|
||||
Server: env.Destination.Server,
|
||||
Params: params,
|
||||
}
|
||||
if env != nil {
|
||||
res.Namespace = env.Destination.Namespace
|
||||
res.Server = env.Destination.Server
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: cacheKey,
|
||||
Object: &res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("manifest cache set error %s: %v", cacheKey, err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
@@ -244,28 +220,6 @@ func tempRepoPath(repo string) string {
|
||||
return path.Join(os.TempDir(), strings.Replace(repo, "/", "_", -1))
|
||||
}
|
||||
|
||||
// IdentifyAppSourceTypeByAppDir examines a directory and determines its application source type
|
||||
func IdentifyAppSourceTypeByAppDir(appDirPath string) AppSourceType {
|
||||
if pathExists(path.Join(appDirPath, "app.yaml")) {
|
||||
return AppSourceKsonnet
|
||||
}
|
||||
if pathExists(path.Join(appDirPath, "Chart.yaml")) {
|
||||
return AppSourceHelm
|
||||
}
|
||||
return AppSourceDirectory
|
||||
}
|
||||
|
||||
// IdentifyAppSourceTypeByAppPath determines application source type by app file path
|
||||
func IdentifyAppSourceTypeByAppPath(appFilePath string) AppSourceType {
|
||||
if strings.HasSuffix(appFilePath, "app.yaml") {
|
||||
return AppSourceKsonnet
|
||||
}
|
||||
if strings.HasSuffix(appFilePath, "Chart.yaml") {
|
||||
return AppSourceHelm
|
||||
}
|
||||
return AppSourceDirectory
|
||||
}
|
||||
|
||||
// checkoutRevision is a convenience function to initialize a repo, fetch, and checkout a revision
|
||||
func checkoutRevision(gitClient git.Client, revision string) error {
|
||||
err := gitClient.Fetch()
|
||||
@@ -285,92 +239,9 @@ func checkoutRevision(gitClient git.Client, revision string) error {
|
||||
|
||||
func manifestCacheKey(commitSHA string, q *ManifestRequest) string {
|
||||
pStr, _ := json.Marshal(q.ComponentParameterOverrides)
|
||||
valuesFiles := strings.Join(q.ValueFiles, ",")
|
||||
return fmt.Sprintf("mfst|%s|%s|%s|%s|%s|%s", q.AppLabel, q.Path, q.Environment, commitSHA, string(pStr), valuesFiles)
|
||||
return fmt.Sprintf("mfst|%s|%s|%s|%s", q.Path, q.Environment, commitSHA, string(pStr))
|
||||
}
|
||||
|
||||
func listDirCacheKey(commitSHA string, q *ListDirRequest) string {
|
||||
return fmt.Sprintf("ldir|%s|%s", q.Path, commitSHA)
|
||||
}
|
||||
|
||||
// ksShow runs `ks show` in an app directory after setting any component parameter overrides
|
||||
func ksShow(appPath, envName string, overrides []*v1alpha1.ComponentParameter) ([]*unstructured.Unstructured, []*v1alpha1.ComponentParameter, *app.EnvironmentSpec, error) {
|
||||
ksApp, err := ksutil.NewKsonnetApp(appPath)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("unable to load application from %s: %v", appPath, err)
|
||||
}
|
||||
params, err := ksApp.ListEnvParams(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("Failed to list ksonnet app params: %v", err)
|
||||
}
|
||||
if overrides != nil {
|
||||
for _, override := range overrides {
|
||||
err = ksApp.SetComponentParams(envName, override.Component, override.Name, override.Value)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
appSpec := ksApp.App()
|
||||
env, err := appSpec.Environment(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("environment '%s' does not exist in ksonnet app", envName)
|
||||
}
|
||||
targetObjs, err := ksApp.Show(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return targetObjs, params, env, nil
|
||||
}
|
||||
|
||||
var manifestFile = regexp.MustCompile(`^.*\.(yaml|yml|json)$`)
|
||||
|
||||
// findManifests looks at all yaml files in a directory and unmarshals them into a list of unstructured objects
|
||||
func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
|
||||
files, err := ioutil.ReadDir(appPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read dir %s: %v", appPath, err)
|
||||
}
|
||||
var objs []*unstructured.Unstructured
|
||||
for _, f := range files {
|
||||
if f.IsDir() || !manifestFile.MatchString(f.Name()) {
|
||||
continue
|
||||
}
|
||||
out, err := ioutil.ReadFile(path.Join(appPath, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.HasSuffix(f.Name(), ".json") {
|
||||
var obj unstructured.Unstructured
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &obj)
|
||||
} else {
|
||||
yamlObjs, err := kube.SplitYAML(string(out))
|
||||
if err != nil {
|
||||
if len(yamlObjs) > 0 {
|
||||
// If we get here, we had a multiple objects in a single YAML file which had some
|
||||
// valid k8s objects, but errors parsing others (within the same file). It's very
|
||||
// likely the user messed up a portion of the YAML, so report on that.
|
||||
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, it might be a unrelated YAML file which we will ignore
|
||||
continue
|
||||
}
|
||||
objs = append(objs, yamlObjs...)
|
||||
}
|
||||
}
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
// pathExists reports whether the named file or directory exists.
|
||||
func pathExists(name string) bool {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ type ManifestRequest struct {
|
||||
Environment string `protobuf:"bytes,4,opt,name=environment,proto3" json:"environment,omitempty"`
|
||||
AppLabel string `protobuf:"bytes,5,opt,name=appLabel,proto3" json:"appLabel,omitempty"`
|
||||
ComponentParameterOverrides []*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter `protobuf:"bytes,6,rep,name=componentParameterOverrides" json:"componentParameterOverrides,omitempty"`
|
||||
ValueFiles []string `protobuf:"bytes,7,rep,name=valueFiles" json:"valueFiles,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ManifestRequest) Reset() { *m = ManifestRequest{} }
|
||||
@@ -99,13 +98,6 @@ func (m *ManifestRequest) GetComponentParameterOverrides() []*github_com_argopro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ManifestRequest) GetValueFiles() []string {
|
||||
if m != nil {
|
||||
return m.ValueFiles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ManifestResponse struct {
|
||||
Manifests []string `protobuf:"bytes,1,rep,name=manifests" json:"manifests,omitempty"`
|
||||
Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
@@ -468,21 +460,6 @@ func (m *ManifestRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
i += n
|
||||
}
|
||||
}
|
||||
if len(m.ValueFiles) > 0 {
|
||||
for _, s := range m.ValueFiles {
|
||||
dAtA[i] = 0x3a
|
||||
i++
|
||||
l = len(s)
|
||||
for l >= 1<<7 {
|
||||
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
|
||||
l >>= 7
|
||||
i++
|
||||
}
|
||||
dAtA[i] = uint8(l)
|
||||
i++
|
||||
i += copy(dAtA[i:], s)
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -724,12 +701,6 @@ func (m *ManifestRequest) Size() (n int) {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
}
|
||||
if len(m.ValueFiles) > 0 {
|
||||
for _, s := range m.ValueFiles {
|
||||
l = len(s)
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1043,35 +1014,6 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 7:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ValueFiles", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ValueFiles = append(m.ValueFiles, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
@@ -1840,41 +1782,40 @@ var (
|
||||
func init() { proto.RegisterFile("reposerver/repository/repository.proto", fileDescriptorRepository) }
|
||||
|
||||
var fileDescriptorRepository = []byte{
|
||||
// 576 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0xae, 0xc9, 0x5f, 0xb3, 0x41, 0xb4, 0xac, 0x22, 0x64, 0x39, 0x51, 0x64, 0x59, 0x02, 0xe5,
|
||||
0x82, 0xad, 0x84, 0x0b, 0x17, 0x84, 0x04, 0x85, 0x0a, 0xa9, 0x55, 0x91, 0x39, 0xc1, 0x05, 0x6d,
|
||||
0x9c, 0xc1, 0x59, 0x62, 0xef, 0x2e, 0xbb, 0x1b, 0x4b, 0xbc, 0x03, 0x12, 0x0f, 0xc0, 0x0b, 0x71,
|
||||
0xe4, 0x11, 0x50, 0x6e, 0x7d, 0x0b, 0xe4, 0x8d, 0x1d, 0x3b, 0x6d, 0xd4, 0x0b, 0xaa, 0xd4, 0xdb,
|
||||
0xcc, 0x37, 0xb3, 0xf3, 0xcd, 0x7e, 0x33, 0x1a, 0xf4, 0x44, 0x82, 0xe0, 0x0a, 0x64, 0x06, 0x32,
|
||||
0x30, 0x26, 0xd5, 0x5c, 0x7e, 0xaf, 0x99, 0xbe, 0x90, 0x5c, 0x73, 0x8c, 0x2a, 0xc4, 0xe9, 0xc7,
|
||||
0x3c, 0xe6, 0x06, 0x0e, 0x72, 0x6b, 0x93, 0xe1, 0x0c, 0x63, 0xce, 0xe3, 0x04, 0x02, 0x22, 0x68,
|
||||
0x40, 0x18, 0xe3, 0x9a, 0x68, 0xca, 0x99, 0x2a, 0xa2, 0xde, 0xf2, 0xb9, 0xf2, 0x29, 0x37, 0xd1,
|
||||
0x88, 0x4b, 0x08, 0xb2, 0x49, 0x10, 0x03, 0x03, 0x49, 0x34, 0xcc, 0x8b, 0x9c, 0x77, 0x31, 0xd5,
|
||||
0x8b, 0xd5, 0xcc, 0x8f, 0x78, 0x1a, 0x10, 0x69, 0x28, 0xbe, 0x1a, 0xe3, 0x69, 0x34, 0x0f, 0xc4,
|
||||
0x32, 0xce, 0x1f, 0xab, 0x80, 0x08, 0x91, 0xd0, 0xc8, 0x14, 0x0f, 0xb2, 0x09, 0x49, 0xc4, 0x82,
|
||||
0x5c, 0x2b, 0xe5, 0xfd, 0x68, 0xa0, 0xa3, 0x73, 0xc2, 0xe8, 0x17, 0x50, 0x3a, 0x84, 0x6f, 0x2b,
|
||||
0x50, 0x1a, 0x7f, 0x44, 0xcd, 0xfc, 0x13, 0xb6, 0xe5, 0x5a, 0xe3, 0xde, 0xf4, 0x8d, 0x5f, 0xb1,
|
||||
0xf9, 0x25, 0x9b, 0x31, 0x3e, 0x47, 0x73, 0x5f, 0x2c, 0x63, 0x3f, 0x67, 0xf3, 0x6b, 0x6c, 0x7e,
|
||||
0xc9, 0xe6, 0x87, 0x5b, 0x2d, 0x42, 0x53, 0x12, 0x3b, 0xe8, 0x50, 0x42, 0x46, 0x15, 0xe5, 0xcc,
|
||||
0xbe, 0xe7, 0x5a, 0xe3, 0x6e, 0xb8, 0xf5, 0x31, 0x46, 0x4d, 0x41, 0xf4, 0xc2, 0x6e, 0x18, 0xdc,
|
||||
0xd8, 0xd8, 0x45, 0x3d, 0x60, 0x19, 0x95, 0x9c, 0xa5, 0xc0, 0xb4, 0xdd, 0x34, 0xa1, 0x3a, 0x94,
|
||||
0x57, 0x24, 0x42, 0x9c, 0x91, 0x19, 0x24, 0x76, 0x6b, 0x53, 0xb1, 0xf4, 0xf1, 0x4f, 0x0b, 0x0d,
|
||||
0x22, 0x9e, 0x0a, 0xce, 0x80, 0xe9, 0xf7, 0x44, 0x92, 0x14, 0x34, 0xc8, 0x8b, 0x0c, 0xa4, 0xa4,
|
||||
0x73, 0x50, 0x76, 0xdb, 0x6d, 0x8c, 0x7b, 0xd3, 0xf3, 0xff, 0xf8, 0xe0, 0xeb, 0x6b, 0xd5, 0xc3,
|
||||
0x9b, 0x18, 0xf1, 0x08, 0xa1, 0x8c, 0x24, 0x2b, 0x78, 0x4b, 0x13, 0x50, 0x76, 0xc7, 0x6d, 0x8c,
|
||||
0xbb, 0x61, 0x0d, 0xf1, 0x2e, 0x2d, 0x74, 0x5c, 0x8d, 0x43, 0x09, 0xce, 0x14, 0xe0, 0x21, 0xea,
|
||||
0xa6, 0x05, 0xa6, 0x6c, 0xcb, 0xbc, 0xa9, 0x80, 0x3c, 0xca, 0x48, 0x0a, 0x4a, 0x90, 0x08, 0x0a,
|
||||
0x4d, 0x2b, 0x00, 0x3f, 0x42, 0xed, 0xcd, 0xd2, 0x16, 0xb2, 0x16, 0xde, 0xce, 0x20, 0x9a, 0x57,
|
||||
0x06, 0x01, 0xa8, 0x2d, 0xf2, 0xd6, 0x95, 0xdd, 0xba, 0x0d, 0x81, 0x8a, 0xe2, 0xde, 0x2f, 0x0b,
|
||||
0x3d, 0x38, 0xa3, 0x4a, 0x9f, 0x50, 0x79, 0xf7, 0x36, 0xcf, 0x73, 0xd1, 0x61, 0x3e, 0x92, 0xbc,
|
||||
0x41, 0xdc, 0x47, 0x2d, 0xaa, 0x21, 0x2d, 0xc5, 0xdf, 0x38, 0xa6, 0xff, 0x53, 0xd0, 0x79, 0xd6,
|
||||
0x1d, 0xec, 0xff, 0x31, 0x3a, 0xda, 0x36, 0x57, 0xec, 0x11, 0x46, 0xcd, 0x39, 0xd1, 0xc4, 0x74,
|
||||
0x77, 0x3f, 0x34, 0xf6, 0xf4, 0xd2, 0x42, 0x0f, 0x2b, 0xae, 0x0f, 0x20, 0x33, 0x1a, 0x01, 0xbe,
|
||||
0x40, 0xc7, 0xa7, 0xc5, 0xa1, 0x28, 0xb7, 0x11, 0x0f, 0xfc, 0xda, 0xad, 0xbb, 0x72, 0x32, 0x9c,
|
||||
0xe1, 0xfe, 0xe0, 0x86, 0xd8, 0x3b, 0xc0, 0x2f, 0x50, 0xa7, 0x18, 0x35, 0x76, 0xea, 0xa9, 0xbb,
|
||||
0xf3, 0x77, 0xfa, 0xf5, 0x58, 0x29, 0xbf, 0x77, 0x80, 0x4f, 0x50, 0xa7, 0xf8, 0xcc, 0xee, 0xf3,
|
||||
0x5d, 0xf9, 0x9d, 0xc1, 0xde, 0x58, 0xd9, 0xc4, 0xab, 0x97, 0xbf, 0xd7, 0x23, 0xeb, 0xcf, 0x7a,
|
||||
0x64, 0xfd, 0x5d, 0x8f, 0xac, 0x4f, 0x93, 0x9b, 0x8e, 0xe8, 0xde, 0x63, 0x3f, 0x6b, 0x9b, 0x9b,
|
||||
0xf9, 0xec, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0x81, 0x49, 0x46, 0x0c, 0x06, 0x00, 0x00,
|
||||
// 560 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0x4d, 0x8b, 0xd3, 0x40,
|
||||
0x18, 0xde, 0x6c, 0x3f, 0x76, 0x3b, 0x15, 0x77, 0x1d, 0x8a, 0x84, 0xb4, 0x94, 0x10, 0x50, 0x7a,
|
||||
0x31, 0xa1, 0xf5, 0xe2, 0x45, 0x04, 0x5d, 0x5d, 0x84, 0x5d, 0x56, 0xe2, 0x49, 0x2f, 0x32, 0x4d,
|
||||
0x5f, 0xd3, 0xb1, 0xcd, 0xcc, 0x38, 0x33, 0x1b, 0xf0, 0x57, 0xf8, 0x03, 0xfc, 0x43, 0x1e, 0xfd,
|
||||
0x09, 0xd2, 0xdb, 0x82, 0x3f, 0x42, 0x32, 0x9d, 0x34, 0xe9, 0x6e, 0xd9, 0x8b, 0x08, 0x7b, 0x7b,
|
||||
0xbf, 0xf2, 0x3c, 0xcf, 0x3c, 0x79, 0x79, 0xd1, 0x63, 0x09, 0x82, 0x2b, 0x90, 0x39, 0xc8, 0xc8,
|
||||
0x84, 0x54, 0x73, 0xf9, 0xad, 0x16, 0x86, 0x42, 0x72, 0xcd, 0x31, 0xaa, 0x2a, 0x5e, 0x2f, 0xe5,
|
||||
0x29, 0x37, 0xe5, 0xa8, 0x88, 0xd6, 0x13, 0xde, 0x20, 0xe5, 0x3c, 0x5d, 0x42, 0x44, 0x04, 0x8d,
|
||||
0x08, 0x63, 0x5c, 0x13, 0x4d, 0x39, 0x53, 0xb6, 0x1b, 0x2c, 0x9e, 0xa9, 0x90, 0x72, 0xd3, 0x4d,
|
||||
0xb8, 0x84, 0x28, 0x1f, 0x47, 0x29, 0x30, 0x90, 0x44, 0xc3, 0xcc, 0xce, 0xbc, 0x4d, 0xa9, 0x9e,
|
||||
0x5f, 0x4e, 0xc3, 0x84, 0x67, 0x11, 0x91, 0x86, 0xe2, 0x8b, 0x09, 0x9e, 0x24, 0xb3, 0x48, 0x2c,
|
||||
0xd2, 0xe2, 0x63, 0x15, 0x11, 0x21, 0x96, 0x34, 0x31, 0xe0, 0x51, 0x3e, 0x26, 0x4b, 0x31, 0x27,
|
||||
0x37, 0xa0, 0x82, 0x3f, 0xfb, 0xe8, 0xe8, 0x9c, 0x30, 0xfa, 0x19, 0x94, 0x8e, 0xe1, 0xeb, 0x25,
|
||||
0x28, 0x8d, 0x3f, 0xa0, 0x66, 0xf1, 0x08, 0xd7, 0xf1, 0x9d, 0x51, 0x77, 0xf2, 0x3a, 0xac, 0xd8,
|
||||
0xc2, 0x92, 0xcd, 0x04, 0x9f, 0x92, 0x59, 0x28, 0x16, 0x69, 0x58, 0xb0, 0x85, 0x35, 0xb6, 0xb0,
|
||||
0x64, 0x0b, 0xe3, 0x8d, 0x17, 0xb1, 0x81, 0xc4, 0x1e, 0x3a, 0x94, 0x90, 0x53, 0x45, 0x39, 0x73,
|
||||
0xf7, 0x7d, 0x67, 0xd4, 0x89, 0x37, 0x39, 0xc6, 0xa8, 0x29, 0x88, 0x9e, 0xbb, 0x0d, 0x53, 0x37,
|
||||
0x31, 0xf6, 0x51, 0x17, 0x58, 0x4e, 0x25, 0x67, 0x19, 0x30, 0xed, 0x36, 0x4d, 0xab, 0x5e, 0x2a,
|
||||
0x10, 0x89, 0x10, 0x67, 0x64, 0x0a, 0x4b, 0xb7, 0xb5, 0x46, 0x2c, 0x73, 0xfc, 0xdd, 0x41, 0xfd,
|
||||
0x84, 0x67, 0x82, 0x33, 0x60, 0xfa, 0x1d, 0x91, 0x24, 0x03, 0x0d, 0xf2, 0x22, 0x07, 0x29, 0xe9,
|
||||
0x0c, 0x94, 0xdb, 0xf6, 0x1b, 0xa3, 0xee, 0xe4, 0xfc, 0x1f, 0x1e, 0xf8, 0xea, 0x06, 0x7a, 0x7c,
|
||||
0x1b, 0x63, 0x70, 0xe5, 0xa0, 0xe3, 0xca, 0x6e, 0x25, 0x38, 0x53, 0x80, 0x07, 0xa8, 0x93, 0xd9,
|
||||
0x9a, 0x72, 0x1d, 0xbf, 0x31, 0xea, 0xc4, 0x55, 0xa1, 0xe8, 0x32, 0x92, 0x81, 0x12, 0x24, 0x01,
|
||||
0xeb, 0x59, 0x55, 0xc0, 0x0f, 0x51, 0x7b, 0xbd, 0x94, 0xd6, 0x36, 0x9b, 0x6d, 0x19, 0xdd, 0xbc,
|
||||
0x66, 0x34, 0xa0, 0xb6, 0x28, 0xa4, 0x29, 0xb7, 0xf5, 0x3f, 0x0c, 0xb0, 0xe0, 0xc1, 0x0f, 0x07,
|
||||
0xdd, 0x3f, 0xa3, 0x4a, 0x9f, 0x50, 0x79, 0xf7, 0x36, 0x2b, 0xf0, 0xd1, 0xe1, 0x1b, 0xba, 0x84,
|
||||
0x42, 0x20, 0xee, 0xa1, 0x16, 0xd5, 0x90, 0x95, 0xe6, 0xaf, 0x13, 0xa3, 0xff, 0x14, 0x74, 0x31,
|
||||
0x75, 0x07, 0xf5, 0x3f, 0x42, 0x47, 0x1b, 0x71, 0x76, 0x8f, 0x30, 0x6a, 0xce, 0x88, 0x26, 0x46,
|
||||
0xdd, 0xbd, 0xd8, 0xc4, 0x93, 0x2b, 0x07, 0x3d, 0xa8, 0xb8, 0xde, 0x83, 0xcc, 0x69, 0x02, 0xf8,
|
||||
0x02, 0x1d, 0x9f, 0xda, 0x43, 0x50, 0x6e, 0x23, 0xee, 0x87, 0xb5, 0x5b, 0x76, 0xed, 0x24, 0x78,
|
||||
0x83, 0xdd, 0xcd, 0x35, 0x71, 0xb0, 0x87, 0x9f, 0xa3, 0x03, 0xfb, 0xab, 0xb1, 0x57, 0x1f, 0xdd,
|
||||
0xfe, 0xff, 0x5e, 0xaf, 0xde, 0x2b, 0xed, 0x0f, 0xf6, 0xf0, 0x09, 0x3a, 0xb0, 0x8f, 0xd9, 0xfe,
|
||||
0x7c, 0xdb, 0x7e, 0xaf, 0xbf, 0xb3, 0x57, 0x8a, 0x78, 0xf9, 0xe2, 0xe7, 0x6a, 0xe8, 0xfc, 0x5a,
|
||||
0x0d, 0x9d, 0xdf, 0xab, 0xa1, 0xf3, 0x71, 0x7c, 0xdb, 0x91, 0xdc, 0x79, 0xcc, 0xa7, 0x6d, 0x73,
|
||||
0x13, 0x9f, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x96, 0x09, 0x12, 0xec, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ message ManifestRequest {
|
||||
string environment = 4;
|
||||
string appLabel = 5;
|
||||
repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ComponentParameter componentParameterOverrides = 6;
|
||||
repeated string valueFiles = 7;
|
||||
}
|
||||
|
||||
message ManifestResponse {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateManifestInDir(t *testing.T) {
|
||||
q := ManifestRequest{}
|
||||
res1, err := generateManifests("../../manifests/components", &q)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, len(res1.Manifests) == 16) // update this value if we add/remove manifests
|
||||
|
||||
// this will test concatenated manifests to verify we split YAMLs correctly
|
||||
res2, err := generateManifests("../../manifests", &q)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, len(res2.Manifests) == len(res1.Manifests))
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
package account
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
jwtutil "github.com/argoproj/argo-cd/util/jwt"
|
||||
"github.com/argoproj/argo-cd/util/password"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
@@ -30,17 +27,16 @@ func NewServer(sessionMgr *session.SessionManager, settingsMgr *settings.Setting
|
||||
|
||||
}
|
||||
|
||||
// UpdatePassword updates the password of the local admin superuser.
|
||||
//UpdatePassword is used to Update a User's Passwords
|
||||
func (s *Server) UpdatePassword(ctx context.Context, q *UpdatePasswordRequest) (*UpdatePasswordResponse, error) {
|
||||
username := getAuthenticatedUser(ctx)
|
||||
if username != common.ArgoCDAdminUsername {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "password can only be changed for local users, not user %q", username)
|
||||
}
|
||||
|
||||
cdSettings, err := s.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, ok := cdSettings.LocalUsers[username]; !ok {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "password can only be changed for local users")
|
||||
}
|
||||
|
||||
err = s.sessionMgr.VerifyUsernamePassword(username, q.CurrentPassword)
|
||||
if err != nil {
|
||||
@@ -52,8 +48,7 @@ func (s *Server) UpdatePassword(ctx context.Context, q *UpdatePasswordRequest) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cdSettings.AdminPasswordHash = hashedPassword
|
||||
cdSettings.AdminPasswordMtime = time.Now().UTC()
|
||||
cdSettings.LocalUsers[username] = hashedPassword
|
||||
|
||||
err = s.settingsMgr.SaveSettings(cdSettings)
|
||||
if err != nil {
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
)
|
||||
|
||||
// Server provides a Application service
|
||||
@@ -45,7 +44,6 @@ type Server struct {
|
||||
appComparator controller.AppStateManager
|
||||
enf *rbac.Enforcer
|
||||
projectLock *util.KeyLock
|
||||
auditLogger *argo.AuditLogger
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Application service
|
||||
@@ -68,7 +66,6 @@ func NewServer(
|
||||
appComparator: controller.NewAppStateManager(db, appclientset, repoClientset, namespace),
|
||||
enf: enf,
|
||||
projectLock: projectLock,
|
||||
auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,10 +128,6 @@ func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
s.logEvent(out, ctx, argo.EventReasonResourceCreated, "create")
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
|
||||
@@ -173,7 +166,6 @@ func (s *Server) GetManifests(ctx context.Context, q *ApplicationManifestQuery)
|
||||
Revision: revision,
|
||||
ComponentParameterOverrides: overrides,
|
||||
AppLabel: a.Name,
|
||||
ValueFiles: a.Spec.Source.ValuesFiles,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -214,41 +206,24 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *ApplicationResourceE
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/events", "get", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
var (
|
||||
kubeClientset kubernetes.Interface
|
||||
fieldSelector string
|
||||
namespace string
|
||||
)
|
||||
// There are two places where we get events. If we are getting application events, we query
|
||||
// our own cluster. If it is events on a resource on an external cluster, then we query the
|
||||
// external cluster using its rest.Config
|
||||
if q.ResourceName == "" && q.ResourceUID == "" {
|
||||
kubeClientset = s.kubeclientset
|
||||
namespace = a.Namespace
|
||||
fieldSelector = fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": a.Name,
|
||||
"involvedObject.uid": string(a.UID),
|
||||
"involvedObject.namespace": a.Namespace,
|
||||
}).String()
|
||||
} else {
|
||||
var config *rest.Config
|
||||
config, namespace, err = s.getApplicationClusterConfig(*q.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeClientset, err = kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldSelector = fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": q.ResourceName,
|
||||
"involvedObject.uid": q.ResourceUID,
|
||||
"involvedObject.namespace": namespace,
|
||||
}).String()
|
||||
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeClientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fieldSelector := fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": q.ResourceName,
|
||||
"involvedObject.uid": q.ResourceUID,
|
||||
"involvedObject.namespace": namespace,
|
||||
}).String()
|
||||
|
||||
log.Infof("Querying for resource events with field selector: %s", fieldSelector)
|
||||
opts := metav1.ListOptions{FieldSelector: fieldSelector}
|
||||
|
||||
return kubeClientset.CoreV1().Events(namespace).List(opts)
|
||||
}
|
||||
|
||||
@@ -276,10 +251,6 @@ func (s *Server) Update(ctx context.Context, q *ApplicationUpdateRequest) (*appv
|
||||
// throws an error is passed override is invalid
|
||||
// if passed override and old overrides are invalid, throws error, old overrides not dropped
|
||||
func (s *Server) removeInvalidOverrides(a *appv1.Application, q *ApplicationUpdateSpecRequest) (*ApplicationUpdateSpecRequest, error) {
|
||||
if a.Spec.Source.Environment == "" {
|
||||
// this method is only valid for ksonnet apps
|
||||
return q, nil
|
||||
}
|
||||
oldParams := argo.ParamToMap(a.Spec.Source.ComponentParameterOverrides)
|
||||
validAppSet := argo.ParamToMap(a.Status.Parameters)
|
||||
|
||||
@@ -289,7 +260,7 @@ func (s *Server) removeInvalidOverrides(a *appv1.Application, q *ApplicationUpda
|
||||
if !argo.CheckValidParam(validAppSet, param) {
|
||||
alreadySet := argo.CheckValidParam(oldParams, param)
|
||||
if !alreadySet {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Parameter '%s' in '%s' does not exist in ksonnet app", param.Name, param.Component)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Parameter '%s' in '%s' does not exist in ksonnet", param.Name, param.Component)
|
||||
}
|
||||
} else {
|
||||
params = append(params, param)
|
||||
@@ -322,23 +293,14 @@ func (s *Server) UpdateSpec(ctx context.Context, q *ApplicationUpdateSpecRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
a.Spec = q.Spec
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(a)
|
||||
if err == nil {
|
||||
if err != nil {
|
||||
s.logEvent(a, ctx, argo.EventReasonResourceUpdated, "update")
|
||||
}
|
||||
return &q.Spec, nil
|
||||
}
|
||||
if !apierr.IsConflict(err) {
|
||||
return nil, err
|
||||
}
|
||||
a, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patch, err := json.Marshal(map[string]appv1.ApplicationSpec{
|
||||
"spec": q.Spec,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Patch(*q.Name, types.MergePatchType, patch)
|
||||
return &q.Spec, err
|
||||
}
|
||||
|
||||
// Delete removes an application and all associated resources
|
||||
@@ -393,7 +355,6 @@ func (s *Server) Delete(ctx context.Context, q *ApplicationDeleteRequest) (*Appl
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.logEvent(a, ctx, argo.EventReasonResourceDeleted, "delete")
|
||||
return &ApplicationResponse{}, nil
|
||||
}
|
||||
|
||||
@@ -427,7 +388,6 @@ func (s *Server) Watch(q *ApplicationQuery, ws ApplicationService_WatchServer) e
|
||||
case <-ws.Context().Done():
|
||||
w.Stop()
|
||||
case <-done:
|
||||
w.Stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -448,7 +408,7 @@ func (s *Server) validateApp(ctx context.Context, spec *appv1.ApplicationSpec) e
|
||||
return err
|
||||
}
|
||||
if len(conditions) > 0 {
|
||||
return status.Errorf(codes.InvalidArgument, "application spec is invalid: %s", argo.FormatAppConditions(conditions))
|
||||
return status.Errorf(codes.InvalidArgument, "application spec is invalid: \n%s", argo.FormatAppConditions(conditions))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -610,7 +570,7 @@ func (s *Server) Sync(ctx context.Context, syncReq *ApplicationSyncRequest) (*ap
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "sync", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return s.setAppOperation(ctx, *syncReq.Name, "sync", func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
return s.setAppOperation(ctx, *syncReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
syncOp := appv1.SyncOperation{
|
||||
Revision: syncReq.Revision,
|
||||
Prune: syncReq.Prune,
|
||||
@@ -631,7 +591,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *ApplicationRollbackR
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "rollback", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return s.setAppOperation(ctx, *rollbackReq.Name, "rollback", func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
return s.setAppOperation(ctx, *rollbackReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
return &appv1.Operation{
|
||||
Rollback: &appv1.RollbackOperation{
|
||||
ID: rollbackReq.ID,
|
||||
@@ -642,7 +602,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *ApplicationRollbackR
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) setAppOperation(ctx context.Context, appName string, operationName string, operationCreator func(app *appv1.Application) (*appv1.Operation, error)) (*appv1.Application, error) {
|
||||
func (s *Server) setAppOperation(ctx context.Context, appName string, operationCreator func(app *appv1.Application) (*appv1.Operation, error)) (*appv1.Application, error) {
|
||||
for {
|
||||
a, err := s.Get(ctx, &ApplicationQuery{Name: &appName})
|
||||
if err != nil {
|
||||
@@ -661,9 +621,6 @@ func (s *Server) setAppOperation(ctx context.Context, appName string, operationN
|
||||
if err != nil && apierr.IsConflict(err) {
|
||||
log.Warnf("Failed to set operation for app '%s' due to update conflict. Retrying again...", appName)
|
||||
} else {
|
||||
if err == nil {
|
||||
s.logEvent(a, ctx, argo.EventReasonResourceUpdated, operationName)
|
||||
}
|
||||
return a, err
|
||||
}
|
||||
}
|
||||
@@ -695,13 +652,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *OperationTer
|
||||
a, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*termOpReq.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
s.logEvent(a, ctx, argo.EventReasonResourceUpdated, "terminateop")
|
||||
}
|
||||
}
|
||||
return nil, status.Errorf(codes.Internal, "Failed to terminate app. Too many conflicts")
|
||||
}
|
||||
|
||||
func (s *Server) logEvent(a *appv1.Application, ctx context.Context, reason string, action string) {
|
||||
s.auditLogger.LogAppEvent(a, argo.EventInfo{Reason: reason, Action: action, Username: session.Username(ctx)}, v1.EventTypeNormal)
|
||||
}
|
||||
|
||||
@@ -64,14 +64,6 @@ version: 0.0.1
|
||||
}
|
||||
}
|
||||
|
||||
func fakeListDirResponse() *repository.FileList {
|
||||
return &repository.FileList{
|
||||
Items: []string{
|
||||
"some/path/app.yaml",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// return an ApplicationServiceServer which returns fake data
|
||||
func newTestAppServer() ApplicationServiceServer {
|
||||
kubeclientset := fake.NewSimpleClientset()
|
||||
@@ -88,7 +80,6 @@ func newTestAppServer() ApplicationServiceServer {
|
||||
|
||||
mockRepoServiceClient := mockreposerver.RepositoryServiceClient{}
|
||||
mockRepoServiceClient.On("GetFile", mock.Anything, mock.Anything).Return(fakeFileResponse(), nil)
|
||||
mockRepoServiceClient.On("ListDir", mock.Anything, mock.Anything).Return(fakeListDirResponse(), nil)
|
||||
|
||||
mockRepoClient := &mockrepo.Clientset{}
|
||||
mockRepoClient.On("NewRepositoryClient").Return(&fakeCloser{}, &mockRepoServiceClient, nil)
|
||||
@@ -111,7 +102,7 @@ func TestCreateApp(t *testing.T) {
|
||||
Spec: appsv1.ApplicationSpec{
|
||||
Source: appsv1.ApplicationSource{
|
||||
RepoURL: fakeRepoURL,
|
||||
Path: "some/path",
|
||||
Path: ".",
|
||||
Environment: "default",
|
||||
TargetRevision: "HEAD",
|
||||
},
|
||||
|
||||
@@ -14,12 +14,9 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// Server provides a Project service
|
||||
@@ -27,14 +24,12 @@ type Server struct {
|
||||
ns string
|
||||
enf *rbac.Enforcer
|
||||
appclientset appclientset.Interface
|
||||
auditLogger *argo.AuditLogger
|
||||
projectLock *util.KeyLock
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Project service
|
||||
func NewServer(ns string, kubeclientset kubernetes.Interface, appclientset appclientset.Interface, enf *rbac.Enforcer, projectLock *util.KeyLock) *Server {
|
||||
auditLogger := argo.NewAuditLogger(ns, kubeclientset, "argocd-server")
|
||||
return &Server{enf: enf, appclientset: appclientset, ns: ns, projectLock: projectLock, auditLogger: auditLogger}
|
||||
func NewServer(ns string, appclientset appclientset.Interface, enf *rbac.Enforcer, projectLock *util.KeyLock) *Server {
|
||||
return &Server{enf: enf, appclientset: appclientset, ns: ns, projectLock: projectLock}
|
||||
}
|
||||
|
||||
// Create a new project.
|
||||
@@ -49,11 +44,7 @@ func (s *Server) Create(ctx context.Context, q *ProjectCreateRequest) (*v1alpha1
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Create(q.Project)
|
||||
if err == nil {
|
||||
s.logEvent(res, ctx, argo.EventReasonResourceCreated, "create")
|
||||
}
|
||||
return res, err
|
||||
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Create(q.Project)
|
||||
}
|
||||
|
||||
// List returns list of projects
|
||||
@@ -196,11 +187,7 @@ func (s *Server) Update(ctx context.Context, q *ProjectUpdateRequest) (*v1alpha1
|
||||
codes.InvalidArgument, "following source repos are used by one or more application and cannot be removed: %s", strings.Join(removedSrcUsed, ";"))
|
||||
}
|
||||
|
||||
res, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(q.Project)
|
||||
if err == nil {
|
||||
s.logEvent(res, ctx, argo.EventReasonResourceUpdated, "update")
|
||||
}
|
||||
return res, err
|
||||
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(q.Project)
|
||||
}
|
||||
|
||||
// Delete deletes a project
|
||||
@@ -212,11 +199,6 @@ func (s *Server) Delete(ctx context.Context, q *ProjectQuery) (*EmptyResponse, e
|
||||
s.projectLock.Lock(q.Name)
|
||||
defer s.projectLock.Unlock(q.Name)
|
||||
|
||||
p, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appsList, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -225,13 +207,5 @@ func (s *Server) Delete(ctx context.Context, q *ProjectQuery) (*EmptyResponse, e
|
||||
if len(apps) > 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "project is referenced by %d applications", len(apps))
|
||||
}
|
||||
err = s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Delete(q.Name, &metav1.DeleteOptions{})
|
||||
if err == nil {
|
||||
s.logEvent(p, ctx, argo.EventReasonResourceDeleted, "delete")
|
||||
}
|
||||
return &EmptyResponse{}, err
|
||||
}
|
||||
|
||||
func (s *Server) logEvent(p *v1alpha1.AppProject, ctx context.Context, reason string, action string) {
|
||||
s.auditLogger.LogAppProjEvent(p, argo.EventInfo{Reason: reason, Action: action, Username: session.Username(ctx)}, v1.EventTypeNormal)
|
||||
return &EmptyResponse{}, s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Delete(q.Name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import math "math"
|
||||
import _ "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
import _ "k8s.io/api/core/v1"
|
||||
import _ "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
import github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
import context "golang.org/x/net/context"
|
||||
@@ -882,36 +881,36 @@ var (
|
||||
func init() { proto.RegisterFile("server/project/project.proto", fileDescriptorProject) }
|
||||
|
||||
var fileDescriptorProject = []byte{
|
||||
// 487 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xcd, 0x6e, 0x13, 0x31,
|
||||
0x10, 0xc7, 0x65, 0x28, 0x41, 0x98, 0x4f, 0x59, 0x2d, 0x94, 0xa5, 0x04, 0xb4, 0xa7, 0x2a, 0x52,
|
||||
0x6d, 0xa5, 0xe5, 0x50, 0x71, 0xe3, 0xa3, 0x42, 0x95, 0x38, 0x40, 0x10, 0x12, 0xe2, 0x52, 0xb9,
|
||||
0xde, 0x91, 0xe3, 0x26, 0xbb, 0x36, 0xb6, 0xb3, 0x28, 0x42, 0x5c, 0x2a, 0x6e, 0x1c, 0x79, 0x04,
|
||||
0x6e, 0x3c, 0x09, 0x47, 0x24, 0x5e, 0x00, 0x45, 0x3c, 0x08, 0x5a, 0x67, 0x4d, 0x9a, 0xa6, 0xe1,
|
||||
0xb4, 0xe2, 0x94, 0xc9, 0xf8, 0xe3, 0xff, 0x9b, 0xf1, 0x7f, 0x07, 0x6f, 0x38, 0xb0, 0x25, 0x58,
|
||||
0x66, 0xac, 0x3e, 0x02, 0xe1, 0xe3, 0x2f, 0x35, 0x56, 0x7b, 0x4d, 0x2e, 0xd6, 0x7f, 0x93, 0x55,
|
||||
0xa9, 0xa5, 0x0e, 0x39, 0x56, 0x45, 0xd3, 0xe5, 0x64, 0x43, 0x6a, 0x2d, 0x87, 0xc0, 0xb8, 0x51,
|
||||
0x8c, 0x17, 0x85, 0xf6, 0xdc, 0x2b, 0x5d, 0xb8, 0x7a, 0x35, 0x1d, 0xec, 0x3a, 0xaa, 0x74, 0x58,
|
||||
0x15, 0xda, 0x02, 0x2b, 0xbb, 0x4c, 0x42, 0x01, 0x96, 0x7b, 0xc8, 0xea, 0x3d, 0x0f, 0x66, 0x7b,
|
||||
0x72, 0x2e, 0xfa, 0xaa, 0x00, 0x3b, 0x66, 0x66, 0x20, 0xab, 0x84, 0x63, 0x39, 0x78, 0x7e, 0xd6,
|
||||
0xa9, 0x7d, 0xa9, 0x7c, 0x7f, 0x74, 0x48, 0x85, 0xce, 0x19, 0xb7, 0x01, 0xec, 0x28, 0x04, 0x5b,
|
||||
0x22, 0x9b, 0x9d, 0xe6, 0xc6, 0x0c, 0x95, 0x08, 0x48, 0xac, 0xec, 0xf2, 0xa1, 0xe9, 0xf3, 0x85,
|
||||
0xab, 0xd2, 0xf7, 0x78, 0xf5, 0xc5, 0xb4, 0xc6, 0x27, 0x16, 0xb8, 0x87, 0x1e, 0xbc, 0x1b, 0x81,
|
||||
0xf3, 0xe4, 0x00, 0xc7, 0xda, 0xd7, 0xd1, 0x7d, 0xb4, 0x79, 0x79, 0x7b, 0x8f, 0xce, 0x44, 0x69,
|
||||
0x14, 0x0d, 0xc1, 0x81, 0xc8, 0xa8, 0x19, 0x48, 0x5a, 0x89, 0xd2, 0x13, 0xa2, 0x34, 0x8a, 0xd2,
|
||||
0x47, 0xc6, 0xd4, 0x22, 0xbd, 0x78, 0x6b, 0x9a, 0xe2, 0x2b, 0x75, 0xee, 0xe5, 0x08, 0xec, 0x98,
|
||||
0x10, 0xbc, 0x52, 0xf0, 0x1c, 0x82, 0xda, 0xa5, 0x5e, 0x88, 0x4f, 0xc0, 0xbd, 0x36, 0xd9, 0xff,
|
||||
0x84, 0xbb, 0x8e, 0xaf, 0xee, 0xe5, 0xc6, 0x8f, 0x7b, 0xe0, 0x8c, 0x2e, 0x1c, 0x6c, 0x7f, 0xbb,
|
||||
0x80, 0xaf, 0xd5, 0xbb, 0x5e, 0x81, 0x2d, 0x95, 0x00, 0xf2, 0x19, 0xe1, 0xd6, 0xb4, 0x67, 0xe4,
|
||||
0x2e, 0x8d, 0xb6, 0x39, 0xab, 0x97, 0x49, 0x33, 0x74, 0xe9, 0x9d, 0xe3, 0x9f, 0xbf, 0xbf, 0x9c,
|
||||
0x5b, 0x4b, 0x6f, 0x04, 0x47, 0x95, 0xdd, 0xe8, 0x55, 0xf7, 0x10, 0x75, 0xc8, 0x31, 0xc2, 0x2b,
|
||||
0xcf, 0x95, 0xf3, 0x64, 0xed, 0x34, 0x4b, 0x68, 0x6f, 0xb2, 0xdf, 0x08, 0x43, 0xa5, 0x90, 0xae,
|
||||
0x07, 0x0e, 0x42, 0x16, 0x38, 0xc8, 0x27, 0x84, 0xcf, 0x3f, 0x83, 0xa5, 0x0c, 0x0d, 0xf5, 0xe1,
|
||||
0x5e, 0xd0, 0xbf, 0x4d, 0x6e, 0x9d, 0xd6, 0x67, 0x1f, 0x2a, 0xd7, 0x7c, 0x24, 0x5f, 0x11, 0x6e,
|
||||
0x4d, 0x0d, 0xb3, 0xf8, 0x32, 0x73, 0x46, 0x6a, 0x8a, 0x68, 0x27, 0x10, 0x6d, 0x25, 0x9b, 0x8b,
|
||||
0x44, 0x51, 0xbe, 0xfa, 0x94, 0x33, 0xee, 0x39, 0x0d, 0x88, 0xd5, 0x8b, 0xbd, 0xc1, 0xad, 0xa7,
|
||||
0x30, 0x04, 0x0f, 0xcb, 0xda, 0x75, 0xf3, 0x6f, 0x7a, 0xce, 0x8b, 0xb1, 0xfe, 0xce, 0xb2, 0xfa,
|
||||
0x1f, 0xef, 0x7e, 0x9f, 0xb4, 0xd1, 0x8f, 0x49, 0x1b, 0xfd, 0x9a, 0xb4, 0xd1, 0xdb, 0xce, 0xbf,
|
||||
0x86, 0xc5, 0xfc, 0xf4, 0x3b, 0x6c, 0x85, 0xa1, 0xb0, 0xf3, 0x27, 0x00, 0x00, 0xff, 0xff, 0x59,
|
||||
0x47, 0x12, 0x67, 0x16, 0x05, 0x00, 0x00,
|
||||
// 484 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x4d, 0x6b, 0x14, 0x31,
|
||||
0x18, 0xc7, 0x89, 0xd6, 0x15, 0xe3, 0x2b, 0xa1, 0xd5, 0x3a, 0x6d, 0x57, 0x19, 0x2f, 0xb2, 0x68,
|
||||
0xc2, 0xd6, 0x83, 0xc5, 0x9b, 0x2f, 0x45, 0x0a, 0x1e, 0x74, 0xc5, 0x8b, 0x08, 0x25, 0x9d, 0x79,
|
||||
0x48, 0xd3, 0xdd, 0x9d, 0xc4, 0x24, 0x3b, 0x52, 0x8a, 0x97, 0xe2, 0xcd, 0xa3, 0x1f, 0xc2, 0xbb,
|
||||
0x9f, 0xc2, 0xa3, 0xe0, 0x17, 0x90, 0xc5, 0x0f, 0x22, 0xf3, 0xec, 0x44, 0xbb, 0xdd, 0xae, 0xa7,
|
||||
0xa1, 0xa7, 0x79, 0x26, 0xc9, 0xe4, 0xf7, 0x9b, 0x27, 0x7f, 0x42, 0x57, 0x3d, 0xb8, 0x12, 0x9c,
|
||||
0xb0, 0xce, 0xec, 0x41, 0x16, 0xe2, 0x93, 0x5b, 0x67, 0x82, 0x61, 0xe7, 0xeb, 0xd7, 0x64, 0x51,
|
||||
0x19, 0x65, 0x70, 0x4c, 0x54, 0xd5, 0x64, 0x3a, 0x59, 0x55, 0xc6, 0xa8, 0x01, 0x08, 0x69, 0xb5,
|
||||
0x90, 0x45, 0x61, 0x82, 0x0c, 0xda, 0x14, 0xbe, 0x9e, 0x4d, 0xfb, 0x1b, 0x9e, 0x6b, 0x83, 0xb3,
|
||||
0x99, 0x71, 0x20, 0xca, 0xae, 0x50, 0x50, 0x80, 0x93, 0x01, 0xf2, 0x7a, 0xcd, 0x96, 0xd2, 0x61,
|
||||
0x77, 0xb4, 0xc3, 0x33, 0x33, 0x14, 0xd2, 0x21, 0x62, 0x0f, 0x8b, 0xfb, 0x59, 0x2e, 0x6c, 0x5f,
|
||||
0x55, 0x1f, 0x7b, 0x21, 0xad, 0x1d, 0xe8, 0x0c, 0x37, 0x17, 0x65, 0x57, 0x0e, 0xec, 0xae, 0x9c,
|
||||
0xd9, 0x2a, 0xfd, 0x40, 0x17, 0x5f, 0x4e, 0x6c, 0x9f, 0x3a, 0x90, 0x01, 0x7a, 0xf0, 0x7e, 0x04,
|
||||
0x3e, 0xb0, 0x6d, 0x1a, 0xff, 0x62, 0x99, 0xdc, 0x26, 0x77, 0x2f, 0xae, 0x6f, 0xf2, 0x7f, 0x50,
|
||||
0x1e, 0xa1, 0x58, 0x6c, 0x67, 0x39, 0xb7, 0x7d, 0xc5, 0x2b, 0x28, 0x3f, 0x02, 0xe5, 0x11, 0xca,
|
||||
0x1f, 0x5b, 0x5b, 0x43, 0x7a, 0x71, 0xd7, 0x34, 0xa5, 0x97, 0xea, 0xb1, 0x57, 0x23, 0x70, 0xfb,
|
||||
0x8c, 0xd1, 0x85, 0x42, 0x0e, 0x01, 0x69, 0x17, 0x7a, 0x58, 0x1f, 0x91, 0x7b, 0x63, 0xf3, 0xd3,
|
||||
0x94, 0xbb, 0x4a, 0x2f, 0x6f, 0x0e, 0x6d, 0xd8, 0xef, 0x81, 0xb7, 0xa6, 0xf0, 0xb0, 0xfe, 0xed,
|
||||
0x1c, 0xbd, 0x52, 0xaf, 0x7a, 0x0d, 0xae, 0xd4, 0x19, 0xb0, 0xcf, 0x84, 0xb6, 0x26, 0x3d, 0x63,
|
||||
0x6b, 0x3c, 0x06, 0xe0, 0xa4, 0x5e, 0x26, 0xcd, 0xd8, 0xa5, 0x2b, 0x87, 0x3f, 0x7f, 0x7f, 0x39,
|
||||
0xb3, 0x94, 0x5e, 0xc3, 0x6c, 0x94, 0xdd, 0x98, 0x3a, 0xff, 0x88, 0x74, 0xd8, 0x21, 0xa1, 0x0b,
|
||||
0x2f, 0xb4, 0x0f, 0x6c, 0xe9, 0xb8, 0x0b, 0xb6, 0x37, 0xd9, 0x6a, 0xc4, 0xa1, 0x22, 0xa4, 0xcb,
|
||||
0xe8, 0xc1, 0xd8, 0x8c, 0x07, 0xfb, 0x44, 0xe8, 0xd9, 0xe7, 0x30, 0xd7, 0xa1, 0xa1, 0x3e, 0xdc,
|
||||
0x42, 0xfe, 0x4d, 0x76, 0xe3, 0x38, 0x5f, 0x1c, 0x54, 0xa9, 0xf9, 0xc8, 0xbe, 0x12, 0xda, 0x9a,
|
||||
0x04, 0x66, 0xf6, 0x64, 0xa6, 0x82, 0xd4, 0x94, 0xd1, 0x43, 0x34, 0xea, 0x26, 0xf7, 0xa2, 0x91,
|
||||
0x03, 0x6b, 0xbc, 0x0e, 0xc6, 0x69, 0xf0, 0xe2, 0x20, 0x2a, 0x0c, 0x21, 0xc8, 0x5c, 0x06, 0xc9,
|
||||
0x51, 0xb3, 0x3a, 0xb5, 0x77, 0xb4, 0xf5, 0x0c, 0x06, 0x10, 0x60, 0x5e, 0xcb, 0xae, 0xff, 0x1d,
|
||||
0x9e, 0xca, 0x63, 0x7a, 0x07, 0x89, 0x6b, 0x9d, 0x95, 0x93, 0x89, 0x08, 0x78, 0xb2, 0xf1, 0x7d,
|
||||
0xdc, 0x26, 0x3f, 0xc6, 0x6d, 0xf2, 0x6b, 0xdc, 0x26, 0x6f, 0x3b, 0xff, 0xbb, 0x34, 0xa6, 0xef,
|
||||
0xb3, 0x9d, 0x16, 0x5e, 0x0e, 0x0f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x95, 0xb1, 0xb7, 0x37,
|
||||
0xe8, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -336,9 +336,9 @@ var (
|
||||
|
||||
pattern_ProjectService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "projects", "name"}, ""))
|
||||
|
||||
pattern_ProjectService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "projects", "project.metadata.name"}, ""))
|
||||
pattern_ProjectService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "project.metadata.name"}, ""))
|
||||
|
||||
pattern_ProjectService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "projects", "name"}, ""))
|
||||
pattern_ProjectService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "name"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -9,7 +9,6 @@ package project;
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto";
|
||||
|
||||
|
||||
@@ -53,13 +52,13 @@ service ProjectService {
|
||||
// Update updates a project
|
||||
rpc Update(ProjectUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.AppProject) {
|
||||
option (google.api.http) = {
|
||||
put: "/api/v1/projects/{project.metadata.name}"
|
||||
put: "/api/v1/repositories/{project.metadata.name}"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// Delete deletes a project
|
||||
rpc Delete(ProjectQuery) returns (EmptyResponse) {
|
||||
option (google.api.http).delete = "/api/v1/projects/{name}";
|
||||
option (google.api.http).delete = "/api/v1/repositories/{name}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func TestProjectServer(t *testing.T) {
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns3", Server: "https://server3"}},
|
||||
}
|
||||
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
|
||||
updatedProj := existingProj.DeepCopy()
|
||||
updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
|
||||
@@ -55,7 +55,7 @@ func TestProjectServer(t *testing.T) {
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns1", Server: "https://server1"}},
|
||||
}
|
||||
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
|
||||
updatedProj := existingProj.DeepCopy()
|
||||
updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
|
||||
@@ -72,7 +72,7 @@ func TestProjectServer(t *testing.T) {
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "test"},
|
||||
}
|
||||
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
|
||||
updatedProj := existingProj.DeepCopy()
|
||||
updatedProj.Spec.SourceRepos = []string{}
|
||||
@@ -88,7 +88,7 @@ func TestProjectServer(t *testing.T) {
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "test", Source: v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argo-cd.git"}},
|
||||
}
|
||||
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
|
||||
updatedProj := existingProj.DeepCopy()
|
||||
updatedProj.Spec.SourceRepos = []string{}
|
||||
@@ -100,7 +100,7 @@ func TestProjectServer(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("TestDeleteProjectSuccessful", func(t *testing.T) {
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj), enforcer, util.NewKeyLock())
|
||||
|
||||
_, err := projectServer.Delete(context.Background(), &ProjectQuery{Name: "test"})
|
||||
|
||||
@@ -113,7 +113,7 @@ func TestProjectServer(t *testing.T) {
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "test"},
|
||||
}
|
||||
|
||||
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
projectServer := NewServer("default", apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
|
||||
|
||||
_, err := projectServer.Delete(context.Background(), &ProjectQuery{Name: "test"})
|
||||
|
||||
|
||||
150
server/repository/mocks/RepositoryServiceServer.go
Normal file
150
server/repository/mocks/RepositoryServiceServer.go
Normal file
@@ -0,0 +1,150 @@
|
||||
// Code generated by mockery v1.0.0
|
||||
package mocks
|
||||
|
||||
import context "context"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import repository "github.com/argoproj/argo-cd/server/repository"
|
||||
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
// RepositoryServiceServer is an autogenerated mock type for the RepositoryServiceServer type
|
||||
type RepositoryServiceServer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Create(_a0 context.Context, _a1 *repository.RepoCreateRequest) (*v1alpha1.Repository, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoCreateRequest) *v1alpha1.Repository); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoCreateRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Delete(_a0 context.Context, _a1 *repository.RepoQuery) (*repository.RepoResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *repository.RepoResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoQuery) *repository.RepoResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*repository.RepoResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Get(_a0 context.Context, _a1 *repository.RepoQuery) (*v1alpha1.Repository, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoQuery) *v1alpha1.Repository); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) List(_a0 context.Context, _a1 *repository.RepoQuery) (*v1alpha1.RepositoryList, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.RepositoryList
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoQuery) *v1alpha1.RepositoryList); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.RepositoryList)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListKsonnetApps provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) ListKsonnetApps(_a0 context.Context, _a1 *repository.RepoKsonnetQuery) (*repository.RepoKsonnetResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *repository.RepoKsonnetResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoKsonnetQuery) *repository.RepoKsonnetResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*repository.RepoKsonnetResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoKsonnetQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Update(_a0 context.Context, _a1 *repository.RepoUpdateRequest) (*v1alpha1.Repository, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoUpdateRequest) *v1alpha1.Repository); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoUpdateRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"path"
|
||||
"reflect"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -55,7 +54,7 @@ func (s *Server) List(ctx context.Context, q *RepoQuery) (*appsv1.RepositoryList
|
||||
}
|
||||
|
||||
// ListKsonnetApps returns list of Ksonnet apps in the repo
|
||||
func (s *Server) ListApps(ctx context.Context, q *RepoAppsQuery) (*RepoAppsResponse, error) {
|
||||
func (s *Server) ListKsonnetApps(ctx context.Context, q *RepoKsonnetQuery) (*RepoKsonnetResponse, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories/apps", "get", q.Repo) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
@@ -76,96 +75,39 @@ func (s *Server) ListApps(ctx context.Context, q *RepoAppsQuery) (*RepoAppsRespo
|
||||
revision = "HEAD"
|
||||
}
|
||||
|
||||
ksonnetRes, err := repoClient.ListDir(ctx, &repository.ListDirRequest{Repo: repo, Revision: revision, Path: "*app.yaml"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
helmRes, err := repoClient.ListDir(ctx, &repository.ListDirRequest{Repo: repo, Revision: revision, Path: "*Chart.yaml"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]*AppInfo, 0)
|
||||
|
||||
for i := range ksonnetRes.Items {
|
||||
items = append(items, &AppInfo{Type: string(repository.AppSourceKsonnet), Path: ksonnetRes.Items[i]})
|
||||
}
|
||||
|
||||
for i := range helmRes.Items {
|
||||
items = append(items, &AppInfo{Type: string(repository.AppSourceHelm), Path: helmRes.Items[i]})
|
||||
}
|
||||
|
||||
return &RepoAppsResponse{Items: items}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetAppDetails(ctx context.Context, q *RepoAppDetailsQuery) (*RepoAppDetailsResponse, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories/apps", "get", q.Repo) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
repo, err := s.db.GetRepository(ctx, q.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Test the repo
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
|
||||
revision := q.Revision
|
||||
if revision == "" {
|
||||
revision = "HEAD"
|
||||
}
|
||||
|
||||
appSpecRes, err := repoClient.GetFile(ctx, &repository.GetFileRequest{
|
||||
// Verify app.yaml is functional
|
||||
req := repository.ListDirRequest{
|
||||
Repo: repo,
|
||||
Revision: revision,
|
||||
Path: q.Path,
|
||||
})
|
||||
Path: "*app.yaml",
|
||||
}
|
||||
getRes, err := repoClient.ListDir(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appSourceType := repository.IdentifyAppSourceTypeByAppPath(q.Path)
|
||||
switch appSourceType {
|
||||
case repository.AppSourceKsonnet:
|
||||
var appSpec KsonnetAppSpec
|
||||
appSpec.Path = q.Path
|
||||
err = yaml.Unmarshal(appSpecRes.Data, &appSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RepoAppDetailsResponse{
|
||||
Type: string(appSourceType),
|
||||
Ksonnet: &appSpec,
|
||||
}, nil
|
||||
case repository.AppSourceHelm:
|
||||
var appSpec HelmAppSpec
|
||||
appSpec.Path = q.Path
|
||||
err = yaml.Unmarshal(appSpecRes.Data, &appSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valuesFilesRes, err := repoClient.ListDir(ctx, &repository.ListDirRequest{
|
||||
Revision: revision,
|
||||
out := make([]*KsonnetAppSpec, 0)
|
||||
for _, path := range getRes.Items {
|
||||
getFileRes, err := repoClient.GetFile(ctx, &repository.GetFileRequest{
|
||||
Repo: repo,
|
||||
Path: path.Join(path.Dir(q.Path), "*values*.yaml"),
|
||||
Revision: revision,
|
||||
Path: path,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appSpec.ValueFiles = valuesFilesRes.Items
|
||||
return &RepoAppDetailsResponse{
|
||||
Type: string(appSourceType),
|
||||
Helm: &appSpec,
|
||||
}, nil
|
||||
|
||||
var appSpec KsonnetAppSpec
|
||||
appSpec.Path = path
|
||||
err = yaml.Unmarshal(getFileRes.Data, &appSpec)
|
||||
if err == nil && appSpec.Name != "" && len(appSpec.Environments) > 0 {
|
||||
out = append(out, &appSpec)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, status.Errorf(codes.InvalidArgument, "specified application path is not supported")
|
||||
return &RepoKsonnetResponse{
|
||||
Items: out,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create creates a repository
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,11 +46,11 @@ func request_RepositoryService_List_0(ctx context.Context, marshaler runtime.Mar
|
||||
}
|
||||
|
||||
var (
|
||||
filter_RepositoryService_ListApps_0 = &utilities.DoubleArray{Encoding: map[string]int{"repo": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
filter_RepositoryService_ListKsonnetApps_0 = &utilities.DoubleArray{Encoding: map[string]int{"repo": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_RepositoryService_ListApps_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoAppsQuery
|
||||
func request_RepositoryService_ListKsonnetApps_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoKsonnetQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
@@ -71,57 +71,11 @@ func request_RepositoryService_ListApps_0(ctx context.Context, marshaler runtime
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "repo", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_RepositoryService_ListApps_0); err != nil {
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_RepositoryService_ListKsonnetApps_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListApps(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_RepositoryService_GetAppDetails_0 = &utilities.DoubleArray{Encoding: map[string]int{"repo": 0, "path": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
|
||||
)
|
||||
|
||||
func request_RepositoryService_GetAppDetails_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoAppDetailsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["repo"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "repo")
|
||||
}
|
||||
|
||||
protoReq.Repo, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "repo", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["path"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "path")
|
||||
}
|
||||
|
||||
protoReq.Path, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "path", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_RepositoryService_GetAppDetails_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetAppDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
msg, err := client.ListKsonnetApps(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
@@ -299,7 +253,7 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_RepositoryService_ListApps_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("GET", pattern_RepositoryService_ListKsonnetApps_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
@@ -317,43 +271,14 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_RepositoryService_ListApps_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
resp, md, err := request_RepositoryService_ListKsonnetApps_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_RepositoryService_ListApps_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_RepositoryService_GetAppDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_RepositoryService_GetAppDetails_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_RepositoryService_GetAppDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_RepositoryService_ListKsonnetApps_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
@@ -479,9 +404,7 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
var (
|
||||
pattern_RepositoryService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "repositories"}, ""))
|
||||
|
||||
pattern_RepositoryService_ListApps_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "repositories", "repo", "apps"}, ""))
|
||||
|
||||
pattern_RepositoryService_GetAppDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "repositories", "repo", "apps", "path"}, ""))
|
||||
pattern_RepositoryService_ListKsonnetApps_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "repositories", "repo", "ksonnet"}, ""))
|
||||
|
||||
pattern_RepositoryService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "repositories"}, ""))
|
||||
|
||||
@@ -495,9 +418,7 @@ var (
|
||||
var (
|
||||
forward_RepositoryService_List_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_ListApps_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_GetAppDetails_0 = runtime.ForwardResponseMessage
|
||||
forward_RepositoryService_ListKsonnetApps_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_Create_0 = runtime.ForwardResponseMessage
|
||||
|
||||
|
||||
@@ -11,36 +11,15 @@ import "google/api/annotations.proto";
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto";
|
||||
|
||||
// RepoAppsQuery is a query for Repository apps
|
||||
message RepoAppsQuery {
|
||||
// RepoKsonnetQuery is a query for Repository contents matching a particular path
|
||||
message RepoKsonnetQuery {
|
||||
string repo = 1;
|
||||
string revision = 2;
|
||||
}
|
||||
|
||||
|
||||
// AppInfo contains application type and app file path
|
||||
message AppInfo {
|
||||
string type = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
// RepoAppDetailsQuery contains query information for app details request
|
||||
message RepoAppDetailsQuery {
|
||||
string repo = 1;
|
||||
string revision = 2;
|
||||
string path = 3;
|
||||
}
|
||||
|
||||
// RepoAppDetailsResponse application details
|
||||
message RepoAppDetailsResponse {
|
||||
string type = 1;
|
||||
KsonnetAppSpec ksonnet = 2;
|
||||
HelmAppSpec helm = 3;
|
||||
}
|
||||
|
||||
// RepoAppsResponse contains applications of specified repository
|
||||
message RepoAppsResponse {
|
||||
repeated AppInfo items = 1;
|
||||
// RepoKsonnetResponse is a response for Repository contents matching a particular path
|
||||
message RepoKsonnetResponse {
|
||||
repeated KsonnetAppSpec items = 1;
|
||||
}
|
||||
|
||||
// KsonnetAppSpec contains Ksonnet app response
|
||||
@@ -51,13 +30,6 @@ message KsonnetAppSpec {
|
||||
map<string, KsonnetEnvironment> environments = 3;
|
||||
}
|
||||
|
||||
// HelmAppSpec contains helm app name and path in source repo
|
||||
message HelmAppSpec {
|
||||
string name = 1;
|
||||
string path = 2;
|
||||
repeated string valueFiles = 3;
|
||||
}
|
||||
|
||||
message KsonnetEnvironment {
|
||||
// Name is the user defined name of an environment
|
||||
string name = 1;
|
||||
@@ -100,14 +72,9 @@ service RepositoryService {
|
||||
option (google.api.http).get = "/api/v1/repositories";
|
||||
}
|
||||
|
||||
// ListApps returns list of apps in the repo
|
||||
rpc ListApps(RepoAppsQuery) returns (RepoAppsResponse) {
|
||||
option (google.api.http).get = "/api/v1/repositories/{repo}/apps";
|
||||
}
|
||||
|
||||
// GetAppDetails returns application details by given path
|
||||
rpc GetAppDetails(RepoAppDetailsQuery) returns (RepoAppDetailsResponse) {
|
||||
option (google.api.http).get = "/api/v1/repositories/{repo}/apps/{path}";
|
||||
// ListKsonnetApps returns list of Ksonnet apps in the repo
|
||||
rpc ListKsonnetApps(RepoKsonnetQuery) returns (RepoKsonnetResponse) {
|
||||
option (google.api.http).get = "/api/v1/repositories/{repo}/ksonnet";
|
||||
}
|
||||
|
||||
// Create creates a repo
|
||||
|
||||
@@ -8,15 +8,14 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gobuffalo/packr"
|
||||
golang_proto "github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/soheilhy/cmux"
|
||||
@@ -29,9 +28,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/argoproj/argo-cd"
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
@@ -55,7 +55,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/swagger"
|
||||
tlsutil "github.com/argoproj/argo-cd/util/tls"
|
||||
"github.com/argoproj/argo-cd/util/webhook"
|
||||
netCtx "golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -300,18 +299,11 @@ func (a *ArgoCDServer) useTLS() bool {
|
||||
|
||||
func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
var sOpts []grpc.ServerOption
|
||||
sensitiveMethods := map[string]bool{
|
||||
"/session.SessionService/Create": true,
|
||||
"/account.AccountService/UpdatePassword": true,
|
||||
}
|
||||
// NOTE: notice we do not configure the gRPC server here with TLS (e.g. grpc.Creds(creds))
|
||||
// This is because TLS handshaking occurs in cmux handling
|
||||
sOpts = append(sOpts, grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_logrus.StreamServerInterceptor(a.log),
|
||||
grpc_auth.StreamServerInterceptor(a.authenticate),
|
||||
grpc_util.PayloadStreamServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool {
|
||||
return !sensitiveMethods[fullMethodName]
|
||||
}),
|
||||
grpc_util.ErrorCodeStreamServerInterceptor(),
|
||||
grpc_util.PanicLoggerStreamServerInterceptor(a.log),
|
||||
)))
|
||||
@@ -319,9 +311,6 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
bug21955WorkaroundInterceptor,
|
||||
grpc_logrus.UnaryServerInterceptor(a.log),
|
||||
grpc_auth.UnaryServerInterceptor(a.authenticate),
|
||||
grpc_util.PayloadUnaryServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool {
|
||||
return !sensitiveMethods[fullMethodName]
|
||||
}),
|
||||
grpc_util.ErrorCodeUnaryServerInterceptor(),
|
||||
grpc_util.PanicLoggerUnaryServerInterceptor(a.log),
|
||||
)))
|
||||
@@ -333,7 +322,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
sessionService := session.NewServer(a.sessionMgr)
|
||||
projectLock := util.NewKeyLock()
|
||||
applicationService := application.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.RepoClientset, db, a.enf, projectLock)
|
||||
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock)
|
||||
projectService := project.NewServer(a.Namespace, a.AppClientset, a.enf, projectLock)
|
||||
settingsService := settings.NewServer(a.settingsMgr)
|
||||
accountService := account.NewServer(a.sessionMgr, a.settingsMgr)
|
||||
version.RegisterVersionServiceServer(grpcS, &version.Server{})
|
||||
@@ -503,6 +492,11 @@ func getToken(md metadata.MD) string {
|
||||
if ok && len(tokens) > 0 {
|
||||
return tokens[0]
|
||||
}
|
||||
// check the legacy key (v0.3.2 and below). 'tokens' was renamed to 'token'
|
||||
tokens, ok = md["tokens"]
|
||||
if ok && len(tokens) > 0 {
|
||||
return tokens[0]
|
||||
}
|
||||
// check the HTTP cookie
|
||||
for _, cookieToken := range md["grpcgateway-cookie"] {
|
||||
header := http.Header{}
|
||||
@@ -521,17 +515,22 @@ type bug21955Workaround struct {
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
var pathPatters = []*regexp.Regexp{
|
||||
regexp.MustCompile(`/api/v1/clusters/[^/]+`),
|
||||
regexp.MustCompile(`/api/v1/repositories/[^/]+`),
|
||||
regexp.MustCompile(`/api/v1/repositories/[^/]+/apps`),
|
||||
regexp.MustCompile(`/api/v1/repositories/[^/]+/apps/[^/]+`),
|
||||
}
|
||||
|
||||
func (bf *bug21955Workaround) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
for _, pattern := range pathPatters {
|
||||
if pattern.MatchString(r.URL.RawPath) {
|
||||
r.URL.Path = r.URL.RawPath
|
||||
paths := map[string][]string{
|
||||
"/api/v1/repositories/": {"ksonnet"},
|
||||
"/api/v1/clusters/": {},
|
||||
}
|
||||
for path, subPaths := range paths {
|
||||
if strings.Index(r.URL.Path, path) > -1 {
|
||||
postfix := ""
|
||||
for _, subPath := range subPaths {
|
||||
if strings.LastIndex(r.URL.Path, subPath) == len(r.URL.Path)-len(subPath) {
|
||||
postfix = "/" + subPath
|
||||
r.URL.Path = r.URL.Path[0 : len(r.URL.Path)-len(subPath)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
r.URL.Path = path + url.QueryEscape(r.URL.Path[len(path):]) + postfix
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -545,23 +544,12 @@ func bug21955WorkaroundInterceptor(ctx context.Context, req interface{}, _ *grpc
|
||||
return nil, err
|
||||
}
|
||||
rq.Repo = repo
|
||||
} else if rk, ok := req.(*repository.RepoAppsQuery); ok {
|
||||
} else if rk, ok := req.(*repository.RepoKsonnetQuery); ok {
|
||||
repo, err := url.QueryUnescape(rk.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rk.Repo = repo
|
||||
} else if rdq, ok := req.(*repository.RepoAppDetailsQuery); ok {
|
||||
repo, err := url.QueryUnescape(rdq.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path, err := url.QueryUnescape(rdq.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rdq.Repo = repo
|
||||
rdq.Path = path
|
||||
} else if ru, ok := req.(*repository.RepoUpdateRequest); ok {
|
||||
repo, err := url.QueryUnescape(ru.Repo.Repo)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,10 +2,12 @@ package session
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/argoproj/argo-cd/util/jwt"
|
||||
sessionmgr "github.com/argoproj/argo-cd/util/session"
|
||||
)
|
||||
|
||||
@@ -21,23 +23,40 @@ func NewServer(mgr *sessionmgr.SessionManager) *Server {
|
||||
}
|
||||
}
|
||||
|
||||
// Create generates a JWT token signed by ArgoCD intended for web/CLI logins of the admin user
|
||||
// using username/password
|
||||
// Create generates a non-expiring JWT token signed by ArgoCD. This endpoint is used in two circumstances:
|
||||
// 1. Web/CLI logins for local users (i.e. admin), for when SSO is not configured. In this case,
|
||||
// username/password.
|
||||
// 2. CLI login which completed an OAuth2 login flow but wish to store a permanent token in their config
|
||||
func (s *Server) Create(ctx context.Context, q *SessionCreateRequest) (*SessionResponse, error) {
|
||||
if q.Token != "" {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "token-based session creation no longer supported. please upgrade argocd cli to v0.7+")
|
||||
}
|
||||
if q.Username == "" || q.Password == "" {
|
||||
var tokenString string
|
||||
var err error
|
||||
if q.Password != "" {
|
||||
// first case
|
||||
err = s.mgr.VerifyUsernamePassword(q.Username, q.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, err = s.mgr.Create(q.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if q.Token != "" {
|
||||
// second case
|
||||
claimsIf, err := s.mgr.VerifyToken(q.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
claims, err := jwt.MapClaims(claimsIf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, err = s.mgr.ReissueClaims(claims)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to resign claims: %v", err)
|
||||
}
|
||||
} else {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "no credentials supplied")
|
||||
}
|
||||
err := s.mgr.VerifyUsernamePassword(q.Username, q.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, err := s.mgr.Create(q.Username, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SessionResponse{Token: tokenString}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -691,62 +691,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"ProjectService"
|
||||
],
|
||||
"summary": "Delete deletes a project",
|
||||
"operationId": "DeleteMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/projectEmptyResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/projects/{project.metadata.name}": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"ProjectService"
|
||||
],
|
||||
"summary": "Update updates a project",
|
||||
"operationId": "UpdateMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project.metadata.name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/projectProjectUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1alpha1AppProject"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories": {
|
||||
@@ -798,6 +742,64 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories/{name}": {
|
||||
"delete": {
|
||||
"tags": [
|
||||
"ProjectService"
|
||||
],
|
||||
"summary": "Delete deletes a project",
|
||||
"operationId": "DeleteMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/projectEmptyResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories/{project.metadata.name}": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"ProjectService"
|
||||
],
|
||||
"summary": "Update updates a project",
|
||||
"operationId": "UpdateMixin3",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "project.metadata.name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/projectProjectUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1alpha1AppProject"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories/{repo.repo}": {
|
||||
"put": {
|
||||
"tags": [
|
||||
@@ -879,13 +881,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories/{repo}/apps": {
|
||||
"/api/v1/repositories/{repo}/ksonnet": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"RepositoryService"
|
||||
],
|
||||
"summary": "ListApps returns list of apps in the repo",
|
||||
"operationId": "ListApps",
|
||||
"summary": "ListKsonnetApps returns list of Ksonnet apps in the repo",
|
||||
"operationId": "ListKsonnetApps",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
@@ -903,43 +905,7 @@
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/repositoryRepoAppsResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/repositories/{repo}/apps/{path}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"RepositoryService"
|
||||
],
|
||||
"summary": "GetAppDetails returns application details by given path",
|
||||
"operationId": "GetAppDetails",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "repo",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "path",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "revision",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/repositoryRepoAppDetailsResponse"
|
||||
"$ref": "#/definitions/repositoryRepoKsonnetResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1272,36 +1238,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositoryAppInfo": {
|
||||
"type": "object",
|
||||
"title": "AppInfo contains application type and app file path",
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositoryHelmAppSpec": {
|
||||
"type": "object",
|
||||
"title": "HelmAppSpec contains helm app name and path in source repo",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"valueFiles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositoryKsonnetAppSpec": {
|
||||
"type": "object",
|
||||
"title": "KsonnetAppSpec contains Ksonnet app response\nThis roughly reflects: ksonnet/ksonnet/metadata/app/schema.go",
|
||||
@@ -1379,29 +1315,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositoryRepoAppDetailsResponse": {
|
||||
"repositoryRepoKsonnetResponse": {
|
||||
"type": "object",
|
||||
"title": "RepoAppDetailsResponse application details",
|
||||
"properties": {
|
||||
"helm": {
|
||||
"$ref": "#/definitions/repositoryHelmAppSpec"
|
||||
},
|
||||
"ksonnet": {
|
||||
"$ref": "#/definitions/repositoryKsonnetAppSpec"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repositoryRepoAppsResponse": {
|
||||
"type": "object",
|
||||
"title": "RepoAppsResponse contains applications of specified repository",
|
||||
"title": "RepoKsonnetResponse is a response for Repository contents matching a particular path",
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/repositoryAppInfo"
|
||||
"$ref": "#/definitions/repositoryKsonnetAppSpec"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1805,7 +1726,7 @@
|
||||
"$ref": "#/definitions/v1alpha1ApplicationDestination"
|
||||
}
|
||||
},
|
||||
"sourceRepos": {
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"title": "SourceRepos contains list of git repository URLs which can be used for deployment",
|
||||
"items": {
|
||||
@@ -1881,33 +1802,26 @@
|
||||
"properties": {
|
||||
"componentParameterOverrides": {
|
||||
"type": "array",
|
||||
"title": "ComponentParameterOverrides are a list of parameter override values",
|
||||
"title": "Environment parameter override values",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1alpha1ComponentParameter"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"title": "Environment is a ksonnet application environment name"
|
||||
"description": "Environment is a ksonnet application environment name.",
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"title": "Path is a directory path within the repository containing a"
|
||||
"description": "Path is a directory path within repository which contains ksonnet application.",
|
||||
"type": "string"
|
||||
},
|
||||
"repoURL": {
|
||||
"type": "string",
|
||||
"title": "RepoURL is the git repository URL of the application manifests"
|
||||
"description": "RepoURL is the repository URL containing the ksonnet application.",
|
||||
"type": "string"
|
||||
},
|
||||
"targetRevision": {
|
||||
"type": "string",
|
||||
"title": "TargetRevision defines the commit, tag, or branch in which to sync the application to.\nIf omitted, will sync to HEAD"
|
||||
},
|
||||
"valuesFiles": {
|
||||
"type": "array",
|
||||
"title": "ValuesFiles is a list of Helm values files to use when generating a template",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2431,9 +2345,6 @@
|
||||
"GoVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"KsonnetVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"Platform": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,6 @@ package version
|
||||
|
||||
import (
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
ksutil "github.com/argoproj/argo-cd/util/ksonnet"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@@ -12,20 +11,15 @@ type Server struct{}
|
||||
// Version returns the version of the API server
|
||||
func (s *Server) Version(context.Context, *empty.Empty) (*VersionMessage, error) {
|
||||
vers := argocd.GetVersion()
|
||||
ksonnetVersion, err := ksutil.KsonnetVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &VersionMessage{
|
||||
Version: vers.Version,
|
||||
BuildDate: vers.BuildDate,
|
||||
GitCommit: vers.GitCommit,
|
||||
GitTag: vers.GitTag,
|
||||
GitTreeState: vers.GitTreeState,
|
||||
GoVersion: vers.GoVersion,
|
||||
Compiler: vers.Compiler,
|
||||
Platform: vers.Platform,
|
||||
KsonnetVersion: ksonnetVersion,
|
||||
Version: vers.Version,
|
||||
BuildDate: vers.BuildDate,
|
||||
GitCommit: vers.GitCommit,
|
||||
GitTag: vers.GitTag,
|
||||
GitTreeState: vers.GitTreeState,
|
||||
GoVersion: vers.GoVersion,
|
||||
Compiler: vers.Compiler,
|
||||
Platform: vers.Platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -40,15 +40,14 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// VersionMessage represents version of the ArgoCD API server
|
||||
type VersionMessage struct {
|
||||
Version string `protobuf:"bytes,1,opt,name=Version,proto3" json:"Version,omitempty"`
|
||||
BuildDate string `protobuf:"bytes,2,opt,name=BuildDate,proto3" json:"BuildDate,omitempty"`
|
||||
GitCommit string `protobuf:"bytes,3,opt,name=GitCommit,proto3" json:"GitCommit,omitempty"`
|
||||
GitTag string `protobuf:"bytes,4,opt,name=GitTag,proto3" json:"GitTag,omitempty"`
|
||||
GitTreeState string `protobuf:"bytes,5,opt,name=GitTreeState,proto3" json:"GitTreeState,omitempty"`
|
||||
GoVersion string `protobuf:"bytes,6,opt,name=GoVersion,proto3" json:"GoVersion,omitempty"`
|
||||
Compiler string `protobuf:"bytes,7,opt,name=Compiler,proto3" json:"Compiler,omitempty"`
|
||||
Platform string `protobuf:"bytes,8,opt,name=Platform,proto3" json:"Platform,omitempty"`
|
||||
KsonnetVersion string `protobuf:"bytes,9,opt,name=KsonnetVersion,proto3" json:"KsonnetVersion,omitempty"`
|
||||
Version string `protobuf:"bytes,1,opt,name=Version,proto3" json:"Version,omitempty"`
|
||||
BuildDate string `protobuf:"bytes,2,opt,name=BuildDate,proto3" json:"BuildDate,omitempty"`
|
||||
GitCommit string `protobuf:"bytes,3,opt,name=GitCommit,proto3" json:"GitCommit,omitempty"`
|
||||
GitTag string `protobuf:"bytes,4,opt,name=GitTag,proto3" json:"GitTag,omitempty"`
|
||||
GitTreeState string `protobuf:"bytes,5,opt,name=GitTreeState,proto3" json:"GitTreeState,omitempty"`
|
||||
GoVersion string `protobuf:"bytes,6,opt,name=GoVersion,proto3" json:"GoVersion,omitempty"`
|
||||
Compiler string `protobuf:"bytes,7,opt,name=Compiler,proto3" json:"Compiler,omitempty"`
|
||||
Platform string `protobuf:"bytes,8,opt,name=Platform,proto3" json:"Platform,omitempty"`
|
||||
}
|
||||
|
||||
func (m *VersionMessage) Reset() { *m = VersionMessage{} }
|
||||
@@ -112,13 +111,6 @@ func (m *VersionMessage) GetPlatform() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *VersionMessage) GetKsonnetVersion() string {
|
||||
if m != nil {
|
||||
return m.KsonnetVersion
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*VersionMessage)(nil), "version.VersionMessage")
|
||||
}
|
||||
@@ -260,12 +252,6 @@ func (m *VersionMessage) MarshalTo(dAtA []byte) (int, error) {
|
||||
i = encodeVarintVersion(dAtA, i, uint64(len(m.Platform)))
|
||||
i += copy(dAtA[i:], m.Platform)
|
||||
}
|
||||
if len(m.KsonnetVersion) > 0 {
|
||||
dAtA[i] = 0x4a
|
||||
i++
|
||||
i = encodeVarintVersion(dAtA, i, uint64(len(m.KsonnetVersion)))
|
||||
i += copy(dAtA[i:], m.KsonnetVersion)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -313,10 +299,6 @@ func (m *VersionMessage) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovVersion(uint64(l))
|
||||
}
|
||||
l = len(m.KsonnetVersion)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovVersion(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -594,35 +576,6 @@ func (m *VersionMessage) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.Platform = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 9:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field KsonnetVersion", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowVersion
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthVersion
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.KsonnetVersion = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipVersion(dAtA[iNdEx:])
|
||||
@@ -752,27 +705,26 @@ var (
|
||||
func init() { proto.RegisterFile("server/version/version.proto", fileDescriptorVersion) }
|
||||
|
||||
var fileDescriptorVersion = []byte{
|
||||
// 343 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xcf, 0x4a, 0xc3, 0x40,
|
||||
0x10, 0xc6, 0x49, 0xd5, 0xfe, 0x59, 0x4a, 0x0f, 0x8b, 0xd4, 0x25, 0x96, 0x22, 0x3d, 0x88, 0x08,
|
||||
0x26, 0xa0, 0x17, 0xcf, 0xad, 0xd2, 0x83, 0x08, 0xc5, 0x8a, 0x07, 0x6f, 0x9b, 0x76, 0x1a, 0x57,
|
||||
0x92, 0x4c, 0xd8, 0x4c, 0x0b, 0x5e, 0x7d, 0x05, 0x5f, 0xc0, 0xc7, 0xf1, 0x28, 0xf8, 0x02, 0x52,
|
||||
0x7c, 0x10, 0xc9, 0x26, 0x1b, 0x89, 0xa7, 0xcc, 0xf7, 0xfd, 0x86, 0x2f, 0xe1, 0x9b, 0xb0, 0x41,
|
||||
0x06, 0x7a, 0x03, 0xda, 0xdf, 0x80, 0xce, 0x14, 0x26, 0xf6, 0xe9, 0xa5, 0x1a, 0x09, 0x79, 0xab,
|
||||
0x94, 0xee, 0x20, 0x44, 0x0c, 0x23, 0xf0, 0x65, 0xaa, 0x7c, 0x99, 0x24, 0x48, 0x92, 0x14, 0x26,
|
||||
0x59, 0xb1, 0xe6, 0x1e, 0x96, 0xd4, 0xa8, 0x60, 0xbd, 0xf2, 0x21, 0x4e, 0xe9, 0xa5, 0x80, 0xa3,
|
||||
0xf7, 0x06, 0xeb, 0x3d, 0x14, 0x31, 0xb7, 0x90, 0x65, 0x32, 0x04, 0x2e, 0x58, 0xab, 0x74, 0x84,
|
||||
0x73, 0xe4, 0x9c, 0x74, 0xee, 0xac, 0xe4, 0x03, 0xd6, 0x19, 0xaf, 0x55, 0xb4, 0xbc, 0x92, 0x04,
|
||||
0xa2, 0x61, 0xd8, 0x9f, 0x91, 0xd3, 0xa9, 0xa2, 0x09, 0xc6, 0xb1, 0x22, 0xb1, 0x53, 0xd0, 0xca,
|
||||
0xe0, 0x7d, 0xd6, 0x9c, 0x2a, 0xba, 0x97, 0xa1, 0xd8, 0x35, 0xa8, 0x54, 0x7c, 0xc4, 0xba, 0xf9,
|
||||
0xa4, 0x01, 0xe6, 0x94, 0xc7, 0xee, 0x19, 0x5a, 0xf3, 0x4c, 0x32, 0xda, 0x6f, 0x6a, 0x96, 0xc9,
|
||||
0xd6, 0xe0, 0x2e, 0x6b, 0x4f, 0x30, 0x4e, 0x55, 0x04, 0x5a, 0xb4, 0x0c, 0xac, 0x74, 0xce, 0x66,
|
||||
0x91, 0xa4, 0x15, 0xea, 0x58, 0xb4, 0x0b, 0x66, 0x35, 0x3f, 0x66, 0xbd, 0x9b, 0x0c, 0x93, 0x04,
|
||||
0xc8, 0x46, 0x77, 0xcc, 0xc6, 0x3f, 0xf7, 0x3c, 0xa8, 0x1a, 0x9a, 0x83, 0xde, 0xa8, 0x05, 0xf0,
|
||||
0x59, 0xd5, 0x10, 0xef, 0x7b, 0x45, 0xbb, 0x9e, 0x6d, 0xd7, 0xbb, 0xce, 0xdb, 0x75, 0x0f, 0x3c,
|
||||
0x7b, 0xab, 0x7a, 0xbb, 0xa3, 0xfd, 0xd7, 0xaf, 0x9f, 0xb7, 0x46, 0x8f, 0x77, 0xcd, 0xb5, 0xca,
|
||||
0xa5, 0xf1, 0xe5, 0xc7, 0x76, 0xe8, 0x7c, 0x6e, 0x87, 0xce, 0xf7, 0x76, 0xe8, 0x3c, 0x9e, 0x86,
|
||||
0x8a, 0x9e, 0xd6, 0x81, 0xb7, 0xc0, 0xd8, 0x97, 0x3a, 0xc4, 0x54, 0xe3, 0xb3, 0x19, 0xce, 0x16,
|
||||
0x4b, 0xbf, 0xfe, 0x4b, 0x04, 0x4d, 0xf3, 0xe2, 0x8b, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x82,
|
||||
0x85, 0x6d, 0x31, 0x2b, 0x02, 0x00, 0x00,
|
||||
// 327 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x91, 0xcd, 0x4a, 0xfb, 0x40,
|
||||
0x14, 0xc5, 0x49, 0xff, 0x7f, 0xfb, 0x31, 0x94, 0x2e, 0x06, 0xa9, 0x43, 0x2c, 0x45, 0xba, 0x12,
|
||||
0xc1, 0x04, 0x74, 0xe3, 0xba, 0x55, 0xba, 0x12, 0x8a, 0x15, 0x17, 0xee, 0x26, 0xed, 0x6d, 0x1c,
|
||||
0xc9, 0xe4, 0x86, 0xc9, 0xb4, 0xe0, 0xd6, 0x57, 0xf0, 0xa5, 0x5c, 0x0a, 0xbe, 0x80, 0x14, 0x1f,
|
||||
0xc2, 0xa5, 0x64, 0x3e, 0x22, 0x59, 0x65, 0xce, 0xf9, 0x0d, 0x27, 0x73, 0xcf, 0x25, 0xa3, 0x12,
|
||||
0xd4, 0x0e, 0x54, 0xbc, 0x03, 0x55, 0x0a, 0xcc, 0xfd, 0x37, 0x2a, 0x14, 0x6a, 0xa4, 0x1d, 0x27,
|
||||
0xc3, 0x51, 0x8a, 0x98, 0x66, 0x10, 0xf3, 0x42, 0xc4, 0x3c, 0xcf, 0x51, 0x73, 0x2d, 0x30, 0x2f,
|
||||
0xed, 0xb5, 0xf0, 0xd8, 0x51, 0xa3, 0x92, 0xed, 0x26, 0x06, 0x59, 0xe8, 0x17, 0x0b, 0x27, 0x3f,
|
||||
0x01, 0x19, 0x3c, 0xd8, 0x98, 0x5b, 0x28, 0x4b, 0x9e, 0x02, 0x65, 0xa4, 0xe3, 0x1c, 0x16, 0x9c,
|
||||
0x04, 0xa7, 0xbd, 0x3b, 0x2f, 0xe9, 0x88, 0xf4, 0xa6, 0x5b, 0x91, 0xad, 0xaf, 0xb9, 0x06, 0xd6,
|
||||
0x32, 0xec, 0xcf, 0xa8, 0xe8, 0x5c, 0xe8, 0x19, 0x4a, 0x29, 0x34, 0xfb, 0x67, 0x69, 0x6d, 0xd0,
|
||||
0x21, 0x69, 0xcf, 0x85, 0xbe, 0xe7, 0x29, 0xfb, 0x6f, 0x90, 0x53, 0x74, 0x42, 0xfa, 0xd5, 0x49,
|
||||
0x01, 0x2c, 0x75, 0x15, 0x7b, 0x60, 0x68, 0xc3, 0x33, 0xc9, 0xe8, 0xdf, 0xd4, 0x76, 0xc9, 0xde,
|
||||
0xa0, 0x21, 0xe9, 0xce, 0x50, 0x16, 0x22, 0x03, 0xc5, 0x3a, 0x06, 0xd6, 0xba, 0x62, 0x8b, 0x8c,
|
||||
0xeb, 0x0d, 0x2a, 0xc9, 0xba, 0x96, 0x79, 0x7d, 0x91, 0xd4, 0x93, 0x2f, 0x41, 0xed, 0xc4, 0x0a,
|
||||
0xe8, 0xa2, 0x9e, 0x9c, 0x0e, 0x23, 0xdb, 0x5a, 0xe4, 0x5b, 0x8b, 0x6e, 0xaa, 0xd6, 0xc2, 0xa3,
|
||||
0xc8, 0xef, 0xa0, 0xd9, 0xda, 0xe4, 0xf0, 0xf5, 0xf3, 0xfb, 0xad, 0x35, 0xa0, 0x7d, 0xb3, 0x05,
|
||||
0x77, 0x69, 0x7a, 0xf5, 0xbe, 0x1f, 0x07, 0x1f, 0xfb, 0x71, 0xf0, 0xb5, 0x1f, 0x07, 0x8f, 0x67,
|
||||
0xa9, 0xd0, 0x4f, 0xdb, 0x24, 0x5a, 0xa1, 0x8c, 0xb9, 0x4a, 0xb1, 0x50, 0xf8, 0x6c, 0x0e, 0xe7,
|
||||
0xab, 0x75, 0xdc, 0x5c, 0x75, 0xd2, 0x36, 0x3f, 0xbe, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x19,
|
||||
0x01, 0x2c, 0x30, 0x03, 0x02, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ message VersionMessage {
|
||||
string GoVersion = 6;
|
||||
string Compiler = 7;
|
||||
string Platform = 8;
|
||||
string KsonnetVersion = 9;
|
||||
}
|
||||
|
||||
// VersionService returns the version of the API server.
|
||||
|
||||
@@ -11,34 +11,12 @@ import (
|
||||
|
||||
// load the gcp plugin (required to authenticate against GKE clusters).
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
|
||||
"github.com/argoproj/argo-cd/util/argo"
|
||||
// load the oidc plugin (required to authenticate with OpenID Connect).
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||
)
|
||||
|
||||
func TestAppManagement(t *testing.T) {
|
||||
assertAppHasEvent := func(a *v1alpha1.Application, action string, reason string) {
|
||||
list, err := fixture.KubeClient.CoreV1().Events(fixture.Namespace).List(metav1.ListOptions{
|
||||
FieldSelector: fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": a.Name,
|
||||
"involvedObject.uid": string(a.UID),
|
||||
"involvedObject.namespace": fixture.Namespace,
|
||||
}).String(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to get app events %v", err)
|
||||
}
|
||||
for i := range list.Items {
|
||||
event := list.Items[i]
|
||||
if event.Reason == reason && event.Action == action {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("Unable to find event with reason=%s; action=%s", reason, action)
|
||||
}
|
||||
|
||||
testApp := &v1alpha1.Application{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: v1alpha1.ApplicationSource{
|
||||
@@ -74,7 +52,6 @@ func TestAppManagement(t *testing.T) {
|
||||
assert.Equal(t, ".", app.Spec.Source.Path)
|
||||
assert.Equal(t, fixture.Namespace, app.Spec.Destination.Namespace)
|
||||
assert.Equal(t, fixture.Config.Host, app.Spec.Destination.Server)
|
||||
assertAppHasEvent(app, "create", argo.EventReasonResourceCreated)
|
||||
})
|
||||
|
||||
t.Run("TestAppDeletion", func(t *testing.T) {
|
||||
@@ -85,15 +62,10 @@ func TestAppManagement(t *testing.T) {
|
||||
t.Fatalf("Unable to delete app %v", err)
|
||||
}
|
||||
|
||||
a, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.Name, metav1.GetOptions{})
|
||||
_, err = fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.Name, metav1.GetOptions{})
|
||||
|
||||
if err != nil && !errors.IsNotFound(err) {
|
||||
t.Fatalf("Unable to get app %v", err)
|
||||
} else {
|
||||
assert.NotNil(t, a.DeletionTimestamp)
|
||||
}
|
||||
|
||||
assertAppHasEvent(app, "delete", argo.EventReasonResourceDeleted)
|
||||
assert.NotNil(t, err)
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
})
|
||||
|
||||
t.Run("TestTrackAppStateAndSyncApp", func(t *testing.T) {
|
||||
@@ -108,7 +80,6 @@ func TestAppManagement(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to sync app %v", err)
|
||||
}
|
||||
assertAppHasEvent(app, "sync", argo.EventReasonResourceUpdated)
|
||||
|
||||
WaitUntil(t, func() (done bool, err error) {
|
||||
app, err = fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
@@ -149,8 +120,6 @@ func TestAppManagement(t *testing.T) {
|
||||
t.Fatalf("Unable to sync app %v", err)
|
||||
}
|
||||
|
||||
assertAppHasEvent(app, "rollback", argo.EventReasonResourceUpdated)
|
||||
|
||||
WaitUntil(t, func() (done bool, err error) {
|
||||
app, err = fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
return err == nil && app.Status.ComparisonResult.Status == v1alpha1.ComparisonStatusSynced, err
|
||||
@@ -170,7 +139,7 @@ func TestAppManagement(t *testing.T) {
|
||||
|
||||
WaitUntil(t, func() (done bool, err error) {
|
||||
app, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
return err == nil && app.Status.ComparisonResult.Status == v1alpha1.ComparisonStatusUnknown && len(app.Status.Conditions) > 0, err
|
||||
return err == nil && app.Status.ComparisonResult.Status != v1alpha1.ComparisonStatusUnknown && len(app.Status.Conditions) > 0, err
|
||||
})
|
||||
|
||||
app, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
|
||||
@@ -21,9 +21,6 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/argoproj/argo-cd/cmd/argocd/commands"
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/controller"
|
||||
@@ -413,14 +410,7 @@ func (c *FakeGitClient) LsRemote(s string) (string, error) {
|
||||
}
|
||||
|
||||
func (c *FakeGitClient) LsFiles(s string) ([]string, error) {
|
||||
matches, err := filepath.Glob(path.Join(c.root, s))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range matches {
|
||||
matches[i] = strings.TrimPrefix(matches[i], c.root)
|
||||
}
|
||||
return matches, nil
|
||||
return []string{"abcdef123456890"}, nil
|
||||
}
|
||||
|
||||
func (c *FakeGitClient) CommitSHA() (string, error) {
|
||||
|
||||
@@ -17,8 +17,7 @@ func TestMain(m *testing.M) {
|
||||
println(fmt.Sprintf("Unable to create e2e fixture: %v", err))
|
||||
os.Exit(-1)
|
||||
} else {
|
||||
code := m.Run()
|
||||
fixture.TearDown()
|
||||
os.Exit(code)
|
||||
defer fixture.TearDown()
|
||||
m.Run()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,34 +7,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/argo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
)
|
||||
|
||||
func TestProjectManagement(t *testing.T) {
|
||||
assertProjHasEvent := func(a *v1alpha1.AppProject, action string, reason string) {
|
||||
list, err := fixture.KubeClient.CoreV1().Events(fixture.Namespace).List(metav1.ListOptions{
|
||||
FieldSelector: fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": a.Name,
|
||||
"involvedObject.uid": string(a.UID),
|
||||
"involvedObject.namespace": fixture.Namespace,
|
||||
}).String(),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to get app events %v", err)
|
||||
}
|
||||
for i := range list.Items {
|
||||
event := list.Items[i]
|
||||
if event.Reason == reason && event.Action == action {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("Unable to find event with reason=%s; action=%s", reason, action)
|
||||
}
|
||||
|
||||
t.Run("TestProjectCreation", func(t *testing.T) {
|
||||
projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
_, err := fixture.RunCli("proj", "create", projectName,
|
||||
@@ -61,13 +39,11 @@ func TestProjectManagement(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 1, len(proj.Spec.SourceRepos))
|
||||
assert.Equal(t, "https://github.com/argoproj/argo-cd.git", proj.Spec.SourceRepos[0])
|
||||
|
||||
assertProjHasEvent(proj, "create", argo.EventReasonResourceCreated)
|
||||
})
|
||||
|
||||
t.Run("TestProjectDeletion", func(t *testing.T) {
|
||||
projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
|
||||
proj, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Create(&v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}})
|
||||
_, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Create(&v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}})
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create project %v", err)
|
||||
}
|
||||
@@ -79,7 +55,6 @@ func TestProjectManagement(t *testing.T) {
|
||||
|
||||
_, err = fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Get(projectName, metav1.GetOptions{})
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
assertProjHasEvent(proj, "delete", argo.EventReasonResourceDeleted)
|
||||
})
|
||||
|
||||
t.Run("TestSetProject", func(t *testing.T) {
|
||||
@@ -109,7 +84,6 @@ func TestProjectManagement(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[1].Server)
|
||||
assert.Equal(t, "service", proj.Spec.Destinations[1].Namespace)
|
||||
assertProjHasEvent(proj, "update", argo.EventReasonResourceUpdated)
|
||||
})
|
||||
|
||||
t.Run("TestAddProjectDestination", func(t *testing.T) {
|
||||
@@ -144,7 +118,6 @@ func TestProjectManagement(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[0].Server)
|
||||
assert.Equal(t, "test1", proj.Spec.Destinations[0].Namespace)
|
||||
assertProjHasEvent(proj, "update", argo.EventReasonResourceUpdated)
|
||||
})
|
||||
|
||||
t.Run("TestRemoveProjectDestination", func(t *testing.T) {
|
||||
@@ -185,7 +158,6 @@ func TestProjectManagement(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, projectName, proj.Name)
|
||||
assert.Equal(t, 0, len(proj.Spec.Destinations))
|
||||
assertProjHasEvent(proj, "update", argo.EventReasonResourceUpdated)
|
||||
})
|
||||
|
||||
t.Run("TestAddProjectSource", func(t *testing.T) {
|
||||
@@ -244,6 +216,5 @@ func TestProjectManagement(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, projectName, proj.Name)
|
||||
assert.Equal(t, 0, len(proj.Spec.SourceRepos))
|
||||
assertProjHasEvent(proj, "update", argo.EventReasonResourceUpdated)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,20 +6,17 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/ksonnet/ksonnet/pkg/app"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
@@ -29,10 +26,10 @@ import (
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
)
|
||||
|
||||
const (
|
||||
errDestinationMissing = "Destination server and/or namespace missing from app spec"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/ksonnet/ksonnet/pkg/app"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// FormatAppConditions returns string representation of give app condition list
|
||||
@@ -214,31 +211,59 @@ func GetSpecErrors(
|
||||
}
|
||||
|
||||
if repoAccessable {
|
||||
appSourceType, err := queryAppSourceType(ctx, spec, repoRes, repoClient)
|
||||
// Verify app.yaml is functional
|
||||
req := repository.GetFileRequest{
|
||||
Repo: &argoappv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: path.Join(spec.Source.Path, "app.yaml"),
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
getRes, err := repoClient.GetFile(ctx, &req)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("Unable to determine app source type: %v", err),
|
||||
Message: fmt.Sprintf("Unable to load app.yaml: %v", err),
|
||||
})
|
||||
} else {
|
||||
switch appSourceType {
|
||||
case repository.AppSourceKsonnet:
|
||||
appYamlConditions := verifyAppYAML(ctx, repoRes, spec, repoClient)
|
||||
if len(appYamlConditions) > 0 {
|
||||
conditions = append(conditions, appYamlConditions...)
|
||||
var appSpec app.Spec
|
||||
err = yaml.Unmarshal(getRes.Data, &appSpec)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: "app.yaml is not a valid ksonnet app spec",
|
||||
})
|
||||
} else {
|
||||
// Default revision to HEAD if unspecified
|
||||
if spec.Source.TargetRevision == "" {
|
||||
spec.Source.TargetRevision = "HEAD"
|
||||
}
|
||||
case repository.AppSourceHelm:
|
||||
helmConditions := verifyHelmChart(ctx, repoRes, spec, repoClient)
|
||||
if len(helmConditions) > 0 {
|
||||
conditions = append(conditions, helmConditions...)
|
||||
}
|
||||
case repository.AppSourceDirectory:
|
||||
maniDirConditions := verifyManifestDirectory(ctx, repoRes, spec, repoClient)
|
||||
if len(maniDirConditions) > 0 {
|
||||
conditions = append(conditions, maniDirConditions...)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the specified environment is defined in it
|
||||
envSpec, ok := appSpec.Environments[spec.Source.Environment]
|
||||
if !ok || envSpec == nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("environment '%s' does not exist in ksonnet app", spec.Source.Environment),
|
||||
})
|
||||
}
|
||||
|
||||
if envSpec != nil {
|
||||
// If server and namespace are not supplied, pull it from the app.yaml
|
||||
if spec.Destination.Server == "" {
|
||||
spec.Destination.Server = envSpec.Destination.Server
|
||||
}
|
||||
if spec.Destination.Namespace == "" {
|
||||
spec.Destination.Namespace = envSpec.Destination.Namespace
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,161 +312,3 @@ func GetAppProject(spec *argoappv1.ApplicationSpec, appclientset appclientset.In
|
||||
}
|
||||
return proj, err
|
||||
}
|
||||
|
||||
// queryAppSourceType queries repo server for yaml files in a directory, and determines its
|
||||
// application source type based on the files in the directory.
|
||||
func queryAppSourceType(ctx context.Context, spec *argoappv1.ApplicationSpec, repoRes *argoappv1.Repository, repoClient repository.RepositoryServiceClient) (repository.AppSourceType, error) {
|
||||
req := repository.ListDirRequest{
|
||||
Repo: &argoappv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: fmt.Sprintf("%s/*.yaml", spec.Source.Path),
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
getRes, err := repoClient.ListDir(ctx, &req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, gitPath := range getRes.Items {
|
||||
// gitPath may look like: app.yaml, or some/subpath/app.yaml
|
||||
trimmedPath := strings.TrimPrefix(gitPath, spec.Source.Path)
|
||||
trimmedPath = strings.TrimPrefix(trimmedPath, "/")
|
||||
if trimmedPath == "app.yaml" {
|
||||
return repository.AppSourceKsonnet, nil
|
||||
}
|
||||
if trimmedPath == "Chart.yaml" {
|
||||
return repository.AppSourceHelm, nil
|
||||
}
|
||||
}
|
||||
return repository.AppSourceDirectory, nil
|
||||
}
|
||||
|
||||
// verifyAppYAML verifies that a ksonnet app.yaml is functional
|
||||
func verifyAppYAML(ctx context.Context, repoRes *argoappv1.Repository, spec *argoappv1.ApplicationSpec, repoClient repository.RepositoryServiceClient) []argoappv1.ApplicationCondition {
|
||||
req := repository.GetFileRequest{
|
||||
Repo: &argoappv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: path.Join(spec.Source.Path, "app.yaml"),
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
getRes, err := repoClient.GetFile(ctx, &req)
|
||||
var conditions []argoappv1.ApplicationCondition
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("Unable to load app.yaml: %v", err),
|
||||
})
|
||||
} else {
|
||||
var appSpec app.Spec
|
||||
err = yaml.Unmarshal(getRes.Data, &appSpec)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: "app.yaml is not a valid ksonnet app spec",
|
||||
})
|
||||
} else {
|
||||
// Default revision to HEAD if unspecified
|
||||
if spec.Source.TargetRevision == "" {
|
||||
spec.Source.TargetRevision = "HEAD"
|
||||
}
|
||||
|
||||
// Verify the specified environment is defined in it
|
||||
envSpec, ok := appSpec.Environments[spec.Source.Environment]
|
||||
if !ok || envSpec == nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("environment '%s' does not exist in ksonnet app", spec.Source.Environment),
|
||||
})
|
||||
}
|
||||
|
||||
if envSpec != nil {
|
||||
// If server and namespace are not supplied, pull it from the app.yaml
|
||||
if spec.Destination.Server == "" {
|
||||
spec.Destination.Server = envSpec.Destination.Server
|
||||
}
|
||||
if spec.Destination.Namespace == "" {
|
||||
spec.Destination.Namespace = envSpec.Destination.Namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
||||
// verifyHelmChart verifies a helm chart is functional
|
||||
func verifyHelmChart(ctx context.Context, repoRes *argoappv1.Repository, spec *argoappv1.ApplicationSpec, repoClient repository.RepositoryServiceClient) []argoappv1.ApplicationCondition {
|
||||
var conditions []argoappv1.ApplicationCondition
|
||||
if spec.Destination.Server == "" || spec.Destination.Namespace == "" {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: errDestinationMissing,
|
||||
})
|
||||
}
|
||||
req := repository.GetFileRequest{
|
||||
Repo: &argoappv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: path.Join(spec.Source.Path, "Chart.yaml"),
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
_, err := repoClient.GetFile(ctx, &req)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("Unable to load Chart.yaml: %v", err),
|
||||
})
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
||||
// verifyManifestDirectory verifies a repo path contains at least one valid k8s manifest
|
||||
func verifyManifestDirectory(ctx context.Context, repoRes *argoappv1.Repository, spec *argoappv1.ApplicationSpec, repoClient repository.RepositoryServiceClient) []argoappv1.ApplicationCondition {
|
||||
var conditions []argoappv1.ApplicationCondition
|
||||
if spec.Destination.Server == "" || spec.Destination.Namespace == "" {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: errDestinationMissing,
|
||||
})
|
||||
}
|
||||
req := repository.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: spec.Source.Path,
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
manRes, err := repoClient.GenerateManifest(ctx, &req)
|
||||
if err != nil {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("Unable to get manifests in %s: %v", spec.Source.Path, err),
|
||||
})
|
||||
} else if len(manRes.Manifests) == 0 {
|
||||
conditions = append(conditions, argoappv1.ApplicationCondition{
|
||||
Type: argoappv1.ApplicationConditionInvalidSpecError,
|
||||
Message: fmt.Sprintf("Path '%s' contained no kubernetes manifests", spec.Source.Path),
|
||||
})
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package argo
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
type AuditLogger struct {
|
||||
kIf kubernetes.Interface
|
||||
component string
|
||||
ns string
|
||||
}
|
||||
|
||||
type EventInfo struct {
|
||||
Action string
|
||||
Reason string
|
||||
Username string
|
||||
}
|
||||
|
||||
const (
|
||||
EventReasonStatusRefreshed = "StatusRefreshed"
|
||||
EventReasonResourceCreated = "ResourceCreated"
|
||||
EventReasonResourceUpdated = "ResourceUpdated"
|
||||
EventReasonResourceDeleted = "ResourceDeleted"
|
||||
)
|
||||
|
||||
func (l *AuditLogger) logEvent(objMeta metav1.ObjectMeta, gvk schema.GroupVersionKind, info EventInfo, eventType string) {
|
||||
var message string
|
||||
if info.Username != "" {
|
||||
message = fmt.Sprintf("User %s executed action %s", info.Username, info.Action)
|
||||
} else {
|
||||
message = fmt.Sprintf("Unknown user executed action %s", info.Action)
|
||||
}
|
||||
t := metav1.Time{Time: time.Now()}
|
||||
_, err := l.kIf.CoreV1().Events(l.ns).Create(&v1.Event{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%v.%x", objMeta.Name, t.UnixNano()),
|
||||
},
|
||||
Source: v1.EventSource{
|
||||
Component: l.component,
|
||||
},
|
||||
InvolvedObject: v1.ObjectReference{
|
||||
Kind: gvk.Kind,
|
||||
Name: objMeta.Name,
|
||||
Namespace: objMeta.Namespace,
|
||||
ResourceVersion: objMeta.ResourceVersion,
|
||||
APIVersion: gvk.Version,
|
||||
UID: objMeta.UID,
|
||||
},
|
||||
FirstTimestamp: t,
|
||||
LastTimestamp: t,
|
||||
Count: 1,
|
||||
Message: message,
|
||||
Type: eventType,
|
||||
Action: info.Action,
|
||||
Reason: info.Reason,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("Unable to create audit event: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AuditLogger) LogAppEvent(app *v1alpha1.Application, info EventInfo, eventType string) {
|
||||
l.logEvent(app.ObjectMeta, v1alpha1.ApplicationSchemaGroupVersionKind, info, eventType)
|
||||
}
|
||||
|
||||
func (l *AuditLogger) LogAppProjEvent(proj *v1alpha1.AppProject, info EventInfo, eventType string) {
|
||||
l.logEvent(proj.ObjectMeta, v1alpha1.AppProjectSchemaGroupVersionKind, info, eventType)
|
||||
}
|
||||
|
||||
func NewAuditLogger(ns string, kIf kubernetes.Interface, component string) *AuditLogger {
|
||||
return &AuditLogger{
|
||||
ns: ns,
|
||||
kIf: kIf,
|
||||
component: component,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package config
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package config
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -58,7 +58,6 @@ func (s *db) CreateCluster(ctx context.Context, c *appv1.Cluster) (*appv1.Cluste
|
||||
},
|
||||
}
|
||||
clusterSecret.Data = clusterToData(c)
|
||||
clusterSecret.Annotations = AnnotationsFromConnectionState(&c.ConnectionState)
|
||||
clusterSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Create(clusterSecret)
|
||||
if err != nil {
|
||||
if apierr.IsAlreadyExists(err) {
|
||||
@@ -89,24 +88,17 @@ func (s *db) WatchClusters(ctx context.Context, callback func(*ClusterEvent)) er
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer w.Stop()
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
for next := range w.ResultChan() {
|
||||
secret := next.Object.(*apiv1.Secret)
|
||||
cluster := SecretToCluster(secret)
|
||||
callback(&ClusterEvent{
|
||||
Type: next.Type,
|
||||
Cluster: cluster,
|
||||
})
|
||||
}
|
||||
done <- true
|
||||
<-ctx.Done()
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-ctx.Done():
|
||||
for next := range w.ResultChan() {
|
||||
secret := next.Object.(*apiv1.Secret)
|
||||
cluster := SecretToCluster(secret)
|
||||
callback(&ClusterEvent{
|
||||
Type: next.Type,
|
||||
Cluster: cluster,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ func (s *db) CreateRepository(ctx context.Context, r *appsv1.Repository) (*appsv
|
||||
},
|
||||
}
|
||||
repoSecret.Data = repoToData(r)
|
||||
repoSecret.Annotations = AnnotationsFromConnectionState(&r.ConnectionState)
|
||||
repoSecret, err := s.kubeclientset.CoreV1().Secrets(s.ns).Create(repoSecret)
|
||||
if err != nil {
|
||||
if apierr.IsAlreadyExists(err) {
|
||||
|
||||
@@ -13,8 +13,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
|
||||
jsonutil "github.com/argoproj/argo-cd/util/json"
|
||||
)
|
||||
|
||||
type DiffResult struct {
|
||||
@@ -45,7 +43,7 @@ func TwoWayDiff(config, live *unstructured.Unstructured) *DiffResult {
|
||||
configObj = config.Object
|
||||
}
|
||||
if live != nil {
|
||||
liveObj = jsonutil.RemoveMapFields(configObj, live.Object)
|
||||
liveObj = RemoveMapFields(configObj, live.Object)
|
||||
}
|
||||
gjDiff := gojsondiff.New().CompareObjects(configObj, liveObj)
|
||||
dr := DiffResult{
|
||||
@@ -60,7 +58,7 @@ func TwoWayDiff(config, live *unstructured.Unstructured) *DiffResult {
|
||||
func ThreeWayDiff(orig, config, live *unstructured.Unstructured) *DiffResult {
|
||||
orig = removeNamespaceAnnotation(orig)
|
||||
// remove extra fields in the live, that were not in the original object
|
||||
liveObj := jsonutil.RemoveMapFields(orig.Object, live.Object)
|
||||
liveObj := RemoveMapFields(orig.Object, live.Object)
|
||||
// now we have a pruned live object
|
||||
gjDiff := gojsondiff.New().CompareObjects(config.Object, liveObj)
|
||||
dr := DiffResult{
|
||||
@@ -230,3 +228,42 @@ func (d *DiffResult) ASCIIFormat(left *unstructured.Unstructured, formatOpts for
|
||||
asciiFmt := formatter.NewAsciiFormatter(left.Object, formatOpts)
|
||||
return asciiFmt.Format(d.Diff)
|
||||
}
|
||||
|
||||
// https://github.com/ksonnet/ksonnet/blob/master/pkg/kubecfg/diff.go
|
||||
func removeFields(config, live interface{}) interface{} {
|
||||
switch c := config.(type) {
|
||||
case map[string]interface{}:
|
||||
return RemoveMapFields(c, live.(map[string]interface{}))
|
||||
case []interface{}:
|
||||
return removeListFields(c, live.([]interface{}))
|
||||
default:
|
||||
return live
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveMapFields remove all non-existent fields in the live that don't exist in the config
|
||||
func RemoveMapFields(config, live map[string]interface{}) map[string]interface{} {
|
||||
result := map[string]interface{}{}
|
||||
for k, v1 := range config {
|
||||
v2, ok := live[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
result[k] = removeFields(v1, v2)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func removeListFields(config, live []interface{}) []interface{} {
|
||||
// If live is longer than config, then the extra elements at the end of the
|
||||
// list will be returned as-is so they appear in the diff.
|
||||
result := make([]interface{}, 0, len(live))
|
||||
for i, v2 := range live {
|
||||
if len(config) > i {
|
||||
result = append(result, removeFields(config[i], v2))
|
||||
} else {
|
||||
result = append(result, v2)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func logRequest(entry *logrus.Entry, info string, pbMsg interface{}, ctx context.Context, logClaims bool) {
|
||||
if logClaims {
|
||||
if data, err := json.Marshal(ctx.Value("claims")); err == nil {
|
||||
entry = entry.WithField("grpc.request.claims", string(data))
|
||||
}
|
||||
}
|
||||
if p, ok := pbMsg.(proto.Message); ok {
|
||||
entry = entry.WithField("grpc.request.content", &jsonpbMarshalleble{p})
|
||||
}
|
||||
entry.Info(info)
|
||||
}
|
||||
|
||||
type jsonpbMarshalleble struct {
|
||||
proto.Message
|
||||
}
|
||||
|
||||
func (j *jsonpbMarshalleble) MarshalJSON() ([]byte, error) {
|
||||
b := &bytes.Buffer{}
|
||||
if err := grpc_logrus.JsonPbMarshaller.Marshal(b, j.Message); err != nil {
|
||||
return nil, fmt.Errorf("jsonpb serializer failed: %v", err)
|
||||
}
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
type loggingServerStream struct {
|
||||
grpc.ServerStream
|
||||
entry *logrus.Entry
|
||||
logClaims bool
|
||||
info string
|
||||
}
|
||||
|
||||
func (l *loggingServerStream) SendMsg(m interface{}) error {
|
||||
return l.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (l *loggingServerStream) RecvMsg(m interface{}) error {
|
||||
err := l.ServerStream.RecvMsg(m)
|
||||
if err == nil {
|
||||
logRequest(l.entry, l.info, m, l.ServerStream.Context(), l.logClaims)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func PayloadStreamServerInterceptor(entry *logrus.Entry, logClaims bool, decider grpc_logging.ServerPayloadLoggingDecider) grpc.StreamServerInterceptor {
|
||||
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
if !decider(stream.Context(), info.FullMethod, srv) {
|
||||
return handler(srv, stream)
|
||||
}
|
||||
logEntry := entry.WithFields(ctx_logrus.Extract(stream.Context()).Data)
|
||||
newStream := &loggingServerStream{ServerStream: stream, entry: logEntry, logClaims: logClaims, info: fmt.Sprintf("received streaming call %s", info.FullMethod)}
|
||||
return handler(srv, newStream)
|
||||
}
|
||||
}
|
||||
|
||||
func PayloadUnaryServerInterceptor(entry *logrus.Entry, logClaims bool, decider grpc_logging.ServerPayloadLoggingDecider) grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
if !decider(ctx, info.FullMethod, info.Server) {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
logEntry := entry.WithFields(ctx_logrus.Extract(ctx).Data)
|
||||
logRequest(logEntry, fmt.Sprintf("received unary call %s", info.FullMethod), req, ctx, logClaims)
|
||||
resp, err := handler(ctx, req)
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
@@ -16,32 +16,22 @@ import (
|
||||
)
|
||||
|
||||
func GetAppHealth(obj *unstructured.Unstructured) (*appv1.HealthStatus, error) {
|
||||
|
||||
var err error
|
||||
var health *appv1.HealthStatus
|
||||
|
||||
switch obj.GetKind() {
|
||||
case kube.DeploymentKind:
|
||||
health, err = getDeploymentHealth(obj)
|
||||
return getDeploymentHealth(obj)
|
||||
case kube.ServiceKind:
|
||||
health, err = getServiceHealth(obj)
|
||||
return getServiceHealth(obj)
|
||||
case kube.IngressKind:
|
||||
health, err = getIngressHealth(obj)
|
||||
return getIngressHealth(obj)
|
||||
case kube.StatefulSetKind:
|
||||
health, err = getStatefulSetHealth(obj)
|
||||
return getStatefulSetHealth(obj)
|
||||
case kube.ReplicaSetKind:
|
||||
health, err = getReplicaSetHealth(obj)
|
||||
return getReplicaSetHealth(obj)
|
||||
case kube.DaemonSetKind:
|
||||
health, err = getDaemonSetHealth(obj)
|
||||
return getDaemonSetHealth(obj)
|
||||
default:
|
||||
health = &appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
return &appv1.HealthStatus{Status: appv1.HealthStatusHealthy}, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
health.Status = appv1.HealthStatusUnknown
|
||||
health.StatusDetails = err.Error()
|
||||
}
|
||||
return health, err
|
||||
}
|
||||
|
||||
// healthOrder is a list of health codes in order of most healthy to least healthy
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
)
|
||||
|
||||
// Helm provides wrapper functionality around the `helm` command.
|
||||
type Helm interface {
|
||||
// Template returns a list of unstructured objects from a `helm template` command
|
||||
Template(name string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error)
|
||||
// GetParameters returns a list of chart parameters taking into account values in provided YAML files.
|
||||
GetParameters(valuesFiles []string) ([]*argoappv1.ComponentParameter, error)
|
||||
}
|
||||
|
||||
// NewHelmApp create a new wrapper to run commands on the `helm` command-line tool.
|
||||
func NewHelmApp(path string) Helm {
|
||||
return &helm{path: path}
|
||||
}
|
||||
|
||||
type helm struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (h *helm) Template(name string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error) {
|
||||
args := []string{
|
||||
"template", h.path, "--name", name,
|
||||
}
|
||||
for _, valuesFile := range valuesFiles {
|
||||
args = append(args, "-f", path.Join(h.path, valuesFile))
|
||||
}
|
||||
for _, p := range overrides {
|
||||
args = append(args, "--set", fmt.Sprintf("%s=%s", p.Name, p.Value))
|
||||
}
|
||||
out, err := helmCmd(args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kube.SplitYAML(out)
|
||||
}
|
||||
|
||||
func (h *helm) GetParameters(valuesFiles []string) ([]*argoappv1.ComponentParameter, error) {
|
||||
out, err := helmCmd("inspect", "values", h.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values := append([]string{out})
|
||||
for _, file := range valuesFiles {
|
||||
fileValues, err := ioutil.ReadFile(path.Join(h.path, file))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read value file %s: %s", file, err)
|
||||
}
|
||||
values = append(values, string(fileValues))
|
||||
}
|
||||
|
||||
output := map[string]string{}
|
||||
for _, file := range values {
|
||||
values := map[string]interface{}{}
|
||||
if err = yaml.Unmarshal([]byte(file), &values); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse values: %s", err)
|
||||
}
|
||||
flatVals(values, output)
|
||||
}
|
||||
|
||||
params := make([]*argoappv1.ComponentParameter, 0)
|
||||
for key, val := range output {
|
||||
params = append(params, &argoappv1.ComponentParameter{
|
||||
Name: key,
|
||||
Value: val,
|
||||
})
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func helmCmd(args ...string) (string, error) {
|
||||
cmd := exec.Command("helm", args...)
|
||||
cmdStr := strings.Join(cmd.Args, " ")
|
||||
log.Info(cmdStr)
|
||||
outBytes, err := cmd.Output()
|
||||
if err != nil {
|
||||
exErr, ok := err.(*exec.ExitError)
|
||||
if !ok {
|
||||
return "", err
|
||||
}
|
||||
errOutput := string(exErr.Stderr)
|
||||
log.Errorf("`%s` failed: %s", cmdStr, errOutput)
|
||||
return "", fmt.Errorf(strings.TrimSpace(errOutput))
|
||||
}
|
||||
out := string(outBytes)
|
||||
log.Debug(out)
|
||||
return out, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package helm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
func findParameter(params []*argoappv1.ComponentParameter, name string) *argoappv1.ComponentParameter {
|
||||
for _, param := range params {
|
||||
if param.Name == name {
|
||||
return param
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestHelmTemplateParams(t *testing.T) {
|
||||
h := NewHelmApp("./testdata/minio")
|
||||
overrides := []*argoappv1.ComponentParameter{
|
||||
{
|
||||
Name: "service.type",
|
||||
Value: "LoadBalancer",
|
||||
},
|
||||
{
|
||||
Name: "service.port",
|
||||
Value: "1234",
|
||||
},
|
||||
}
|
||||
objs, err := h.Template("test", nil, overrides)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 5, len(objs))
|
||||
|
||||
for _, obj := range objs {
|
||||
if obj.GetKind() == "Service" && obj.GetName() == "test-minio" {
|
||||
var svc apiv1.Service
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &svc)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, apiv1.ServiceTypeLoadBalancer, svc.Spec.Type)
|
||||
assert.Equal(t, int32(1234), svc.Spec.Ports[0].TargetPort.IntVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelmTemplateValues(t *testing.T) {
|
||||
h := NewHelmApp("./testdata/redis")
|
||||
valuesFiles := []string{"values-production.yaml"}
|
||||
objs, err := h.Template("test", valuesFiles, nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 8, len(objs))
|
||||
|
||||
for _, obj := range objs {
|
||||
if obj.GetKind() == "Deployment" && obj.GetName() == "test-redis-slave" {
|
||||
var dep appsv1.Deployment
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &dep)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int32(3), *dep.Spec.Replicas)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHelmGetParams(t *testing.T) {
|
||||
h := NewHelmApp("./testdata/redis")
|
||||
params, err := h.GetParameters([]string{})
|
||||
assert.Nil(t, err)
|
||||
|
||||
slaveCountParam := findParameter(params, "cluster.slaveCount")
|
||||
assert.NotNil(t, slaveCountParam)
|
||||
assert.Equal(t, slaveCountParam.Value, "1")
|
||||
}
|
||||
|
||||
func TestHelmGetParamsValueFiles(t *testing.T) {
|
||||
h := NewHelmApp("./testdata/redis")
|
||||
params, err := h.GetParameters([]string{"values-production.yaml"})
|
||||
assert.Nil(t, err)
|
||||
|
||||
slaveCountParam := findParameter(params, "cluster.slaveCount")
|
||||
assert.NotNil(t, slaveCountParam)
|
||||
assert.Equal(t, slaveCountParam.Value, "3")
|
||||
}
|
||||
21
util/helm/testdata/minio/.helmignore
vendored
21
util/helm/testdata/minio/.helmignore
vendored
@@ -1,21 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
18
util/helm/testdata/minio/Chart.yaml
vendored
18
util/helm/testdata/minio/Chart.yaml
vendored
@@ -1,18 +0,0 @@
|
||||
apiVersion: v1
|
||||
description: Minio is a high performance distributed object storage server, designed for large-scale private cloud infrastructure.
|
||||
name: minio
|
||||
version: 1.6.0
|
||||
appVersion: RELEASE.2018-07-10T01-42-11Z
|
||||
keywords:
|
||||
- storage
|
||||
- object-storage
|
||||
- S3
|
||||
home: https://minio.io
|
||||
icon: https://www.minio.io/img/logo_160x160.png
|
||||
sources:
|
||||
- https://github.com/minio/minio
|
||||
maintainers:
|
||||
- name: Acaleph
|
||||
email: hello@acale.ph
|
||||
- name: Minio
|
||||
email: dev@minio.io
|
||||
226
util/helm/testdata/minio/README.md
vendored
226
util/helm/testdata/minio/README.md
vendored
@@ -1,226 +0,0 @@
|
||||
Minio
|
||||
=====
|
||||
|
||||
[Minio](https://minio.io) is a lightweight, AWS S3 compatible object storage server. It is best suited for storing unstructured data such as photos, videos, log files, backups, VM and container images. Size of an object can range from a few KBs to a maximum of 5TB. Minio server is light enough to be bundled with the application stack, similar to NodeJS, Redis and MySQL.
|
||||
|
||||
Minio supports [distributed mode](https://docs.minio.io/docs/distributed-minio-quickstart-guide). In distributed mode, you can pool multiple drives (even on different machines) into a single object storage server.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This chart bootstraps Minio deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
- Kubernetes 1.4+ with Beta APIs enabled for default standalone mode.
|
||||
- Kubernetes 1.5+ with Beta APIs enabled to run Minio in [distributed mode](#distributed-minio).
|
||||
- PV provisioner support in the underlying infrastructure.
|
||||
|
||||
Installing the Chart
|
||||
--------------------
|
||||
|
||||
Install this chart using:
|
||||
|
||||
```bash
|
||||
$ helm install stable/minio
|
||||
```
|
||||
|
||||
The command deploys Minio on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
|
||||
### Release name
|
||||
|
||||
An instance of a chart running in a Kubernetes cluster is called a release. Each release is identified by a unique name within the cluster. Helm automatically assigns a unique release name after installing the chart. You can also set your preferred name by:
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release stable/minio
|
||||
```
|
||||
|
||||
### Access and Secret keys
|
||||
|
||||
By default a pre-generated access and secret key will be used. To override the default keys, pass the access and secret keys as arguments to helm install.
|
||||
|
||||
```bash
|
||||
$ helm install --set accessKey=myaccesskey,secretKey=mysecretkey \
|
||||
stable/minio
|
||||
```
|
||||
|
||||
### Updating Minio configuration via Helm
|
||||
|
||||
[ConfigMap](https://kubernetes.io/docs/user-guide/configmap/) allows injecting containers with configuration data even while a Helm release is deployed.
|
||||
|
||||
To update your Minio server configuration while it is deployed in a release, you need to
|
||||
|
||||
1. Check all the configurable values in the Minio chart using `helm inspect values stable/minio`.
|
||||
2. Override the `minio_server_config` settings in a YAML formatted file, and then pass that file like this `helm upgrade -f config.yaml stable/minio`.
|
||||
3. Restart the Minio server(s) for the changes to take effect.
|
||||
|
||||
You can also check the history of upgrades to a release using `helm history my-release`. Replace `my-release` with the actual release name.
|
||||
|
||||
Uninstalling the Chart
|
||||
----------------------
|
||||
|
||||
Assuming your release is named as `my-release`, delete it using the command:
|
||||
|
||||
```bash
|
||||
$ helm delete my-release
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The following table lists the configurable parameters of the Minio chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|----------------------------|-------------------------------------|---------------------------------------------------------|
|
||||
| `image.repository` | Image repository | `minio/minio` |
|
||||
| `image.tag` | Minio image tag. Possible values listed [here](https://hub.docker.com/r/minio/minio/tags/).| `RELEASE.2018-07-10T01-42-11Z`|
|
||||
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
||||
| `mcImage.repository` | Client image repository | `minio/mc` |
|
||||
| `mcImage.tag` | mc image tag. Possible values listed [here](https://hub.docker.com/r/minio/mc/tags/).| `RELEASE.2018-06-09T02-18-09Z`|
|
||||
| `mcImage.pullPolicy` | mc Image pull policy | `IfNotPresent` |
|
||||
| `ingress.enabled` | Enables Ingress | `false` |
|
||||
| `ingress.annotations` | Ingress annotations | `{}` |
|
||||
| `ingress.hosts` | Ingress accepted hostnames | `[]` |
|
||||
| `ingress.tls` | Ingress TLS configuration | `[]` |
|
||||
| `mode` | Minio server mode (`standalone` or `distributed`)| `standalone` |
|
||||
| `replicas` | Number of nodes (applicable only for Minio distributed mode). Should be 4 <= x <= 32 | `4` |
|
||||
| `accessKey` | Default access key (5 to 20 characters) | `AKIAIOSFODNN7EXAMPLE` |
|
||||
| `secretKey` | Default secret key (8 to 40 characters) | `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` |
|
||||
| `configPath` | Default config file location | `~/.minio` |
|
||||
| `mountPath` | Default mount location for persistent drive| `/export` |
|
||||
| `service.type` | Kubernetes service type | `ClusterIP` |
|
||||
| `service.port` | Kubernetes port where service is exposed| `9000` |
|
||||
| `service.annotations` | Service annotations | `{}` |
|
||||
| `persistence.enabled` | Use persistent volume to store data | `true` |
|
||||
| `persistence.size` | Size of persistent volume claim | `10Gi` |
|
||||
| `persistence.existingClaim`| Use an existing PVC to persist data | `nil` |
|
||||
| `persistence.storageClass` | Type of persistent volume claim | `generic` |
|
||||
| `persistence.accessMode` | ReadWriteOnce or ReadOnly | `ReadWriteOnce` |
|
||||
| `persistence.subPath` | Mount a sub directory of the persistent volume if set | `""` |
|
||||
| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` |
|
||||
| `priorityClassName` | Pod priority settings | `""` |
|
||||
| `nodeSelector` | Node labels for pod assignment | `{}` |
|
||||
| `affinity` | Affinity settings for pod assignment | `{}` |
|
||||
| `tolerations` | Toleration labels for pod assignment | `[]` |
|
||||
| `defaultBucket.enabled` | If set to true, a bucket will be created after minio install | `false` |
|
||||
| `defaultBucket.name` | Bucket name | `bucket` |
|
||||
| `defaultBucket.policy` | Bucket policy | `none` |
|
||||
| `defaultBucket.purge` | Purge the bucket if already exists | `false` |
|
||||
| `azuregateway.enabled` | Use minio as an [azure gateway](https://docs.minio.io/docs/minio-gateway-for-azure)| `false` |
|
||||
| `gcsgateway.enabled` | Use minio as a [Google Cloud Storage gateway](https://docs.minio.io/docs/minio-gateway-for-gcs)| `false` |
|
||||
| `gcsgateway.gcsKeyJson` | credential json file of service account key | `""` |
|
||||
| `gcsgateway.projectId` | Google cloud project id | `""` |
|
||||
| `nasgateway.enabled` | Use minio as a [NAS gateway](https://docs.minio.io/docs/minio-gateway-for-nas) | `false` |
|
||||
| `nasgateway.replicas` | Number of NAS gateway instances to be run in parallel on a PV | `4` |
|
||||
|
||||
Some of the parameters above map to the env variables defined in the [Minio DockerHub image](https://hub.docker.com/r/minio/minio/).
|
||||
|
||||
You can specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release \
|
||||
--set persistence.size=100Gi \
|
||||
stable/minio
|
||||
```
|
||||
|
||||
The above command deploys Minio server with a 100Gi backing persistent volume.
|
||||
|
||||
Alternately, you can provide a YAML file that specifies parameter values while installing the chart. For example,
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release -f values.yaml stable/minio
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
||||
|
||||
Distributed Minio
|
||||
-----------
|
||||
|
||||
This chart provisions a Minio server in standalone mode, by default. To provision Minio server in [distributed mode](https://docs.minio.io/docs/distributed-minio-quickstart-guide), set the `mode` field to `distributed`,
|
||||
|
||||
```bash
|
||||
$ helm install --set mode=distributed stable/minio
|
||||
```
|
||||
|
||||
This provisions Minio server in distributed mode with 4 nodes. To change the number of nodes in your distributed Minio server, set the `replicas` field,
|
||||
|
||||
```bash
|
||||
$ helm install --set mode=distributed,replicas=8 stable/minio
|
||||
```
|
||||
|
||||
This provisions Minio server in distributed mode with 8 nodes. Note that the `replicas` value should be an integer between 4 and 16 (inclusive).
|
||||
|
||||
### StatefulSet [limitations](http://kubernetes.io/docs/concepts/abstractions/controllers/statefulsets/#limitations) applicable to distributed Minio
|
||||
|
||||
1. StatefulSets need persistent storage, so the `persistence.enabled` flag is ignored when `mode` is set to `distributed`.
|
||||
2. When uninstalling a distributed Minio release, you'll need to manually delete volumes associated with the StatefulSet.
|
||||
|
||||
NAS Gateway
|
||||
-----------
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Minio in [NAS gateway mode](https://docs.minio.io/docs/minio-gateway-for-nas) can be used to create multiple Minio instances backed by single PV in `ReadWriteMany` mode. Currently few [Kubernetes volume plugins](https://kubernetes.io/docs/user-guide/persistent-volumes/#access-modes) support `ReadWriteMany` mode. To deploy Minio NAS gateway with Helm chart you'll need to have a Persistent Volume running with one of the supported volume plugins. [This document](https://kubernetes.io/docs/user-guide/volumes/#nfs)
|
||||
outlines steps to create a NFS PV in Kubernetes cluster.
|
||||
|
||||
### Provision NAS Gateway Minio instances
|
||||
|
||||
To provision Minio servers in [NAS gateway mode](https://docs.minio.io/docs/minio-gateway-for-nas), set the `nasgateway.enabled` field to `true`,
|
||||
|
||||
```bash
|
||||
$ helm install --set nasgateway.enabled=true stable/minio
|
||||
```
|
||||
|
||||
This provisions 4 Minio NAS gateway instances backed by single storage. To change the number of instances in your Minio deployment, set the `replicas` field,
|
||||
|
||||
```bash
|
||||
$ helm install --set nasgateway.enabled=true,nasgateway.replicas=8 stable/minio
|
||||
```
|
||||
|
||||
This provisions Minio NAS gateway with 8 instances.
|
||||
|
||||
Persistence
|
||||
-----------
|
||||
|
||||
This chart provisions a PersistentVolumeClaim and mounts corresponding persistent volume to default location `/export`. You'll need physical storage available in the Kubernetes cluster for this to work. If you'd rather use `emptyDir`, disable PersistentVolumeClaim by:
|
||||
|
||||
```bash
|
||||
$ helm install --set persistence.enabled=false stable/minio
|
||||
```
|
||||
|
||||
> *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."*
|
||||
|
||||
Existing PersistentVolumeClaim
|
||||
------------------------------
|
||||
|
||||
If a Persistent Volume Claim already exists, specify it during installation.
|
||||
|
||||
1. Create the PersistentVolume
|
||||
1. Create the PersistentVolumeClaim
|
||||
1. Install the chart
|
||||
|
||||
```bash
|
||||
$ helm install --set persistence.existingClaim=PVC_NAME stable/minio
|
||||
```
|
||||
|
||||
NetworkPolicy
|
||||
-------------
|
||||
|
||||
To enable network policy for Minio,
|
||||
install [a networking plugin that implements the Kubernetes
|
||||
NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin),
|
||||
and set `networkPolicy.enabled` to `true`.
|
||||
|
||||
For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting
|
||||
the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace:
|
||||
|
||||
kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}"
|
||||
|
||||
With NetworkPolicy enabled, traffic will be limited to just port 9000.
|
||||
|
||||
For more precise policy, set `networkPolicy.allowExternal=true`. This will
|
||||
only allow pods with the generated client label to connect to Minio.
|
||||
This label will be displayed in the output of a successful install.
|
||||
44
util/helm/testdata/minio/templates/NOTES.txt
vendored
44
util/helm/testdata/minio/templates/NOTES.txt
vendored
@@ -1,44 +0,0 @@
|
||||
{{- if eq .Values.service.type "ClusterIP" "NodePort" }}
|
||||
Minio can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster:
|
||||
{{ template "minio.fullname" . }}-svc.{{ .Release.Namespace }}.svc.cluster.local
|
||||
|
||||
To access Minio from localhost, run the below commands:
|
||||
|
||||
1. export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "release={{ template "minio.fullname" . }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
|
||||
2. kubectl port-forward $POD_NAME 9000 --namespace {{ .Release.Namespace }}
|
||||
|
||||
Read more about port forwarding here: http://kubernetes.io/docs/user-guide/kubectl/kubectl_port-forward/
|
||||
|
||||
You can now access Minio server on http://localhost:9000. Follow the below steps to connect to Minio server with mc client:
|
||||
|
||||
1. Download the Minio mc client - https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
|
||||
2. mc config host add {{ template "minio.fullname" . }}-local http://localhost:9000 {{ .Values.accessKey }} {{ .Values.secretKey }} S3v4
|
||||
|
||||
3. mc ls {{ template "minio.fullname" . }}-local
|
||||
|
||||
Alternately, you can use your browser or the Minio SDK to access the server - https://docs.minio.io/categories/17
|
||||
{{- end }}
|
||||
{{- if eq .Values.service.type "LoadBalancer" }}
|
||||
Minio can be accessed via port {{ .Values.service.port }} on an external IP address. Get the service external IP address by:
|
||||
kubectl get svc --namespace {{ .Release.Namespace }} -l app={{ template "minio.fullname" . }}
|
||||
|
||||
Note that the public IP may take a couple of minutes to be available.
|
||||
|
||||
You can now access Minio server on http://<External-IP>:9000. Follow the below steps to connect to Minio server with mc client:
|
||||
|
||||
1. Download the Minio mc client - https://docs.minio.io/docs/minio-client-quickstart-guide
|
||||
|
||||
2. mc config host add {{ template "minio.fullname" . }}-local http://<External-IP>:{{ .Values.service.port }} {{ .Values.accessKey }} {{ .Values.secretKey }} S3v4
|
||||
|
||||
3. mc ls {{ template "minio.fullname" . }}-local
|
||||
|
||||
Alternately, you can use your browser or the Minio SDK to access the server - https://docs.minio.io/categories/17
|
||||
{{- end }}
|
||||
|
||||
{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}
|
||||
Note: Since NetworkPolicy is enabled, only pods with label
|
||||
{{ template "minio.fullname" . }}-client=true"
|
||||
will be able to connect to this minio cluster.
|
||||
{{- end }}
|
||||
@@ -1,75 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e ; # Have script exit in the event of a failed command.
|
||||
|
||||
# connectToMinio
|
||||
# Use a check-sleep-check loop to wait for Minio service to be available
|
||||
connectToMinio() {
|
||||
ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts
|
||||
set -e ; # fail if we can't read the keys.
|
||||
ACCESS=$(cat /config/accesskey) ; SECRET=$(cat /config/secretkey) ;
|
||||
set +e ; # The connections to minio are allowed to fail.
|
||||
echo "Connecting to Minio server: http://$MINIO_ENDPOINT:$MINIO_PORT" ;
|
||||
MC_COMMAND="mc config host add myminio http://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ;
|
||||
$MC_COMMAND ;
|
||||
STATUS=$? ;
|
||||
until [ $STATUS = 0 ]
|
||||
do
|
||||
ATTEMPTS=`expr $ATTEMPTS + 1` ;
|
||||
echo \"Failed attempts: $ATTEMPTS\" ;
|
||||
if [ $ATTEMPTS -gt $LIMIT ]; then
|
||||
exit 1 ;
|
||||
fi ;
|
||||
sleep 2 ; # 1 second intervals between attempts
|
||||
$MC_COMMAND ;
|
||||
STATUS=$? ;
|
||||
done ;
|
||||
set -e ; # reset `e` as active
|
||||
return 0
|
||||
}
|
||||
|
||||
# checkBucketExists ($bucket)
|
||||
# Check if the bucket exists, by using the exit code of `mc ls`
|
||||
checkBucketExists() {
|
||||
BUCKET=$1
|
||||
CMD=$(/usr/bin/mc ls myminio/$BUCKET > /dev/null 2>&1)
|
||||
return $?
|
||||
}
|
||||
|
||||
# createBucket ($bucket, $policy, $purge)
|
||||
# Ensure bucket exists, purging if asked to
|
||||
createBucket() {
|
||||
BUCKET=$1
|
||||
POLICY=$2
|
||||
PURGE=$3
|
||||
|
||||
# Purge the bucket, if set & exists
|
||||
# Since PURGE is user input, check explicitly for `true`
|
||||
if [ $PURGE = true ]; then
|
||||
if checkBucketExists $BUCKET ; then
|
||||
echo "Purging bucket '$BUCKET'."
|
||||
set +e ; # don't exit if this fails
|
||||
/usr/bin/mc rm -r --force myminio/$BUCKET
|
||||
set -e ; # reset `e` as active
|
||||
else
|
||||
echo "Bucket '$BUCKET' does not exist, skipping purge."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create the bucket if it does not exist
|
||||
if ! checkBucketExists $BUCKET ; then
|
||||
echo "Creating bucket '$BUCKET'"
|
||||
/usr/bin/mc mb myminio/$BUCKET
|
||||
else
|
||||
echo "Bucket '$BUCKET' already exists."
|
||||
fi
|
||||
|
||||
# At this point, the bucket should exist, skip checking for existence
|
||||
# Set policy on the bucket
|
||||
echo "Setting policy of bucket '$BUCKET' to '$POLICY'."
|
||||
/usr/bin/mc policy $POLICY myminio/$BUCKET
|
||||
}
|
||||
|
||||
# Try connecting to Minio instance
|
||||
connectToMinio
|
||||
# Create the bucket
|
||||
createBucket {{ .Values.defaultBucket.name }} {{ .Values.defaultBucket.policy }} {{ .Values.defaultBucket.purge }}
|
||||
43
util/helm/testdata/minio/templates/_helpers.tpl
vendored
43
util/helm/testdata/minio/templates/_helpers.tpl
vendored
@@ -1,43 +0,0 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "minio.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "minio.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "minio.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return the appropriate apiVersion for networkpolicy.
|
||||
*/}}
|
||||
{{- define "minio.networkPolicy.apiVersion" -}}
|
||||
{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
{{- print "extensions/v1beta1" -}}
|
||||
{{- else if semverCompare "^1.7-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
{{- print "networking.k8s.io/v1" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
140
util/helm/testdata/minio/templates/configmap.yaml
vendored
140
util/helm/testdata/minio/templates/configmap.yaml
vendored
@@ -1,140 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
data:
|
||||
initialize: |-
|
||||
{{ include (print $.Template.BasePath "/_helper_create_bucket.txt") . | indent 4 }}
|
||||
config.json: |-
|
||||
{
|
||||
"version": "26",
|
||||
"credential": {
|
||||
"accessKey": {{ .Values.accessKey | quote }},
|
||||
"secretKey": {{ .Values.secretKey | quote }}
|
||||
},
|
||||
"region": {{ .Values.minioConfig.region | quote }},
|
||||
"browser": {{ .Values.minioConfig.browser | quote }},
|
||||
"worm": {{ .Values.minioConfig.worm | quote }},
|
||||
"domain": {{ .Values.minioConfig.domain | quote }},
|
||||
"storageclass": {
|
||||
"standard": {{ .Values.minioConfig.storageClass.standardStorageClass | quote }},
|
||||
"rrs": {{ .Values.minioConfig.storageClass.reducedRedundancyStorageClass | quote }}
|
||||
},
|
||||
"cache": {
|
||||
"drives": {{ .Values.minioConfig.cache.drives }},
|
||||
"expiry": {{ .Values.minioConfig.cache.expiry | int }},
|
||||
"maxuse": {{ .Values.minioConfig.cache.maxuse | int }},
|
||||
"exclude": {{ .Values.minioConfig.cache.exclude }}
|
||||
},
|
||||
"notify": {
|
||||
"amqp": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.aqmp.enable }},
|
||||
"url": {{ .Values.minioConfig.aqmp.url | quote }},
|
||||
"exchange": {{ .Values.minioConfig.aqmp.exchange | quote }},
|
||||
"routingKey": {{ .Values.minioConfig.aqmp.routingKey | quote }},
|
||||
"exchangeType": {{ .Values.minioConfig.aqmp.exchangeType | quote }},
|
||||
"deliveryMode": {{ .Values.minioConfig.aqmp.deliveryMode }},
|
||||
"mandatory": {{ .Values.minioConfig.aqmp.mandatory }},
|
||||
"immediate": {{ .Values.minioConfig.aqmp.immediate }},
|
||||
"durable": {{ .Values.minioConfig.aqmp.durable }},
|
||||
"internal": {{ .Values.minioConfig.aqmp.internal }},
|
||||
"noWait": {{ .Values.minioConfig.aqmp.noWait }},
|
||||
"autoDeleted": {{ .Values.minioConfig.aqmp.autoDeleted }}
|
||||
}
|
||||
},
|
||||
"nats": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.nats.enable }},
|
||||
"address": {{ .Values.minioConfig.nats.address | quote }},
|
||||
"subject": {{ .Values.minioConfig.nats.subject | quote }},
|
||||
"username": {{ .Values.minioConfig.nats.username | quote }},
|
||||
"password": {{ .Values.minioConfig.nats.password | quote }},
|
||||
"token": {{ .Values.minioConfig.nats.token | quote }},
|
||||
"secure": {{ .Values.minioConfig.nats.secure }},
|
||||
"pingInterval": {{ .Values.minioConfig.nats.pingInterval | int64 }},
|
||||
"streaming": {
|
||||
"enable": {{ .Values.minioConfig.nats.enableStreaming }},
|
||||
"clusterID": {{ .Values.minioConfig.nats.clusterID | quote }},
|
||||
"clientID": {{ .Values.minioConfig.nats.clientID | quote }},
|
||||
"async": {{ .Values.minioConfig.nats.async }},
|
||||
"maxPubAcksInflight": {{ .Values.minioConfig.nats.maxPubAcksInflight | int }}
|
||||
}
|
||||
}
|
||||
},
|
||||
"elasticsearch": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.elasticsearch.enable }},
|
||||
"format": {{ .Values.minioConfig.elasticsearch.format | quote }},
|
||||
"url": {{ .Values.minioConfig.elasticsearch.url | quote }},
|
||||
"index": {{ .Values.minioConfig.elasticsearch.index | quote }}
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.redis.enable }},
|
||||
"format": {{ .Values.minioConfig.redis.format | quote }},
|
||||
"address": {{ .Values.minioConfig.redis.address | quote }},
|
||||
"password": {{ .Values.minioConfig.redis.password | quote }},
|
||||
"key": {{ .Values.minioConfig.redis.key | quote }}
|
||||
}
|
||||
},
|
||||
"postgresql": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.postgresql.enable }},
|
||||
"format": {{ .Values.minioConfig.postgresql.format | quote }},
|
||||
"connectionString": {{ .Values.minioConfig.postgresql.connectionString | quote }},
|
||||
"table": {{ .Values.minioConfig.postgresql.table | quote }},
|
||||
"host": {{ .Values.minioConfig.postgresql.host | quote }},
|
||||
"port": {{ .Values.minioConfig.postgresql.port | quote }},
|
||||
"user": {{ .Values.minioConfig.postgresql.user | quote }},
|
||||
"password": {{ .Values.minioConfig.postgresql.password | quote }},
|
||||
"database": {{ .Values.minioConfig.postgresql.database | quote }}
|
||||
}
|
||||
},
|
||||
"kafka": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.kafka.enable }},
|
||||
"brokers": {{ .Values.minioConfig.kafka.brokers }},
|
||||
"topic": {{ .Values.minioConfig.kafka.topic | quote }}
|
||||
}
|
||||
},
|
||||
"webhook": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.webhook.enable }},
|
||||
"endpoint": {{ .Values.minioConfig.webhook.endpoint | quote }}
|
||||
}
|
||||
},
|
||||
"mysql": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.mysql.enable }},
|
||||
"format": {{ .Values.minioConfig.mysql.format | quote }},
|
||||
"dsnString": {{ .Values.minioConfig.mysql.dsnString | quote }},
|
||||
"table": {{ .Values.minioConfig.mysql.table | quote }},
|
||||
"host": {{ .Values.minioConfig.mysql.host | quote }},
|
||||
"port": {{ .Values.minioConfig.mysql.port | quote }},
|
||||
"user": {{ .Values.minioConfig.mysql.user | quote }},
|
||||
"password": {{ .Values.minioConfig.mysql.password | quote }},
|
||||
"database": {{ .Values.minioConfig.mysql.database | quote }}
|
||||
}
|
||||
},
|
||||
"mqtt": {
|
||||
"1": {
|
||||
"enable": {{ .Values.minioConfig.mqtt.enable }},
|
||||
"broker": {{ .Values.minioConfig.mqtt.broker | quote }},
|
||||
"topic": {{ .Values.minioConfig.mqtt.topic | quote }},
|
||||
"qos": {{ .Values.minioConfig.mqtt.qos | int }},
|
||||
"clientId": {{ .Values.minioConfig.mqtt.clientId | quote }},
|
||||
"username": {{ .Values.minioConfig.mqtt.username | quote }},
|
||||
"password": {{ .Values.minioConfig.mqtt.password | quote }},
|
||||
"reconnectInterval": {{ .Values.minioConfig.mqtt.reconnectInterval | int }},
|
||||
"keepAliveInterval": {{ .Values.minioConfig.mqtt.keepAliveInterval | int }}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
util/helm/testdata/minio/templates/deployment.yaml
vendored
126
util/helm/testdata/minio/templates/deployment.yaml
vendored
@@ -1,126 +0,0 @@
|
||||
{{- if eq .Values.mode "standalone" }}
|
||||
apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
{{- if .Values.nasgateway.enabled }}
|
||||
replicas: {{ .Values.nasgateway.replicas }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.priorityClassName }}
|
||||
priorityClassName: "{{ .Values.priorityClassName }}"
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
{{- if .Values.azuregateway.enabled }}
|
||||
command: [ "/bin/sh",
|
||||
"-ce",
|
||||
"cp /tmp/config.json {{ .Values.configPath }} &&
|
||||
/usr/bin/docker-entrypoint.sh minio -C {{ .Values.configPath }} gateway azure"]
|
||||
{{- else }}
|
||||
{{- if .Values.gcsgateway.enabled }}
|
||||
command: [ "/bin/sh",
|
||||
"-ce",
|
||||
"cp /tmp/config.json {{ .Values.configPath }} &&
|
||||
/usr/bin/docker-entrypoint.sh minio -C {{ .Values.configPath }} gateway gcs {{ .Values.gcsgateway.projectId }}"]
|
||||
{{- else }}
|
||||
{{- if .Values.nasgateway.enabled }}
|
||||
command: [ "/bin/sh",
|
||||
"-ce",
|
||||
"cp /tmp/config.json {{ .Values.configPath }} &&
|
||||
/usr/bin/docker-entrypoint.sh minio -C {{ .Values.configPath }} gateway nas {{ .Values.mountPath }}"]
|
||||
{{- else }}
|
||||
command: [ "/bin/sh",
|
||||
"-ce",
|
||||
"cp /tmp/config.json {{ .Values.configPath }} &&
|
||||
/usr/bin/docker-entrypoint.sh minio -C {{ .Values.configPath }} server {{ .Values.mountPath }}" ]
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: export
|
||||
mountPath: {{ .Values.mountPath }}
|
||||
{{- if and .Values.persistence.enabled .Values.persistence.subPath }}
|
||||
subPath: "{{ .Values.persistence.subPath }}"
|
||||
{{- end }}
|
||||
{{- if .Values.gcsgateway.enabled }}
|
||||
- name: minio-user
|
||||
mountPath: "/etc/credentials"
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
- name: minio-server-config
|
||||
mountPath: "/tmp/config.json"
|
||||
subPath: config.json
|
||||
- name: minio-config-dir
|
||||
mountPath: {{ .Values.configPath }}
|
||||
ports:
|
||||
- name: service
|
||||
containerPort: 9000
|
||||
env:
|
||||
- name: MINIO_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
key: accesskey
|
||||
- name: MINIO_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
key: secretkey
|
||||
{{- if .Values.gcsgateway.enabled }}
|
||||
- name: GOOGLE_APPLICATION_CREDENTIALS
|
||||
value: "/etc/credentials/gcs_key.json"
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 9000
|
||||
timeoutSeconds: 1
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: export
|
||||
{{- if .Values.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim | default (include "minio.fullname" .) }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
- name: minio-server-config
|
||||
configMap:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
- name: minio-user
|
||||
secret:
|
||||
secretName: {{ template "minio.fullname" . }}
|
||||
- name: minio-config-dir
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
39
util/helm/testdata/minio/templates/ingress.yaml
vendored
39
util/helm/testdata/minio/templates/ingress.yaml
vendored
@@ -1,39 +0,0 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "minio.fullname" . -}}
|
||||
{{- $servicePort := .Values.service.port -}}
|
||||
{{- $ingressPath := .Values.ingress.path -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ . }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ $ingressPath }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $servicePort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,25 +0,0 @@
|
||||
{{- if .Values.networkPolicy.enabled }}
|
||||
kind: NetworkPolicy
|
||||
apiVersion: {{ template "minio.networkPolicy.apiVersion" . }}
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
ingress:
|
||||
- ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
{{- if not .Values.networkPolicy.allowExternal }}
|
||||
from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{ template "minio.name" . }}-client: "true"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,47 +0,0 @@
|
||||
{{- if .Values.defaultBucket.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}-make-bucket-job
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: minio-configuration
|
||||
projected:
|
||||
sources:
|
||||
- configMap:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
- secret:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
containers:
|
||||
- name: minio-mc
|
||||
image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}"
|
||||
imagePullPolicy: {{ .Values.mcImage.pullPolicy }}
|
||||
command: ["/bin/sh", "/config/initialize"]
|
||||
env:
|
||||
- name: MINIO_ENDPOINT
|
||||
value: {{ template "minio.fullname" . }}
|
||||
- name: MINIO_PORT
|
||||
value: {{ .Values.service.port | quote }}
|
||||
volumeMounts:
|
||||
- name: minio-configuration
|
||||
mountPath: /config
|
||||
{{- end }}
|
||||
27
util/helm/testdata/minio/templates/pvc.yaml
vendored
27
util/helm/testdata/minio/templates/pvc.yaml
vendored
@@ -1,27 +0,0 @@
|
||||
{{- if eq .Values.mode "standalone" }}
|
||||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
{{- if .Values.nasgateway.enabled }}
|
||||
selector:
|
||||
matchLabels:
|
||||
pv: {{ .Values.nasgateway.pv | quote }}
|
||||
{{- end }}
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode | quote }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size | quote }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
16
util/helm/testdata/minio/templates/secrets.yaml
vendored
16
util/helm/testdata/minio/templates/secrets.yaml
vendored
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
type: Opaque
|
||||
data:
|
||||
accesskey: {{ .Values.accessKey | b64enc }}
|
||||
secretkey: {{ .Values.secretKey | b64enc }}
|
||||
{{- if .Values.gcsgateway.enabled }}
|
||||
gcs_key.json: {{ .Values.gcsgateway.gcsKeyJson | b64enc }}
|
||||
{{- end }}
|
||||
42
util/helm/testdata/minio/templates/service.yaml
vendored
42
util/helm/testdata/minio/templates/service.yaml
vendored
@@ -1,42 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
{{- if .Values.service.annotations }}
|
||||
annotations:
|
||||
{{ toYaml .Values.service.annotations | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if (or (eq .Values.service.type "ClusterIP" "") (empty .Values.service.type)) }}
|
||||
type: ClusterIP
|
||||
{{- if .Values.service.clusterIP }}
|
||||
clusterIP: {{ .Values.service.clusterIP }}
|
||||
{{end}}
|
||||
{{- else if eq .Values.service.type "LoadBalancer" }}
|
||||
type: {{ .Values.service.type }}
|
||||
loadBalancerIP: {{ default "" .Values.service.loadBalancerIP }}
|
||||
{{- else }}
|
||||
type: {{ .Values.service.type }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: service
|
||||
port: 9000
|
||||
targetPort: {{ .Values.service.port }}
|
||||
protocol: TCP
|
||||
{{- if (and (eq .Values.service.type "NodePort") ( .Values.service.nodePort)) }}
|
||||
nodePort: {{ .Values.service.nodePort }}
|
||||
{{- end}}
|
||||
{{- if .Values.service.externalIPs }}
|
||||
externalIPs:
|
||||
{{- range $i , $ip := .Values.service.externalIPs }}
|
||||
- {{ $ip }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
@@ -1,99 +0,0 @@
|
||||
{{- if eq .Values.mode "distributed" }}
|
||||
{{ $nodeCount := .Values.replicas | int }}
|
||||
apiVersion: apps/v1beta1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
chart: {{ template "minio.chart" . }}
|
||||
release: {{ .Release.Name }}
|
||||
heritage: {{ .Release.Service }}
|
||||
spec:
|
||||
serviceName: {{ template "minio.fullname" . }}
|
||||
replicas: {{ .Values.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
labels:
|
||||
app: {{ template "minio.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.priorityClassName }}
|
||||
priorityClassName: "{{ .Values.priorityClassName }}"
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command: [ "/bin/sh",
|
||||
"-ce",
|
||||
"cp /tmp/config.json {{ .Values.configPath }} &&
|
||||
/usr/bin/docker-entrypoint.sh minio -C {{ .Values.configPath }} server
|
||||
{{- range $i := until $nodeCount }}
|
||||
http://{{ template `minio.fullname` $ }}-{{ $i }}.{{ template `minio.fullname` $ }}.{{ $.Release.Namespace }}.svc.cluster.local{{ $.Values.mountPath }}
|
||||
{{- end }}" ]
|
||||
volumeMounts:
|
||||
- name: export
|
||||
mountPath: {{ .Values.mountPath }}
|
||||
{{- if and .Values.persistence.enabled .Values.persistence.subPath }}
|
||||
subPath: "{{ .Values.persistence.subPath }}"
|
||||
{{- end }}
|
||||
- name: minio-server-config
|
||||
mountPath: "/tmp/config.json"
|
||||
subPath: config.json
|
||||
- name: minio-config-dir
|
||||
mountPath: {{ .Values.configPath }}
|
||||
ports:
|
||||
- name: service
|
||||
containerPort: 9000
|
||||
env:
|
||||
- name: MINIO_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
key: accesskey
|
||||
- name: MINIO_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
key: secretkey
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: minio-user
|
||||
secret:
|
||||
secretName: {{ template "minio.fullname" . }}
|
||||
- name: minio-server-config
|
||||
configMap:
|
||||
name: {{ template "minio.fullname" . }}
|
||||
- name: minio-config-dir
|
||||
emptyDir: {}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: export
|
||||
spec:
|
||||
accessModes: [ {{ .Values.persistence.accessMode | quote }} ]
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.persistence.storageClass }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size }}
|
||||
{{- end }}
|
||||
237
util/helm/testdata/minio/values.yaml
vendored
237
util/helm/testdata/minio/values.yaml
vendored
@@ -1,237 +0,0 @@
|
||||
## Set default image, imageTag, and imagePullPolicy. mode is used to indicate the
|
||||
##
|
||||
image:
|
||||
repository: minio/minio
|
||||
tag: RELEASE.2018-07-10T01-42-11Z
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
## Set default image, imageTag, and imagePullPolicy for the `mc` (the minio
|
||||
## client used to create a default bucket).
|
||||
##
|
||||
mcImage:
|
||||
repository: minio/mc
|
||||
tag: RELEASE.2018-06-09T02-18-09Z
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
## minio server mode, i.e. standalone or distributed.
|
||||
## Distributed Minio ref: https://docs.minio.io/docs/distributed-minio-quickstart-guide
|
||||
##
|
||||
mode: standalone
|
||||
|
||||
## Pod priority settings
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/
|
||||
##
|
||||
priorityClassName: ""
|
||||
|
||||
## Set default accesskey, secretkey, Minio config file path, volume mount path and
|
||||
## number of nodes (only used for Minio distributed mode)
|
||||
## Distributed Minio ref: https://docs.minio.io/docs/distributed-minio-quickstart-guide
|
||||
##
|
||||
accessKey: "AKIAIOSFODNN7EXAMPLE"
|
||||
secretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
||||
configPath: "/root/.minio/"
|
||||
mountPath: "/export"
|
||||
replicas: 4
|
||||
|
||||
## Enable persistence using Persistent Volume Claims
|
||||
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
|
||||
##
|
||||
persistence:
|
||||
enabled: true
|
||||
|
||||
## A manually managed Persistent Volume and Claim
|
||||
## Requires persistence.enabled: true
|
||||
## If defined, PVC must be created manually before volume will be bound
|
||||
# existingClaim:
|
||||
|
||||
## minio data Persistent Volume Storage Class
|
||||
## If defined, storageClassName: <storageClass>
|
||||
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
## If undefined (the default) or set to null, no storageClassName spec is
|
||||
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
## GKE, AWS & OpenStack)
|
||||
##
|
||||
## Storage class of PV to bind. By default it looks for standard storage class.
|
||||
## If the PV uses a different storage class, specify that here.
|
||||
storageClass: standard
|
||||
accessMode: ReadWriteOnce
|
||||
size: 10Gi
|
||||
|
||||
## If subPath is set mount a sub folder of a volume instead of the root of the volume.
|
||||
## This is especially handy for volume plugins that don't natively support sub mounting (like glusterfs).
|
||||
##
|
||||
subPath: ""
|
||||
|
||||
## Expose the Minio service to be accessed from outside the cluster (LoadBalancer service).
|
||||
## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it.
|
||||
## ref: http://kubernetes.io/docs/user-guide/services/
|
||||
##
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
clusterIP: None
|
||||
port: 9000
|
||||
# nodePort: 31311
|
||||
annotations: {}
|
||||
# prometheus.io/scrape: 'true'
|
||||
# prometheus.io/path: '/minio/prometheus/metrics'
|
||||
# prometheus.io/port: '9000'
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
annotations: {}
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
path: /
|
||||
hosts:
|
||||
- chart-example.local
|
||||
tls: []
|
||||
# - secretName: chart-example-tls
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
## Node labels for pod assignment
|
||||
## Ref: https://kubernetes.io/docs/user-guide/node-selection/
|
||||
##
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
## Configure resource requests and limits
|
||||
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
|
||||
##
|
||||
resources:
|
||||
requests:
|
||||
memory: 256Mi
|
||||
cpu: 250m
|
||||
|
||||
## Create a bucket after minio install
|
||||
##
|
||||
defaultBucket:
|
||||
enabled: false
|
||||
## If enabled, must be a string with length > 0
|
||||
name: bucket
|
||||
## Can be one of none|download|upload|public
|
||||
policy: none
|
||||
## Purge if bucket exists already
|
||||
purge: false
|
||||
|
||||
## Use minio as an azure blob gateway, you should disable data persistence so no volume claim are created.
|
||||
## https://docs.minio.io/docs/minio-gateway-for-azure
|
||||
azuregateway:
|
||||
enabled: false
|
||||
|
||||
## Use minio as GCS (Google Cloud Storage) gateway, you should disable data persistence so no volume claim are created.
|
||||
## https://docs.minio.io/docs/minio-gateway-for-gcs
|
||||
|
||||
gcsgateway:
|
||||
enabled: false
|
||||
# credential json file of service account key
|
||||
gcsKeyJson: ""
|
||||
# Google cloud project-id
|
||||
projectId: ""
|
||||
|
||||
## Use minio on NAS backend
|
||||
## https://docs.minio.io/docs/minio-gateway-for-nas
|
||||
|
||||
nasgateway:
|
||||
enabled: false
|
||||
# Number of parallel instances
|
||||
replicas: 4
|
||||
# Generally for NAS Gateway, you'd like to bind the PVC to a specific PV. To ensure that happens, PV to bind to should have
|
||||
# a label like "pv: <value>", use value here.
|
||||
pv: ""
|
||||
|
||||
## https://docs.minio.io/docs/minio-bucket-notification-guide
|
||||
## https://github.com/minio/minio/blob/master/docs/config
|
||||
minioConfig:
|
||||
region: "us-east-1"
|
||||
browser: "on"
|
||||
domain: ""
|
||||
worm: "off"
|
||||
storageClass:
|
||||
standardStorageClass: ""
|
||||
reducedRedundancyStorageClass: ""
|
||||
cache:
|
||||
drives: []
|
||||
expiry: 90
|
||||
maxuse: 80
|
||||
exclude: []
|
||||
aqmp:
|
||||
enable: false
|
||||
url: ""
|
||||
exchange: ""
|
||||
routingKey: ""
|
||||
exchangeType: ""
|
||||
deliveryMode: 0
|
||||
mandatory: false
|
||||
immediate: false
|
||||
durable: false
|
||||
internal: false
|
||||
noWait: false
|
||||
autoDeleted: false
|
||||
nats:
|
||||
enable: false
|
||||
address: ""
|
||||
subject: ""
|
||||
username: ""
|
||||
password: ""
|
||||
token: ""
|
||||
secure: false
|
||||
pingInterval: 0
|
||||
enableStreaming: false
|
||||
clusterID: ""
|
||||
clientID: ""
|
||||
async: false
|
||||
maxPubAcksInflight: 0
|
||||
elasticsearch:
|
||||
enable: false
|
||||
format: "namespace"
|
||||
url: ""
|
||||
index: ""
|
||||
redis:
|
||||
enable: false
|
||||
format: "namespace"
|
||||
address: ""
|
||||
password: ""
|
||||
key: ""
|
||||
postgresql:
|
||||
enable: false
|
||||
format: "namespace"
|
||||
connectionString: ""
|
||||
table: ""
|
||||
host: ""
|
||||
port: ""
|
||||
user: ""
|
||||
password: ""
|
||||
database: ""
|
||||
kafka:
|
||||
enable: false
|
||||
brokers: "null"
|
||||
topic: ""
|
||||
webhook:
|
||||
enable: false
|
||||
endpoint: ""
|
||||
mysql:
|
||||
enable: false
|
||||
format: "namespace"
|
||||
dsnString: ""
|
||||
table: ""
|
||||
host: ""
|
||||
port: ""
|
||||
user: ""
|
||||
password: ""
|
||||
database: ""
|
||||
mqtt:
|
||||
enable: false
|
||||
broker: ""
|
||||
topic: ""
|
||||
qos: 0
|
||||
clientId: ""
|
||||
username: ""
|
||||
password: ""
|
||||
reconnectInterval: 0
|
||||
keepAliveInterval: 0
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
allowExternal: true
|
||||
3
util/helm/testdata/redis/.helmignore
vendored
3
util/helm/testdata/redis/.helmignore
vendored
@@ -1,3 +0,0 @@
|
||||
.git
|
||||
# OWNERS file for Kubernetes
|
||||
OWNERS
|
||||
16
util/helm/testdata/redis/Chart.yaml
vendored
16
util/helm/testdata/redis/Chart.yaml
vendored
@@ -1,16 +0,0 @@
|
||||
name: redis
|
||||
version: 3.6.5
|
||||
appVersion: 4.0.10
|
||||
description: Open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.
|
||||
keywords:
|
||||
- redis
|
||||
- keyvalue
|
||||
- database
|
||||
home: http://redis.io/
|
||||
icon: https://bitnami.com/assets/stacks/redis/img/redis-stack-220x234.png
|
||||
sources:
|
||||
- https://github.com/bitnami/bitnami-docker-redis
|
||||
maintainers:
|
||||
- name: bitnami-bot
|
||||
email: containers@bitnami.com
|
||||
engine: gotpl
|
||||
12
util/helm/testdata/redis/OWNERS
vendored
12
util/helm/testdata/redis/OWNERS
vendored
@@ -1,12 +0,0 @@
|
||||
approvers:
|
||||
- prydonius
|
||||
- tompizmor
|
||||
- sameersbn
|
||||
- carrodher
|
||||
- juan131
|
||||
reviewers:
|
||||
- prydonius
|
||||
- tompizmor
|
||||
- sameersbn
|
||||
- carrodher
|
||||
- juan131
|
||||
205
util/helm/testdata/redis/README.md
vendored
205
util/helm/testdata/redis/README.md
vendored
@@ -1,205 +0,0 @@
|
||||
# Redis
|
||||
|
||||
[Redis](http://redis.io/) is an advanced key-value cache and store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets, sorted sets, bitmaps and hyperloglogs.
|
||||
|
||||
## TL;DR
|
||||
|
||||
```bash
|
||||
# Testing configuration
|
||||
$ helm install stable/redis
|
||||
```
|
||||
|
||||
```bash
|
||||
# Production configuration
|
||||
$ helm install stable/redis --values values-production.yaml
|
||||
```
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart bootstraps a [Redis](https://github.com/bitnami/bitnami-docker-redis) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.8+
|
||||
- PV provisioner support in the underlying infrastructure
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `my-release`:
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release stable/redis
|
||||
```
|
||||
|
||||
The command deploys Redis on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `my-release` deployment:
|
||||
|
||||
```bash
|
||||
$ helm delete my-release
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following table lists the configurable parameters of the Redis chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|--------------------------------------------|----------------------------------------------------------------------------------------------------------------|--------------------------------------|
|
||||
| `image.registry` | Redis Image registry | `docker.io` |
|
||||
| `image.repository` | Redis Image name | `bitnami/redis` |
|
||||
| `image.tag` | Redis Image tag | `{VERSION}` |
|
||||
| `image.pullPolicy` | Image pull policy | `Always` |
|
||||
| `image.pullSecrets` | Specify docker-registry secret names as an array | `nil` |
|
||||
| `cluster.enabled` | Use master-slave topology | `true` |
|
||||
| `cluster.slaveCount` | Number of slaves | 1 |
|
||||
| `existingSecret` | Name of existing secret object (for password authentication) | `nil` |
|
||||
| `usePassword` | Use password | `true` |
|
||||
| `password` | Redis password (ignored if existingSecret set) | Randomly generated |
|
||||
| `networkPolicy.enabled` | Enable NetworkPolicy | `false` |
|
||||
| `networkPolicy.allowExternal` | Don't require client label for connections | `true` |
|
||||
| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `false` |
|
||||
| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the fullname template |
|
||||
| `rbac.create` | Specifies whether RBAC resources should be created | `false` |
|
||||
| `rbac.role.rules` | Rules to create | `[]` |
|
||||
| `metrics.enabled` | Start a side-car prometheus exporter | `false` |
|
||||
| `metrics.image.registry` | Redis exporter image registry | `docker.io` |
|
||||
| `metrics.image.repository` | Redis exporter image name | `bitnami/redis` |
|
||||
| `metrics.image.tag` | Redis exporter image tag | `v0.20.2` |
|
||||
| `metrics.image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
||||
| `metrics.image.pullSecrets` | Specify docker-registry secret names as an array | `nil` |
|
||||
| `metrics.podLabels` | Additional labels for Metrics exporter pod | {} |
|
||||
| `metrics.podAnnotations` | Additional annotations for Metrics exporter pod | {} |
|
||||
| `master.service.type` | Kubernetes Service type (redis metrics) | `LoadBalancer` |
|
||||
| `metrics.service.annotations` | Annotations for the services to monitor (redis master and redis slave service) | {} |
|
||||
| `metrics.service.loadBalancerIP` | loadBalancerIP if redis metrics service type is `LoadBalancer` | `nil` |
|
||||
| `metrics.resources` | Exporter resource requests/limit | Memory: `256Mi`, CPU: `100m` |
|
||||
| `persistence.existingClaim` | Provide an existing PersistentVolumeClaim | `nil` |
|
||||
| `master.persistence.enabled` | Use a PVC to persist data (master node) | `true` |
|
||||
| `master.persistence.path` | Path to mount the volume at, to use other images | `/bitnami` |
|
||||
| `master.persistence.subPath` | Subdirectory of the volume to mount at | `""` |
|
||||
| `master.persistence.storageClass` | Storage class of backing PVC | `generic` |
|
||||
| `master.persistence.accessModes` | Persistent Volume Access Modes | `[ReadWriteOnce]` |
|
||||
| `master.persistence.size` | Size of data volume | `8Gi` |
|
||||
| `master.statefulset.updateStrategy` | Update strategy for StatefulSet | onDelete |
|
||||
| `master.statefulset.rollingUpdatePartition`| Partition update strategy | `nil` |
|
||||
| `master.podLabels` | Additional labels for Redis master pod | {} |
|
||||
| `master.podAnnotations` | Additional annotations for Redis master pod | {} |
|
||||
| `master.port` | Redis master port | 6379 |
|
||||
| `master.args` | Redis master command-line args | [] |
|
||||
| `master.disableCommands` | Comma-separated list of Redis commands to disable (master) | `FLUSHDB,FLUSHALL` |
|
||||
| `master.extraFlags` | Redis master additional command line flags | [] |
|
||||
| `master.nodeSelector` | Redis master Node labels for pod assignment | {"beta.kubernetes.io/arch": "amd64"} |
|
||||
| `master.tolerations` | Toleration labels for Redis master pod assignment | [] |
|
||||
| `master.affinity ` | Affinity settings for Redis master pod assignment | [] |
|
||||
| `master.schedulerName` | Name of an alternate scheduler | `nil` |
|
||||
| `master.service.type` | Kubernetes Service type (redis master) | `ClusterIP` |
|
||||
| `master.service.annotations` | annotations for redis master service | {} |
|
||||
| `master.service.loadBalancerIP` | loadBalancerIP if redis master service type is `LoadBalancer` | `nil` |
|
||||
| `master.securityContext.enabled` | Enable security context (redis master pod) | `true` |
|
||||
| `master.securityContext.fsGroup` | Group ID for the container (redis master pod) | `1001` |
|
||||
| `master.securityContext.runAsUser` | User ID for the container (redis master pod) | `1001` |
|
||||
| `master.resources` | Redis master CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` |
|
||||
| `master.livenessProbe.enabled` | Turn on and off liveness probe (redis master pod) | `true` |
|
||||
| `master.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated (redis master pod) | `30` |
|
||||
| `master.livenessProbe.periodSeconds` | How often to perform the probe (redis master pod) | `30` |
|
||||
| `master.livenessProbe.timeoutSeconds` | When the probe times out (redis master pod) | `5` |
|
||||
| `master.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed (redis master pod) | `1` |
|
||||
| `master.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `5` |
|
||||
| `master.readinessProbe.enabled` | Turn on and off readiness probe (redis master pod) | `true` |
|
||||
| `master.readinessProbe.initialDelaySeconds`| Delay before readiness probe is initiated (redis master pod) | `5` |
|
||||
| `master.readinessProbe.periodSeconds` | How often to perform the probe (redis master pod) | `10` |
|
||||
| `master.readinessProbe.timeoutSeconds` | When the probe times out (redis master pod) | `1` |
|
||||
| `master.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed (redis master pod) | `1` |
|
||||
| `master.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `5` |
|
||||
| `slave.serviceType` | Kubernetes Service type (redis slave) | `LoadBalancer` |
|
||||
| `slave.service.annotations` | annotations for redis slave service | {} |
|
||||
| `slave.service.loadBalancerIP` | LoadBalancerIP if Redis slave service type is `LoadBalancer` | `nil` |
|
||||
| `slave.port` | Redis slave port | `master.port` |
|
||||
| `slave.args` | Redis slave command-line args | `master.args` |
|
||||
| `slave.disableCommands` | Comma-separated list of Redis commands to disable (slave) | `master.disableCommands` |
|
||||
| `slave.extraFlags` | Redis slave additional command line flags | `master.extraFlags` |
|
||||
| `slave.livenessProbe.enabled` | Turn on and off liveness probe (redis slave pod) | `master.livenessProbe.enabled` |
|
||||
| `slave.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated (redis slave pod) | `master.livenessProbe.initialDelaySeconds` |
|
||||
| `slave.livenessProbe.periodSeconds` | How often to perform the probe (redis slave pod) | `master.livenessProbe.periodSeconds` |
|
||||
| `slave.livenessProbe.timeoutSeconds` | When the probe times out (redis slave pod) | `master.livenessProbe.timeoutSeconds` |
|
||||
| `slave.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed (redis slave pod) | `master.livenessProbe.successThreshold` |
|
||||
| `slave.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `master.livenessProbe.failureThreshold` |
|
||||
| `slave.readinessProbe.enabled` | Turn on and off slave.readiness probe (redis slave pod) | `master.readinessProbe.enabled` |
|
||||
| `slave.readinessProbe.initialDelaySeconds` | Delay before slave.readiness probe is initiated (redis slave pod) | `master.readinessProbe.initialDelaySeconds` |
|
||||
| `slave.readinessProbe.periodSeconds` | How often to perform the probe (redis slave pod) | `master.readinessProbe.periodSeconds` |
|
||||
| `slave.readinessProbe.timeoutSeconds` | When the probe times out (redis slave pod) | `master.readinessProbe.timeoutSeconds` |
|
||||
| `slave.readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed (redis slave pod) | `master.readinessProbe.successThreshold` |
|
||||
| `slave.readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. (redis slave pod) | `master.readinessProbe.failureThreshold` |
|
||||
| `slave.podLabels` | Additional labels for Redis slave pod | `master.podLabels` |
|
||||
| `slave.podAnnotations` | Additional annotations for Redis slave pod | `master.podAnnotations` |
|
||||
| `slave.schedulerName` | Name of an alternate scheduler | `nil` |
|
||||
| `slave.securityContext.enabled` | Enable security context (redis slave pod) | `master.securityContext.enabled` |
|
||||
| `slave.securityContext.fsGroup` | Group ID for the container (redis slave pod) | `master.securityContext.fsGroup` |
|
||||
| `slave.securityContext.runAsUser` | User ID for the container (redis slave pod) | `master.securityContext.runAsUser` |
|
||||
| `slave.resources` | Redis slave CPU/Memory resource requests/limits | `master.resources` |
|
||||
| `slave.affinity` | Enable node/pod affinity for slaves | {} |
|
||||
|
||||
The above parameters map to the env variables defined in [bitnami/redis](http://github.com/bitnami/bitnami-docker-redis). For more information please refer to the [bitnami/redis](http://github.com/bitnami/bitnami-docker-redis) image documentation.
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release \
|
||||
--set password=secretpassword \
|
||||
stable/redis
|
||||
```
|
||||
|
||||
The above command sets the Redis server password to `secretpassword`.
|
||||
|
||||
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release -f values.yaml stable/redis
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
||||
|
||||
> **Note for minikube users**: Current versions of minikube (v0.24.1 at the time of writing) provision `hostPath` persistent volumes that are only writable by root. Using chart defaults cause pod failure for the Redis pod as it attempts to write to the `/bitnami` directory. Consider installing Redis with `--set persistence.enabled=false`. See minikube issue [1990](https://github.com/kubernetes/minikube/issues/1990) for more information.
|
||||
|
||||
## NetworkPolicy
|
||||
|
||||
To enable network policy for Redis, install
|
||||
[a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin),
|
||||
and set `networkPolicy.enabled` to `true`.
|
||||
|
||||
For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting
|
||||
the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace:
|
||||
|
||||
kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}"
|
||||
|
||||
With NetworkPolicy enabled, only pods with the generated client label will be
|
||||
able to connect to Redis. This label will be displayed in the output
|
||||
after a successful install.
|
||||
|
||||
## Persistence
|
||||
|
||||
The [Bitnami Redis](https://github.com/bitnami/bitnami-docker-redis) image stores the Redis data and configurations at the `/bitnami` path of the container.
|
||||
|
||||
By default, the chart mounts a [Persistent Volume](http://kubernetes.io/docs/user-guide/persistent-volumes/) at this location. The volume is created using dynamic volume provisioning. If a Persistent Volume Claim already exists, specify it during installation.
|
||||
|
||||
By default, the chart persists both data and configuration. If you wish to persist only the data directory set `persistence.path` to `/bitnami/redis/data` and `persistence.subPath` to `redis/data`.
|
||||
|
||||
### Existing PersistentVolumeClaim
|
||||
|
||||
1. Create the PersistentVolume
|
||||
1. Create the PersistentVolumeClaim
|
||||
1. Install the chart
|
||||
|
||||
```bash
|
||||
$ helm install --set persistence.existingClaim=PVC_NAME stable/redis
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9121) is exposed in the service. Metrics can be scraped from within the cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). If metrics are to be scraped from outside the cluster, the Kubernetes API proxy can be utilized to access the endpoint.
|
||||
89
util/helm/testdata/redis/templates/NOTES.txt
vendored
89
util/helm/testdata/redis/templates/NOTES.txt
vendored
@@ -1,89 +0,0 @@
|
||||
** Please be patient while the chart is being deployed **
|
||||
|
||||
{{- if contains .Values.master.service.type "LoadBalancer" }}
|
||||
{{- if not .Values.usePassword }}
|
||||
{{ if and (not .Values.networkPolicy.enabled) (.Values.networkPolicy.allowExternal) }}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
WARNING
|
||||
|
||||
By specifying "master.service.type=LoadBalancer" and "usePassword=false" you have
|
||||
most likely exposed the Redis service externally without any authentication
|
||||
mechanism.
|
||||
|
||||
For security reasons, we strongly suggest that you switch to "ClusterIP" or
|
||||
"NodePort". As alternative, you can also switch to "usePassword=true"
|
||||
providing a valid password on "password" parameter.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.cluster.enabled }}
|
||||
Redis can be accessed via port {{ .Values.master.port }} on the following DNS names from within your cluster:
|
||||
|
||||
{{ template "redis.fullname" . }}-master.{{ .Release.Namespace }}.svc.cluster.local for read/write operations
|
||||
{{ template "redis.fullname" . }}-slave.{{ .Release.Namespace }}.svc.cluster.local for read-only operations
|
||||
|
||||
{{- else }}
|
||||
Redis can be accessed via port {{ .Values.master.port }} on the following DNS name from within your cluster:
|
||||
|
||||
{{ template "redis.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
|
||||
|
||||
{{- end }}
|
||||
|
||||
{{ if .Values.usePassword }}
|
||||
To get your password run:
|
||||
|
||||
export REDIS_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "redis.fullname" . }} -o jsonpath="{.data.redis-password}" | base64 --decode)
|
||||
{{- end }}
|
||||
|
||||
To connect to your Redis server:
|
||||
|
||||
1. Run a Redis pod that you can use as a client:
|
||||
|
||||
kubectl run --namespace {{ .Release.Namespace }} {{ template "redis.fullname" . }}-client --rm --tty -i \
|
||||
{{ if .Values.usePassword }} --env REDIS_PASSWORD=$REDIS_PASSWORD \{{ end }}
|
||||
{{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}--labels="{{ template "redis.name" . }}-client=true" \{{- end }}
|
||||
--image {{ template "redis.image" . }} -- bash
|
||||
|
||||
2. Connect using the Redis CLI:
|
||||
|
||||
{{- if .Values.cluster.enabled }}
|
||||
redis-cli -h {{ template "redis.fullname" . }}-master{{ if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
redis-cli -h {{ template "redis.fullname" . }}-slave{{ if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
{{- else }}
|
||||
redis-cli -h {{ template "redis.fullname" . }}{{ if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
{{- end }}
|
||||
|
||||
{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}
|
||||
Note: Since NetworkPolicy is enabled, only pods with label
|
||||
{{ template "redis.fullname" . }}-client=true"
|
||||
will be able to connect to redis.
|
||||
{{- else -}}
|
||||
|
||||
To connect to your database from outside the cluster execute the following commands:
|
||||
|
||||
{{- if contains "NodePort" .Values.master.service.type }}
|
||||
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "redis.fullname" . }}-master)
|
||||
redis-cli -h $NODE_IP -p $NODE_PORT {{- if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
|
||||
{{- else if contains "LoadBalancer" .Values.master.service.type }}
|
||||
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "redis.fullname" . }}'
|
||||
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "redis.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
redis-cli -h $SERVICE_IP -p {{ .Values.master.service.nodePort }} {{- if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
|
||||
{{- else if contains "ClusterIP" .Values.master.service.type }}
|
||||
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "redis.name" . }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME {{ .Values.master.port }}:{{ .Values.master.port }}
|
||||
redis-cli -h 127.0.0.1 -p {{ .Values.master.port }} {{- if .Values.usePassword }} -a $REDIS_PASSWORD{{ end }}
|
||||
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
130
util/helm/testdata/redis/templates/_helpers.tpl
vendored
130
util/helm/testdata/redis/templates/_helpers.tpl
vendored
@@ -1,130 +0,0 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "redis.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Expand the chart plus release name (used by the chart label)
|
||||
*/}}
|
||||
{{- define "redis.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "redis.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return the appropriate apiVersion for networkpolicy.
|
||||
*/}}
|
||||
{{- define "networkPolicy.apiVersion" -}}
|
||||
{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
{{- print "extensions/v1beta1" -}}
|
||||
{{- else -}}
|
||||
{{- print "networking.k8s.io/v1" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return the proper image name
|
||||
*/}}
|
||||
{{- define "redis.image" -}}
|
||||
{{- $registryName := .Values.image.registry -}}
|
||||
{{- $repositoryName := .Values.image.repository -}}
|
||||
{{- $tag := .Values.image.tag | toString -}}
|
||||
{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return the proper image name (for the metrics image)
|
||||
*/}}
|
||||
{{- define "metrics.image" -}}
|
||||
{{- $registryName := .Values.metrics.image.registry -}}
|
||||
{{- $repositoryName := .Values.metrics.image.repository -}}
|
||||
{{- $tag := .Values.metrics.image.tag | toString -}}
|
||||
{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return slave readiness probe
|
||||
*/}}
|
||||
{{- define "redis.slave.readinessProbe" -}}
|
||||
{{- $readinessProbe := .Values.slave.readinessProbe | default .Values.master.readinessProbe -}}
|
||||
{{- if $readinessProbe }}
|
||||
{{- if $readinessProbe.enabled }}
|
||||
readinessProbe:
|
||||
initialDelaySeconds: {{ $readinessProbe.initialDelaySeconds | default .Values.master.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $readinessProbe.periodSeconds | default .Values.master.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $readinessProbe.timeoutSeconds | default .Values.master.readinessProbe.timeoutSeconds }}
|
||||
successThreshold: {{ $readinessProbe.successThreshold | default .Values.master.readinessProbe.successThreshold }}
|
||||
failureThreshold: {{ $readinessProbe.failureThreshold | default .Values.master.readinessProbe.failureThreshold }}
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return slave liveness probe
|
||||
*/}}
|
||||
{{- define "redis.slave.livenessProbe" -}}
|
||||
{{- $livenessProbe := .Values.slave.livenessProbe | default .Values.master.livenessProbe -}}
|
||||
{{- if $livenessProbe }}
|
||||
{{- if $livenessProbe.enabled }}
|
||||
livenessProbe:
|
||||
initialDelaySeconds: {{ $livenessProbe.initialDelaySeconds | default .Values.master.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $livenessProbe.periodSeconds | default .Values.master.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $livenessProbe.timeoutSeconds | default .Values.master.livenessProbe.timeoutSeconds }}
|
||||
successThreshold: {{ $livenessProbe.successThreshold | default .Values.master.livenessProbe.successThreshold }}
|
||||
failureThreshold: {{ $livenessProbe.failureThreshold | default .Values.master.livenessProbe.failureThreshold}}
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Return slave security context
|
||||
*/}}
|
||||
{{- define "redis.slave.securityContext" -}}
|
||||
{{- $securityContext := .Values.slave.securityContext | default .Values.master.securityContext -}}
|
||||
{{- if $securityContext }}
|
||||
{{- if $securityContext.enabled }}
|
||||
securityContext:
|
||||
fsGroup: {{ $securityContext.fsGroup | default .Values.master.securityContext.fsGroup }}
|
||||
runAsUser: {{ $securityContext.runAsUser | default .Values.master.securityContext.runAsUser }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "redis.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{ default (include "redis.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
@@ -1,70 +0,0 @@
|
||||
{{- if .Values.metrics.enabled }}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "redis.fullname" . }}-metrics
|
||||
labels:
|
||||
app: {{ template "redis.name" . }}
|
||||
chart: {{ template "redis.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
release: "{{ .Release.Name }}"
|
||||
role: metrics
|
||||
app: {{ template "redis.name" . }}
|
||||
{{- if .Values.metrics.podLabels }}
|
||||
{{ toYaml .Values.metrics.podLabels | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.metrics.podAnnotations }}
|
||||
annotations:
|
||||
{{ toYaml .Values.metrics.podAnnotations | indent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.metrics.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- range .Values.metrics.image.pullSecrets }}
|
||||
- name: {{ . }}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- if .Values.metrics.nodeSelector }}
|
||||
serviceAccountName: "{{ template "redis.serviceAccountName" . }}"
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.metrics.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.metrics.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml .Values.metrics.tolerations | indent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: metrics
|
||||
image: {{ template "metrics.image" . }}
|
||||
imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }}
|
||||
env:
|
||||
- name: REDIS_ADDR
|
||||
{{- if .Values.cluster.enabled }}
|
||||
value: {{ printf "%s-master:%d,%s-slave:%d" ( include "redis.fullname" . ) ( int .Values.master.port ) ( include "redis.fullname" . ) ( .Values.slave.port | default .Values.master.port | int ) | quote }}
|
||||
{{- else }}
|
||||
value: {{ printf "%s-master:%d" (include "redis.fullname" . ) (int .Values.master.port) | quote }}
|
||||
{{- end }}
|
||||
- name: REDIS_ALIAS
|
||||
value: {{ template "redis.fullname" . }}
|
||||
{{- if .Values.usePassword }}
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
{{- if .Values.existingSecret }}
|
||||
name: {{ .Values.existingSecret }}
|
||||
{{- else }}
|
||||
name: {{ template "redis.fullname" . }}
|
||||
{{- end }}
|
||||
key: redis-password
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: metrics
|
||||
containerPort: 9121
|
||||
resources:
|
||||
{{ toYaml .Values.metrics.resources | indent 10 }}
|
||||
{{- end }}
|
||||
@@ -1,27 +0,0 @@
|
||||
{{- if .Values.metrics.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "redis.fullname" . }}-metrics
|
||||
labels:
|
||||
app: {{ template "redis.name" . }}
|
||||
chart: {{ template "redis.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
annotations:
|
||||
{{ toYaml .Values.metrics.service.annotations | indent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.metrics.service.type }}
|
||||
{{ if eq .Values.metrics.service.type "LoadBalancer" -}} {{ if .Values.metrics.service.loadBalancerIP -}}
|
||||
loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }}
|
||||
{{ end -}}
|
||||
{{- end -}}
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 9121
|
||||
targetPort: metrics
|
||||
selector:
|
||||
app: {{ template "redis.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
role: metrics
|
||||
{{- end }}
|
||||
@@ -1,30 +0,0 @@
|
||||
{{- if .Values.networkPolicy.enabled }}
|
||||
kind: NetworkPolicy
|
||||
apiVersion: {{ template "networkPolicy.apiVersion" . }}
|
||||
metadata:
|
||||
name: "{{ template "redis.fullname" . }}"
|
||||
labels:
|
||||
app: {{ template "redis.name" . }}
|
||||
chart: {{ template "redis.chart" . }}
|
||||
release: "{{ .Release.Name }}"
|
||||
heritage: "{{ .Release.Service }}"
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: {{ template "redis.name" . }}
|
||||
ingress:
|
||||
# Allow inbound connections
|
||||
- ports:
|
||||
- port: 6379
|
||||
{{- if not .Values.networkPolicy.allowExternal }}
|
||||
from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{ template "redis.fullname" . }}-client: "true"
|
||||
{{- end }}
|
||||
{{- if .Values.metrics.enabled }}
|
||||
# Allow prometheus scrapes for metrics
|
||||
- ports:
|
||||
- port: 9121
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user