Skip to content

Commit

Permalink
initial consolidation of executeGalaxy configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
nywilken authored and lbajolet-hashicorp committed Oct 20, 2023
1 parent 1d15f3b commit c7e8a41
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 58 deletions.
64 changes: 18 additions & 46 deletions provisioner/ansible-local/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"strings"

"github.com/hashicorp/hcl/v2/hcldec"
ansiblecommon "github.com/hashicorp/packer-plugin-ansible/provisioner/common"
"github.com/hashicorp/packer-plugin-sdk/common"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
Expand All @@ -27,8 +28,10 @@ import (
const DefaultStagingDir = "/tmp/packer-provisioner-ansible-local"

type Config struct {
common.PackerConfig `mapstructure:",squash"`
ctx interpolate.Context
common.PackerConfig `mapstructure:",squash"`
ansiblecommon.GalaxyConfig `mapstructure:",squash"`

ctx interpolate.Context
// The command to invoke ansible. Defaults to
// `ansible-playbook`. If you would like to provide a more complex command,
// for example, something that sets up a virtual environment before calling
Expand Down Expand Up @@ -103,7 +106,6 @@ type Config struct {

// An array of local paths of collections to upload.
CollectionPaths []string `mapstructure:"collection_paths"`

// The directory where files will be uploaded. Packer requires write
// permissions in this directory.
StagingDir string `mapstructure:"staging_directory"`
Expand Down Expand Up @@ -164,7 +166,6 @@ type Config struct {
// Adds `--force` option to `ansible-galaxy` command. By default, this is
// `false`.
GalaxyForceInstall bool `mapstructure:"galaxy_force_install"`

// The path to the directory on the remote system in which to
// install the roles. Adds `--roles-path /path/to/your/roles` to
// `ansible-galaxy` command. By default, this will install to a 'galaxy_roles' subfolder in the
Expand Down Expand Up @@ -485,47 +486,6 @@ func (p *Provisioner) provisionPlaybookFile(ui packersdk.Ui, comm packersdk.Comm
return nil
}

func (p *Provisioner) executeGalaxy(ui packersdk.Ui, comm packersdk.Communicator) error {
galaxyFile := filepath.ToSlash(filepath.Join(p.config.StagingDir, filepath.Base(p.config.GalaxyFile)))

// ansible-galaxy install -r requirements.yml
roleArgs := []string{"install", "-r", galaxyFile, "-p", filepath.ToSlash(p.config.GalaxyRolesPath)}

// Instead of modifying args depending on config values and removing or modifying values from
// the slice between role and collection installs, just use 2 slices and simplify everything
collectionArgs := []string{"collection", "install", "-r", galaxyFile, "-p", filepath.ToSlash(p.config.GalaxyCollectionsPath)}

// Add force to arguments
if p.config.GalaxyForceInstall {
roleArgs = append(roleArgs, "-f")
collectionArgs = append(collectionArgs, "-f")
}

// Search galaxy_file for roles and collections keywords
f, err := ioutil.ReadFile(p.config.GalaxyFile)
if err != nil {
return err
}
hasRoles, _ := regexp.Match(`(?m)^roles:`, f)
hasCollections, _ := regexp.Match(`(?m)^collections:`, f)

// If if roles keyword present (v2 format), or no collections keyword present (v1), install roles
if hasRoles || !hasCollections {
if roleInstallError := p.invokeGalaxyCommand(roleArgs, ui, comm); roleInstallError != nil {
return roleInstallError
}
}

// If collections keyword present (v2 format), install collections
if hasCollections {
if collectionInstallError := p.invokeGalaxyCommand(collectionArgs, ui, comm); collectionInstallError != nil {
return collectionInstallError
}
}

return nil
}

// Intended to be invoked from p.executeGalaxy depending on the Ansible Galaxy parameters passed to Packer
func (p *Provisioner) invokeGalaxyCommand(args []string, ui packersdk.Ui, comm packersdk.Communicator) error {
ctx := context.TODO()
Expand Down Expand Up @@ -557,7 +517,19 @@ func (p *Provisioner) executeAnsible(ui packersdk.Ui, comm packersdk.Communicato

// Fetch external dependencies
if len(p.config.GalaxyFile) > 0 {
if err := p.executeGalaxy(ui, comm); err != nil {
executeConfig := ansiblecommon.GalaxyExectureArgsConfig{
Filepath: filepath.ToSlash(filepath.Join(p.config.StagingDir, filepath.Base(p.config.GalaxyFile))),
RolesPath: filepath.ToSlash(p.config.GalaxyRolesPath),
CollectionsPath: filepath.ToSlash(p.config.GalaxyCollectionsPath),
ForceInstall: p.config.GalaxyForceInstall,
}

args, err := ansiblecommon.BuildGalaxyArgs(executeConfig)
if err != nil {
return fmt.Errorf("Error building Ansible Galaxy: %s", err)
}

if err := p.invokeGalaxyCommand(args, ui, comm); err != nil {
return fmt.Errorf("Error executing Ansible Galaxy: %s", err)
}
}
Expand Down
30 changes: 18 additions & 12 deletions provisioner/ansible/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"golang.org/x/crypto/ssh"

"github.com/hashicorp/hcl/v2/hcldec"
ansiblecommon "github.com/hashicorp/packer-plugin-ansible/provisioner/common"
"github.com/hashicorp/packer-plugin-sdk/adapter"
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
Expand All @@ -45,8 +46,10 @@ import (
)

type Config struct {
common.PackerConfig `mapstructure:",squash"`
ctx interpolate.Context
common.PackerConfig `mapstructure:",squash"`
ansiblecommon.GalaxyConfig `mapstructur:",squash"`

ctx interpolate.Context
// The command to invoke ansible. Defaults to
// `ansible-playbook`. If you would like to provide a more complex command,
// for example, something that sets up a virtual environment before calling
Expand Down Expand Up @@ -211,10 +214,6 @@ type Config struct {
// Adds `--force` option to `ansible-galaxy` command. By default, this is
// `false`.
GalaxyForceInstall bool `mapstructure:"galaxy_force_install"`
// Force overwriting an existing role and its dependencies.
// Adds `--force-with-deps` option to `ansible-galaxy` command. By default,
// this is `false`.
GalaxyForceWithDeps bool `mapstructure:"galaxy_force_with_deps"`
// The path to the directory on your local system in which to
// install the roles. Adds `--roles-path /path/to/your/roles` to
// `ansible-galaxy` command. By default, this is empty, and thus `--roles-path`
Expand Down Expand Up @@ -726,11 +725,6 @@ func (p *Provisioner) executeGalaxy(ui packersdk.Ui, comm packersdk.Communicator
roleArgs = append(roleArgs, "-f")
collectionArgs = append(collectionArgs, "-f")
}
// Add --force-with-deps to arguments
if p.config.GalaxyForceWithDeps {
roleArgs = append(roleArgs, "--force-with-deps")
collectionArgs = append(collectionArgs, "--force-with-deps")
}

// Add roles_path argument if specified
if p.config.RolesPath != "" {
Expand Down Expand Up @@ -875,7 +869,19 @@ func (p *Provisioner) executeAnsible(ui packersdk.Ui, comm packersdk.Communicato

// Fetch external dependencies
if len(p.config.GalaxyFile) > 0 {
if err := p.executeGalaxy(ui, comm); err != nil {
executeConfig := ansiblecommon.GalaxyExectureArgsConfig{
Filepath: filepath.ToSlash(p.config.GalaxyFile),
RolesPath: filepath.ToSlash(p.config.RolesPath),
CollectionsPath: filepath.ToSlash(p.config.CollectionsPath),
ForceInstall: p.config.GalaxyForceInstall,
}

args, err := ansiblecommon.BuildGalaxyArgs(executeConfig)
if err != nil {
return fmt.Errorf("Error building Ansible Galaxy: %s", err)
}

if err := p.invokeGalaxyCommand(args, ui, comm); err != nil {
return fmt.Errorf("Error executing Ansible Galaxy: %s", err)
}
}
Expand Down
75 changes: 75 additions & 0 deletions provisioner/common/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:generate packer-sdc struct-markdown
package common

import (
"io/ioutil"
"regexp"
)

type GalaxyConfig struct {
// A requirements file which provides a way to
// install roles or collections with the [ansible-galaxy
// cli](https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#the-ansible-galaxy-command-line-tool)
// on the local machine before executing `ansible-playbook`. By default, this is empty.
GalaxyFile string `mapstructure:"galaxy_file"`
// The command to invoke ansible-galaxy. By default, this is
// `ansible-galaxy`.
GalaxyCommand string `mapstructure:"galaxy_command"`
// Force overwriting an existing role.
// Adds `--force` option to `ansible-galaxy` command. By default, this is
// `false`.
GalaxyForceInstall bool `mapstructure:"galaxy_force_install"`
// The path to the directory on your local system in which to
// install the roles. Adds `--roles-path /path/to/your/roles` to
// `ansible-galaxy` command. By default, this is empty, and thus `--roles-path`
// option is not added to the command.
RolesPath string `mapstructure:"roles_path"`
// The path to the directory on your local system in which to
// install the collections. Adds `--collections-path /path/to/your/collections` to
// `ansible-galaxy` command. By default, this is empty, and thus `--collections-path`
// option is not added to the command.
CollectionsPath string `mapstructure:"collections_path"`
}

type GalaxyExectureArgsConfig struct {
Filepath string
RolesPath string
CollectionsPath string
ForceInstall bool
}

func BuildGalaxyArgs(conf GalaxyExectureArgsConfig) ([]string, error) {

// ansible-galaxy install -r requirements.yml
roleArgs := []string{"install", "-r", conf.Filepath, "-p", conf.RolesPath}

// Instead of modifying args depending on config values and removing or modifying values from
// the slice between role and collection installs, just use 2 slices and simplify everything
collectionArgs := []string{"collection", "install", "-r", conf.Filepath, "-p", conf.CollectionsPath}

// Add force to arguments
if conf.ForceInstall {
roleArgs = append(roleArgs, "-f")
collectionArgs = append(collectionArgs, "-f")
}

// Search galaxy_file for roles and collections keywords
f, err := ioutil.ReadFile(conf.Filepath)
if err != nil {
return nil, err
}
hasRoles, _ := regexp.Match(`(?m)^roles:`, f)
hasCollections, _ := regexp.Match(`(?m)^collections:`, f)

// If if roles keyword present (v2 format), or no collections keyword present (v1), install roles
if hasRoles || !hasCollections {
return roleArgs, nil
}

// If collections keyword present (v2 format), install collections
if hasCollections {
return collectionArgs, nil
}

return nil, nil
}

0 comments on commit c7e8a41

Please sign in to comment.