From 913ed06dd16b8030320b7db3f1e0056f0d624536 Mon Sep 17 00:00:00 2001 From: petergmurphy Date: Tue, 28 Sep 2021 12:45:56 +0100 Subject: [PATCH] (GH-136) Implement Clone Template Functions Implemented functions that allow for the cloning of templates from a remote repository using a git URI. Modified existing code in the `executeInstall` method so that it checks if the `--git-uri` flag is being used. The appropriate function for template installation will be called based on this check. `preExecute` function changed to provide the correct template installation path for the `--git-uri` flag. --- cmd/install/install.go | 24 +++++++----- internal/pkg/mock/install.go | 4 ++ internal/pkg/pct/install.go | 76 +++++++++++++++++++++++++++++++----- 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/cmd/install/install.go b/cmd/install/install.go index 973952f5..f3d58916 100644 --- a/cmd/install/install.go +++ b/cmd/install/install.go @@ -15,7 +15,7 @@ type InstallCommand struct { InstallPath string Force bool PctInstaller pct.PctInstallerI - GitUri string + GitUri string } type InstallCommandI interface { @@ -41,7 +41,14 @@ func (ic *InstallCommand) CreateCommand() *cobra.Command { } func (ic *InstallCommand) executeInstall(cmd *cobra.Command, args []string) error { - templateInstallationPath, err := ic.PctInstaller.Install(ic.TemplatePkgPath, ic.InstallPath, ic.Force) + var templateInstallationPath string = "" + var err error = nil + if ic.GitUri != "" { // For cloning a template + templateInstallationPath, err = ic.PctInstaller.InstallClone(ic.GitUri, ic.InstallPath, ic.Force) + } else { // For downloading and/or locally installing a template + templateInstallationPath, err = ic.PctInstaller.Install(ic.TemplatePkgPath, ic.InstallPath, ic.Force) + } + if err != nil { return err } @@ -64,18 +71,17 @@ func (ic *InstallCommand) setInstallPath() error { } func (ic *InstallCommand) preExecute(cmd *cobra.Command, args []string) error { - if len(args) < 1 { + if len(args) < 1 && ic.GitUri == "" { return fmt.Errorf("Path to template package (tar.gz) should be first argument") } - if len(args) == 1 { - ic.TemplatePkgPath = args[0] - return ic.setInstallPath() - } - if len(args) > 1 { return fmt.Errorf("Incorrect number of arguments; path to template package (tar.gz) should be first argument") } - return nil + if len(args) == 1 { + ic.TemplatePkgPath = args[0] + } + + return ic.setInstallPath() } diff --git a/internal/pkg/mock/install.go b/internal/pkg/mock/install.go index 3b7f1145..fac7fbc2 100644 --- a/internal/pkg/mock/install.go +++ b/internal/pkg/mock/install.go @@ -21,3 +21,7 @@ func (p *PctInstaller) Install(templatePkg string, targetDir string, force bool) return filepath.Clean("/unit/test/path"), nil } + +func (p *PctInstaller) InstallClone(templatePkg string, targetDir string, force bool) (string, error) { + return "WIP", fmt.Errorf("Work in Progress") +} diff --git a/internal/pkg/pct/install.go b/internal/pkg/pct/install.go index a1af86f5..33822cef 100644 --- a/internal/pkg/pct/install.go +++ b/internal/pkg/pct/install.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "os" + "os/exec" "path/filepath" "strings" @@ -26,6 +27,7 @@ type PctInstaller struct { type PctInstallerI interface { Install(templatePkg string, targetDir string, force bool) (string, error) + InstallClone(templatePkg string, targetDir string, force bool) (string, error) } func (p *PctInstaller) Install(templatePkg string, targetDir string, force bool) (string, error) { @@ -66,25 +68,56 @@ func (p *PctInstaller) Install(templatePkg string, targetDir string, force bool) return "", fmt.Errorf("Could not create tempdir to gunzip template: %v", err) } - // gunzip the tar.gz to created tempdir - tarfile, err := p.Gunzip.Gunzip(templatePkg, tempDir) + folderPath, err := p.unTarGz(templatePkg, tempDir) if err != nil { - return "", fmt.Errorf("Could not extract TAR from GZIP (%v): %v", templatePkg, err) + return "", err } - // untar the above archive to the temp dir - untarPath, err := p.Tar.Untar(tarfile, tempDir) + // determine the properties of the template + info, err := p.readConfig(filepath.Join(folderPath, "pct-config.yml")) if err != nil { - return "", fmt.Errorf("Could not UNTAR template (%v): %v", templatePkg, err) + return "", fmt.Errorf("Invalid config: %v", err.Error()) } - // determine the properties of the template - info, err := p.readConfig(filepath.Join(untarPath, "pct-config.yml")) + namespacedPath, err := p.setupTemplateNamespace(targetDir, info, folderPath, force) + if err != nil { + return "", fmt.Errorf("Unable to install in namespace: %v", err.Error()) + } + + return namespacedPath, nil +} + +func (p *PctInstaller) InstallClone(gitUri string, targetDir string, force bool) (string, error) { + // Validate git URI + log.Info().Msgf("Git URI: ", gitUri) + if !strings.HasPrefix(gitUri, "http") || !strings.HasSuffix(gitUri, ".git") { + return "", fmt.Errorf("Could not clone git repo: Invalid URI provided") + } + + // Create temp folder + tempDir, err := p.AFS.TempDir("", "") + defer func() { + err := p.AFS.Remove(tempDir) + log.Debug().Msgf("Failed to remove temp dir: %v", err) + }() + if err != nil { + return "", fmt.Errorf("Could not create tempdir to gunzip template: %v", err) + } + + // Clone git repository to temp folder + folderPath, err := p.cloneTemplate(gitUri, tempDir) + if err != nil { + return "", fmt.Errorf("Could not clone git repository: %v", err) + } + + // Read config to determine template properties + info, err := p.readConfig(filepath.Join(folderPath, "pct-config.yml")) if err != nil { return "", fmt.Errorf("Invalid config: %v", err.Error()) } - namespacedPath, err := p.setupTemplateNamespace(targetDir, info, untarPath, force) + // Create namespaced directory and move contents of temp folder to it + namespacedPath, err := p.setupTemplateNamespace(targetDir, info, folderPath, force) if err != nil { return "", fmt.Errorf("Unable to install in namespace: %v", err.Error()) } @@ -92,6 +125,31 @@ func (p *PctInstaller) Install(templatePkg string, targetDir string, force bool) return namespacedPath, nil } +func (p *PctInstaller) cloneTemplate(gitUri string, tempDir string) (string, error) { + clonePath := filepath.Join(tempDir, "temp") + command := exec.Command("git", "clone", gitUri, clonePath) + err := command.Run() + if err != nil { + return "", err + } + return clonePath, nil +} + +func (p *PctInstaller) unTarGz(templatePkg string, tempDir string) (string, error) { + // gunzip the tar.gz to created tempdir + tarfile, err := p.Gunzip.Gunzip(templatePkg, tempDir) + if err != nil { + return "", fmt.Errorf("Could not extract TAR from GZIP (%v): %v", templatePkg, err) + } + + // untar the above archive to the temp dir + untarPath, err := p.Tar.Untar(tarfile, tempDir) + if err != nil { + return "", fmt.Errorf("Could not UNTAR template (%v): %v", templatePkg, err) + } + return untarPath, nil +} + func (p *PctInstaller) readConfig(configFile string) (info PuppetContentTemplateInfo, err error) { fileBytes, err := p.AFS.ReadFile(configFile) if err != nil {