Documentation
¶
Overview ¶
Package cli contains shared CLI infrastructure used by command packages.
Command-specific behavior belongs in internal/cli/<command>; this package is limited to config, constants, errors, runtime composition, process execution, kubectl clients, terminal output, and test doubles.
Index ¶
- Constants
- Variables
- func ComponentNamespace(key string) string
- func Cyan(msg string) string
- func Error(msg string)
- func GetAnalyticsIngestURLOverride() string
- func GetCertTimeout() time.Duration
- func GetClusterName() string
- func GetDefaultServerPort() int
- func GetDeploymentTimeout() time.Duration
- func GetGatewayOTLPEndpointOverride() string
- func GetGatewayProxyImageOverride() string
- func GetHelperPodTimeout() time.Duration
- func GetMcpIngressHost() string
- func GetOperatorImageOverride() string
- func GetPlatformIngressHost() string
- func GetProvidedTLSSecrets() bool
- func GetRegistryClusterIssuerName() string
- func GetRegistryEndpoint() string
- func GetRegistryIngressHost() string
- func GetRegistryPort() int
- func GetSkopeoImage() string
- func Green(msg string) string
- func Header(title string)
- func Info(msg string)
- func IsDebugMode() bool
- func LogStructuredError(logger *zap.Logger, err error, msg string)
- func NewSetupStepFailedError() error
- func NewWithSentinel(base error, msg string) error
- func Red(msg string) string
- func ResolveEmailAlias(email, username string) (string, error)
- func Section(title string)
- func SetDebugMode(enabled bool)
- func SpinnerStart(msg string) func(success bool, finalMsg string)
- func Step(title string)
- func Success(msg string)
- func SwapDefaultKubectlClient(c *KubectlClient) (restore func())
- func SwapExecExecutor(e Executor) (restore func())
- func Table(data [][]string)
- func TableBoxed(data [][]string)
- func ValidateK8sNameAndNamespace(nameLabel string, nameSentinel error, name, namespace string) (string, string, error)
- func ValidateManifestField(field, value string) (string, error)
- func Warn(msg string)
- func WrapWithSentinel(base, cause error, msg string) error
- func WrapWithSentinelAndContext(base, cause error, msg string, context map[string]any) error
- func Yellow(msg string) string
- type CLIConfig
- type Command
- type ExecSpec
- type ExecValidator
- type Executor
- type KubectlClient
- func (c *KubectlClient) CombinedOutput(args []string) ([]byte, error)
- func (c *KubectlClient) CommandArgs(args []string) (Command, error)
- func (c *KubectlClient) Output(args []string) ([]byte, error)
- func (c *KubectlClient) Run(args []string) error
- func (c *KubectlClient) RunWithOutput(args []string, stdout, stderr io.Writer) error
- type KubectlRunner
- type MockCommand
- type MockExecutor
- type Printer
- func (p *Printer) Cyan(msg string) string
- func (p *Printer) Error(msg string)
- func (p *Printer) Green(msg string) string
- func (p *Printer) Header(title string)
- func (p *Printer) Info(msg string)
- func (p *Printer) Printf(format string, a ...interface{})
- func (p *Printer) Println(a ...interface{})
- func (p *Printer) Red(msg string) string
- func (p *Printer) Section(title string)
- func (p *Printer) SpinnerStart(msg string) func(success bool, finalMsg string)
- func (p *Printer) Step(title string)
- func (p *Printer) Success(msg string)
- func (p *Printer) Table(data [][]string)
- func (p *Printer) TableBoxed(data [][]string)
- func (p *Printer) Warn(msg string)
- func (p *Printer) Yellow(msg string) string
- type Runtime
Constants ¶
const ( // Exported aliases for tests and subpackages (same values as above). DefaultRegistryEndpoint = defaultRegistryEndpoint DefaultRegistryIngressHost = defaultRegistryIngressHost )
Default values
const ( // NamespaceMCPRuntime is the namespace for the MCP runtime operator. NamespaceMCPRuntime = "github.com/mcp-runtime/mcp-runtime" // NamespaceRegistry is the namespace for the container registry. NamespaceRegistry = "registry" // NamespaceMCPServers is the default namespace for MCP server deployments. NamespaceMCPServers = mcpdefaults.MCPServersNamespace // PlatformNamespace holds control-plane services. PlatformNamespace = platforminventory.PlatformNamespace // ObservabilityNamespace holds the event pipeline and telemetry stack. ObservabilityNamespace = platforminventory.ObservabilityNamespace // LogCollectorNamespace isolates the node log collector and its hostPath access. LogCollectorNamespace = mcpdefaults.LogCollectorNamespace )
This file defines constants used across the CLI, including:
- Kubernetes namespace names
- Deployment and resource names
- Label selectors
- Default values
const ( // OperatorDeploymentName is the name of the operator deployment. OperatorDeploymentName = "mcp-runtime-operator-controller-manager" // OperatorManagerContainerName is the main manager container in the operator deployment. OperatorManagerContainerName = "manager" // RegistryDeploymentName is the name of the registry deployment. RegistryDeploymentName = "registry" // RegistryServiceName is the name of the registry service. RegistryServiceName = "registry" // RegistryPVCName is the name of the registry persistent volume claim. RegistryPVCName = "registry-storage" )
Deployment and resource names.
const ( // MCPServerCRDName is the full name of the MCPServer CRD. MCPServerCRDName = "mcpservers.mcpruntime.org" // CertManagerCRDName is the full name of the cert-manager Certificate CRD. CertManagerCRDName = "certificates.cert-manager.io" )
CRD identifiers.
const ( // LabelApp is the standard app label key. LabelApp = "app" // LabelManagedBy is the label indicating the managing controller. LabelManagedBy = "app.kubernetes.io/managed-by" // LabelManagedByValue is the value for the managed-by label. LabelManagedByValue = "github.com/mcp-runtime/mcp-runtime" )
Labels used for resource identification.
const ( // SelectorRegistry is the label selector for registry pods. SelectorRegistry = "app=registry" // SelectorOperator is the label selector for operator pods. SelectorOperator = "control-plane=controller-manager" // SelectorManagedBy is the label selector for MCP-managed resources. SelectorManagedBy = "app.kubernetes.io/managed-by=mcp-runtime" )
Selector strings for kubectl queries.
Variables ¶
var ( // CLI errors. ErrImageRequired = newSentinelError("image is required", errx.CodeCLI, errx.DescCLI) ErrInvalidServerName = newSentinelError("invalid server name", errx.CodeCLI, errx.DescCLI) ErrGetWorkingDirectoryFailed = newSentinelError("get working directory", errx.CodeCLI, errx.DescCLI) ErrControlCharsNotAllowed = newSentinelError("value must not contain control characters", errx.CodeCLI, errx.DescCLI) ErrFieldRequired = newSentinelError("field is required", errx.CodeCLI, errx.DescCLI) ErrGetHomeDirectoryFailed = newSentinelError("failed to get home directory", errx.CodeCLI, errx.DescCLI) ErrUnknownRegistryMode = newSentinelError("unknown registry mode", errx.CodeCLI, errx.DescCLI) // Auth package errors. ErrAuthAPIURLRequired = newSentinelError("api URL is required", errx.CodeAuth, errx.DescAuth) ErrAuthAPIURLInvalid = newSentinelError("api URL must include scheme and host", errx.CodeAuth, errx.DescAuth) ErrAuthEmailPasswordRequired = newSentinelError("email and password are both required for password login", errx.CodeAuth, errx.DescAuth) ErrAuthPlatformLoginFailed = newSentinelError("platform login failed", errx.CodeAuth, errx.DescAuth) ErrAuthReadStdinFailed = newSentinelError("read stdin", errx.CodeAuth, errx.DescAuth) ErrAuthTTYRequired = newSentinelError("not a TTY: pass --token, --token-stdin, or run in an interactive terminal", errx.CodeAuth, errx.DescAuth) ErrAuthReadTokenFailed = newSentinelError("read token", errx.CodeAuth, errx.DescAuth) ErrAuthTokenRequired = newSentinelError("token is required", errx.CodeAuth, errx.DescAuth) ErrAuthTokenVerificationFailed = newSentinelError("API token could not be verified", errx.CodeAuth, errx.DescAuth) ErrAuthLoginHTTPStatus = newSentinelError("login HTTP status failed", errx.CodeAuth, errx.DescAuth) ErrAuthLoginResponseMissingAccessToken = newSentinelError("login response did not include access_token", errx.CodeAuth, errx.DescAuth) ErrAuthServerRejectedToken = newSentinelError("server rejected the token", errx.CodeAuth, errx.DescAuth) ErrAuthAPIURLMayBeWrong = newSentinelError("API URL may be wrong", errx.CodeAuth, errx.DescAuth) ErrAuthVerifyRequestFailed = newSentinelError("verify request failed", errx.CodeAuth, errx.DescAuth) ErrAuthFileDescriptorOutOfRange = newSentinelError("file descriptor out of range", errx.CodeAuth, errx.DescAuth) // Pipeline errors. ErrLoadMetadataFailed = newSentinelError("failed to load metadata", errx.CodePipeline, errx.DescPipeline) ErrNoServersInMetadata = newSentinelError("no servers found in metadata", errx.CodePipeline, errx.DescPipeline) ErrGenerateCRDsFailed = newSentinelError("failed to generate CRDs", errx.CodePipeline, errx.DescPipeline) ErrListManifestFilesFailed = newSentinelError("failed to list manifest files", errx.CodePipeline, errx.DescPipeline) ErrNoManifestFilesFound = newSentinelError("no manifest files found", errx.CodePipeline, errx.DescPipeline) ErrApplyManifestFailed = newSentinelError("failed to apply manifest", errx.CodePipeline, errx.DescPipeline) // Operator errors. ErrOperatorNotFound = newSentinelError("operator not found", errx.CodeOperator, errx.DescOperator) ErrOperatorNotReady = newSentinelError("operator not ready", errx.CodeOperator, errx.DescOperator) // Setup errors. ErrClusterInitFailed = newSentinelError("failed to initialize cluster", errx.CodeSetup, errx.DescSetup) ErrClusterConfigFailed = newSentinelError("cluster configuration failed", errx.CodeSetup, errx.DescSetup) ErrTLSSetupFailed = newSentinelError("TLS setup failed", errx.CodeSetup, errx.DescSetup) ErrDeployRegistryFailed = newSentinelError("failed to deploy registry", errx.CodeSetup, errx.DescSetup) ErrOperatorImageBuildFailed = newSentinelError("operator image build failed", errx.CodeSetup, errx.DescSetup) ErrGatewayProxyImageBuildFailed = newSentinelError("gateway proxy image build failed", errx.CodeSetup, errx.DescSetup) ErrEnsureRegistryNamespaceFailed = newSentinelError("failed to ensure registry namespace", errx.CodeSetup, errx.DescSetup) ErrPushOperatorImageInternalFailed = newSentinelError("failed to push operator image to internal registry", errx.CodeSetup, errx.DescSetup) ErrPushGatewayProxyImageInternalFailed = newSentinelError("failed to push gateway proxy image to internal registry", errx.CodeSetup, errx.DescSetup) ErrOperatorDeploymentFailed = newSentinelError("operator deployment failed", errx.CodeSetup, errx.DescSetup) ErrConfigureExternalRegistryEnvFailed = newSentinelError("failed to configure external registry env on operator", errx.CodeSetup, errx.DescSetup) ErrRestartOperatorDeploymentFailed = newSentinelError("failed to restart operator deployment after registry env update", errx.CodeSetup, errx.DescSetup) ErrCRDCheckFailed = newSentinelError("CRD check failed", errx.CodeSetup, errx.DescSetup) ErrRenderSecretManifestFailed = newSentinelError("render secret manifest", errx.CodeSetup, errx.DescSetup) ErrApplySecretManifestFailed = newSentinelError("apply secret manifest", errx.CodeSetup, errx.DescSetup) ErrMarshalDockerConfigFailed = newSentinelError("marshal docker config", errx.CodeSetup, errx.DescSetup) ErrApplyImagePullSecretFailed = newSentinelError("apply imagePullSecret", errx.CodeSetup, errx.DescSetup) ErrPushImageInClusterFailed = newSentinelError("failed to push image in-cluster", errx.CodeSetup, errx.DescSetup) ErrSetupStepFailed = newSentinelError("setup step failed", errx.CodeSetup, errx.DescSetup) ErrApplyCRDFailed = newSentinelError("failed to apply CRD", errx.CodeSetup, errx.DescSetup) ErrEnsureOperatorNamespaceFailed = newSentinelError("failed to ensure operator namespace", errx.CodeSetup, errx.DescSetup) ErrApplyRBACFailed = newSentinelError("failed to apply RBAC", errx.CodeSetup, errx.DescSetup) ErrReadManagerYAMLFailed = newSentinelError("failed to read manager.yaml", errx.CodeSetup, errx.DescSetup) ErrReadIngressManifestFailed = newSentinelError("failed to read ingress manifest", errx.CodeSetup, errx.DescSetup) ErrParseManagerYAMLFailed = newSentinelError("failed to parse manager.yaml", errx.CodeSetup, errx.DescSetup) ErrSetOperatorImageFailed = newSentinelError("failed to set operator image", errx.CodeSetup, errx.DescSetup) ErrMutateManagerYAMLFailed = newSentinelError("failed to mutate manager.yaml", errx.CodeSetup, errx.DescSetup) ErrRenderManagerYAMLFailed = newSentinelError("failed to render mutated manager.yaml", errx.CodeSetup, errx.DescSetup) ErrCreateTempFileFailed = newSentinelError("failed to create temp file", errx.CodeSetup, errx.DescSetup) ErrCloseTempFileFailed = newSentinelError("failed to close temp file", errx.CodeSetup, errx.DescSetup) ErrWriteTempFileFailed = newSentinelError("failed to write temp file", errx.CodeSetup, errx.DescSetup) ErrApplyManagerDeploymentFailed = newSentinelError("failed to apply manager deployment", errx.CodeSetup, errx.DescSetup) ErrClusterIssuerApplyFailed = newSentinelError("failed to apply ClusterIssuer", errx.CodeSetup, errx.DescSetup) ErrCreateRegistryNamespaceFailed = newSentinelError("failed to create registry namespace", errx.CodeSetup, errx.DescSetup) ErrApplyCertificateFailed = newSentinelError("failed to apply Certificate", errx.CodeSetup, errx.DescSetup) // Setup platform package errors. ErrSetupImagePlatformNoNodeArchitectures = newSentinelError("could not resolve setup image platform: no Kubernetes node architectures were reported", errx.CodeSetup, errx.DescSetup) ErrSetupImagePlatformMixedNodeArchitectures = newSentinelError("mixed Kubernetes node architectures detected", errx.CodeSetup, errx.DescSetup) ErrSetupImagePlatformMismatch = newSentinelError("MCP_IMAGE_PLATFORM does not match Kubernetes node architecture", errx.CodeSetup, errx.DescSetup) ErrSetupImagePlatformInvalid = newSentinelError("invalid MCP_IMAGE_PLATFORM", errx.CodeSetup, errx.DescSetup) ErrSetupImagePlatformUnsupported = newSentinelError("unsupported MCP_IMAGE_PLATFORM", errx.CodeSetup, errx.DescSetup) ErrSetupImagePlatformKubectlNil = newSentinelError("could not resolve setup image platform: kubectl runner is nil", errx.CodeSetup, errx.DescSetup) ErrSetupInspectNodeArchitecturesFailed = newSentinelError("could not inspect Kubernetes node architectures", errx.CodeSetup, errx.DescSetup) ErrSetupInvalidStorageMode = newSentinelError("invalid storage mode", errx.CodeSetup, errx.DescSetup) ErrSetupInvalidPlatformMode = newSentinelError("invalid platform mode", errx.CodeSetup, errx.DescSetup) ErrSetupInvalidRegistryMode = newSentinelError("invalid registry mode", errx.CodeSetup, errx.DescSetup) ErrSetupSetRuntimeTestModeFailed = newSentinelError("set MCP_RUNTIME_TEST_MODE", errx.CodeSetup, errx.DescSetup) ErrSetupUnsetRuntimeTestModeFailed = newSentinelError("unset MCP_RUNTIME_TEST_MODE", errx.CodeSetup, errx.DescSetup) ErrSetupSetPlatformModeFailed = newSentinelError("set MCP_PLATFORM_MODE", errx.CodeSetup, errx.DescSetup) ErrSetupListTraefikDeploymentsFailed = newSentinelError("list traefik deployments", errx.CodeSetup, errx.DescSetup) ErrSetupMarshalTraefikDeploymentPatchFailed = newSentinelError("marshal traefik deployment patch", errx.CodeSetup, errx.DescSetup) ErrSetupReadTraefikDeploymentFailed = newSentinelError("read traefik deployment", errx.CodeSetup, errx.DescSetup) ErrSetupDecodeTraefikDeploymentFailed = newSentinelError("decode traefik deployment", errx.CodeSetup, errx.DescSetup) ErrSetupDeploymentReadinessDeadlineExceeded = newSentinelError("deployment readiness deadline exceeded", errx.CodeSetup, errx.DescSetup) ErrSetupTLSKubectlRunnerNil = newSentinelError("kubectl runner is nil", errx.CodeSetup, errx.DescSetup) ErrSetupInspectClusterIssuerFailed = newSentinelError("inspect ClusterIssuer", errx.CodeSetup, errx.DescSetup) ErrSetupTLSCertificateSANsEmpty = newSentinelError("no DNS names or IP addresses resolved for the Certificate", errx.CodeSetup, errx.DescSetup) ErrSetupDeleteClickHouseInitJobFailed = newSentinelError("delete existing clickhouse init job", errx.CodeSetup, errx.DescSetup) ErrSetupAnalyticsRolloutFailed = newSentinelError("analytics components failed to roll out", errx.CodeSetup, errx.DescSetup) ErrSetupRenderManifestFailed = newSentinelError("render manifest", errx.CodeSetup, errx.DescSetup) ErrSetupApplyPlatformUIIngressFailed = newSentinelError("apply platform UI ingress", errx.CodeSetup, errx.DescSetup) ErrSetupRemovePathBasedSentinelIngressesFailed = newSentinelError("remove path-based sentinel ingresses for public platform host", errx.CodeSetup, errx.DescSetup) ErrSetupDecodeAnalyticsConfigManifestFailed = newSentinelError("decode analytics config manifest", errx.CodeSetup, errx.DescSetup) ErrSetupEncodeAnalyticsConfigManifestFailed = newSentinelError("encode analytics config manifest", errx.CodeSetup, errx.DescSetup) ErrSetupReadConfigMapFailed = newSentinelError("read configmap", errx.CodeSetup, errx.DescSetup) ErrSetupDecodeConfigMapFailed = newSentinelError("decode configmap", errx.CodeSetup, errx.DescSetup) ErrSetupReadSecretKeyFailed = newSentinelError("read secret key", errx.CodeSetup, errx.DescSetup) ErrSetupDecodeSecretKeyFailed = newSentinelError("decode secret key", errx.CodeSetup, errx.DescSetup) // Platform update errors. ErrUpdateTargetRequired = newSentinelError("update target required", errx.CodeSetup, errx.DescSetup) ErrUpdateManifestInvalid = newSentinelError("release manifest invalid", errx.CodeSetup, errx.DescSetup) ErrUpdateTargetMismatch = newSentinelError("release manifest version does not match --to", errx.CodeSetup, errx.DescSetup) ErrUpdateInvalidFlag = newSentinelError("invalid update flag", errx.CodeSetup, errx.DescSetup) ErrUpdateKubeClientFailed = newSentinelError("create Kubernetes client for update", errx.CodeSetup, errx.DescSetup) ErrUpdateNotInstalled = newSentinelError("cluster is not an MCP Runtime install", errx.CodeSetup, errx.DescSetup) ErrUpdateInventoryFailed = newSentinelError("read installed platform inventory", errx.CodeSetup, errx.DescSetup) ErrUpdateCRDChange = newSentinelError("release changes CRDs", errx.CodeSetup, errx.DescSetup) ErrUpdateBlocked = newSentinelError("update plan has blocked components", errx.CodeSetup, errx.DescSetup) ErrUpdateConfirmationMissing = newSentinelError("update confirmation required", errx.CodeSetup, errx.DescSetup) ErrUpdateAborted = newSentinelError("update aborted", errx.CodeSetup, errx.DescSetup) ErrUpdateRolloutFailed = newSentinelError("platform update rollout failed", errx.CodeSetup, errx.DescSetup) ErrUpdateBuildFailed = newSentinelError("platform update image build failed", errx.CodeSetup, errx.DescSetup) // Cert errors. ErrCertManagerNotInstalled = newSentinelError("cert-manager not installed", errx.CodeCert, errx.DescCert) ErrCertManagerInstallFailed = newSentinelError("cert-manager install failed", errx.CodeCert, errx.DescCert) ErrCASecretNotFound = newSentinelError("CA secret not found", errx.CodeCert, errx.DescCert) ErrCASecretInvalid = newSentinelError("CA secret invalid", errx.CodeCert, errx.DescCert) ErrCAExpired = newSentinelError("CA certificate expired", errx.CodeCert, errx.DescCert) ErrCANearExpiry = newSentinelError("CA certificate near expiry", errx.CodeCert, errx.DescCert) ErrCertificateNotReady = newSentinelError("certificate not ready", errx.CodeCert, errx.DescCert) ErrClusterIssuerNotFound = newSentinelError("ClusterIssuer not found", errx.CodeCert, errx.DescCert) ErrRegistryCertificateNotFound = newSentinelError("registry Certificate not found", errx.CodeCert, errx.DescCert) // Certmanager package errors. ErrCertEncodeGeneratedCAFailed = newSentinelError("failed to encode generated internal CA", errx.CodeCert, errx.DescCert) ErrCertLookupRegistryIngressFailed = newSentinelError("failed to look up registry ingress", errx.CodeCert, errx.DescCert) ErrCertRemoveRegistryIngressAnnotation = newSentinelError("failed to remove cert-manager.io/cluster-issuer from registry ingress", errx.CodeCert, errx.DescCert) ErrCertRegistryTLSSecretConflict = newSentinelError("registry TLS secret is already referenced by Certificate(s)", errx.CodeCert, errx.DescCert) ErrCertListCertificatesFailed = newSentinelError("failed to list cert-manager Certificates", errx.CodeCert, errx.DescCert) ErrCertParseCertificatesFailed = newSentinelError("failed to parse cert-manager Certificates", errx.CodeCert, errx.DescCert) ErrCertACMEPublicDNSNameRequired = newSentinelError("ACME public CA requires a public DNS name", errx.CodeCert, errx.DescCert) ErrCertACMEPublicDNSNameInvalid = newSentinelError("ACME public CA requires a public DNS name; invalid host", errx.CodeCert, errx.DescCert) ErrCertACMEIngressManifestInvalid = newSentinelError("http-01 ingress manifest is not valid for Let's Encrypt", errx.CodeCert, errx.DescCert) ErrCertTraefikNotReady = newSentinelError("traefik not ready", errx.CodeCert, errx.DescCert) ErrCertACMEEmailRequired = newSentinelError("ACME email is required", errx.CodeCert, errx.DescCert) ErrCertCertificateSANsEmpty = newSentinelError("TLS has no DNS names or IP addresses to request", errx.CodeCert, errx.DescCert) // Cluster errors. ErrCRDNotInstalled = newSentinelError("MCPServer CRD not installed", errx.CodeCluster, errx.DescCluster) ErrClusterNotAccessible = newSentinelError("cluster not accessible", errx.CodeCluster, errx.DescCluster) ErrNamespaceNotFound = newSentinelError("namespace not found", errx.CodeCluster, errx.DescCluster) ErrDeploymentTimeout = newSentinelError("deployment timed out waiting for readiness", errx.CodeCluster, errx.DescCluster) ErrInstallCRDFailed = newSentinelError("failed to install CRD", errx.CodeCluster, errx.DescCluster) ErrEnsureRuntimeNamespaceFailed = newSentinelError("failed to ensure mcp-runtime namespace", errx.CodeCluster, errx.DescCluster) ErrEnsureServersNamespaceFailed = newSentinelError("failed to ensure mcp-servers namespace", errx.CodeCluster, errx.DescCluster) ErrKubeconfigNotReadable = newSentinelError("kubeconfig not found or not readable", errx.CodeCluster, errx.DescCluster) ErrSetKubeconfigFailed = newSentinelError("failed to set KUBECONFIG", errx.CodeCluster, errx.DescCluster) ErrSetContextFailed = newSentinelError("failed to set context", errx.CodeCluster, errx.DescCluster) ErrAKSKubeconfigNotImplemented = newSentinelError("AKS kubeconfig not yet implemented", errx.CodeCluster, errx.DescCluster) ErrGKEKubeconfigNotImplemented = newSentinelError("GKE kubeconfig not yet implemented", errx.CodeCluster, errx.DescCluster) ErrUnsupportedProvider = newSentinelError("unsupported provider", errx.CodeCluster, errx.DescCluster) ErrInvalidClusterName = newSentinelError("invalid cluster name", errx.CodeCluster, errx.DescCluster) ErrInvalidNodeCount = newSentinelError("invalid node count", errx.CodeCluster, errx.DescCluster) ErrUnsupportedIngressController = newSentinelError("unsupported ingress controller", errx.CodeCluster, errx.DescCluster) ErrInstallIngressControllerFailed = newSentinelError("failed to install ingress controller", errx.CodeCluster, errx.DescCluster) ErrCreateKindConfigFailed = newSentinelError("failed to create temp kind config", errx.CodeCluster, errx.DescCluster) ErrCloseKindConfigFailed = newSentinelError("failed to close kind config", errx.CodeCluster, errx.DescCluster) ErrWriteKindConfigFailed = newSentinelError("failed to write kind config", errx.CodeCluster, errx.DescCluster) ErrCreateKindClusterFailed = newSentinelError("failed to create kind cluster", errx.CodeCluster, errx.DescCluster) ErrDockerDaemonNotReachable = newSentinelError("docker daemon not reachable", errx.CodeCluster, errx.DescCluster) ErrKindClusterAlreadyExists = newSentinelError("kind cluster already exists", errx.CodeCluster, errx.DescCluster) ErrGKEProvisioningNotImplemented = newSentinelError("GKE provisioning not yet implemented", errx.CodeCluster, errx.DescCluster) ErrProvisionEKSFailed = newSentinelError("failed to provision EKS cluster", errx.CodeCluster, errx.DescCluster) ErrAKSProvisioningNotImplemented = newSentinelError("AKS provisioning not yet implemented", errx.CodeCluster, errx.DescCluster) // Cluster doctor package errors. ErrDoctorResourceNotFoundBeforeTimeout = newSentinelError("resource not found before timeout", errx.CodeCluster, errx.DescCluster) ErrDoctorDeploymentRolloutFailed = newSentinelError("deployment rollout failed", errx.CodeCluster, errx.DescCluster) ErrDoctorPodsNotScheduledBeforeTimeout = newSentinelError("no scheduled pod found before timeout", errx.CodeCluster, errx.DescCluster) ErrDoctorDecodeBase64Failed = newSentinelError("decode base64 value", errx.CodeCluster, errx.DescCluster) ErrDoctorImagePullStatusFailed = newSentinelError("pod image pull status failed", errx.CodeCluster, errx.DescCluster) ErrDoctorPodPhaseFailed = newSentinelError("pod phase Failed", errx.CodeCluster, errx.DescCluster) ErrDoctorKubectlError = newSentinelError("kubectl error", errx.CodeCluster, errx.DescCluster) ErrDoctorTraefikServiceNotFound = newSentinelError("traefik service not found", errx.CodeCluster, errx.DescCluster) ErrDoctorDeploymentNotFound = newSentinelError("deployment not found", errx.CodeCluster, errx.DescCluster) ErrDoctorUnexpectedReplicaStatus = newSentinelError("unexpected replica status", errx.CodeCluster, errx.DescCluster) // Registry errors. ErrRegistryNotReady = newSentinelError("registry not ready", errx.CodeRegistry, errx.DescRegistry) ErrRegistryNotFound = newSentinelError("registry not found", errx.CodeRegistry, errx.DescRegistry) ErrBuildOperatorImageFailed = newSentinelError("failed to build operator image", errx.CodeRegistry, errx.DescRegistry) ErrPushOperatorImageFailed = newSentinelError("failed to push operator image", errx.CodeRegistry, errx.DescRegistry) ErrBuildGatewayProxyImageFailed = newSentinelError("failed to build gateway proxy image", errx.CodeRegistry, errx.DescRegistry) ErrPushGatewayProxyImageFailed = newSentinelError("failed to push gateway proxy image", errx.CodeRegistry, errx.DescRegistry) ErrUnsupportedRegistryType = newSentinelError("unsupported registry type", errx.CodeRegistry, errx.DescRegistry) ErrEnsureNamespaceFailed = newSentinelError("failed to ensure namespace", errx.CodeRegistry, errx.DescRegistry) ErrReadRegistryStorageFailed = newSentinelError("failed to read current registry storage size", errx.CodeRegistry, errx.DescRegistry) ErrUpdateRegistryStorageFailed = newSentinelError("failed to update registry storage size", errx.CodeRegistry, errx.DescRegistry) ErrRegistryLoginFailed = newSentinelError("failed to login to registry", errx.CodeRegistry, errx.DescRegistry) ErrTagImageFailed = newSentinelError("failed to tag image", errx.CodeRegistry, errx.DescRegistry) ErrPushImageFailed = newSentinelError("failed to push image", errx.CodeRegistry, errx.DescRegistry) ErrHelperNamespaceNotFound = newSentinelError("helper namespace not found", errx.CodeRegistry, errx.DescRegistry) ErrSaveImageFailed = newSentinelError("failed to save image", errx.CodeRegistry, errx.DescRegistry) ErrStartHelperPodFailed = newSentinelError("failed to start helper pod", errx.CodeRegistry, errx.DescRegistry) ErrHelperPodNotReady = newSentinelError("helper pod not ready", errx.CodeRegistry, errx.DescRegistry) ErrCopyImageToHelperFailed = newSentinelError("failed to copy image tar to helper pod", errx.CodeRegistry, errx.DescRegistry) ErrPushImageFromHelperFailed = newSentinelError("failed to push image from helper pod", errx.CodeRegistry, errx.DescRegistry) // Config errors. ErrRegistryURLRequired = newSentinelError("registry url is required", errx.CodeConfig, errx.DescConfig) ErrRegistryURLMissingInConfig = newSentinelError("registry url missing in config", errx.CodeConfig, errx.DescConfig) ErrSaveRegistryConfigFailed = newSentinelError("failed to save registry config", errx.CodeConfig, errx.DescConfig) ErrReadRegistryConfigFailed = newSentinelError("failed to read registry config", errx.CodeConfig, errx.DescConfig) ErrUnmarshalRegistryConfigFailed = newSentinelError("failed to unmarshal registry config", errx.CodeConfig, errx.DescConfig) // Build errors. ErrBuildImageFailed = newSentinelError("failed to build image", errx.CodeBuild, errx.DescBuild) ErrMetadataFileNotFound = newSentinelError("metadata file not found", errx.CodeBuild, errx.DescBuild) ErrServerNotFoundInMetadata = newSentinelError("server not found in metadata", errx.CodeBuild, errx.DescBuild) ErrMarshalMetadataFailed = newSentinelError("failed to marshal metadata", errx.CodeBuild, errx.DescBuild) ErrWriteMetadataFailed = newSentinelError("failed to write metadata", errx.CodeBuild, errx.DescBuild) // Server errors. ErrMarshalManifestFailed = newSentinelError("failed to marshal manifest", errx.CodeServer, errx.DescServer) ErrWriteManifestFailed = newSentinelError("failed to write manifest", errx.CodeServer, errx.DescServer) ErrInvalidFilePath = newSentinelError("invalid file path", errx.CodeServer, errx.DescServer) ErrFileNotAccessible = newSentinelError("cannot access file", errx.CodeServer, errx.DescServer) ErrFileIsDirectory = newSentinelError("path is a directory, not a file", errx.CodeServer, errx.DescServer) ErrGetMCPServerFailed = newSentinelError("kubectl get mcpserver failed", errx.CodeServer, errx.DescServer) ErrListServersFailed = newSentinelError("failed to list servers", errx.CodeServer, errx.DescServer) ErrCreateServerFailed = newSentinelError("failed to create server", errx.CodeServer, errx.DescServer) ErrDeleteServerFailed = newSentinelError("failed to delete server", errx.CodeServer, errx.DescServer) ErrViewServerLogsFailed = newSentinelError("failed to view server logs", errx.CodeServer, errx.DescServer) )
Sentinel errors for CLI operations. Errors are defined and registered in one step using newSentinelError to eliminate redundancy.
var DefaultCLIConfig = LoadCLIConfig()
DefaultCLIConfig is the global CLI configuration loaded at startup.
var DefaultPrinter = &Printer{}
DefaultPrinter is the default printer instance used by package-level functions.
var ValidK8sName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`)
ValidK8sName matches Kubernetes resource name requirements (RFC 1123 subdomain).
Functions ¶
func ComponentNamespace ¶
ComponentNamespace returns the install namespace for a catalog component.
func GetAnalyticsIngestURLOverride ¶
func GetAnalyticsIngestURLOverride() string
GetAnalyticsIngestURLOverride returns the analytics ingest URL override, empty if not set.
func GetCertTimeout ¶
GetCertTimeout returns the certificate issuance timeout.
func GetClusterName ¶
func GetClusterName() string
GetClusterName returns the cluster label attached to analytics/audit events.
func GetDefaultServerPort ¶
func GetDefaultServerPort() int
GetDefaultServerPort returns the default MCP server port.
func GetDeploymentTimeout ¶
GetDeploymentTimeout returns the deployment wait timeout.
func GetGatewayOTLPEndpointOverride ¶
func GetGatewayOTLPEndpointOverride() string
GetGatewayOTLPEndpointOverride returns the gateway OTLP endpoint override, empty if not set.
func GetGatewayProxyImageOverride ¶
func GetGatewayProxyImageOverride() string
GetGatewayProxyImageOverride returns the gateway proxy image override, empty if not set.
func GetHelperPodTimeout ¶
GetHelperPodTimeout returns the helper pod ready timeout (e.g. registry pusher pod).
func GetMcpIngressHost ¶
func GetMcpIngressHost() string
GetMcpIngressHost returns the public MCP / gateway host (mcp.<domain> when MCP_PLATFORM_DOMAIN is set), or empty if not configured.
func GetOperatorImageOverride ¶
func GetOperatorImageOverride() string
GetOperatorImageOverride returns the operator image override, empty if not set.
func GetPlatformIngressHost ¶
func GetPlatformIngressHost() string
GetPlatformIngressHost returns the public dashboard UI host (platform.<domain> when MCP_PLATFORM_DOMAIN is set), or empty if not configured. When empty the dev path-based routing on the gateway ingress is used.
func GetProvidedTLSSecrets ¶
func GetProvidedTLSSecrets() bool
GetProvidedTLSSecrets reports whether setup references operator-provided TLS Secrets rather than cert-manager-issued Certificates.
func GetRegistryClusterIssuerName ¶
func GetRegistryClusterIssuerName() string
GetRegistryClusterIssuerName returns the setup-selected cert-manager ClusterIssuer name (empty if unset).
func GetRegistryEndpoint ¶
func GetRegistryEndpoint() string
GetRegistryEndpoint returns the configured registry endpoint for image refs and pushes.
func GetRegistryIngressHost ¶
func GetRegistryIngressHost() string
GetRegistryIngressHost returns the configured registry ingress host.
func GetSkopeoImage ¶
func GetSkopeoImage() string
GetSkopeoImage returns the skopeo image for in-cluster operations.
func NewSetupStepFailedError ¶
func NewSetupStepFailedError() error
func NewWithSentinel ¶
func ResolveEmailAlias ¶
ResolveEmailAlias returns the single account email represented by --email and the deprecated/alias --username flag.
func SetDebugMode ¶
func SetDebugMode(enabled bool)
SetDebugMode sets the global debug mode flag. When enabled, logStructuredError will output structured error logs to terminal.
func SpinnerStart ¶
SpinnerStart starts a spinner.
func SwapDefaultKubectlClient ¶
func SwapDefaultKubectlClient(c *KubectlClient) (restore func())
SwapDefaultKubectlClient replaces the shared kubectl client (tests only).
func SwapExecExecutor ¶
func SwapExecExecutor(e Executor) (restore func())
SwapExecExecutor replaces the global process executor (tests only).
func ValidateK8sNameAndNamespace ¶
func ValidateK8sNameAndNamespace(nameLabel string, nameSentinel error, name, namespace string) (string, string, error)
ValidateK8sNameAndNamespace validates a name+namespace pair against RFC-1123 subdomain rules plus ValidateManifestField. nameLabel customizes the invalid-name error message ("server name", "resource name"); nameSentinel (may be nil) selects the sentinel error category.
func ValidateManifestField ¶
ValidateManifestField rejects control characters, requires non-empty after trimming, and returns the trimmed value.
func WrapWithSentinel ¶
Types ¶
type CLIConfig ¶
type CLIConfig struct {
// Timeouts
DeploymentTimeout time.Duration
CertTimeout time.Duration
HelperPodTimeout time.Duration
// Registry settings
RegistryPort int
// KubernetesAPIPort is the host-facing Kubernetes API port used by the
// runtime API NetworkPolicy on distributions such as k3s.
KubernetesAPIPort int
RegistryEndpoint string
RegistryIngressHost string
// McpIngressHost is the public gateway / MCP host (e.g. mcp.mcpruntime.com), from
// MCP_MCP_INGRESS_HOST or mcp.<MCP_PLATFORM_DOMAIN>. Empty if unset.
McpIngressHost string
// PlatformIngressHost is the public dashboard UI host (e.g. platform.mcpruntime.com), from
// MCP_PLATFORM_INGRESS_HOST or platform.<MCP_PLATFORM_DOMAIN>. Empty falls back to path-based dev routing.
PlatformIngressHost string
// RegistryClusterIssuerName is the cert-manager ClusterIssuer selected by
// setup --with-tls for TLS-rendered resources (e.g. platform UI ingress).
// The registry Secret itself is owned by an explicit registry-cert Certificate.
RegistryClusterIssuerName string
// ProvidedTLSSecrets selects operator-managed TLS Secrets in place of
// cert-manager-issued Certificates.
ProvidedTLSSecrets bool
SkopeoImage string
OperatorImage string // Override for operator image
GatewayProxyImage string // Optional default image for the MCP gateway sidecar
ImagePlatform string // Optional Docker image platform for setup-built images, e.g. linux/amd64
GatewayOTLPEndpoint string // Optional OTLP/HTTP endpoint for MCP gateway sidecar tracing
AnalyticsIngestURL string // Optional analytics ingest URL override for the MCP gateway sidecar
IngressReadinessMode string // Optional operator ingress readiness mode: strict or permissive
ClusterName string // Optional cluster label attached to analytics/audit events
// Server defaults
DefaultServerPort int
// External/Provisioned registry credentials
ProvisionedRegistryURL string
ProvisionedRegistryUsername string
ProvisionedRegistryPassword string
}
CLIConfig holds all CLI configuration loaded from environment variables. Use LoadCLIConfig() to create an instance with values from the environment.
func LoadCLIConfig ¶
func LoadCLIConfig() *CLIConfig
LoadCLIConfig loads CLI configuration from environment variables.
type Command ¶
type Command interface {
Output() ([]byte, error)
CombinedOutput() ([]byte, error)
Run() error
SetStdout(w io.Writer)
SetStderr(w io.Writer)
SetStdin(r io.Reader)
}
Command represents a command that can be executed.
func ExecCommandWithValidators ¶
func ExecCommandWithValidators(name string, args []string, validators ...ExecValidator) (Command, error)
ExecCommandWithValidators runs the named binary with args after validators pass.
type ExecValidator ¶
func AllowlistBins ¶
func AllowlistBins(allowed ...string) ExecValidator
func NoControlChars ¶
func NoControlChars() ExecValidator
func NoShellMeta ¶
func NoShellMeta() ExecValidator
func PathUnder ¶
func PathUnder(root string) ExecValidator
type Executor ¶
type Executor interface {
Command(name string, args []string, validators ...ExecValidator) (Command, error)
}
Executor creates commands for execution.
func DefaultExecutor ¶
func DefaultExecutor() Executor
DefaultExecutor returns the shared process executor used by CLI commands.
type KubectlClient ¶
type KubectlClient struct {
// contains filtered or unexported fields
}
KubectlClient wraps kubectl command execution with validation.
func DefaultKubectlClient ¶
func DefaultKubectlClient() *KubectlClient
DefaultKubectlClient returns the shared kubectl client used by CLI commands.
func NewKubectlClient ¶
func NewKubectlClient(exec Executor) (*KubectlClient, error)
NewKubectlClient creates a KubectlClient with default validators.
func NewTestKubectlClient ¶
func NewTestKubectlClient(exec Executor) *KubectlClient
NewTestKubectlClient returns a KubectlClient for tests (no path validators).
func NewTestKubectlClientWithValidators ¶
func NewTestKubectlClientWithValidators(exec Executor, validators []ExecValidator) *KubectlClient
NewTestKubectlClientWithValidators returns a KubectlClient for tests using the given validator list (or nil for none).
func (*KubectlClient) CombinedOutput ¶
func (c *KubectlClient) CombinedOutput(args []string) ([]byte, error)
CombinedOutput runs kubectl with the given arguments and returns combined stdout/stderr.
func (*KubectlClient) CommandArgs ¶
func (c *KubectlClient) CommandArgs(args []string) (Command, error)
CommandArgs builds a kubectl command with the given arguments. Validates arguments against configured validators before building.
func (*KubectlClient) Output ¶
func (c *KubectlClient) Output(args []string) ([]byte, error)
Output runs kubectl with the given arguments and returns stdout.
func (*KubectlClient) Run ¶
func (c *KubectlClient) Run(args []string) error
Run runs kubectl with the given arguments.
func (*KubectlClient) RunWithOutput ¶
func (c *KubectlClient) RunWithOutput(args []string, stdout, stderr io.Writer) error
RunWithOutput runs kubectl with the given arguments, piping to the provided writers.
type KubectlRunner ¶
type KubectlRunner interface {
CommandArgs(args []string) (Command, error)
Run(args []string) error
RunWithOutput(args []string, stdout, stderr io.Writer) error
}
KubectlRunner captures the kubectl methods used by setup helpers.
func DefaultKubectlRunner ¶
func DefaultKubectlRunner() KubectlRunner
DefaultKubectlRunner returns the shared kubectl runner used by CLI commands.
type MockCommand ¶
type MockCommand struct {
Args []string
OutputData []byte
OutputErr error
RunErr error
StdoutW io.Writer
StderrW io.Writer
StdinR io.Reader
RunFunc func() error
}
MockCommand is a test double for Command interface.
func (*MockCommand) CombinedOutput ¶
func (m *MockCommand) CombinedOutput() ([]byte, error)
func (*MockCommand) Output ¶
func (m *MockCommand) Output() ([]byte, error)
func (*MockCommand) Run ¶
func (m *MockCommand) Run() error
func (*MockCommand) SetStderr ¶
func (m *MockCommand) SetStderr(w io.Writer)
func (*MockCommand) SetStdin ¶
func (m *MockCommand) SetStdin(r io.Reader)
func (*MockCommand) SetStdout ¶
func (m *MockCommand) SetStdout(w io.Writer)
type MockExecutor ¶
type MockExecutor struct {
// Commands records all commands that were created.
Commands []ExecSpec
// DefaultOutput is returned by commands when CommandFunc is nil.
DefaultOutput []byte
// DefaultErr is the error returned by Output/CombinedOutput.
DefaultErr error
// DefaultRunErr is the error returned by Run.
DefaultRunErr error
// CommandFunc allows custom behavior per command.
CommandFunc func(spec ExecSpec) *MockCommand
}
MockExecutor is a test double for Executor interface.
func (*MockExecutor) Command ¶
func (m *MockExecutor) Command(name string, args []string, validators ...ExecValidator) (Command, error)
func (*MockExecutor) HasCommand ¶
func (m *MockExecutor) HasCommand(name string) bool
HasCommand checks if a command with the given name was executed.
func (*MockExecutor) LastCommand ¶
func (m *MockExecutor) LastCommand() ExecSpec
LastCommand returns the most recent command spec.
type Printer ¶
type Printer struct {
// Quiet suppresses non-essential output
Quiet bool
// Writer overrides the output destination when set.
Writer io.Writer
}
Printer provides formatted terminal output methods. Use the default instance via package-level functions.
func (*Printer) Error ¶
Error prints an error message. Note: Errors are intentionally not suppressed in quiet mode to ensure critical issues are always visible, even when non-essential output is disabled.
func (*Printer) SpinnerStart ¶
SpinnerStart starts a spinner with the given message. Returns a stop function.
func (*Printer) TableBoxed ¶
TableBoxed prints a formatted table with box borders.
type Runtime ¶
type Runtime struct {
// contains filtered or unexported fields
}
Runtime is the shared CLI facade for wiring common dependencies once and handing typed managers to the foldered command packages.
func NewRuntime ¶
NewRuntime builds the shared CLI runtime facade.
func (*Runtime) KubectlClient ¶
func (r *Runtime) KubectlClient() *KubectlClient
KubectlClient returns the shared kubectl client.
func (*Runtime) KubectlRunner ¶
func (r *Runtime) KubectlRunner() KubectlRunner
KubectlRunner returns the shared kubectl runner.