Skip to content

Commit cce94bd

Browse files
committed
Share logic to start local services
1 parent 12aaebe commit cce94bd

File tree

15 files changed

+301
-158
lines changed

15 files changed

+301
-158
lines changed

internal/agentdeployer/agent.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,11 @@ func (d *DockerComposeAgentDeployer) installDockerCompose(agentInfo AgentInfo) (
258258
fleetURL := "https://fleet-server:8220"
259259
kibanaHost := "https://kibana:5601"
260260
stackVersion := d.stackVersion
261-
if config.Provider == stack.ProviderServerless {
262-
fleetURL = config.Parameters[stack.ParamServerlessFleetURL]
263-
kibanaHost = config.KibanaHost
264-
stackVersion = config.Parameters[stack.ParamServerlessLocalStackVersion]
261+
if url, ok := config.Parameters[stack.ParamServerlessFleetURL]; ok {
262+
fleetURL = url
263+
}
264+
if version, ok := config.Parameters[stack.ParamServerlessLocalStackVersion]; ok {
265+
stackVersion = version
265266
}
266267

267268
agentImage, err := selectElasticAgentImage(stackVersion, agentInfo.Agent.BaseImage)

internal/stack/_static/elastic-agent.env.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ FLEET_ENROLL=1
33
FLEET_URL={{ fact "fleet_url" }}
44
KIBANA_FLEET_HOST={{ fact "kibana_host" }}
55
KIBANA_HOST={{ fact "kibana_host" }}
6+
{{ $api_key := fact "api_key" }}
7+
{{- if eq $api_key "" }}
68
ELASTICSEARCH_USERNAME={{ fact "username" }}
79
ELASTICSEARCH_PASSWORD={{ fact "password" }}
10+
{{- else }}
11+
ELASTICSEARCH_API_KEY={{ $api_key }}
12+
{{- end }}
813
{{ if not (semverLessThan $version "8.0.0") }}
914
FLEET_TOKEN_POLICY_NAME=Elastic-Agent (elastic-package)
1015
{{ end }}

internal/stack/_static/logstash.conf.tmpl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@ input {
99
}
1010

1111
{{ $elasticsearch_host := fact "elasticsearch_host" -}}
12+
{{ $api_key := fact "api_key" -}}
1213
filter {
1314
elastic_integration {
1415
remove_field => ['@version']
1516
hosts => ["{{ $elasticsearch_host }}"]
17+
{{- if eq $api_key "" }}
1618
username => '{{ fact "username" }}'
1719
password => '{{ fact "password" }}'
20+
{{- else }}
21+
api_key => '{{ $api_key }}'
22+
{{- end }}
1823
ssl_enabled => true
1924
ssl_verification_mode => "none"
2025
}
@@ -24,8 +29,12 @@ output {
2429
if [@metadata][_ingest_document][id] {
2530
elasticsearch {
2631
hosts => ["{{ $elasticsearch_host }}"]
32+
{{- if eq $api_key "" -}}
2733
user => '{{ fact "username" }}'
2834
password => '{{ fact "password" }}'
35+
{{- else -}}
36+
api_key => '{{ $api_key }}'
37+
{{- end }}
2938
ssl_enabled => true
3039
{{- if eq $elasticsearch_host "https://elasticsearch:9200" }}
3140
ssl_certificate_authorities => "/usr/share/logstash/config/certs/ca-cert.pem"

internal/stack/certs.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ var tlsServices = []tlsService{
3232
{Name: "elastic-agent", IsClient: true},
3333
}
3434

35-
var tlsServicesServerless = []tlsService{
35+
// tlsLocalServices is the list of server TLS certificates that will
36+
// be created for local services when the stack is not local.
37+
var tlsLocalServices = []tlsService{
3638
{Name: "logstash"},
3739
{Name: "elastic-agent", IsClient: true},
3840
}

internal/stack/certs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestTLSCertsInitialization(t *testing.T) {
2121
services []tlsService
2222
}{
2323
{"tlsServices", tlsServices},
24-
{"tlsServicesServerless", tlsServicesServerless},
24+
{"tlsServicesServerless", tlsLocalServices},
2525
}
2626
profilePath := t.TempDir()
2727
caCertFile := filepath.Join(profilePath, "certs", "ca-cert.pem")

internal/stack/dump.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func dumpStackLogs(ctx context.Context, options DumpOptions) ([]DumpResult, erro
6161
return nil, fmt.Errorf("can't remove output location: %w", err)
6262
}
6363

64-
services, err := localServiceNames(DockerComposeProjectName(options.Profile))
64+
services, err := localServiceNames(options.Profile)
6565
if err != nil {
6666
return nil, fmt.Errorf("failed to get local services: %w", err)
6767
}

internal/stack/environment.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package stack
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"os"
11+
12+
"github.com/elastic/elastic-package/internal/elasticsearch"
13+
"github.com/elastic/elastic-package/internal/kibana"
14+
"github.com/elastic/elastic-package/internal/profile"
15+
)
16+
17+
type environmentProvider struct {
18+
kibana *kibana.Client
19+
elasticsearch *elasticsearch.Client
20+
}
21+
22+
func newEnvironmentProvider(profile *profile.Profile) (*environmentProvider, error) {
23+
return &environmentProvider{}, nil
24+
}
25+
26+
// BootUp configures the profile to use as stack the one indicated using environment variables.
27+
func (p *environmentProvider) BootUp(ctx context.Context, options Options) error {
28+
config := Config{
29+
Provider: ProviderEnvironment,
30+
ElasticsearchAPIKey: os.Getenv(ElasticsearchAPIKeyEnv),
31+
ElasticsearchHost: os.Getenv(ElasticsearchHostEnv),
32+
ElasticsearchUsername: os.Getenv(ElasticsearchUsernameEnv),
33+
ElasticsearchPassword: os.Getenv(ElasticsearchPasswordEnv),
34+
KibanaHost: os.Getenv(KibanaHostEnv),
35+
CACertFile: os.Getenv(CACertificateEnv),
36+
37+
Parameters: make(map[string]string),
38+
}
39+
if err := requiredEnv(config.ElasticsearchHost, ElasticsearchHostEnv); err != nil {
40+
return err
41+
}
42+
if err := requiredEnv(config.KibanaHost, KibanaHostEnv); err != nil {
43+
return err
44+
}
45+
46+
err := p.initClients()
47+
if err != nil {
48+
return err
49+
}
50+
// TODO: Migrate from serverless variables.
51+
config.Parameters[ParamServerlessFleetURL], err = p.kibana.DefaultFleetServerURL(ctx)
52+
if err != nil {
53+
return fmt.Errorf("cannot discover default fleet server URL: %w", err)
54+
}
55+
56+
localServices := &localServicesManager{
57+
profile: options.Profile,
58+
}
59+
err = localServices.start(ctx, options, config)
60+
if err != nil {
61+
return fmt.Errorf("failed to start local services: %w", err)
62+
}
63+
64+
err = storeConfig(options.Profile, config)
65+
if err != nil {
66+
return fmt.Errorf("failed to store config: %w", err)
67+
}
68+
69+
return nil
70+
}
71+
72+
func requiredEnv(value string, envVarName string) error {
73+
if value == "" {
74+
return fmt.Errorf("environment variable %s required", envVarName)
75+
}
76+
return nil
77+
}
78+
79+
func (p *environmentProvider) initClients() error {
80+
kibana, err := NewKibanaClient()
81+
if err != nil {
82+
return fmt.Errorf("cannot create Kibana client: %w", err)
83+
}
84+
p.kibana = kibana
85+
86+
elasticsearch, err := NewElasticsearchClient()
87+
if err != nil {
88+
return fmt.Errorf("cannot create Elasticsearch client: %w", err)
89+
}
90+
p.elasticsearch = elasticsearch
91+
92+
return nil
93+
}
94+
95+
// TearDown stops and/or removes a stack.
96+
func (p *environmentProvider) TearDown(ctx context.Context, options Options) error {
97+
localServices := &localServicesManager{
98+
profile: options.Profile,
99+
}
100+
err := localServices.destroy(ctx)
101+
if err != nil {
102+
return fmt.Errorf("failed ot destroy local services: %v", err)
103+
}
104+
return nil
105+
}
106+
107+
// Update updates resources associated to a stack.
108+
func (p *environmentProvider) Update(context.Context, Options) error {
109+
return fmt.Errorf("not implemented")
110+
}
111+
112+
// Dump dumps data for debug purpouses.
113+
func (p *environmentProvider) Dump(ctx context.Context, options DumpOptions) ([]DumpResult, error) {
114+
for _, service := range options.Services {
115+
if service != "elastic-agent" {
116+
return nil, &ErrNotImplemented{
117+
Operation: fmt.Sprintf("logs dump for service %s", service),
118+
Provider: ProviderServerless,
119+
}
120+
}
121+
}
122+
return Dump(ctx, options)
123+
}
124+
125+
// Status obtains status information of the stack.
126+
func (p *environmentProvider) Status(context.Context, Options) ([]ServiceStatus, error) {
127+
return nil, fmt.Errorf("not implemented")
128+
}

internal/stack/serverlessresources.go renamed to internal/stack/localresources.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ import (
1919
)
2020

2121
var (
22-
serverlessStackResources = []resource.Resource{
22+
localStackResources = []resource.Resource{
2323
&resource.File{
2424
Path: ComposeFile,
25-
Content: staticSource.Template("_static/serverless-docker-compose.yml.tmpl"),
25+
Content: staticSource.Template("_static/local-services-docker-compose.yml.tmpl"),
2626
},
2727
&resource.File{
2828
Path: ElasticAgentEnvFile,
@@ -31,7 +31,9 @@ var (
3131
}
3232
)
3333

34-
func applyServerlessResources(profile *profile.Profile, stackVersion string, config Config) error {
34+
// applyLocalResources creates the local resources needed to run system tests when the stack
35+
// is not local.
36+
func applyLocalResources(profile *profile.Profile, stackVersion string, config Config) error {
3537
appConfig, err := install.Configuration(install.OptionWithStackVersion(stackVersion))
3638
if err != nil {
3739
return fmt.Errorf("can't read application configuration: %w", err)
@@ -46,6 +48,7 @@ func applyServerlessResources(profile *profile.Profile, stackVersion string, con
4648
"agent_image": imageRefs.ElasticAgent,
4749
"logstash_image": imageRefs.Logstash,
4850
"elasticsearch_host": esHostWithPort(config.ElasticsearchHost),
51+
"api_key": config.ElasticsearchAPIKey, // TODO: !! We will need to enroll with an enrollment token?
4952
"username": config.ElasticsearchUsername,
5053
"password": config.ElasticsearchPassword,
5154
"kibana_host": config.KibanaHost,
@@ -58,13 +61,13 @@ func applyServerlessResources(profile *profile.Profile, stackVersion string, con
5861
Prefix: stackDir,
5962
})
6063

61-
resources := append([]resource.Resource{}, serverlessStackResources...)
64+
resources := append([]resource.Resource{}, localStackResources...)
6265

6366
// Keeping certificates in the profile directory for backwards compatibility reasons.
6467
resourceManager.RegisterProvider("certs", &resource.FileProvider{
6568
Prefix: profile.ProfilePath,
6669
})
67-
certResources, err := initTLSCertificates("certs", profile.ProfilePath, tlsServicesServerless)
70+
certResources, err := initTLSCertificates("certs", profile.ProfilePath, tlsLocalServices)
6871
if err != nil {
6972
return fmt.Errorf("failed to create TLS files: %w", err)
7073
}

0 commit comments

Comments
 (0)