Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional isolated environment #673

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
6 changes: 6 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
strict_env

if has nix
then
use flake
fi
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
golang 1.21.13
33 changes: 14 additions & 19 deletions cloud/cpi_cmd_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"os"
"strconv"

bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
Expand Down Expand Up @@ -67,22 +66,25 @@ type CPICmdRunner interface {
}

type cpiCmdRunner struct {
cmdRunner boshsys.CmdRunner
cpi CPI
logger boshlog.Logger
logTag string
cmdRunner boshsys.CmdRunner
cpi CPI
logger boshlog.Logger
logTag string
useIsolatedEnv bool
}

func NewCPICmdRunner(
cmdRunner boshsys.CmdRunner,
cpi CPI,
logger boshlog.Logger,
useIsolatedEnv bool,
) CPICmdRunner {
return &cpiCmdRunner{
cmdRunner: cmdRunner,
cpi: cpi,
logger: logger,
logTag: "cpiCmdRunner",
cmdRunner: cmdRunner,
cpi: cpi,
logger: logger,
logTag: "cpiCmdRunner",
useIsolatedEnv: useIsolatedEnv,
}
}

Expand All @@ -100,26 +102,19 @@ func (r *cpiCmdRunner) Run(context CmdContext, method string, apiVersion int, ar
if err != nil {
return CmdOutput{}, bosherr.WrapErrorf(err, "Marshalling external CPI command input %#v", cmdInput)
}
useIsolatedEnv := true
value, present := os.LookupEnv("BOSH_CPI_USE_ISOLATED_ENV")
if present {
useIsolatedEnv, err = strconv.ParseBool(value)
if err != nil {
return CmdOutput{}, bosherr.WrapErrorf(err, "Parsing $BOSH_CPI_USE_ISOLATED_ENV error, could not parse value: %v", value)
}
}

cmdPath := r.cpi.ExecutablePath()
cmd := boshsys.Command{
Name: cmdPath,
Env: map[string]string{
"BOSH_PACKAGES_DIR": r.cpi.PackagesDir,
"BOSH_JOBS_DIR": r.cpi.JobsDir,
"PATH": "/usr/local/bin:/usr/bin:/bin:/sbin",
"PATH": os.Getenv("PATH"),
},
UseIsolatedEnv: useIsolatedEnv,
UseIsolatedEnv: r.useIsolatedEnv,
Stdin: bytes.NewReader(inputBytes),
}

stdout, stderr, exitCode, err := r.cmdRunner.RunComplexCommand(cmd)
r.logger.Debug(r.logTag, "Exit Code %d when executing external CPI command '%s'\nSTDIN: '%s'\nSTDOUT: '%s'\nSTDERR: '%s'", exitCode, cmdPath, string(inputBytes), stdout, stderr)
if err != nil {
Expand Down
31 changes: 7 additions & 24 deletions cloud/cpi_cmd_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var _ = Describe("CpiCmdRunner", func() {
cmdRunner *fakesys.FakeCmdRunner
cpi CPI
apiVersion int
logger boshlog.Logger
)

BeforeEach(func() {
Expand All @@ -35,8 +36,8 @@ var _ = Describe("CpiCmdRunner", func() {
}

cmdRunner = fakesys.NewFakeCmdRunner()
logger := boshlog.NewLogger(boshlog.LevelNone)
cpiCmdRunner = NewCPICmdRunner(cmdRunner, cpi, logger)
logger = boshlog.NewLogger(boshlog.LevelNone)
cpiCmdRunner = NewCPICmdRunner(cmdRunner, cpi, logger, true)

apiVersion = 1
})
Expand All @@ -63,7 +64,7 @@ var _ = Describe("CpiCmdRunner", func() {
Expect(actualCmd.Env).To(Equal(map[string]string{
"BOSH_PACKAGES_DIR": cpi.PackagesDir,
"BOSH_JOBS_DIR": cpi.JobsDir,
"PATH": "/usr/local/bin:/usr/bin:/bin:/sbin",
"PATH": os.Getenv("PATH"),
}))
Expect(actualCmd.UseIsolatedEnv).To(BeTrue())
bytes, err := io.ReadAll(actualCmd.Stdin)
Expand All @@ -89,11 +90,8 @@ var _ = Describe("CpiCmdRunner", func() {
apiVersion = 2
})

AfterEach(func() {
os.Unsetenv("BOSH_CPI_USE_ISOLATED_ENV")
})
It("creates correct command with UseIsolatedEnv false if BOSH_CPI_USE_ISOLATED_ENV is set", func() {
os.Setenv("BOSH_CPI_USE_ISOLATED_ENV", "false")
It("creates correct command with UseIsolatedEnv false if NewCPICmdRunner is initialized with false", func() {
cpiCmdRunner = NewCPICmdRunner(cmdRunner, cpi, logger, false)
cmdOutput := CmdOutput{}
outputBytes, err := json.Marshal(cmdOutput)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -109,21 +107,6 @@ var _ = Describe("CpiCmdRunner", func() {
Expect(actualCmd.UseIsolatedEnv).To(BeFalse())

})
It("throws helpful error if the value of BOSH_CPI_USE_ISOLATED_ENV cannot be parsed into a bool", func() {
os.Setenv("BOSH_CPI_USE_ISOLATED_ENV", "falasdse")
cmdOutput := CmdOutput{}
outputBytes, err := json.Marshal(cmdOutput)
Expect(err).NotTo(HaveOccurred())

result := fakesys.FakeCmdResult{
Stdout: string(outputBytes),
ExitStatus: 0,
}
cmdRunner.AddCmdResult("/jobs/cpi/bin/cpi", result)
_, err = cpiCmdRunner.Run(context, "fake-method", apiVersion, "fake-argument-1", "fake-argument-2")
Expect(err).To(HaveOccurred())
Expect(MatchRegexp("BOSH_CPI_USE_ISOLATED_ENV cannot be parsed", err))
})
It("creates correct command with stemcell api_version in context", func() {
cmdOutput := CmdOutput{}
outputBytes, err := json.Marshal(cmdOutput)
Expand All @@ -145,7 +128,7 @@ var _ = Describe("CpiCmdRunner", func() {
Expect(actualCmd.Env).To(Equal(map[string]string{
"BOSH_PACKAGES_DIR": cpi.PackagesDir,
"BOSH_JOBS_DIR": cpi.JobsDir,
"PATH": "/usr/local/bin:/usr/bin:/bin:/sbin",
"PATH": os.Getenv("PATH"),
}))
Expect(actualCmd.UseIsolatedEnv).To(BeTrue())
bytes, err := io.ReadAll(actualCmd.Stdin)
Expand Down
17 changes: 10 additions & 7 deletions cloud/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@ type Factory interface {
}

type factory struct {
fs boshsys.FileSystem
cmdRunner boshsys.CmdRunner
logger boshlog.Logger
fs boshsys.FileSystem
cmdRunner boshsys.CmdRunner
logger boshlog.Logger
useIsolatedEnv bool
}

func NewFactory(
fs boshsys.FileSystem,
cmdRunner boshsys.CmdRunner,
logger boshlog.Logger,
useIsolatedEnv bool,
) Factory {
return &factory{
fs: fs,
cmdRunner: cmdRunner,
logger: logger,
fs: fs,
cmdRunner: cmdRunner,
logger: logger,
useIsolatedEnv: useIsolatedEnv,
}
}

Expand All @@ -53,6 +56,6 @@ func (f *factory) NewCloud(installation biinstall.Installation, directorID strin
return nil, bosherr.Errorf("Found %d Jobs with a 'bin/cpi' binary. Expected 1.", numberCpiBinariesFound)
}

cpiCmdRunner := NewCPICmdRunner(f.cmdRunner, foundCPI, f.logger)
cpiCmdRunner := NewCPICmdRunner(f.cmdRunner, foundCPI, f.logger, f.useIsolatedEnv)
return NewCloud(cpiCmdRunner, directorID, stemcellApiVersion, f.logger), nil
}
8 changes: 4 additions & 4 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,31 +72,31 @@ func (c Cmd) Execute() (cmdErr error) {

case *CreateEnvOpts:
envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentPreparer {
return NewEnvFactory(deps, manifestPath, statePath, vars, op, opts.RecreatePersistentDisks, opts.PackageDir).Preparer()
return NewEnvFactory(deps, manifestPath, statePath, vars, op, opts.RecreatePersistentDisks, opts.PackageDir, !opts.AvoidIsolatedEnv).Preparer()
}

stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger)
return NewCreateEnvCmd(deps.UI, envProvider).Run(stage, *opts)

case *DeleteEnvOpts:
envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentDeleter {
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, opts.PackageDir).Deleter()
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, opts.PackageDir, true).Deleter()
}

stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger)
return NewDeleteEnvCmd(deps.UI, envProvider).Run(stage, *opts)

case *StopEnvOpts:
envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentStateManager {
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "").StateManager()
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "", true).StateManager()
}

stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger)
return NewStopEnvCmd(deps.UI, envProvider).Run(stage, *opts)

case *StartEnvOpts:
envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentStateManager {
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "").StateManager()
return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "", true).StateManager()
}

stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger)
Expand Down
5 changes: 3 additions & 2 deletions cmd/env_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func NewEnvFactory(
manifestOp patch.Op,
recreatePersistentDisks bool,
packageDir string,
useIsolatedEnv bool,
) *envFactory {
f := envFactory{
deps: deps,
Expand Down Expand Up @@ -117,7 +118,7 @@ func NewEnvFactory(
{
installerFactory := boshinst.NewInstallerFactory(
deps.UI, deps.CmdRunner, deps.Compressor, releaseJobResolver,
deps.UUIDGen, deps.Logger, deps.FS, deps.DigestCreationAlgorithms)
deps.UUIDGen, deps.Logger, useIsolatedEnv, deps.FS, deps.DigestCreationAlgorithms)

f.cpiInstaller = bicpirel.CpiInstaller{
ReleaseManager: f.releaseManager,
Expand Down Expand Up @@ -149,7 +150,7 @@ func NewEnvFactory(
f.blobstoreFactory = biblobstore.NewBlobstoreFactory(deps.UUIDGen, deps.FS, deps.Logger)
f.deploymentFactory = bidepl.NewFactory(10*time.Second, 500*time.Millisecond)
f.agentClientFactory = bihttpagent.NewAgentClientFactory(1*time.Second, deps.Logger)
f.cloudFactory = bicloud.NewFactory(deps.FS, deps.CmdRunner, deps.Logger)
f.cloudFactory = bicloud.NewFactory(deps.FS, deps.CmdRunner, deps.Logger, useIsolatedEnv)
}

{
Expand Down
1 change: 1 addition & 0 deletions cmd/opts/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ type CreateEnvOpts struct {
StatePath string `long:"state" value-name:"PATH" description:"State file path"`
Recreate bool `long:"recreate" description:"Recreate VM in deployment"`
RecreatePersistentDisks bool `long:"recreate-persistent-disks" description:"Recreate persistent disks in the deployment"`
AvoidIsolatedEnv bool `long:"avoid-isolated-environment" short:"I" description:"Compile and run cpi-commands in a clean environment or not"`
PackageDir string `long:"package-dir" value-name:"DIR" description:"Package cache location override"`
cmd
}
Expand Down
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
description = "Flake for development on the bosh-cli featuring a nix-shell";

inputs = {
nixpkgsRepo.url = github:NixOS/nixpkgs/nixos-24.05;
};

outputs = { self, nixpkgsRepo }:
let
nixpkgsLib = nixpkgsRepo.lib;
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];

# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
forAllSystems = nixpkgsLib.genAttrs supportedSystems;

# Nixpkgs instantiated for supported system types.
nixpkgsFor = forAllSystems (system: import nixpkgsRepo { inherit system; });
in {
devShells = forAllSystems (system:
let
nixpkgs = nixpkgsFor.${system};
in {
default = nixpkgs.mkShell {
buildInputs = with nixpkgs; [
delve
go
gopls
gotools
];
};
});
};
}
6 changes: 6 additions & 0 deletions installation/installer_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type installerFactory struct {
releaseJobResolver bideplrel.JobResolver
uuidGenerator boshuuid.Generator
logger boshlog.Logger
useIsolatedEnv bool
logTag string
fs boshsys.FileSystem
digestCreateAlgorithms []boshcrypto.Algorithm
Expand All @@ -42,6 +43,7 @@ func NewInstallerFactory(
releaseJobResolver bideplrel.JobResolver,
uuidGenerator boshuuid.Generator,
logger boshlog.Logger,
useIsolatedEnv bool,
fs boshsys.FileSystem,
digestCreateAlgorithms []boshcrypto.Algorithm,
) InstallerFactory {
Expand All @@ -52,6 +54,7 @@ func NewInstallerFactory(
releaseJobResolver: releaseJobResolver,
uuidGenerator: uuidGenerator,
logger: logger,
useIsolatedEnv: useIsolatedEnv,
logTag: "installer",
fs: fs,
digestCreateAlgorithms: digestCreateAlgorithms,
Expand All @@ -63,6 +66,7 @@ func (f *installerFactory) NewInstaller(target Target) Installer {
target: target,
runner: f.runner,
logger: f.logger,
useIsolatedEnv: f.useIsolatedEnv,
extractor: f.extractor,
uuidGenerator: f.uuidGenerator,
releaseJobResolver: f.releaseJobResolver,
Expand All @@ -85,6 +89,7 @@ type installerFactoryContext struct {
fs boshsys.FileSystem
runner boshsys.CmdRunner
logger boshlog.Logger
useIsolatedEnv bool
extractor boshcmd.Compressor
uuidGenerator boshuuid.Generator
releaseJobResolver bideplrel.JobResolver
Expand Down Expand Up @@ -148,6 +153,7 @@ func (c *installerFactoryContext) InstallationStatePackageCompiler() bistatepkg.
c.CompiledPackageRepo(),
c.BlobExtractor(),
c.logger,
c.useIsolatedEnv,
)

return c.packageCompiler
Expand Down
Loading