diff --git a/Furyfile.yml b/Furyfile.yml index 3b2d7cfd2..13e3e1cfd 100644 --- a/Furyfile.yml +++ b/Furyfile.yml @@ -1,4 +1,3 @@ - versions: aws: v1.15.4 monitoring: master @@ -10,8 +9,48 @@ roles: modules: - name: aws/aws-vpc - name: aws/aws-kubernetes + - name: terraform-aws-acm + version: v2.5.0 + provider: + name: aws + label: official-modules + registry: true + - name: tf_aws_bastion_s3_keys + version: v2.0.0 + provider: + name: aws + label: community-modules + registry: true + - name: terraform-google-kubernetes-engine + version: v6.2.0 + provider: + name: gcp + label: official-modules + registry: true + - name: terraform-azurerm-aks + version: v2.0 + provider: + name: azure + label: official-modules + registry: true bases: - name: monitoring - name: logging version: master + +provider: + roles: {} + bases: {} + modules: + aws: + - url: https://github.com/terraform-aws-modules + label: official-modules + - url: https://github.com/terraform-community-modules + label: community-modules + gcp: + - url: https://github.com/terraform-google-modules + label: official-modules + azure: + - url: https://github.com/Azure + label: official-modules diff --git a/cmd/config.go b/cmd/config.go index bc20d3235..5bb480bb1 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -29,26 +29,57 @@ const ( // Furyconf is reponsible for the structure of the Furyfile type Furyconf struct { - VendorFolderName string `yaml:"vendorFolderName"` - Versions VersionPattern `yaml:"versions"` - Roles []Package `yaml:"roles"` - Modules []Package `yaml:"modules"` - Bases []Package `yaml:"bases"` + VendorFolderName string `yaml:"vendorFolderName"` + Versions VersionPattern `yaml:"versions"` + Roles []Package `yaml:"roles"` + Modules []Package `yaml:"modules"` + Bases []Package `yaml:"bases"` + Provider ProviderPattern `mapstructure:"provider"` } -// Map from glob pattern to version associated (e.g. {"aws/*" : "v1.15.4-1"} +// ProviderPattern is the abstraction of the following structure: +//provider: +// modules: +// aws +// - uri: https://github.com/terraform-aws-modules +// label: ufficial-modules +type ProviderPattern map[string]ProviderKind + +// ProviderKind is the abstraction of the following structure: +// +// modules: +// aws +// - uri: https://github.com/terraform-aws-modules +// label: ufficial-modules +type ProviderKind map[string][]RegistrySpec + +//RegistrySpec contains the couple uri/label to identify each tf new repo declared +type RegistrySpec struct { + BaseURI string `mapstructure:"url"` + Label string `mapstructure:"label"` +} + +//VersionPattern Map from glob pattern to version associated (e.g. {"aws/*" : "v1.15.4-1"} type VersionPattern map[string]string // Package is the type to contain the definition of a single package type Package struct { - Name string `yaml:"name"` - Version string `yaml:"version"` - url string - dir string - kind string + Name string `yaml:"name"` + Version string `yaml:"version"` + url string + dir string + kind string + ProviderOpt ProviderOptSpec `mapstructure:"provider"` + Registry bool `mapstructure:"registry"` } -// Validate is used for validation of configuration and initization of default paramethers +// ProviderSpec is the type that allows to explicit name of cloud provider and referenced label +type ProviderOptSpec struct { + Name string `mapstructure:"name"` + Label string `mapstructure:"label"` +} + +// Validate is used for validation of configuration and initization of default parameters func (f *Furyconf) Validate() error { if f.VendorFolderName == "" { f.VendorFolderName = defaultVendorFolderName @@ -72,7 +103,6 @@ func (f *Furyconf) Parse() ([]Package, error) { v.kind = "katalog" pkgs = append(pkgs, v) } - repoPrefix := sshRepoPrefix dotGitParticle := "" if https { @@ -82,7 +112,14 @@ func (f *Furyconf) Parse() ([]Package, error) { // Now we generate the dowload url and local dir for i := 0; i < len(pkgs); i++ { + url := new(URLSpec) + directory := new(DirSpec) version := pkgs[i].Version + registry := pkgs[i].Registry + cloudPlatform := pkgs[i].ProviderOpt + urlPrefix := repoPrefix + pkgKind := pkgs[i].kind + if version == "" { for k, v := range f.Versions { if strings.HasPrefix(pkgs[i].Name, k) { @@ -92,13 +129,116 @@ func (f *Furyconf) Parse() ([]Package, error) { } } } + + kindSpec := newKind(pkgKind, f.Provider) block := strings.Split(pkgs[i].Name, "/") - if len(block) == 2 { - pkgs[i].url = fmt.Sprintf("%s-%s%s//%s/%s?ref=%s", repoPrefix, block[0], dotGitParticle, pkgs[i].kind, block[1], version) - } else if len(block) == 1 { - pkgs[i].url = fmt.Sprintf("%s-%s%s//%s?ref=%s", repoPrefix, block[0], dotGitParticle, pkgs[i].kind, version) - } - pkgs[i].dir = fmt.Sprintf("%s/%s/%s", f.VendorFolderName, pkgs[i].kind, pkgs[i].Name) + url = newURL(urlPrefix, block, dotGitParticle, pkgKind, version, registry, cloudPlatform, kindSpec) + pkgs[i].url = url.strategy() + directory = newDir(f.VendorFolderName, pkgKind, pkgs[i].Name, registry, cloudPlatform) + pkgs[i].dir = directory.strategy() } + return pkgs, nil } + +func newKind(kind string, provider ProviderPattern) ProviderKind { + providerChoosen := provider[kind] + return providerChoosen +} + +func (k *ProviderKind) getLabeledURI(providerName, label string) (string, error) { + for name, providerSpecList := range *k { + if name == providerName { + for _, providerMap := range providerSpecList { + if providerMap.Label == label { + return fmt.Sprintf("git::%s", providerMap.BaseURI), nil + } + } + } + } + return "", fmt.Errorf("no label %s found", label) +} + +func (k *ProviderKind) pickCloudProviderURL(cloudProvider ProviderOptSpec) string { + name := cloudProvider.Name + label := cloudProvider.Label + url, err := k.getLabeledURI(name, label) + if err != nil { + log.Fatal(err) + } + return url +} + +// DirSpec is the abstraction of the fields needed for generating a destination directory +type DirSpec struct { + VendorFolder string + Kind string + Name string + Registry bool + Provider ProviderOptSpec +} + +func newDir(folder, kind, name string, registry bool, provider ProviderOptSpec) *DirSpec { + return &DirSpec{ + VendorFolder: folder, + Kind: kind, + Name: name, + Registry: registry, + Provider: provider, + } +} + +func (d *DirSpec) strategy() string { + if d.Registry { + return fmt.Sprintf("%s/%s/%s/%s/%s", d.VendorFolder, d.Kind, d.Provider.Label, d.Provider.Name, d.Name) + } + return fmt.Sprintf("%s/%s/%s", d.VendorFolder, d.Kind, d.Name) +} + +//URLSpec is the rappresentation of the fields needed to elaborate a url +type URLSpec struct { + Prefix string + Blocks []string + DotGitParticle string + Kind string + Version string + Registry bool + CloudProvider ProviderOptSpec + KindSpec ProviderKind +} + +// newUrl initialize the URLSpec struct +func newURL(prefix string, blocks []string, dotGitParticle, kind, version string, registry bool, cloud ProviderOptSpec, kindSpec ProviderKind) *URLSpec { + return &URLSpec{ + Registry: registry, + Prefix: prefix, + Blocks: blocks, + DotGitParticle: dotGitParticle, + Kind: kind, + Version: version, + CloudProvider: cloud, + KindSpec: kindSpec, + } +} + +func (n *URLSpec) strategy() string { + var url string + if n.Registry { + urlPrefix := n.KindSpec.pickCloudProviderURL(n.CloudProvider) + dotGitParticle := ".git" + url = fmt.Sprintf("%s/%s%s?ref=%s", urlPrefix, n.Blocks[0], dotGitParticle, n.Version) + } else { + url = n.getURLfromCompanyRepos() + } + return url +} + +func (n *URLSpec) getURLfromCompanyRepos() string { + var url string + if len(n.Blocks) == 2 { + url = fmt.Sprintf("%s-%s%s//%s/%s?ref=%s", n.Prefix, n.Blocks[0], n.DotGitParticle, n.Kind, n.Blocks[1], n.Version) + } else if len(n.Blocks) == 1 { + url = fmt.Sprintf("%s-%s%s//%s?ref=%s", n.Prefix, n.Blocks[0], n.DotGitParticle, n.Kind, n.Version) + } + return url +}