55package profile
66
77import (
8- "embed"
98 "errors"
109 "fmt"
1110 "os"
1211 "path/filepath"
1312 "strings"
14- "text/template"
1513
16- "github.com/Masterminds/semver"
1714 "github.com/elastic/elastic-package/internal/configuration/locations"
15+ "github.com/elastic/elastic-package/internal/files"
1816 "github.com/elastic/go-resource"
1917)
2018
2119const (
2220 // PackageProfileMetaFile is the filename of the profile metadata file
2321 PackageProfileMetaFile = "profile.json"
2422
25- // SnapshotFile is the docker-compose snapshot.yml file name.
26- SnapshotFile = "snapshot.yml"
27-
28- // ElasticsearchConfigFile is the elasticsearch config file.
29- ElasticsearchConfigFile = "elasticsearch.yml"
30-
31- // KibanaConfigFile is the kibana config file.
32- KibanaConfigFile = "kibana.yml"
33-
34- // KibanaHealthcheckFile is the kibana healthcheck.
35- KibanaHealthcheckFile = "kibana_healthcheck.sh"
36-
37- // PackageRegistryConfigFile is the config file for the Elastic Package registry
38- PackageRegistryConfigFile = "package-registry.yml"
39-
40- // PackageRegistryBaseImage is the base Docker image of the Elastic Package Registry.
41- PackageRegistryBaseImage = "docker.elastic.co/package-registry/package-registry:v1.15.0"
42-
43- // ElasticAgentEnvFile is the elastic agent environment variables file.
44- ElasticAgentEnvFile = "elastic-agent.env"
45-
4623 // DefaultProfile is the name of the default profile.
4724 DefaultProfile = "default"
48-
49- profileStackPath = "stack"
5025)
5126
52- //go:embed _static
53- var static embed.FS
54-
5527var (
56- templateFuncs = template.FuncMap {
57- "semverLessThan" : semverLessThan ,
58- }
59- staticSource = resource .NewSourceFS (static ).WithTemplateFuncs (templateFuncs )
6028 profileResources = []resource.Resource {
6129 & resource.File {
62- Provider : "profile-file" ,
63- Path : PackageProfileMetaFile ,
64- Content : profileMetadataContent ,
65- },
66- & resource.File {
67- Provider : "stack-file" ,
68- Path : "Dockerfile.package-registry" ,
69- Content : staticSource .Template ("_static/Dockerfile.package-registry.tmpl" ),
70- },
71- & resource.File {
72- Provider : "stack-file" ,
73- Path : SnapshotFile ,
74- Content : staticSource .File ("_static/docker-compose-stack.yml" ),
75- },
76- & resource.File {
77- Provider : "stack-file" ,
78- Path : ElasticsearchConfigFile ,
79- Content : staticSource .Template ("_static/elasticsearch.yml.tmpl" ),
80- },
81- & resource.File {
82- Provider : "stack-file" ,
83- Path : "service_tokens" ,
84- Content : staticSource .File ("_static/service_tokens" ),
85- },
86- & resource.File {
87- Provider : "stack-file" ,
88- Path : "ingest-geoip/GeoLite2-ASN.mmdb" ,
89- CreateParent : true ,
90- Content : staticSource .File ("_static/GeoLite2-ASN.mmdb" ),
91- },
92- & resource.File {
93- Provider : "stack-file" ,
94- Path : "ingest-geoip/GeoLite2-City.mmdb" ,
95- CreateParent : true ,
96- Content : staticSource .File ("_static/GeoLite2-City.mmdb" ),
97- },
98- & resource.File {
99- Provider : "stack-file" ,
100- Path : "ingest-geoip/GeoLite2-Country.mmdb" ,
101- CreateParent : true ,
102- Content : staticSource .File ("_static/GeoLite2-Country.mmdb" ),
103- },
104- & resource.File {
105- Provider : "stack-file" ,
106- Path : KibanaConfigFile ,
107- Content : staticSource .Template ("_static/kibana.yml.tmpl" ),
108- },
109- & resource.File {
110- Provider : "stack-file" ,
111- Path : KibanaHealthcheckFile ,
112- Content : staticSource .File ("_static/kibana_healthcheck.sh" ),
113- },
114- & resource.File {
115- Provider : "stack-file" ,
116- Path : PackageRegistryConfigFile ,
117- Content : staticSource .File ("_static/package-registry.yml" ),
118- },
119- & resource.File {
120- Provider : "stack-file" ,
121- Path : ElasticAgentEnvFile ,
122- Content : staticSource .Template ("_static/elastic-agent.env.tmpl" ),
30+ Path : PackageProfileMetaFile ,
31+ Content : profileMetadataContent ,
12332 },
12433 }
12534)
@@ -140,67 +49,42 @@ func CreateProfile(options Options) error {
14049 options .PackagePath = loc .ProfileDir ()
14150 }
14251
143- // If they're creating from Default, assume they want the actual default, and
144- // not whatever is currently inside default.
145- if from := options .FromProfile ; from != "" && from != DefaultProfile {
146- return createProfileFrom (options )
147- }
148-
149- resources , err := initProfileResources (options )
150- if err != nil {
151- return err
52+ if options .Name == "" {
53+ options .Name = DefaultProfile
15254 }
15355
154- return createProfile (options , resources )
155- }
156-
157- func initProfileResources (options Options ) ([]resource.Resource , error ) {
158- profileName := options .Name
159- if profileName == "" {
160- profileName = DefaultProfile
56+ if ! options .OverwriteExisting {
57+ _ , err := LoadProfile (options .Name )
58+ if err == nil {
59+ return fmt .Errorf ("profile %q already exists" , options .Name )
60+ }
61+ if err != nil && err != ErrNotAProfile {
62+ return fmt .Errorf ("failed to check if profile %q exists: %w" , options .Name , err )
63+ }
16164 }
162- profileDir := filepath .Join (options .PackagePath , profileName )
163-
164- resources := append ([]resource.Resource {}, profileResources ... )
16565
166- certResources , err := initTLSCertificates ("profile-file" , profileDir )
167- if err != nil {
168- return nil , fmt .Errorf ("failed to create TLS files: %w" , err )
66+ // If they're creating from Default, assume they want the actual default, and
67+ // not whatever is currently inside default.
68+ if from := options .FromProfile ; from != "" && from != DefaultProfile {
69+ return createProfileFrom (options )
16970 }
170- resources = append (resources , certResources ... )
17171
172- return resources , nil
72+ return createProfile ( options , profileResources )
17373}
17474
17575func createProfile (options Options , resources []resource.Resource ) error {
176- stackVersion := "8.1.0" // TODO: Parameterize this.
177-
178- profileName := options .Name
179- if profileName == "" {
180- profileName = DefaultProfile
181- }
182- profileDir := filepath .Join (options .PackagePath , profileName )
183- stackDir := filepath .Join (options .PackagePath , profileName , profileStackPath )
76+ profileDir := filepath .Join (options .PackagePath , options .Name )
18477
18578 resourceManager := resource .NewManager ()
18679 resourceManager .AddFacter (resource.StaticFacter {
187- "profile_name" : profileName ,
80+ "profile_name" : options . Name ,
18881 "profile_path" : profileDir ,
189-
190- "registry_base_image" : PackageRegistryBaseImage ,
191-
192- "elasticsearch_version" : stackVersion ,
193- "kibana_version" : stackVersion ,
194- "agent_version" : stackVersion ,
19582 })
19683
197- os .MkdirAll (stackDir , 0755 )
198- resourceManager .RegisterProvider ("profile- file" , & resource.FileProvider {
84+ os .MkdirAll (profileDir , 0755 )
85+ resourceManager .RegisterProvider ("file" , & resource.FileProvider {
19986 Prefix : profileDir ,
20087 })
201- resourceManager .RegisterProvider ("stack-file" , & resource.FileProvider {
202- Prefix : stackDir ,
203- })
20488
20589 results , err := resourceManager .Apply (resources )
20690 if err != nil {
@@ -222,45 +106,38 @@ func createProfileFrom(options Options) error {
222106 return fmt .Errorf ("failed to load profile to copy %q: %w" , options .FromProfile , err )
223107 }
224108
225- return createProfile (options , from .resources )
109+ profileDir := filepath .Join (options .PackagePath , options .Name )
110+ err = files .CopyAll (from .ProfilePath , profileDir )
111+ if err != nil {
112+ return fmt .Errorf ("failed to copy files from profile %q to %q" , options .FromProfile , options .Name )
113+ }
114+
115+ overwriteOptions := options
116+ overwriteOptions .OverwriteExisting = true
117+ return createProfile (overwriteOptions , profileResources )
226118}
227119
228120// Profile manages a a given user config profile
229121type Profile struct {
230122 // ProfilePath is the absolute path to the profile
231- ProfilePath string
232- ProfileStackPath string
233- ProfileName string
123+ ProfilePath string
124+ ProfileName string
125+ }
234126
235- resources []resource.Resource
127+ // Path returns an absolute path to the given file
128+ func (profile Profile ) Path (names ... string ) string {
129+ elems := append ([]string {profile .ProfilePath }, names ... )
130+ return filepath .Join (elems ... )
236131}
237132
238133// ErrNotAProfile is returned in cases where we don't have a valid profile directory
239134var ErrNotAProfile = errors .New ("not a profile" )
240135
241- // FetchPath returns an absolute path to the given file
242- func (profile Profile ) FetchPath (name string ) string {
243- for _ , r := range profile .resources {
244- file , ok := r .(* resource.File )
245- if ! ok {
246- continue
247- }
248-
249- if file .Path != name {
250- continue
251- }
252-
253- return filepath .Join (profile .ProfileStackPath , file .Path )
254- }
255- panic (fmt .Sprintf ("%q profile file is not defined" , name ))
256- }
257-
258136// ComposeEnvVars returns a list of environment variables that can be passed
259137// to docker-compose for the sake of filling out paths and names in the snapshot.yml file.
260138func (profile Profile ) ComposeEnvVars () []string {
261139 return []string {
262140 fmt .Sprintf ("PROFILE_NAME=%s" , profile .ProfileName ),
263- fmt .Sprintf ("STACK_PATH=%s" , profile .ProfileStackPath ),
264141 }
265142}
266143
@@ -333,19 +210,9 @@ func loadProfile(elasticPackagePath string, profileName string) (*Profile, error
333210 return nil , ErrNotAProfile
334211 }
335212
336- resources := append ([]resource.Resource {}, profileResources ... )
337-
338- certResources , err := initTLSCertificates ("profile-file" , profilePath )
339- if err != nil {
340- return nil , fmt .Errorf ("failed to create TLS files: %w" , err )
341- }
342- resources = append (resources , certResources ... )
343-
344213 profile := Profile {
345- ProfileName : profileName ,
346- ProfilePath : profilePath ,
347- ProfileStackPath : filepath .Join (profilePath , profileStackPath ),
348- resources : resources ,
214+ ProfileName : profileName ,
215+ ProfilePath : profilePath ,
349216 }
350217
351218 return & profile , nil
@@ -363,16 +230,3 @@ func isProfileDir(path string) (bool, error) {
363230 }
364231 return true , nil
365232}
366-
367- func semverLessThan (a , b string ) (bool , error ) {
368- sa , err := semver .NewVersion (a )
369- if err != nil {
370- return false , err
371- }
372- sb , err := semver .NewVersion (b )
373- if err != nil {
374- return false , err
375- }
376-
377- return sa .LessThan (sb ), nil
378- }
0 commit comments