github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/cloudconfig/cloudinit/utils.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Copyright 2015 Cloudbase Solutions SRL
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package cloudinit
     6  
     7  import (
     8  	"encoding/base64"
     9  	"fmt"
    10  	"path/filepath"
    11  
    12  	"github.com/juju/packaging/v3"
    13  	"github.com/juju/packaging/v3/config"
    14  	"github.com/juju/utils/v3"
    15  
    16  	jujupackaging "github.com/juju/juju/packaging"
    17  )
    18  
    19  // addPackageSourceCmds is a helper function that returns the corresponding
    20  // runcmds to apply the package source settings on a CentOS machine.
    21  func addPackageSourceCmds(cfg CloudConfig, src packaging.PackageSource) []string {
    22  	cmds := []string{}
    23  
    24  	// if keyfile is required, add it first
    25  	if src.Key != "" {
    26  		keyFilePath := config.YumKeyfileDir + src.KeyFileName()
    27  		cmds = append(cmds, addFileCmds(keyFilePath, []byte(src.Key), 0644, false)...)
    28  	}
    29  
    30  	repoPath := filepath.Join(config.YumSourcesDir, src.Name+".repo")
    31  	sourceFile, _ := cfg.getPackagingConfigurer(jujupackaging.YumPackageManager).RenderSource(src)
    32  	data := []byte(sourceFile)
    33  	cmds = append(cmds, addFileCmds(repoPath, data, 0644, false)...)
    34  
    35  	return cmds
    36  }
    37  
    38  // addFile is a helper function returns all the required shell commands to write
    39  // a file (be it text or binary) with regards to the given parameters
    40  // NOTE: if the file already exists, it will be overwritten.
    41  func addFileCmds(filename string, data []byte, mode uint, binary bool) []string {
    42  	// Note: recent versions of cloud-init have the "write_files"
    43  	// module, which can write arbitrary files. We currently support
    44  	// 12.04 LTS, which uses an older version of cloud-init without
    45  	// this module.
    46  	// TODO (aznashwan): eagerly await 2017 and to do the right thing here
    47  	p := utils.ShQuote(filename)
    48  
    49  	cmds := []string{fmt.Sprintf("install -D -m %o /dev/null %s", mode, p)}
    50  	// Don't use the shell's echo builtin here; the interpretation
    51  	// of escape sequences differs between shells, namely bash and
    52  	// dash. Instead, we use printf (or we could use /bin/echo).
    53  	if binary {
    54  		encoded := base64.StdEncoding.EncodeToString(data)
    55  		cmds = append(cmds, fmt.Sprintf(`echo -n %s | base64 -d > %s`, encoded, p))
    56  	} else {
    57  		cmds = append(cmds, fmt.Sprintf(`echo %s > %s`, utils.ShQuote(string(data)), p))
    58  	}
    59  
    60  	return cmds
    61  }
    62  
    63  // addFileCopyCmds is a helper function returns all the required shell commands to copy
    64  // a file (be it text or binary) with regards to the given parameters
    65  // NOTE: if the file already exists, it will be overwritten.
    66  func addFileCopyCmds(source string, filename string, mode uint) []string {
    67  	s := utils.ShQuote(source)
    68  	p := utils.ShQuote(filename)
    69  
    70  	cmds := []string{fmt.Sprintf("install -D -m %o /dev/null %s", mode, p)}
    71  	cmds = append(cmds, fmt.Sprintf(`cat %s > %s`, s, p))
    72  
    73  	return cmds
    74  }
    75  
    76  // removeStringFromSlice is a helper function which removes a given string from
    77  // the given slice, if it exists it returns the slice, be it modified or unmodified
    78  func removeStringFromSlice(slice []string, val string) []string {
    79  	for i, str := range slice {
    80  		if str == val {
    81  			slice = append(slice[:i], slice[i+1:]...)
    82  		}
    83  	}
    84  
    85  	return slice
    86  }