From 006a64d087b52f8c5f481d5a1beb175722818631 Mon Sep 17 00:00:00 2001 From: Jaime Soriano Pastor Date: Mon, 4 Sep 2023 12:19:20 +0200 Subject: [PATCH] Load stack configuration from profile (#1428) Commands that require an stack to connect with will try to connect with the stack of the current profile by default. This behaviour can be overridden by setting the usual environment variables provided by `elastic-package shellinit`. With this change `elastic-package shellinit` is not necessary when working with stacks managed by elastic-package. shellinit is still useful to export the configuration for other commands or scripts. The environment variables can also be used to work with stacks not managed by elastic-package. --- README.md | 15 ++- cmd/benchmark.go | 11 ++- cmd/dump.go | 18 +++- cmd/export.go | 9 +- cmd/install.go | 9 +- cmd/service.go | 2 +- cmd/stack.go | 17 +++- cmd/testrunner.go | 4 +- cmd/uninstall.go | 9 +- docs/howto/asset_testing.md | 6 -- docs/howto/install_package.md | 3 - docs/howto/pipeline_benchmarking.md | 6 -- docs/howto/pipeline_testing.md | 6 -- docs/howto/system_benchmarking.md | 8 +- docs/howto/system_testing.md | 6 -- internal/servicedeployer/custom_agent.go | 6 +- internal/servicedeployer/kubernetes.go | 18 ++-- internal/stack/clients.go | 112 +++++++++++++++++++++++ internal/stack/errors.go | 18 +++- scripts/test-build-zip.sh | 1 - scripts/test-check-false-positives.sh | 3 - scripts/test-check-packages.sh | 3 - 22 files changed, 222 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 8b4918544..ebb94c6df 100644 --- a/README.md +++ b/README.md @@ -437,7 +437,20 @@ Dump stack data for debug purposes. _Context: global_ -Export environment variables. +Use this command to export to the current shell the configuration of the stack managed by elastic-package. + +The output of this command is intended to be evaluated by the current shell. For example in bash: 'eval $(elastic-package stack shellinit)'. + +Relevant environment variables are: + +- ELASTIC_PACKAGE_ELASTICSEARCH_HOST +- ELASTIC_PACKAGE_ELASTICSEARCH_USERNAME +- ELASTIC_PACKAGE_ELASTICSEARCH_PASSWORD +- ELASTIC_PACKAGE_KIBANA_HOST +- ELASTIC_PACKAGE_CA_CERT + +You can also provide these environment variables manually. In that case elastic-package commands will use these settings. + ### `elastic-package stack status` diff --git a/cmd/benchmark.go b/cmd/benchmark.go index 101fc4e08..7849f25a6 100644 --- a/cmd/benchmark.go +++ b/cmd/benchmark.go @@ -165,7 +165,12 @@ func pipelineCommandAction(cmd *cobra.Command, args []string) error { return errors.New("no pipeline benchmarks found") } - esClient, err := stack.NewElasticsearchClient() + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + esClient, err := stack.NewElasticsearchClientFromProfile(profile) if err != nil { return fmt.Errorf("can't create Elasticsearch client: %w", err) } @@ -269,7 +274,7 @@ func systemCommandAction(cmd *cobra.Command, args []string) error { signal.Enable() - esClient, err := stack.NewElasticsearchClient() + esClient, err := stack.NewElasticsearchClientFromProfile(profile) if err != nil { return fmt.Errorf("can't create Elasticsearch client: %w", err) } @@ -278,7 +283,7 @@ func systemCommandAction(cmd *cobra.Command, args []string) error { return err } - kc, err := stack.NewKibanaClient() + kc, err := stack.NewKibanaClientFromProfile(profile) if err != nil { return fmt.Errorf("can't create Kibana client: %w", err) } diff --git a/cmd/dump.go b/cmd/dump.go index fe75cc1fa..1a3e24a7c 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -12,6 +12,7 @@ import ( "github.com/elastic/elastic-package/internal/cobraext" "github.com/elastic/elastic-package/internal/dump" "github.com/elastic/elastic-package/internal/elasticsearch" + "github.com/elastic/elastic-package/internal/install" "github.com/elastic/elastic-package/internal/kibana" "github.com/elastic/elastic-package/internal/stack" ) @@ -58,6 +59,7 @@ func setupDumpCommand() *cobraext.Command { Long: dumpLongDescription, } cmd.PersistentFlags().StringP(cobraext.DumpOutputFlagName, "o", "package-dump", cobraext.DumpOutputFlagDescription) + cmd.PersistentFlags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar)) cmd.AddCommand(dumpInstalledObjectsCmd) cmd.AddCommand(dumpAgentPoliciesCmd) @@ -82,7 +84,13 @@ func dumpInstalledObjectsCmdAction(cmd *cobra.Command, args []string) error { if tlsSkipVerify { clientOptions = append(clientOptions, elasticsearch.OptionWithSkipTLSVerify()) } - client, err := stack.NewElasticsearchClient(clientOptions...) + + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + client, err := stack.NewElasticsearchClientFromProfile(profile, clientOptions...) if err != nil { return fmt.Errorf("failed to initialize Elasticsearch client: %w", err) } @@ -122,7 +130,13 @@ func dumpAgentPoliciesCmdAction(cmd *cobra.Command, args []string) error { if tlsSkipVerify { clientOptions = append(clientOptions, kibana.TLSSkipVerify()) } - kibanaClient, err := stack.NewKibanaClient(clientOptions...) + + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + kibanaClient, err := stack.NewKibanaClientFromProfile(profile, clientOptions...) if err != nil { return fmt.Errorf("failed to initialize Kibana client: %w", err) } diff --git a/cmd/export.go b/cmd/export.go index ba605e96d..b3c1bbd58 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -14,6 +14,7 @@ import ( "github.com/elastic/elastic-package/internal/cobraext" "github.com/elastic/elastic-package/internal/common" "github.com/elastic/elastic-package/internal/export" + "github.com/elastic/elastic-package/internal/install" "github.com/elastic/elastic-package/internal/kibana" "github.com/elastic/elastic-package/internal/stack" ) @@ -42,6 +43,7 @@ func setupExportCommand() *cobraext.Command { Long: exportLongDescription, } cmd.AddCommand(exportDashboardCmd) + cmd.PersistentFlags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar)) return cobraext.NewCommand(cmd, cobraext.ContextPackage) } @@ -67,7 +69,12 @@ func exportDashboardsCmd(cmd *cobra.Command, args []string) error { return cobraext.FlagParsingError(err, cobraext.AllowSnapshotFlagName) } - kibanaClient, err := stack.NewKibanaClient(opts...) + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + kibanaClient, err := stack.NewKibanaClientFromProfile(profile, opts...) if err != nil { return fmt.Errorf("can't create Kibana client: %w", err) } diff --git a/cmd/install.go b/cmd/install.go index 7a19c06ac..7dc781560 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/elastic/elastic-package/internal/cobraext" + "github.com/elastic/elastic-package/internal/install" "github.com/elastic/elastic-package/internal/packages" "github.com/elastic/elastic-package/internal/packages/installer" "github.com/elastic/elastic-package/internal/stack" @@ -32,6 +33,7 @@ func setupInstallCommand() *cobraext.Command { cmd.Flags().StringP(cobraext.PackageRootFlagName, cobraext.PackageRootFlagShorthand, "", cobraext.PackageRootFlagDescription) cmd.Flags().StringP(cobraext.ZipPackageFilePathFlagName, cobraext.ZipPackageFilePathFlagShorthand, "", cobraext.ZipPackageFilePathFlagDescription) cmd.Flags().Bool(cobraext.BuildSkipValidationFlagName, false, cobraext.BuildSkipValidationFlagDescription) + cmd.Flags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar)) return cobraext.NewCommand(cmd, cobraext.ContextPackage) } @@ -50,7 +52,12 @@ func installCommandAction(cmd *cobra.Command, _ []string) error { return cobraext.FlagParsingError(err, cobraext.BuildSkipValidationFlagName) } - kibanaClient, err := stack.NewKibanaClient() + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + kibanaClient, err := stack.NewKibanaClientFromProfile(profile) if err != nil { return fmt.Errorf("could not create kibana client: %w", err) } diff --git a/cmd/service.go b/cmd/service.go index 0249980ef..05c8d41a4 100644 --- a/cmd/service.go +++ b/cmd/service.go @@ -68,7 +68,7 @@ func upCommandAction(cmd *cobra.Command, args []string) error { return err } - kibanaClient, err := stack.NewKibanaClient() + kibanaClient, err := stack.NewKibanaClientFromProfile(profile) if err != nil { return fmt.Errorf("cannot create Kibana client: %w", err) } diff --git a/cmd/stack.go b/cmd/stack.go index 1797b2b0c..95270564e 100644 --- a/cmd/stack.go +++ b/cmd/stack.go @@ -48,6 +48,21 @@ For details on how to connect the service with the Elastic stack, see the [servi You can customize your stack using profile settings, see [Elastic Package profiles](https://github.com/elastic/elastic-package/blob/main/README.md#elastic-package-profiles-1) section. These settings can be also overriden with the --parameter flag. Settings configured this way are not persisted.` +const stackShellinitLongDescription = `Use this command to export to the current shell the configuration of the stack managed by elastic-package. + +The output of this command is intended to be evaluated by the current shell. For example in bash: 'eval $(elastic-package stack shellinit)'. + +Relevant environment variables are: + +- ELASTIC_PACKAGE_ELASTICSEARCH_HOST +- ELASTIC_PACKAGE_ELASTICSEARCH_USERNAME +- ELASTIC_PACKAGE_ELASTICSEARCH_PASSWORD +- ELASTIC_PACKAGE_KIBANA_HOST +- ELASTIC_PACKAGE_CA_CERT + +You can also provide these environment variables manually. In that case elastic-package commands will use these settings. +` + func setupStackCommand() *cobraext.Command { upCommand := &cobra.Command{ Use: "up", @@ -99,7 +114,6 @@ func setupStackCommand() *cobraext.Command { profile.RuntimeOverrides(userParameters) cmd.Printf("Using profile %s.\n", profile.ProfilePath) - cmd.Println(`Remember to load stack environment variables using 'eval "$(elastic-package stack shellinit)"'.`) err = provider.BootUp(stack.Options{ DaemonMode: daemonMode, StackVersion: stackVersion, @@ -192,6 +206,7 @@ func setupStackCommand() *cobraext.Command { shellInitCommand := &cobra.Command{ Use: "shellinit", Short: "Export environment variables", + Long: stackShellinitLongDescription, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { shellName, err := cmd.Flags().GetString(cobraext.ShellInitShellFlagName) diff --git a/cmd/testrunner.go b/cmd/testrunner.go index 5ff0a1277..c11f790e7 100644 --- a/cmd/testrunner.go +++ b/cmd/testrunner.go @@ -215,7 +215,7 @@ func testTypeCommandActionFactory(runner testrunner.TestRunner) cobraext.Command return err } - esClient, err := stack.NewElasticsearchClient() + esClient, err := stack.NewElasticsearchClientFromProfile(profile) if err != nil { return fmt.Errorf("can't create Elasticsearch client: %w", err) } @@ -224,7 +224,7 @@ func testTypeCommandActionFactory(runner testrunner.TestRunner) cobraext.Command return err } - kibanaClient, err := stack.NewKibanaClient() + kibanaClient, err := stack.NewKibanaClientFromProfile(profile) if err != nil { return fmt.Errorf("can't create Kibana client: %w", err) } diff --git a/cmd/uninstall.go b/cmd/uninstall.go index 96cda2701..7e44522fd 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -11,6 +11,7 @@ import ( "github.com/spf13/cobra" "github.com/elastic/elastic-package/internal/cobraext" + "github.com/elastic/elastic-package/internal/install" "github.com/elastic/elastic-package/internal/packages" "github.com/elastic/elastic-package/internal/packages/installer" "github.com/elastic/elastic-package/internal/stack" @@ -28,6 +29,7 @@ func setupUninstallCommand() *cobraext.Command { Args: cobra.NoArgs, RunE: uninstallCommandAction, } + cmd.Flags().StringP(cobraext.ProfileFlagName, "p", "", fmt.Sprintf(cobraext.ProfileFlagDescription, install.ProfileNameEnvVar)) return cobraext.NewCommand(cmd, cobraext.ContextPackage) } @@ -41,7 +43,12 @@ func uninstallCommandAction(cmd *cobra.Command, args []string) error { return fmt.Errorf("locating package root failed: %w", err) } - kibanaClient, err := stack.NewKibanaClient() + profile, err := cobraext.GetProfileFlag(cmd) + if err != nil { + return err + } + + kibanaClient, err := stack.NewKibanaClientFromProfile(profile) if err != nil { return fmt.Errorf("could not create kibana client: %w", err) } diff --git a/docs/howto/asset_testing.md b/docs/howto/asset_testing.md index cd16a8cdd..45dc373ba 100644 --- a/docs/howto/asset_testing.md +++ b/docs/howto/asset_testing.md @@ -36,12 +36,6 @@ elastic-package stack up -d For a complete listing of options available for this command, run `elastic-package stack up -h` or `elastic-package help stack up`. -Next, you must set environment variables needed for further `elastic-package` commands. - -``` -$(elastic-package stack shellinit) -``` - Next, you must invoke the asset loading test runner. This corresponds to steps 3 through 5 as described in the [_Conceptual process_](#Conceptual-process) section. Navigate to the package's root folder (or any sub-folder under it) and run the following command. diff --git a/docs/howto/install_package.md b/docs/howto/install_package.md index e43c0a0b2..6f6171575 100644 --- a/docs/howto/install_package.md +++ b/docs/howto/install_package.md @@ -9,7 +9,6 @@ For versions of `Kibana<8.7.0`, the packages must be exposed via the Package Reg In case of development, this means that the package should be built previously and then the Elastic stack must be started. Or at least, package-registry service needs to be restarted in the Elastic stack. ```shell -eval "$(elastic-package stack shellinit)" elastic-package build -v elastic-package stack up -v -d # elastic-package stack up -v -d --services package-registry elastic-package install -v @@ -30,7 +29,6 @@ From Kibana 8.7.0 version, `elastic-package install` is able to install packages Example of using `--zip` parameter: ```shell $ elastic-package stack up -v -d - $ eval "$(elastic-package stack shellinit)" $ elastic-package install --zip /home/user/Coding/work/integrations/build/packages/elastic_package_registry-0.0.6.zip -v 2023/02/23 18:44:59 DEBUG Enable verbose logging 2023/02/23 18:44:59 DEBUG Distribution built without a version tag, can't determine release chronology. Please consider using official releases at https://github.com/elastic/elastic-package/releases @@ -50,7 +48,6 @@ Done Example of using `elastic-package install` ```shell $ elastic-package stack up -v -d - $ eval "$(elastic-package stack shellinit)" $ elastic-package install -v 2023/02/28 12:34:44 DEBUG Enable verbose logging 2023/02/28 12:34:44 DEBUG Distribution built without a version tag, can't determine release chronology. Please consider using official releases at https://github.com/elastic/elastic-package/releases diff --git a/docs/howto/pipeline_benchmarking.md b/docs/howto/pipeline_benchmarking.md index 362fa2f08..d77072197 100644 --- a/docs/howto/pipeline_benchmarking.md +++ b/docs/howto/pipeline_benchmarking.md @@ -101,12 +101,6 @@ elastic-package stack up -d --services=elasticsearch For a complete listing of options available for this command, run `elastic-package stack up -h` or `elastic-package help stack up`. -Next, you must set environment variables needed for further `elastic-package` commands. - -``` -$(elastic-package stack shellinit) -``` - Next, you must invoke the pipeline benchmark runner. This corresponds to steps 2 through 4 as described in the [_Conceptual process_](#Conceptual-process) section. If you want to run pipeline benchmarks for **all data streams** in a package, navigate to the package's root folder (or any sub-folder under it) and run the following command. diff --git a/docs/howto/pipeline_testing.md b/docs/howto/pipeline_testing.md index 995cb83f6..7a5517ef0 100644 --- a/docs/howto/pipeline_testing.md +++ b/docs/howto/pipeline_testing.md @@ -156,12 +156,6 @@ elastic-package stack up -d --services=elasticsearch For a complete listing of options available for this command, run `elastic-package stack up -h` or `elastic-package help stack up`. -Next, you must set environment variables needed for further `elastic-package` commands. - -``` -$(elastic-package stack shellinit) -``` - Next, you must invoke the pipeline tests runner. This corresponds to steps 2 through 4 as described in the [_Conceptual process_](#Conceptual-process) section. If you want to run pipeline tests for **all data streams** in a package, navigate to the package's root folder (or any sub-folder under it) and run the following command. diff --git a/docs/howto/system_benchmarking.md b/docs/howto/system_benchmarking.md index 77c50da84..70a843544 100644 --- a/docs/howto/system_benchmarking.md +++ b/docs/howto/system_benchmarking.md @@ -312,12 +312,6 @@ elastic-package stack up -d For a complete listing of options available for this command, run `elastic-package stack up -h` or `elastic-package help stack up`. -Next, you must set environment variables needed for further `elastic-package` commands. - -``` -$(elastic-package stack shellinit) -``` - Next, you must invoke the system benchmark runner. ``` @@ -430,4 +424,4 @@ Ingest pipelines metrics are only collected at the end since its own collection You can see a sample collected metric [here](./sample_metric.json) -Additionally, if the `reindex-to-metricstore` flag is used, the data generated during the benchmark will be sent to the metricstore into an index called `bench-reindex-{datastream}-{testRunID}` for further analysis. The events will be enriched with metadata related to the benchmark run. \ No newline at end of file +Additionally, if the `reindex-to-metricstore` flag is used, the data generated during the benchmark will be sent to the metricstore into an index called `bench-reindex-{datastream}-{testRunID}` for further analysis. The events will be enriched with metadata related to the benchmark run. diff --git a/docs/howto/system_testing.md b/docs/howto/system_testing.md index c14a6f496..15655e702 100644 --- a/docs/howto/system_testing.md +++ b/docs/howto/system_testing.md @@ -532,12 +532,6 @@ elastic-package stack up -d For a complete listing of options available for this command, run `elastic-package stack up -h` or `elastic-package help stack up`. -Next, you must set environment variables needed for further `elastic-package` commands. - -``` -$(elastic-package stack shellinit) -``` - Next, you must invoke the system tests runner. This corresponds to steps 3 through 7 as described in the [_Conceptual process_](#Conceptual-process) section. If you want to run system tests for **all data streams** in a package, navigate to the package's root folder (or any sub-folder under it) and run the following command. diff --git a/internal/servicedeployer/custom_agent.go b/internal/servicedeployer/custom_agent.go index 8c3bb61e7..b63891df9 100644 --- a/internal/servicedeployer/custom_agent.go +++ b/internal/servicedeployer/custom_agent.go @@ -55,9 +55,9 @@ func (d *CustomAgentDeployer) SetUp(inCtxt ServiceContext) (DeployedService, err return nil, fmt.Errorf("can't read application configuration: %w", err) } - caCertPath, ok := os.LookupEnv(stack.CACertificateEnv) - if !ok { - return nil, fmt.Errorf("can't locate CA certificate: %s environment variable not set", stack.CACertificateEnv) + caCertPath, err := stack.FindCACertificate(d.profile) + if err != nil { + return nil, fmt.Errorf("can't locate CA certificate: %w", err) } env := append( diff --git a/internal/servicedeployer/kubernetes.go b/internal/servicedeployer/kubernetes.go index 6d1870eb1..b76c56b2b 100644 --- a/internal/servicedeployer/kubernetes.go +++ b/internal/servicedeployer/kubernetes.go @@ -93,7 +93,7 @@ func (ksd KubernetesServiceDeployer) SetUp(ctxt ServiceContext) (DeployedService return nil, fmt.Errorf("can't connect control plane to Elastic stack network: %w", err) } - err = installElasticAgentInCluster(ksd.stackVersion) + err = installElasticAgentInCluster(ksd.profile, ksd.stackVersion) if err != nil { return nil, fmt.Errorf("can't install Elastic-Agent in the Kubernetes cluster: %w", err) } @@ -147,10 +147,10 @@ func findKubernetesDefinitions(definitionsDir string) ([]string, error) { return definitionPaths, nil } -func installElasticAgentInCluster(stackVersion string) error { +func installElasticAgentInCluster(profile *profile.Profile, stackVersion string) error { logger.Debug("install Elastic Agent in the Kubernetes cluster") - elasticAgentManagedYaml, err := getElasticAgentYAML(stackVersion) + elasticAgentManagedYaml, err := getElasticAgentYAML(profile, stackVersion) if err != nil { return fmt.Errorf("can't retrieve Kubernetes file for Elastic Agent: %w", err) } @@ -165,7 +165,7 @@ func installElasticAgentInCluster(stackVersion string) error { //go:embed elastic-agent-managed.yaml.tmpl var elasticAgentManagedYamlTmpl string -func getElasticAgentYAML(stackVersion string) ([]byte, error) { +func getElasticAgentYAML(profile *profile.Profile, stackVersion string) ([]byte, error) { logger.Debugf("Prepare YAML definition for Elastic Agent running in stack v%s", stackVersion) appConfig, err := install.Configuration() @@ -173,7 +173,7 @@ func getElasticAgentYAML(stackVersion string) ([]byte, error) { return nil, fmt.Errorf("can't read application configuration: %w", err) } - caCert, err := readCACertBase64() + caCert, err := readCACertBase64(profile) if err != nil { return nil, fmt.Errorf("can't read certificate authority file: %w", err) } @@ -195,10 +195,10 @@ func getElasticAgentYAML(stackVersion string) ([]byte, error) { return elasticAgentYaml.Bytes(), nil } -func readCACertBase64() (string, error) { - caCertPath, ok := os.LookupEnv(stack.CACertificateEnv) - if !ok { - return "", fmt.Errorf("%s not defined", stack.CACertificateEnv) +func readCACertBase64(profile *profile.Profile) (string, error) { + caCertPath, err := stack.FindCACertificate(profile) + if err != nil { + return "", fmt.Errorf("can't locate CA certificate: %w", err) } d, err := os.ReadFile(caCertPath) diff --git a/internal/stack/clients.go b/internal/stack/clients.go index 6323f79c2..04a35708f 100644 --- a/internal/stack/clients.go +++ b/internal/stack/clients.go @@ -6,12 +6,17 @@ package stack import ( "errors" + "fmt" "os" "github.com/elastic/elastic-package/internal/elasticsearch" "github.com/elastic/elastic-package/internal/kibana" + "github.com/elastic/elastic-package/internal/logger" + "github.com/elastic/elastic-package/internal/profile" ) +// NewElasticsearchClient creates an Elasticsearch client with the settings provided by the shellinit +// environment variables. func NewElasticsearchClient(customOptions ...elasticsearch.ClientOption) (*elasticsearch.Client, error) { options := []elasticsearch.ClientOption{ elasticsearch.OptionWithAddress(os.Getenv(ElasticsearchHostEnv)), @@ -29,6 +34,53 @@ func NewElasticsearchClient(customOptions ...elasticsearch.ClientOption) (*elast return client, err } +// NewElasticsearchClientFromProfile creates an Elasticsearch client with the settings provided by the shellinit +// environment variables. If these environment variables are not set, it uses the information +// in the provided profile. +func NewElasticsearchClientFromProfile(profile *profile.Profile, customOptions ...elasticsearch.ClientOption) (*elasticsearch.Client, error) { + profileConfig, err := StackInitConfig(profile) + if err != nil { + return nil, fmt.Errorf("failed to load config from profile: %w", err) + } + + elasticsearchHost, found := os.LookupEnv(ElasticsearchHostEnv) + if !found { + status, err := Status(Options{Profile: profile}) + if err != nil { + return nil, fmt.Errorf("failed to check status of stack in current profile: %w", err) + } + if len(status) == 0 { + return nil, ErrUnavailableStack + } + + elasticsearchHost = profileConfig.ElasticsearchHostPort + logger.Debugf("Connecting with Elasticsearch host from current profile (profile: %s, host: %q)", profile.ProfileName, elasticsearchHost) + } + elasticsearchPassword, found := os.LookupEnv(ElasticsearchPasswordEnv) + if !found { + elasticsearchPassword = profileConfig.ElasticsearchPassword + } + elasticsearchUsername, found := os.LookupEnv(ElasticsearchUsernameEnv) + if !found { + elasticsearchUsername = profileConfig.ElasticsearchUsername + } + caCertificate, found := os.LookupEnv(CACertificateEnv) + if !found { + caCertificate = profileConfig.CACertificatePath + } + + options := []elasticsearch.ClientOption{ + elasticsearch.OptionWithAddress(elasticsearchHost), + elasticsearch.OptionWithPassword(elasticsearchPassword), + elasticsearch.OptionWithUsername(elasticsearchUsername), + elasticsearch.OptionWithCertificateAuthority(caCertificate), + } + options = append(options, customOptions...) + return elasticsearch.NewClient(options...) +} + +// NewKibanaClient creates a kibana client with the settings provided by the shellinit +// environment variables. func NewKibanaClient(customOptions ...kibana.ClientOption) (*kibana.Client, error) { options := []kibana.ClientOption{ kibana.Address(os.Getenv(KibanaHostEnv)), @@ -45,3 +97,63 @@ func NewKibanaClient(customOptions ...kibana.ClientOption) (*kibana.Client, erro return client, err } + +// NewKibanaClientFromProfile creates a kibana client with the settings provided by the shellinit +// environment variables. If these environment variables are not set, it uses the information +// in the provided profile. +func NewKibanaClientFromProfile(profile *profile.Profile, customOptions ...kibana.ClientOption) (*kibana.Client, error) { + profileConfig, err := StackInitConfig(profile) + if err != nil { + return nil, fmt.Errorf("failed to load config from profile: %w", err) + } + + kibanaHost, found := os.LookupEnv(KibanaHostEnv) + if !found { + status, err := Status(Options{Profile: profile}) + if err != nil { + return nil, fmt.Errorf("failed to check status of stack in current profile: %w", err) + } + if len(status) == 0 { + return nil, ErrUnavailableStack + } + + kibanaHost = profileConfig.KibanaHostPort + logger.Debugf("Connecting with Kibana host from current profile (profile: %s, host: %q)", profile.ProfileName, kibanaHost) + } + elasticsearchPassword, found := os.LookupEnv(ElasticsearchPasswordEnv) + if !found { + elasticsearchPassword = profileConfig.ElasticsearchPassword + } + elasticsearchUsername, found := os.LookupEnv(ElasticsearchUsernameEnv) + if !found { + elasticsearchUsername = profileConfig.ElasticsearchUsername + } + caCertificate, found := os.LookupEnv(CACertificateEnv) + if !found { + caCertificate = profileConfig.CACertificatePath + } + + options := []kibana.ClientOption{ + kibana.Address(kibanaHost), + kibana.Password(elasticsearchPassword), + kibana.Username(elasticsearchUsername), + kibana.CertificateAuthority(caCertificate), + } + options = append(options, customOptions...) + return kibana.NewClient(options...) +} + +// FindCACertificate looks for the CA certificate for the stack in the current profile. +// If not found, it uses the environment variable provided by shellinit. +func FindCACertificate(profile *profile.Profile) (string, error) { + caCertPath, found := os.LookupEnv(CACertificateEnv) + if !found { + profileConfig, err := StackInitConfig(profile) + if err != nil { + return "", fmt.Errorf("failed to load config from profile: %w", err) + } + caCertPath = profileConfig.CACertificatePath + } + + return caCertPath, nil +} diff --git a/internal/stack/errors.go b/internal/stack/errors.go index 3e6a2b9e1..4ab090a96 100644 --- a/internal/stack/errors.go +++ b/internal/stack/errors.go @@ -5,11 +5,25 @@ package stack import ( + "errors" "fmt" ) +// ErrUndefinedEnv is an error about an undefined environment variable for the current profile. +type ErrUndefinedEnv struct { + EnvName string +} + +// Error returns the error message for this error. +func (err *ErrUndefinedEnv) Error() string { + return fmt.Sprintf("undefined environment variable: %s. If you have started the Elastic Stack using the elastic-package tool, "+ + `please load stack environment variables using '%s' or set their values manually`, err.EnvName, helpText(AutodetectShell())) +} + // UndefinedEnvError formats an error reported for undefined variable. func UndefinedEnvError(envName string) error { - return fmt.Errorf("undefined environment variable: %s. If you have started the Elastic stack using the elastic-package tool, "+ - `please load stack environment variables using '%s' or set their values manually`, envName, helpText(AutodetectShell())) + return &ErrUndefinedEnv{EnvName: envName} } + +// ErrUnavailableStack is an error about an unavailable Elastic stack. +var ErrUnavailableStack = errors.New("the Elastic stack is unavailable, remember to start it with 'elastic-package stack up', or configure elastic-package with environment variables") diff --git a/scripts/test-build-zip.sh b/scripts/test-build-zip.sh index 7c72eafa6..8c5d6ffd9 100755 --- a/scripts/test-build-zip.sh +++ b/scripts/test-build-zip.sh @@ -42,7 +42,6 @@ cd - rm -r build/packages/*/ # Boot up the stack -eval "$(elastic-package stack shellinit)" elastic-package stack up -d -v # Install zipped packages diff --git a/scripts/test-check-false-positives.sh b/scripts/test-check-false-positives.sh index d8e82ea5d..e59b3c69d 100755 --- a/scripts/test-check-false-positives.sh +++ b/scripts/test-check-false-positives.sh @@ -77,12 +77,9 @@ elastic-package stack up -d -v elastic-package stack status # Run package tests -eval "$(elastic-package stack shellinit)" - for d in test/packages/${PACKAGE_TEST_TYPE:-false_positives}/${PACKAGE_UNDER_TEST:-*}/; do ( cd $d - elastic-package install -v # defer-cleanup is set to a short period to verify that the option is available elastic-package test -v --report-format xUnit --report-output file --defer-cleanup 1s --test-coverage diff --git a/scripts/test-check-packages.sh b/scripts/test-check-packages.sh index c62c8593d..384fe4add 100755 --- a/scripts/test-check-packages.sh +++ b/scripts/test-check-packages.sh @@ -61,12 +61,9 @@ if [ "${PACKAGE_TEST_TYPE:-other}" == "with-kind" ]; then fi # Run package tests -eval "$(elastic-package stack shellinit)" - for d in test/packages/${PACKAGE_TEST_TYPE:-other}/${PACKAGE_UNDER_TEST:-*}/; do ( cd $d - elastic-package install -v if [ "${PACKAGE_TEST_TYPE:-other}" == "benchmarks" ]; then # It is not used PACKAGE_UNDER_TEST, so all benchmark packages are run in the same loop