mirror of
https://github.com/hanzoai/deploy.git
synced 2026-10-07 08:44:50 +00:00
Reconcile could never have worked. RealGit set no working directory, so every command ran wherever the process started — for a scheduled job, nowhere — and git answers "fatal: not a git repository" to the fetch. That error arrives on the branch that reports GITHUB as unreadable, so a reconciler with perfect credentials and a perfect table would have called all 24 repos unreachable and asked a person to look at each one. The dry run passed throughout, because a dry run resolves names and never touches git. Git therefore takes the directory as a parameter, and Workspace prepares one store per repo under a root that MAY survive between runs. May, not must: git's fetch negotiation offers whatever is already present, so a kept root makes later runs deltas, and an empty one is equally correct and merely slower. That is what lets the job use an emptyDir instead of a claim — a ReadWriteOnce volume would buy the same time at the price of a job pod deadlocking on Multi-Attach whenever it schedules away from the node holding it. Both sides are now fetched, not just GitHub. The forge goes first for two reasons: its tip has to be local before a genuine divergence can be NAMED rather than reported as "ancestry undetermined", and once its history is present those objects are offered in negotiation, so the internet side of every run is a delta even on an empty store. That is the whole reason ten-minute scheduling is affordable over two dozen repositories. The proof is a real one. TestFastForwardMovesARealRepository builds two bare repositories, leaves the forge a commit behind, and requires it to end on GitHub's tip — then rewinds GitHub so the two genuinely disagree and requires the forge NOT to move. Every other test in this file uses a fake that agrees with the code about what git is, which is exactly why none of them caught this. Verified by mutation: drop `cmd.Dir` and it fails. Shipping is one binary, not two. cmd/hanzo-mirror becomes cmd/cd-mirror, dispatched by argv[0] like every other cd command, so the reconciler travels in the image the control plane already builds, pins and deploys — no second artifact to version, and no second chance for the two to disagree about which repos exist. The table travels with it at common.DefaultMirrorTable rather than living in a ConfigMap, so the JSON that CI validates is the JSON the scheduled run reads. Co-authored-by: Hanzo Dev <[email protected]>
526 lines
27 KiB
Go
526 lines
27 KiB
Go
package common
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
"github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
"github.com/hanzoai/cd/util/env"
|
|
)
|
|
|
|
// Argo CD component names
|
|
const (
|
|
CommandCLI = "hanzocd"
|
|
CommandApplicationController = "hanzocd-application-controller"
|
|
CommandApplicationSetController = "hanzocd-applicationset-controller"
|
|
CommandServer = "hanzocd-server"
|
|
CommandCMPServer = "hanzocd-cmp-server"
|
|
CommandCommitServer = "hanzocd-commit-server"
|
|
CommandGitAskPass = "hanzocd-git-ask-pass"
|
|
CommandK8sAuth = "hanzocd-k8s-auth"
|
|
CommandDex = "hanzocd-dex"
|
|
CommandRepoServer = "hanzocd-repo-server"
|
|
CommandMirror = "hanzocd-mirror"
|
|
)
|
|
|
|
// DefaultMirrorTable is where the Dockerfile installs the repository table, so a
|
|
// scheduled run needs no argument to find it. The flag still overrides it; what the
|
|
// default removes is a job spec that has to know a path baked into an image.
|
|
const DefaultMirrorTable = "/usr/local/share/cd/repos.json"
|
|
|
|
// Default service addresses and URLS of Argo CD internal services
|
|
const (
|
|
// DefaultRepoServerAddr is the gRPC address of the Argo CD repo server
|
|
DefaultRepoServerAddr = "hanzocd-repo-server:8081"
|
|
// DefaultCommitServerAddr is the gRPC address of the Argo CD commit server
|
|
DefaultCommitServerAddr = "hanzocd-commit-server:8086"
|
|
// DefaultDexServerAddr is the HTTP address of the Dex OIDC server, which we run a reverse proxy against
|
|
DefaultDexServerAddr = "hanzocd-dex-server:5556"
|
|
// DefaultRedisAddr is the default redis address
|
|
DefaultRedisAddr = "hanzocd-redis:6379"
|
|
)
|
|
|
|
// Kubernetes ConfigMap and Secret resource names which hold Argo CD settings
|
|
const (
|
|
ArgoCDConfigMapName = "hanzocd-cm"
|
|
ArgoCDSecretName = "hanzocd-secret"
|
|
ArgoCDNotificationsConfigMapName = "hanzocd-notifications-cm"
|
|
ArgoCDNotificationsSecretName = "hanzocd-notifications-secret"
|
|
ArgoCDRBACConfigMapName = "hanzocd-rbac-cm"
|
|
// ArgoCDKnownHostsConfigMapName contains SSH known hosts data for connecting repositories. Will get mounted as volume to pods
|
|
ArgoCDKnownHostsConfigMapName = "hanzocd-ssh-known-hosts-cm"
|
|
// ArgoCDTLSCertsConfigMapName contains TLS certificate data for connecting repositories. Will get mounted as volume to pods
|
|
ArgoCDTLSCertsConfigMapName = "hanzocd-tls-certs-cm"
|
|
ArgoCDGPGKeysConfigMapName = "hanzocd-gpg-keys-cm"
|
|
// ArgoCDAppControllerShardConfigMapName contains the application controller to shard mapping
|
|
ArgoCDAppControllerShardConfigMapName = "hanzocd-app-controller-shard-cm"
|
|
ArgoCDCmdParamsConfigMapName = "hanzocd-cmd-params-cm"
|
|
)
|
|
|
|
// Some default configurables
|
|
const (
|
|
DefaultSystemNamespace = "kube-system"
|
|
DefaultRepoType = "git"
|
|
)
|
|
|
|
// Default listener ports for ArgoCD components
|
|
const (
|
|
DefaultPortAPIServer = 8080
|
|
DefaultPortRepoServer = 8081
|
|
DefaultPortArgoCDMetrics = 8082
|
|
DefaultPortArgoCDAPIServerMetrics = 8083
|
|
DefaultPortRepoServerMetrics = 8084
|
|
DefaultPortCommitServer = 8086
|
|
DefaultPortCommitServerMetrics = 8087
|
|
)
|
|
|
|
// DefaultAddressAPIServer for ArgoCD components
|
|
const (
|
|
DefaultAddressAdminDashboard = "localhost"
|
|
DefaultAddressAPIServer = "0.0.0.0"
|
|
DefaultAddressAPIServerMetrics = "0.0.0.0"
|
|
DefaultAddressRepoServer = "0.0.0.0"
|
|
DefaultAddressRepoServerMetrics = "0.0.0.0"
|
|
DefaultAddressCommitServer = "0.0.0.0"
|
|
DefaultAddressCommitServerMetrics = "0.0.0.0"
|
|
)
|
|
|
|
// Default paths on the pod's file system
|
|
const (
|
|
// DefaultPathTLSConfig is the default path where TLS certificates for repositories are located
|
|
DefaultPathTLSConfig = "/app/config/tls"
|
|
// DefaultPathSSHConfig is the default path where SSH known hosts are stored
|
|
DefaultPathSSHConfig = "/app/config/ssh"
|
|
// DefaultSSHKnownHostsName is the Default name for the SSH known hosts file
|
|
DefaultSSHKnownHostsName = "ssh_known_hosts"
|
|
// DefaultGnuPgHomePath is the Default path to GnuPG home directory
|
|
DefaultGnuPgHomePath = "/app/config/gpg/keys"
|
|
// DefaultAppConfigPath is the Default path to repo server TLS endpoint config
|
|
DefaultAppConfigPath = "/app/config"
|
|
// DefaultPluginSockFilePath is the Default path to cmp server plugin socket file
|
|
DefaultPluginSockFilePath = "/home/cd/cmp-server/plugins"
|
|
// DefaultPluginConfigFilePath is the Default path to cmp server plugin configuration file
|
|
DefaultPluginConfigFilePath = "/home/cd/cmp-server/config"
|
|
// PluginConfigFileName is the Plugin Config File is a ConfigManagementPlugin manifest located inside the plugin container
|
|
PluginConfigFileName = "plugin.yaml"
|
|
)
|
|
|
|
// consts for podrequests metrics in cache/info
|
|
const (
|
|
PodRequestsCPU = "cpu"
|
|
PodRequestsMEM = "memory"
|
|
)
|
|
|
|
// Argo CD application related constants
|
|
const (
|
|
// ArgoCDAdminUsername is the username of the 'admin' user
|
|
ArgoCDAdminUsername = "admin"
|
|
// ArgoCDUserAgentName is the default user-agent name used by the gRPC API client library and grpc-gateway
|
|
ArgoCDUserAgentName = "hanzocd-client"
|
|
// ArgoCDSSAManager is the default cd manager name used by server-side apply syncs
|
|
ArgoCDSSAManager = "hanzocd-controller"
|
|
// AuthCookieName is the HTTP cookie name where we store our auth token
|
|
AuthCookieName = "cd.token"
|
|
// StateCookieName is the HTTP cookie name that holds temporary nonce tokens for CSRF protection
|
|
StateCookieName = "cd.oauthstate"
|
|
// StateCookieMaxAge is the maximum age of the oauth state cookie
|
|
StateCookieMaxAge = time.Minute * 5
|
|
|
|
// ChangePasswordSSOTokenMaxAge is the max token age for password change operation
|
|
ChangePasswordSSOTokenMaxAge = time.Minute * 5
|
|
// GithubAppCredsExpirationDuration is the default time used to cache the GitHub app credentials
|
|
GithubAppCredsExpirationDuration = time.Minute * 60
|
|
// AzureServicePrincipalCredsExpirationDuration is the default time used to cache the Azure service principal credentials
|
|
// SP tokens are valid for 60 minutes, so cache for 59 minutes to avoid issues with token expiration when taking the cleanup interval of 1 minute into account
|
|
AzureServicePrincipalCredsExpirationDuration = time.Minute * 59
|
|
|
|
// PasswordPatten is the default password patten
|
|
PasswordPatten = `^.{8,32}$`
|
|
|
|
// LegacyShardingAlgorithm is the default value for Sharding Algorithm it uses an `uid` based distribution (non-uniform)
|
|
LegacyShardingAlgorithm = "legacy"
|
|
// RoundRobinShardingAlgorithm is a flag value that can be opted for Sharding Algorithm it uses an equal distribution across all shards
|
|
RoundRobinShardingAlgorithm = "round-robin"
|
|
// AppControllerHeartbeatUpdateRetryCount is the retry count for updating the Shard Mapping to the Shard Mapping ConfigMap used by Application Controller
|
|
AppControllerHeartbeatUpdateRetryCount = 3
|
|
|
|
// ConsistentHashingWithBoundedLoadsAlgorithm uses an algorithm that tries to use an equal distribution across
|
|
// all shards but is optimised to handle sharding and/or cluster addition or removal. In case of sharding or
|
|
// cluster changes, this algorithm minimises the changes between shard and clusters assignments.
|
|
ConsistentHashingWithBoundedLoadsAlgorithm = "consistent-hashing"
|
|
|
|
DefaultShardingAlgorithm = LegacyShardingAlgorithm
|
|
)
|
|
|
|
// Dex related constants
|
|
const (
|
|
// DexAPIEndpoint is the endpoint where we serve the Dex API server
|
|
DexAPIEndpoint = "/v1/dex"
|
|
// LoginEndpoint is Argo CD's shorthand login endpoint which redirects to dex's OAuth 2.0 provider's consent page
|
|
LoginEndpoint = "/auth/login"
|
|
// LogoutEndpoint is Argo CD's shorthand logout endpoint which invalidates OIDC session after logout
|
|
LogoutEndpoint = "/auth/logout"
|
|
// CallbackEndpoint is Argo CD's final callback endpoint we reach after OAuth 2.0 login flow has been completed
|
|
CallbackEndpoint = "/auth/callback"
|
|
// DexCallbackEndpoint is Argo CD's final callback endpoint when Dex is configured
|
|
DexCallbackEndpoint = "/v1/dex/callback"
|
|
// ArgoCDClientAppName is name of the Oauth client app used when registering our web app to dex
|
|
ArgoCDClientAppName = "Argo CD"
|
|
// ArgoCDClientAppID is the Oauth client ID we will use when registering our app to dex
|
|
ArgoCDClientAppID = "argo-cd"
|
|
// ArgoCDCLIClientAppName is name of the Oauth client app used when registering our CLI to dex
|
|
ArgoCDCLIClientAppName = "Argo CD CLI"
|
|
// ArgoCDCLIClientAppID is the Oauth client ID we will use when registering our CLI to dex
|
|
ArgoCDCLIClientAppID = "argo-cd-cli"
|
|
// DexFederatedScope allows to receive the federated_claims from Dex. https://dexidp.io/docs/configuration/custom-scopes-claims-clients/
|
|
DexFederatedScope = "federated:id"
|
|
)
|
|
|
|
// Resource metadata labels and annotations (keys and values) used by Argo CD components
|
|
const (
|
|
// LabelKeyAppInstance is the label key to use to uniquely identify the instance of an application
|
|
// The Argo CD application name is used as the instance name
|
|
LabelKeyAppInstance = "app.kubernetes.io/instance"
|
|
// LabelKeyAppName is the label key to use to uniquely identify the name of the Kubernetes application
|
|
LabelKeyAppName = "app.kubernetes.io/name"
|
|
// LabelKeyAutoLabelClusterInfo if set to true will automatically add extra labels from the cluster info (currently it only adds a k8s version label)
|
|
LabelKeyAutoLabelClusterInfo = "apps.hanzo.ai/auto-label-cluster-info"
|
|
// LabelKeyLegacyApplicationName is the legacy label (v0.10 and below) and is superseded by 'app.kubernetes.io/instance'
|
|
LabelKeyLegacyApplicationName = "applications.apps.hanzo.ai/app-name"
|
|
// LabelKeySecretType contains the type of cd secret (currently: 'cluster', 'repository', 'repo-config' or 'repo-creds')
|
|
LabelKeySecretType = "apps.hanzo.ai/secret-type"
|
|
// LabelKeyClusterKubernetesVersion contains the kubernetes version of the cluster secret if it has been enabled
|
|
LabelKeyClusterKubernetesVersion = "apps.hanzo.ai/kubernetes-version"
|
|
// LabelValueSecretTypeCluster indicates a secret type of cluster
|
|
LabelValueSecretTypeCluster = "cluster"
|
|
// LabelValueSecretTypeRepository indicates a secret type of repository
|
|
LabelValueSecretTypeRepository = "repository"
|
|
// LabelValueSecretTypeRepoCreds indicates a secret type of repository credentials
|
|
LabelValueSecretTypeRepoCreds = "repo-creds"
|
|
// LabelValueSecretTypeRepositoryWrite indicates a secret type of repository credentials for writing
|
|
LabelValueSecretTypeRepositoryWrite = "repository-write"
|
|
// LabelValueSecretTypeRepoCredsWrite indicates a secret type of repository credentials for writing for templating
|
|
LabelValueSecretTypeRepoCredsWrite = "repo-write-creds"
|
|
// LabelValueSecretTypeSCMCreds indicates a secret type of SCM credentials
|
|
LabelValueSecretTypeSCMCreds = "scm-creds"
|
|
|
|
// AnnotationKeyAppInstance is the Argo CD application name is used as the instance name
|
|
AnnotationKeyAppInstance = "apps.hanzo.ai/tracking-id"
|
|
AnnotationInstallationID = "apps.hanzo.ai/installation-id"
|
|
|
|
// AnnotationCompareOptions is a comma-separated list of options for comparison
|
|
AnnotationCompareOptions = "apps.hanzo.ai/compare-options"
|
|
|
|
// AnnotationClientSideApplyMigrationManager specifies a custom field manager for client-side apply migration
|
|
AnnotationClientSideApplyMigrationManager = "apps.hanzo.ai/client-side-apply-migration-manager"
|
|
|
|
// AnnotationIgnoreHealthCheck when set on an Application's immediate child indicates that its health check
|
|
// can be disregarded.
|
|
AnnotationIgnoreHealthCheck = "apps.hanzo.ai/ignore-healthcheck"
|
|
|
|
// AnnotationKeyManagedBy is annotation name which indicates that k8s resource is managed by an application.
|
|
AnnotationKeyManagedBy = "managed-by"
|
|
// AnnotationValueManagedByArgoCD is a 'managed-by' annotation value for resources managed by Argo CD
|
|
AnnotationValueManagedByArgoCD = "apps.hanzo.ai"
|
|
|
|
// AnnotationKeyLinkPrefix tells the UI to add an external link icon to the application node
|
|
// that links to the value given in the annotation.
|
|
// The annotation key must be followed by a unique identifier. Ex: link.apps.hanzo.ai/dashboard
|
|
// It's valid to have multiple annotations that match the prefix.
|
|
// Values can simply be a url or they can have
|
|
// an optional link title separated by a "|"
|
|
// Ex: "http://grafana.example.com/d/yu5UH4MMz/deployments"
|
|
// Ex: "Go to Dashboard|http://grafana.example.com/d/yu5UH4MMz/deployments"
|
|
AnnotationKeyLinkPrefix = "link.apps.hanzo.ai/"
|
|
// AnnotationKeyIgnoreDefaultLinks tells the Application to not add autogenerated links from this object into its externalURLs
|
|
// This applies to ingress objects and takes effect if set to "true"
|
|
// This only disables the default behavior of generating links based on the ingress spec, and does not disable AnnotationKeyLinkPrefix
|
|
AnnotationKeyIgnoreDefaultLinks = "apps.hanzo.ai/ignore-default-links"
|
|
|
|
// AnnotationKeyAppSkipReconcile tells the Application to skip the Application controller reconcile.
|
|
// Skip reconcile when the value is "true" or any other string values that can be strconv.ParseBool() to be true.
|
|
AnnotationKeyAppSkipReconcile = "apps.hanzo.ai/skip-reconcile"
|
|
|
|
// LabelKeyComponentRepoServer is the label key to identify the component as repo-server
|
|
LabelKeyComponentRepoServer = "app.kubernetes.io/component"
|
|
// LabelValueComponentRepoServer is the label value for the repo-server component
|
|
LabelValueComponentRepoServer = "repo-server"
|
|
)
|
|
|
|
// Environment variables for tuning and debugging Argo CD
|
|
const (
|
|
// EnvVarSSODebug is an environment variable to enable additional OAuth debugging in the API server
|
|
EnvVarSSODebug = "CD_SSO_DEBUG"
|
|
// EnvVarRBACDebug is an environment variable to enable additional RBAC debugging in the API server
|
|
EnvVarRBACDebug = "CD_RBAC_DEBUG"
|
|
// EnvVarSSHDataPath overrides the location where SSH known hosts for repo access data is stored
|
|
EnvVarSSHDataPath = "CD_SSH_DATA_PATH"
|
|
// EnvVarTLSDataPath overrides the location where TLS certificate for repo access data is stored
|
|
EnvVarTLSDataPath = "CD_TLS_DATA_PATH"
|
|
// EnvGitAttemptsCount specifies number of git remote operations attempts count
|
|
EnvGitAttemptsCount = "CD_GIT_ATTEMPTS_COUNT"
|
|
// EnvGitRetryMaxDuration specifies max duration of git remote operation retry
|
|
EnvGitRetryMaxDuration = "CD_GIT_RETRY_MAX_DURATION"
|
|
// EnvGitRetryDuration specifies duration of git remote operation retry
|
|
EnvGitRetryDuration = "CD_GIT_RETRY_DURATION"
|
|
// EnvGitRetryFactor specifies factor of git remote operation retry
|
|
EnvGitRetryFactor = "CD_GIT_RETRY_FACTOR"
|
|
// EnvGitSubmoduleEnabled overrides git submodule support, true by default
|
|
EnvGitSubmoduleEnabled = "CD_GIT_MODULES_ENABLED"
|
|
// EnvHelmUserAgent specifies the User-Agent header for Helm repository requests
|
|
EnvHelmUserAgent = "CD_HELM_USER_AGENT"
|
|
// EnvGnuPGHome is the path to ArgoCD's GnuPG keyring for signature verification
|
|
EnvGnuPGHome = "CD_GNUPGHOME"
|
|
// EnvWatchAPIBufferSize is the buffer size used to transfer K8S watch events to watch API consumer
|
|
EnvWatchAPIBufferSize = "CD_WATCH_API_BUFFER_SIZE"
|
|
// EnvPauseGenerationAfterFailedAttempts will pause manifest generation after the specified number of failed generation attempts
|
|
EnvPauseGenerationAfterFailedAttempts = "CD_PAUSE_GEN_AFTER_FAILED_ATTEMPTS"
|
|
// EnvPauseGenerationMinutes pauses manifest generation for the specified number of minutes, after sufficient manifest generation failures
|
|
EnvPauseGenerationMinutes = "CD_PAUSE_GEN_MINUTES"
|
|
// EnvPauseGenerationRequests pauses manifest generation for the specified number of requests, after sufficient manifest generation failures
|
|
EnvPauseGenerationRequests = "CD_PAUSE_GEN_REQUESTS"
|
|
// EnvControllerReplicas is the number of controller replicas
|
|
EnvControllerReplicas = "CD_CONTROLLER_REPLICAS"
|
|
// EnvControllerHeartbeatTime will update the heartbeat for application controller to claim shard
|
|
EnvControllerHeartbeatTime = "CD_CONTROLLER_HEARTBEAT_TIME"
|
|
// EnvControllerShard is the shard number that should be handled by controller
|
|
EnvControllerShard = "CD_CONTROLLER_SHARD"
|
|
// EnvControllerShardingAlgorithm is the distribution sharding algorithm to be used: legacy or round-robin
|
|
EnvControllerShardingAlgorithm = "CD_CONTROLLER_SHARDING_ALGORITHM"
|
|
// EnvEnableDynamicClusterDistribution enables dynamic sharding (ALPHA)
|
|
EnvEnableDynamicClusterDistribution = "CD_ENABLE_DYNAMIC_CLUSTER_DISTRIBUTION"
|
|
// EnvEnableGRPCTimeHistogramEnv enables gRPC metrics collection
|
|
EnvEnableGRPCTimeHistogramEnv = "CD_ENABLE_GRPC_TIME_HISTOGRAM"
|
|
// EnvGithubAppCredsExpirationDuration controls the caching of Github app credentials. This value is in minutes (default: 60)
|
|
EnvGithubAppCredsExpirationDuration = "CD_GITHUB_APP_CREDS_EXPIRATION_DURATION"
|
|
// EnvAzureServicePrincipalCredsExpirationDuration controls the caching of Azure service principal credentials. This value is in minutes (default: 59). Any value greater than 59 will be set to 59 minutes
|
|
EnvAzureServicePrincipalCredsExpirationDuration = "CD_AZURE_SERVICE_PRINCIPAL_CREDS_EXPIRATION_DURATION"
|
|
// EnvHelmIndexCacheDuration controls how the helm repository index file is cached for (default: 0)
|
|
EnvHelmIndexCacheDuration = "CD_HELM_INDEX_CACHE_DURATION"
|
|
// EnvAppConfigPath allows to override the configuration path for repo server
|
|
EnvAppConfigPath = "CD_APP_CONF_PATH"
|
|
// EnvAuthToken is the environment variable name for the auth token used by the CLI
|
|
EnvAuthToken = "CD_AUTH_TOKEN"
|
|
// EnvLogFormat log format that is defined by `--logformat` option
|
|
EnvLogFormat = "CD_LOG_FORMAT"
|
|
// EnvLogLevel log level that is defined by `--loglevel` option
|
|
EnvLogLevel = "CD_LOG_LEVEL"
|
|
// EnvLogFormatEnableFullTimestamp enables the FullTimestamp option in logs
|
|
EnvLogFormatEnableFullTimestamp = "CD_LOG_FORMAT_ENABLE_FULL_TIMESTAMP"
|
|
// EnvLogFormatTimestamp is the timestamp format used in logs
|
|
EnvLogFormatTimestamp = "CD_LOG_FORMAT_TIMESTAMP"
|
|
// EnvMaxCookieNumber max number of chunks a cookie can be broken into
|
|
EnvMaxCookieNumber = "CD_MAX_COOKIE_NUMBER"
|
|
// EnvPluginSockFilePath allows to override the pluginSockFilePath for repo server and cmp server
|
|
EnvPluginSockFilePath = "CD_PLUGINSOCKFILEPATH"
|
|
// EnvCMPChunkSize defines the chunk size in bytes used when sending files to the cmp server
|
|
EnvCMPChunkSize = "CD_CMP_CHUNK_SIZE"
|
|
// EnvCMPWorkDir defines the full path of the work directory used by the CMP server
|
|
EnvCMPWorkDir = "CD_CMP_WORKDIR"
|
|
// EnvGPGDataPath overrides the location where GPG keyring for signature verification is stored
|
|
EnvGPGDataPath = "CD_GPG_DATA_PATH"
|
|
// EnvServer is the server address of the Argo CD API server.
|
|
EnvServer = "CD_SERVER"
|
|
// EnvServerName is the name of the Argo CD server component, as specified by the value under the LabelKeyAppName label key.
|
|
EnvServerName = "CD_SERVER_NAME"
|
|
// EnvRepoServerName is the name of the Argo CD repo server component, as specified by the value under the LabelKeyAppName label key.
|
|
EnvRepoServerName = "CD_REPO_SERVER_NAME"
|
|
// EnvAppControllerName is the name of the Argo CD application controller component, as specified by the value under the LabelKeyAppName label key.
|
|
EnvAppControllerName = "CD_APPLICATION_CONTROLLER_NAME"
|
|
// EnvRedisName is the name of the Argo CD redis component, as specified by the value under the LabelKeyAppName label key.
|
|
EnvRedisName = "CD_KV_NAME"
|
|
// EnvRedisHaProxyName is the name of the Argo CD Redis HA proxy component, as specified by the value under the LabelKeyAppName label key.
|
|
EnvRedisHaProxyName = "CD_KV_HAPROXY_NAME"
|
|
// EnvGRPCKeepAliveMin defines the GRPCKeepAliveEnforcementMinimum, used in the grpc.KeepaliveEnforcementPolicy. Expects a "Duration" format (e.g. 10s).
|
|
EnvGRPCKeepAliveMin = "CD_GRPC_KEEP_ALIVE_MIN"
|
|
// EnvServerSideDiff defines the env var used to enable ServerSide Diff feature.
|
|
// If defined, value must be "true" or "false".
|
|
EnvServerSideDiff = "CD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF"
|
|
// EnvGRPCMaxSizeMB is the environment variable to look for a max GRPC message size
|
|
EnvGRPCMaxSizeMB = "CD_GRPC_MAX_SIZE_MB"
|
|
)
|
|
|
|
// Config Management Plugin related constants
|
|
const (
|
|
// DefaultCMPChunkSize defines chunk size in bytes used when sending files to the cmp server
|
|
DefaultCMPChunkSize = 1024
|
|
|
|
// DefaultCMPWorkDirName defines the work directory name used by the cmp-server
|
|
DefaultCMPWorkDirName = "_cmp_server"
|
|
|
|
ConfigMapPluginDeprecationWarning = "hanzocd-cm plugins are deprecated, and support will be removed in v2.7. Upgrade your plugin to be installed via sidecar. https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/"
|
|
)
|
|
|
|
const (
|
|
// MinClientVersion is the minimum client version that can interface with this API server.
|
|
// When introducing breaking changes to the API or datastructures, this number should be bumped.
|
|
// The value here may be lower than the current value in VERSION
|
|
MinClientVersion = "1.4.0"
|
|
// CacheVersion is a objects version cached using util/cache/cache.go.
|
|
// Number should be bumped in case of backward incompatible change to make sure cache is invalidated after upgrade.
|
|
CacheVersion = "1.8.3"
|
|
)
|
|
|
|
// Constants used by util/clusterauth package
|
|
const (
|
|
ClusterAuthRequestTimeout = 10 * time.Second
|
|
)
|
|
|
|
const (
|
|
BearerTokenTimeout = 30 * time.Second
|
|
)
|
|
|
|
// TokenRevocationTimeout is the maximum time allowed for a server-side token revocation call during logout.
|
|
const TokenRevocationTimeout = 10 * time.Second
|
|
|
|
// TokenRevocationClientTimeout is the maximum time the CLI waits for the server to complete token revocation.
|
|
const TokenRevocationClientTimeout = 15 * time.Second
|
|
|
|
const (
|
|
DefaultGitRetryMaxDuration time.Duration = time.Second * 5 // 5s
|
|
DefaultGitRetryDuration time.Duration = time.Millisecond * 250 // 0.25s
|
|
DefaultGitRetryFactor = int64(2)
|
|
)
|
|
|
|
// Constants represent the pod selector labels of the Argo CD component names. These values are determined by the
|
|
// installation manifests.
|
|
const (
|
|
DefaultServerName = "hanzocd-server"
|
|
DefaultRepoServerName = "hanzocd-repo-server"
|
|
DefaultApplicationControllerName = "hanzocd-application-controller"
|
|
DefaultRedisName = "hanzocd-redis"
|
|
DefaultRedisHaProxyName = "hanzocd-redis-ha-haproxy"
|
|
)
|
|
|
|
// GetGnuPGHomePath retrieves the path to use for GnuPG home directory, which is either taken from GNUPGHOME environment or a default value
|
|
func GetGnuPGHomePath() string {
|
|
gnuPgHome := os.Getenv(EnvGnuPGHome)
|
|
if gnuPgHome == "" {
|
|
return DefaultGnuPgHomePath
|
|
}
|
|
return gnuPgHome
|
|
}
|
|
|
|
// GetPluginSockFilePath retrieves the path of plugin sock file, which is either taken from PluginSockFilePath environment or a default value
|
|
func GetPluginSockFilePath() string {
|
|
pluginSockFilePath := os.Getenv(EnvPluginSockFilePath)
|
|
if pluginSockFilePath == "" {
|
|
return DefaultPluginSockFilePath
|
|
}
|
|
return pluginSockFilePath
|
|
}
|
|
|
|
// GetCMPChunkSize will return the env var EnvCMPChunkSize value if defined or DefaultCMPChunkSize otherwise.
|
|
// If EnvCMPChunkSize is defined but not a valid int, DefaultCMPChunkSize will be returned
|
|
func GetCMPChunkSize() int {
|
|
if chunkSizeStr := os.Getenv(EnvCMPChunkSize); chunkSizeStr != "" {
|
|
chunkSize, err := strconv.Atoi(chunkSizeStr)
|
|
if err != nil {
|
|
logrus.Warnf("invalid env var value for %s: not a valid int: %s. Default value will be used.", EnvCMPChunkSize, err)
|
|
return DefaultCMPChunkSize
|
|
}
|
|
return chunkSize
|
|
}
|
|
return DefaultCMPChunkSize
|
|
}
|
|
|
|
// GetCMPWorkDir will return the full path of the work directory used by the CMP server.
|
|
// This directory and all it's contents will be deleted during CMP bootstrap.
|
|
func GetCMPWorkDir() string {
|
|
if workDir := os.Getenv(EnvCMPWorkDir); workDir != "" {
|
|
return filepath.Join(workDir, DefaultCMPWorkDirName)
|
|
}
|
|
return filepath.Join(os.TempDir(), DefaultCMPWorkDirName)
|
|
}
|
|
|
|
const (
|
|
// AnnotationApplicationSetRefresh is an annotation that is added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation.
|
|
AnnotationApplicationSetRefresh = "apps.hanzo.ai/application-set-refresh"
|
|
)
|
|
|
|
// gRPC settings
|
|
const (
|
|
defaultGRPCKeepAliveEnforcementMinimum = 10 * time.Second
|
|
)
|
|
|
|
func GetGRPCKeepAliveEnforcementMinimum() time.Duration {
|
|
if GRPCKeepAliveMinStr := os.Getenv(EnvGRPCKeepAliveMin); GRPCKeepAliveMinStr != "" {
|
|
GRPCKeepAliveMin, err := time.ParseDuration(GRPCKeepAliveMinStr)
|
|
if err != nil {
|
|
logrus.Warnf("invalid env var value for %s: cannot parse: %s. Default value %s will be used.", EnvGRPCKeepAliveMin, err, defaultGRPCKeepAliveEnforcementMinimum)
|
|
return defaultGRPCKeepAliveEnforcementMinimum
|
|
}
|
|
return GRPCKeepAliveMin
|
|
}
|
|
return defaultGRPCKeepAliveEnforcementMinimum
|
|
}
|
|
|
|
func GetGRPCKeepAliveTime() time.Duration {
|
|
// GRPCKeepAliveTime is 2x enforcement minimum to ensure network jitter does not introduce ENHANCE_YOUR_CALM errors
|
|
return 2 * GetGRPCKeepAliveEnforcementMinimum()
|
|
}
|
|
|
|
// Security severity logging
|
|
const (
|
|
SecurityField = "security"
|
|
// SecurityCWEField is the logs field for the CWE associated with a log line. CWE stands for Common Weakness Enumeration. See https://cwe.mitre.org/
|
|
SecurityCWEField = "CWE"
|
|
SecurityCWEIncompleteCleanup = 459
|
|
SecurityCWEMissingReleaseOfFileDescriptor = 775
|
|
SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS)
|
|
SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem)
|
|
SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos)
|
|
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
|
|
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
|
|
)
|
|
|
|
// TokenVerificationError is a generic error message for a failure to verify a JWT
|
|
const TokenVerificationError = "failed to verify the token"
|
|
|
|
var ErrTokenVerification = errors.New(TokenVerificationError)
|
|
|
|
var PermissionDeniedAPIError = status.Error(codes.PermissionDenied, "permission denied")
|
|
|
|
var WatchAPIBufferSize = env.ParseNumFromEnv(EnvWatchAPIBufferSize, 1000, 0, math.MaxInt32)
|
|
|
|
// Redis password consts
|
|
const (
|
|
// RedisInitialCredentials is the name for the cd kubernetes secret which will have the redis password
|
|
RedisInitialCredentials = "hanzocd-redis"
|
|
// RedisInitialCredentialsKey is the key for the cd kubernetes secret that maps to the redis password
|
|
RedisInitialCredentialsKey = "auth"
|
|
)
|
|
|
|
/*
|
|
SetOptionalRedisPasswordFromKubeConfig sets the optional Redis password if it exists in the k8s namespace's secrets.
|
|
|
|
We specify kubeClient as kubernetes.Interface to allow for mocking in tests, but this should be treated as a kubernetes.Clientset param.
|
|
*/
|
|
func SetOptionalRedisPasswordFromKubeConfig(ctx context.Context, kubeClient kubernetes.Interface, namespace string, redisOptions *redis.Options) error {
|
|
secret, err := kubeClient.CoreV1().Secrets(namespace).Get(ctx, RedisInitialCredentials, metav1.GetOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get secret %s/%s: %w", namespace, RedisInitialCredentials, err)
|
|
}
|
|
if secret == nil {
|
|
return fmt.Errorf("failed to get secret %s/%s: secret is nil", namespace, RedisInitialCredentials)
|
|
}
|
|
_, ok := secret.Data[RedisInitialCredentialsKey]
|
|
if !ok {
|
|
return fmt.Errorf("secret %s/%s does not contain key %s", namespace, RedisInitialCredentials, RedisInitialCredentialsKey)
|
|
}
|
|
redisOptions.Password = string(secret.Data[RedisInitialCredentialsKey])
|
|
return nil
|
|
}
|