From fc92f270bc19112d7e30c201a960707ced0ef6fb Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Thu, 2 Mar 2023 11:43:40 +0100 Subject: [PATCH 01/20] WIP Add first test in golang Signed-off-by: Pavel Abramov --- pkg/openevec/defaults.go | 29 +++++--- pkg/openevec/main_test.go | 53 +++++++++++++++ pkg/openevec/mount_test.go | 135 +++++++++++++++++++++++++++++++++++++ pkg/openevec/test.go | 120 --------------------------------- pkg/openevec/utils.go | 102 ++++++++++++++++++++++++++++ 5 files changed, 311 insertions(+), 128 deletions(-) create mode 100644 pkg/openevec/main_test.go create mode 100644 pkg/openevec/mount_test.go delete mode 100644 pkg/openevec/test.go diff --git a/pkg/openevec/defaults.go b/pkg/openevec/defaults.go index 928841da8..5ead76e75 100644 --- a/pkg/openevec/defaults.go +++ b/pkg/openevec/defaults.go @@ -1,21 +1,15 @@ package openevec import ( - "log" - "os" "path/filepath" "runtime" + "github.com/dustin/go-humanize" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/utils" ) -func GetDefaultConfig() *EdenSetupArgs { - - currentPath, err := os.Getwd() - if err != nil { - log.Fatal(err) - } +func GetDefaultConfig(currentPath string) *EdenSetupArgs { defaultEdenConfig := &EdenSetupArgs{ Eden: EdenConfig{ @@ -95,3 +89,22 @@ func GetDefaultConfig() *EdenSetupArgs { return defaultEdenConfig } + +func GetDefaultPodConfig() *PodConfig { + dpc := &PodConfig{ + AppMemory: humanize.Bytes(defaults.DefaultAppMem * 1024), + DiskSize: humanize.Bytes(0), + VolumeType: "qcow2", + AppCpus: defaults.DefaultAppCPU, + ACLOnlyHost: false, + NoHyper: false, + Registry: "remote", + DirectLoad: true, + SftpLoad: false, + VolumeSize: humanize.IBytes(defaults.DefaultVolumeSize), + OpenStackMetadata: false, + PinCpus: false, + } + + return dpc +} diff --git a/pkg/openevec/main_test.go b/pkg/openevec/main_test.go new file mode 100644 index 000000000..55c6284ce --- /dev/null +++ b/pkg/openevec/main_test.go @@ -0,0 +1,53 @@ +package openevec + +import ( + "os" + "path/filepath" + "testing" + + "github.com/lf-edge/eden/pkg/defaults" + "github.com/lf-edge/eden/pkg/utils" +) + +func setup() { + cfg := GetDefaultConfig(curPath) + + err := SetupEden(&cfg.ConfigName, + filepath.Join(curPath, "eve-config-dir"), + filepath.Join(cfg.Eden.Root, "eve-config-dir"), + "", "", "", []string{}, false, false, cfg) + + if err != nil { + panic("Setup Failed") + } + + if err = StartEden(cfg, defaults.DefaultVBoxVMName, "", ""); err != nil { + panic("Start failed") + } + + if err = OnboardEve(cfg.Eve.CertsUUID); err != nil { + panic("Onboard failed") + } +} + +func teardown() { + cfg := GetDefaultConfig() + StopEden(false, false, false, false, cfg.Eve.Remote, cfg.Eve.Pid, swtpmPidFile(cfg), cfg.Sdn.PidFile, cfg.Eve.DevModel, defautls.DefaultVBoxVMName) + + configDist, err := utils.DefaultEdenDir() + if err != nil { + panic() + } + + err = EdenClean(cfg, cfg.ConfigName, configDist, defaults.DefaultVBoxVMName, false) + if err != nil { + panic() + } +} + +func TestMain(m *testing.M) { + setup() + code := m.Run() + teardown() + os.Exit(code) +} diff --git a/pkg/openevec/mount_test.go b/pkg/openevec/mount_test.go new file mode 100644 index 000000000..c37a967b5 --- /dev/null +++ b/pkg/openevec/mount_test.go @@ -0,0 +1,135 @@ +package openevec + +import ( + "fmt" + "path/filepath" + "testing" + "time" + + "github.com/lf-edge/eden/pkg/controller" + "github.com/lf-edge/eden/pkg/defaults" + "github.com/lf-edge/eden/pkg/eve" +) + +func TestEclientMount(t *testing.T) { + ctrl, err := controller.CloudPrepare() + if err != nil { + t.Errorf("CloudPrepare: %v", err) + return + } + devFirst, err := ctrl.GetDeviceCurrent() + if err != nil { + t.Errorf("GetDeviceCurrent error: %v", err) + return + } + devUUID := devFirst.GetID() + + port := 2223 + cfg := GetDefaultConfig() + pc := GetDefaultPodConfig() + pc.PortPublish = []string{fmt.Sprint(port)} + podName := "eclient-mount" + pc.Mount = []string{ + "src=docker://hello-world:linux,dst=/tst", + fmt.Sprintf("src=%s/eclient/testdata,dst=/dir", cfg.Eden.TestScenario), + } + appLink := fmt.Sprintf("docker://%s:%s", defaults.DefaultEClientTag, defaults.DefaultEClientContainerRef) + + if err = PodDeploy(appLink, *pc, cfg); err != nil { + t.Errorf("PodDeploy error: %v", err) + return + } + + eveState := eve.Init(ctrl, devFirst) + + if err := checkAppState(ctrl, devUUID, podName, eveState, "RUNNING", 21*time.Minute); err != nil { + t.Errorf("App state checking failed") + return + } + + ETestsFolder := filepath.Join(cfg.Eden.Root, "tests") + sshCmd := fmt.Sprintf("ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o PasswordAuthentication=no -i %s/eclient/image/cert/id_rsa root@FWD_IP -p FWD_PORT ls", ETestsFolder) + sshOut, err := withCapturingStdout(func() error { + if err := SdnForwardCmd("", "eth0", port, sshCmd+"/tst", cfg); err != nil { + return fmt.Errorf("ssh to tst failed") + } + return nil + }) + if err != nil { + t.Error(err) + } + if err := checkOutput(string(sshOut), []string{"hello"}, []string{}); err != nil { + t.Errorf("Ls to tst failed") + } + + sshOut, err = withCapturingStdout(func() error { + if err := SdnForwardCmd("", "eth0", port, sshCmd+"/dir", cfg); err != nil { + return fmt.Errorf("ssh to dir failed") + } + return nil + }) + if err != nil { + t.Error(err) + } + if err := checkOutput(string(sshOut), []string{"mount.txt"}, []string{}); err != nil { + t.Errorf("ls to dir failed") + } + + sshOut, err = withCapturingStdout(func() error { + return VolumeLs() + }) + if err != nil { + t.Error(err) + } + if err := checkOutput(string(sshOut), []string{"/dir", "/tst"}, []string{}); err != nil { + t.Errorf("Volume ls failed") + } + + volumeName := "eclient-mount_1_m_0" + if err := VolumeDetach(volumeName); err != nil { + t.Errorf("Volume detach failed") + return + } + + if err = checkAppState(ctrl, devUUID, podName, eveState, "RUNNING", 15*time.Minute); err != nil { + t.Errorf("eclient-mount RUNNING state InfoChecker: %v", err) + return + } + + sshOut, err = withCapturingStdout(func() error { + if err := SdnForwardCmd("", "eth0", port, sshCmd+"/dst", cfg); err != nil { + return fmt.Errorf("ssh to dst failed") + } + return nil + }) + if err != nil { + t.Error(err) + } + if err := checkOutput(string(sshOut), []string{"hello"}, []string{}); err != nil { + t.Errorf("Volume ls failed") + } + + sshOut, err = withCapturingStdout(func() error { + return VolumeLs() + }) + if err != nil { + t.Error(err) + } + if err := checkOutput(string(sshOut), []string{"/dir", "/tst"}, []string{}); err != nil { + t.Errorf("Volume ls failed") + } + + if _, err := PodDelete(podName, true); err != nil { + t.Errorf("PodDelete failed") + return + } + + // check that podName was deleted + if err := ResetEve(cfg.Eve.CertsUUID); err != nil { + t.Errorf("Resetting EVE failed") + return + } + + //sleep 30 secs + +} diff --git a/pkg/openevec/test.go b/pkg/openevec/test.go deleted file mode 100644 index b1841555c..000000000 --- a/pkg/openevec/test.go +++ /dev/null @@ -1,120 +0,0 @@ -package openevec - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strconv" - - "github.com/lf-edge/eden/pkg/defaults" - "github.com/lf-edge/eden/pkg/tests" - "github.com/lf-edge/eden/pkg/utils" - log "github.com/sirupsen/logrus" -) - -type TestArgs struct { - TestArgs string - TestOpts bool - TestEscript string - TestRun string - TestTimeout string - TestList string - TestProg string - TestScenario string - FailScenario string - CurDir string - ConfigFile string - Verbosity string -} - -func InitVarsFromConfig(cfg *EdenSetupArgs) (*utils.ConfigVars, error) { - var cv utils.ConfigVars - edenHome, err := utils.DefaultEdenDir() - if err != nil { - return nil, err - } - globalCertsDir := filepath.Join(edenHome, defaults.DefaultCertsDist) - if _, err := os.Stat(globalCertsDir); os.IsNotExist(err) { - if err = os.MkdirAll(globalCertsDir, 0755); err != nil { - return nil, err - } - } - caCertPath := filepath.Join(globalCertsDir, "root-certificate.pem") - - cv.AdamIP = cfg.Adam.CertsIP - cv.AdamPort = strconv.Itoa(cfg.Adam.Port) - cv.AdamDomain = cfg.Adam.CertsDomain - cv.AdamDir = cfg.Adam.Dist - cv.AdamCA = caCertPath - cv.AdamRedisURLEden = cfg.Adam.Redis.RemoteURL - cv.AdamRemote = cfg.Adam.Remote.Enabled - cv.AdamRemoteRedis = cfg.Adam.Remote.Redis - cv.AdamCaching = cfg.Adam.Caching.Enabled - cv.AdamCachingPrefix = cfg.Adam.Caching.Prefix - cv.AdamCachingRedis = cfg.Adam.Caching.Redis - - cv.SSHKey = cfg.Eden.SSHKey - cv.EdenBinDir = cfg.Eden.BinDir - cv.EdenProg = cfg.Eden.EdenBin - cv.TestProg = cfg.Eden.TestBin - cv.TestScenario = cfg.Eden.TestScenario - cv.EServerImageDist = cfg.Eden.Images.EServerImageDist - cv.EServerPort = strconv.Itoa(cfg.Eden.EServer.Port) - cv.EServerIP = cfg.Eden.EServer.IP - - cv.EveCert = cfg.Eve.Cert - cv.EveDeviceCert = cfg.Eve.DeviceCert - cv.EveSerial = cfg.Eve.Serial - cv.EveDist = cfg.Eve.Dist - cv.EveQemuConfig = cfg.Eve.QemuFileToSave - cv.ZArch = cfg.Eve.Arch - cv.EveSSID = cfg.Eve.Ssid - cv.EveHV = cfg.Eve.HV - cv.DevModel = cfg.Eve.DevModel - cv.DevModelFIle = cfg.Eve.DevModelFile - cv.EveName = cfg.Eve.Name - cv.EveUUID = cfg.Eve.CertsUUID - cv.AdamLogLevel = cfg.Eve.AdamLogLevel - cv.EveRemote = cfg.Eve.Remote - cv.EveRemoteAddr = cfg.Eve.RemoteAddr - cv.EveQemuPorts = cfg.Eve.HostFwd - cv.LogLevel = cfg.Eve.LogLevel - - cv.RegistryIP = cfg.Registry.IP - cv.RegistryPort = strconv.Itoa(cfg.Registry.Port) - - redisPasswordFile := filepath.Join(globalCertsDir, defaults.DefaultRedisPasswordFile) - pwd, err := ioutil.ReadFile(redisPasswordFile) - if err == nil { - cv.AdamRedisURLEden = fmt.Sprintf("redis://%s:%s@%s", string(pwd), string(pwd), cv.AdamRedisURLEden) - } else { - log.Errorf("cannot read redis password: %s", err.Error()) - cv.AdamRedisURLEden = fmt.Sprintf("redis://%s", cv.AdamRedisURLEden) - } - return &cv, nil -} - -func Test(tstCfg *TestArgs) error { - - switch { - case tstCfg.TestList != "": - tests.RunTest(tstCfg.TestProg, []string{"-test.list", tstCfg.TestList}, "", tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) - case tstCfg.TestOpts: - tests.RunTest(tstCfg.TestProg, []string{"-h"}, "", tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) - case tstCfg.TestEscript != "": - tests.RunTest("eden.escript.test", []string{"-test.run", "TestEdenScripts/" + tstCfg.TestEscript}, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) - case tstCfg.TestRun != "": - tests.RunTest(tstCfg.TestProg, []string{"-test.run", tstCfg.TestRun}, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) - default: - tests.RunScenario(tstCfg.TestScenario, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) - } - - if tstCfg.CurDir != "" { - err := os.Chdir(tstCfg.CurDir) - if err != nil { - return err - } - } - return nil -} diff --git a/pkg/openevec/utils.go b/pkg/openevec/utils.go index 8ae3c05de..a64792b1f 100644 --- a/pkg/openevec/utils.go +++ b/pkg/openevec/utils.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/docker/docker/client" "github.com/google/go-containerregistry/pkg/name" @@ -19,10 +20,16 @@ import ( "github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/lf-edge/eden/pkg/controller" + "github.com/lf-edge/eden/pkg/controller/einfo" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/eden" + "github.com/lf-edge/eden/pkg/eve" "github.com/lf-edge/eden/pkg/models" + "github.com/lf-edge/eden/pkg/tests" "github.com/lf-edge/eden/pkg/utils" + "github.com/lf-edge/eve/api/go/info" + uuid "github.com/satori/go.uuid" log "github.com/sirupsen/logrus" ) @@ -240,3 +247,98 @@ func UploadGit(absPath, object, branch, directoryToSave string) error { fmt.Println(result) return nil } + +type TestArgs struct { + TestArgs string + TestOpts bool + TestEscript string + TestRun string + TestTimeout string + TestList string + TestProg string + TestScenario string + FailScenario string + CurDir string + ConfigFile string + Verbosity string +} + +func Test(tstCfg *TestArgs) error { + + switch { + case tstCfg.TestList != "": + tests.RunTest(tstCfg.TestProg, []string{"-test.list", tstCfg.TestList}, "", tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) + case tstCfg.TestOpts: + tests.RunTest(tstCfg.TestProg, []string{"-h"}, "", tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) + case tstCfg.TestEscript != "": + tests.RunTest("eden.escript.test", []string{"-test.run", "TestEdenScripts/" + tstCfg.TestEscript}, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) + case tstCfg.TestRun != "": + tests.RunTest(tstCfg.TestProg, []string{"-test.run", tstCfg.TestRun}, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) + default: + tests.RunScenario(tstCfg.TestScenario, tstCfg.TestArgs, tstCfg.TestTimeout, tstCfg.FailScenario, tstCfg.ConfigFile, tstCfg.Verbosity) + } + + if tstCfg.CurDir != "" { + err := os.Chdir(tstCfg.CurDir) + if err != nil { + return err + } + } + return nil +} + +func checkOutput(input string, shouldHave, shouldNotHave []string) error { + for _, str := range shouldHave { + if !strings.Contains(input, str) { + return fmt.Errorf("Input does not contain %v", str) + } + } + + for _, str := range shouldNotHave { + if strings.Contains(input, str) { + return fmt.Errorf("Input contains %v", str) + } + } + + return nil +} + +func checkAppState(ctrl controller.Cloud, devUUID uuid.UUID, appName string, eveState *eve.State, expState string, timeout time.Duration) error { + startTime := time.Now() + + // Waiting for 15 min maximum to get eclient-mount app in state running + handleInfo := func(im *info.ZInfoMsg) bool { + eveState.InfoCallback()(im) + for _, s := range eveState.Applications() { + if s.Name == appName { + if s.EVEState == expState { + return true + } + } + } + if time.Now().After(startTime.Add(timeout)) { + log.Fatal("eclient-mount timeout") + } + return false + } + + if err := ctrl.InfoChecker(devUUID, nil, handleInfo, einfo.InfoNew, 0); err != nil { + return fmt.Errorf("eclient-mount RUNNING state InfoChecker: %w", err) + } + + return nil +} + +func withCapturingStdout(f func() error) ([]byte, error) { + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := f() + + w.Close() + out, _ := ioutil.ReadAll(r) + os.Stdout = rescueStdout + + return out, err +} From b9bd515d66daed62051b0ba7bd2e476eef36c351 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 09:25:03 +0200 Subject: [PATCH 02/20] Add test field to config. Default config resolves paths Signed-off-by: Pavel Abramov --- pkg/openevec/config.go | 9 +++++---- pkg/openevec/defaults.go | 7 +++++++ pkg/utils/files.go | 10 ++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/pkg/openevec/config.go b/pkg/openevec/config.go index ad92d3536..81e824f1a 100644 --- a/pkg/openevec/config.go +++ b/pkg/openevec/config.go @@ -37,6 +37,7 @@ type EdenConfig struct { EdenBin string `mapstructure:"eden-bin"` TestBin string `mapstructure:"test-bin"` TestScenario string `mapstructure:"test-scenario"` + Tests string `mapstructure:"tests" resolvepath:""` EServer EServerConfig `mapstructure:"eserver"` @@ -283,7 +284,7 @@ func LoadConfig(configFile string) (*EdenSetupArgs, error) { return nil, fmt.Errorf("unable to decode into config struct, %w", err) } - resolvePath(reflect.ValueOf(cfg).Elem()) + resolvePath(reflect.ValueOf(cfg).Elem(), cfg.Eden.Root) if configFile == "" { configFile, _ = utils.DefaultConfigPath() @@ -299,17 +300,17 @@ func LoadConfig(configFile string) (*EdenSetupArgs, error) { return cfg, nil } -func resolvePath(v reflect.Value) { +func resolvePath(v reflect.Value, edenRoot string) { for i := 0; i < v.NumField(); i++ { f := v.Field(i) if _, ok := v.Type().Field(i).Tag.Lookup("resolvepath"); ok { if f.IsValid() && f.CanSet() && f.Kind() == reflect.String { val := f.Interface().(string) - f.SetString(utils.ResolveAbsPath(val)) + f.SetString(utils.ResolveAbsPathWithRoot(val, edenRoot)) } } if f.Kind() == reflect.Struct { - resolvePath(f) + resolvePath(f, edenRoot) } } } diff --git a/pkg/openevec/defaults.go b/pkg/openevec/defaults.go index 5ead76e75..17ab318e4 100644 --- a/pkg/openevec/defaults.go +++ b/pkg/openevec/defaults.go @@ -1,7 +1,9 @@ package openevec import ( + "fmt" "path/filepath" + "reflect" "runtime" "github.com/dustin/go-humanize" @@ -16,6 +18,8 @@ func GetDefaultConfig(currentPath string) *EdenSetupArgs { Download: true, BinDir: filepath.Join(currentPath, defaults.DefaultDist, defaults.DefaultBinDist), SSHKey: filepath.Join(currentPath, defaults.DefaultCertsDist, "id_rsa"), + Root: filepath.Join(currentPath, defaults.DefaultDist), + CertsDir: filepath.Join(fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultCertsDist)), EServer: EServerConfig{ Port: defaults.DefaultEserverPort, @@ -60,6 +64,7 @@ func GetDefaultConfig(currentPath string) *EdenSetupArgs { Log: filepath.Join(currentPath, defaults.DefaultDist), TelnetPort: defaults.DefaultTelnetPort, TPM: defaults.DefaultTPMEnabled, + ImageFile: "default-images/eve/live.img", }, Redis: RedisConfig{ @@ -87,6 +92,8 @@ func GetDefaultConfig(currentPath string) *EdenSetupArgs { ConfigFile: utils.GetConfig(defaults.DefaultContext), } + resolvePath(reflect.ValueOf(defaultEdenConfig).Elem(), defaultEdenConfig.Eden.Root) + return defaultEdenConfig } diff --git a/pkg/utils/files.go b/pkg/utils/files.go index 3067fb8bf..7b1962728 100644 --- a/pkg/utils/files.go +++ b/pkg/utils/files.go @@ -115,6 +115,16 @@ func ResolveAbsPath(curPath string) string { return curPath } +func ResolveAbsPathWithRoot(curPath string, edenRoot string) string { + if strings.TrimSpace(curPath) == "" { + return "" + } + if !filepath.IsAbs(curPath) { + return filepath.Join(edenRoot, strings.TrimSpace(curPath)) + } + return curPath +} + //GetFileFollowLinks resolve file by walking through symlinks func GetFileFollowLinks(filePath string) (string, error) { log.Debugf("GetFileFollowLinks %s", filePath) From f5454447087ad93d57772f18910aee9a516ff84c Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 09:27:28 +0200 Subject: [PATCH 03/20] Remove zombie code from cmd/debug.go Signed-off-by: Pavel Abramov --- cmd/debug.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/cmd/debug.go b/cmd/debug.go index e84453f17..91a6c07e3 100644 --- a/cmd/debug.go +++ b/cmd/debug.go @@ -17,21 +17,6 @@ func newDebugCmd(cfg *openevec.EdenSetupArgs) *cobra.Command { Use: "debug", } - /* - if viperLoaded { - eveSSHKey = utils.ResolveAbsPath(viper.GetString("eden.ssh-key")) - extension := filepath.Ext(eveSSHKey) - eveSSHKey = strings.TrimRight(eveSSHKey, extension) - eveRemote = viper.GetBool("eve.remote") - eveRemoteAddr = viper.GetString("eve.remote-addr") - if eveRemote || eveRemoteAddr == "" { - if !cmd.Flags().Changed("eve-ssh-port") { - eveSSHPort = 22 - } - } - } - */ - groups := CommandGroups{ { Message: "Basic Commands", From 953fcec88cd9353b8e69fe5d40757985502bd4f7 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 09:32:00 +0200 Subject: [PATCH 04/20] Move SwptmPidFile as openevec function. Remove viper call from eden.go Since we are using config as file structure it's not reasonable to call viper functions from openevec because that will mean that configuration file should be present and we want to have flexibility of just passing structure to functions Signed-off-by: Pavel Abramov --- cmd/edenStop.go | 2 +- cmd/eve.go | 9 --------- pkg/openevec/eden.go | 11 ++++++++++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/edenStop.go b/cmd/edenStop.go index 6e3c74f32..dc6fead2d 100644 --- a/cmd/edenStop.go +++ b/cmd/edenStop.go @@ -26,7 +26,7 @@ func newStopCmd(configName, verbosity *string) *cobra.Command { adamRm, redisRm, registryRm, eServerRm, cfg.Eve.Remote, cfg.Eve.Pid, - swtpmPidFile(cfg), cfg.Sdn.PidFile, + openevec.SwtpmPidFile(cfg), cfg.Sdn.PidFile, cfg.Eve.DevModel, vmName, ) }, diff --git a/cmd/eve.go b/cmd/eve.go index 4e7ec2ec1..eef4f342c 100644 --- a/cmd/eve.go +++ b/cmd/eve.go @@ -43,15 +43,6 @@ func newEveCmd(configName, verbosity *string) *cobra.Command { return eveCmd } -func swtpmPidFile(cfg *openevec.EdenSetupArgs) string { - if cfg.Eve.TPM { - command := "swtpm" - return filepath.Join(filepath.Join(filepath.Dir(cfg.Eve.ImageFile), command), - fmt.Sprintf("%s.pid", command)) - } - return "" -} - func newStartEveCmd(cfg *openevec.EdenSetupArgs) *cobra.Command { var vmName, tapInterface string diff --git a/pkg/openevec/eden.go b/pkg/openevec/eden.go index 744398313..06e3bc604 100644 --- a/pkg/openevec/eden.go +++ b/pkg/openevec/eden.go @@ -35,6 +35,15 @@ import ( "golang.org/x/term" ) +func SwtpmPidFile(cfg *EdenSetupArgs) string { + if cfg.Eve.TPM { + command := "swtpm" + return filepath.Join(filepath.Join(filepath.Dir(cfg.Eve.ImageFile), command), + fmt.Sprintf("%s.pid", command)) + } + return "" +} + func generateScripts(in string, out string, configFile string) error { tmpl, err := ioutil.ReadFile(in) if err != nil { @@ -355,7 +364,7 @@ func setupEdenScripts(cfg EdenSetupArgs) error { fmt.Printf("Directory %s access error: %s\n", cfgDir, err) } else { - shPath := viper.GetString("eden.root") + "/scripts/shell/" + shPath := cfg.Eden.Root + "/scripts/shell/" if err := generateScripts(shPath+"activate.sh.tmpl", cfgDir+"activate.sh", cfg.ConfigName); err != nil { return err From 26496724aa1b8b406b824f3ae6e07f2895320e0b Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 14:12:54 +0200 Subject: [PATCH 05/20] [AT] Remove viper call from EdgeNodeEVEImageUpdate Signed-off-by: Pavel Abramov --- cmd/edenController.go | 2 +- pkg/openevec/edgeNode.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/edenController.go b/cmd/edenController.go index 0d8bfbcc3..277245684 100644 --- a/cmd/edenController.go +++ b/cmd/edenController.go @@ -107,7 +107,7 @@ func newEdgeNodeEVEImageUpdate(controllerMode string, cfg *openevec.EdenSetupArg Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { baseOSImage := args[0] - if err := openevec.EdgeNodeEVEImageUpdate(baseOSImage, baseOSVersion, registry, controllerMode, baseOSImageActivate, baseOSVDrive); err != nil { + if err := openevec.EdgeNodeEVEImageUpdate(baseOSImage, baseOSVersion, registry, cfg.Registry.IP, controllerMode, cfg.Registry.Port, baseOSImageActivate, baseOSVDrive); err != nil { log.Fatal(err) } }, diff --git a/pkg/openevec/edgeNode.go b/pkg/openevec/edgeNode.go index dbaa778bd..827657860 100644 --- a/pkg/openevec/edgeNode.go +++ b/pkg/openevec/edgeNode.go @@ -18,7 +18,6 @@ import ( "github.com/lf-edge/eden/pkg/utils" "github.com/lf-edge/eve/api/go/config" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" "google.golang.org/protobuf/encoding/protojson" ) @@ -58,7 +57,7 @@ func EdgeNodeShutdown(controllerMode string) error { return nil } -func EdgeNodeEVEImageUpdate(baseOSImage, baseOSVersion, registry, controllerMode string, +func EdgeNodeEVEImageUpdate(baseOSImage, baseOSVersion, registry, registryIp, controllerMode string, registryPort int, baseOSImageActivate, baseOSVDrive bool) error { var opts []expect.ExpectationOption @@ -73,7 +72,7 @@ func EdgeNodeEVEImageUpdate(baseOSImage, baseOSVersion, registry, controllerMode registryToUse := registry switch registry { case "local": - registryToUse = fmt.Sprintf("%s:%d", viper.GetString("registry.ip"), viper.GetInt("registry.port")) + registryToUse = fmt.Sprintf("%s:%d", registryIp, registryPort) case "remote": registryToUse = "" } From efcb4d84f3fb59c5355c25d553e5aa868cf7a54e Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 14:38:22 +0200 Subject: [PATCH 06/20] Remove viper from VolumeCreate Refer to #855 Signed-off-by: Pavel Abramov --- cmd/edenVolume.go | 15 +++++++++------ cmd/root.go | 2 +- pkg/openevec/edenVolume.go | 5 ++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cmd/edenVolume.go b/cmd/edenVolume.go index 9dcbe5cfa..2cd2034f3 100644 --- a/cmd/edenVolume.go +++ b/cmd/edenVolume.go @@ -7,9 +7,12 @@ import ( "github.com/spf13/cobra" ) -func newVolumeCmd() *cobra.Command { +func newVolumeCmd(configName, verbosity *string) *cobra.Command { + cfg := &openevec.EdenSetupArgs{} + var volumeCmd = &cobra.Command{ - Use: "volume", + Use: "volume", + PersistentPreRunE: preRunViperLoadFunction(cfg, configName, verbosity), } groups := CommandGroups{ @@ -17,7 +20,7 @@ func newVolumeCmd() *cobra.Command { Message: "Basic Commands", Commands: []*cobra.Command{ newVolumeLsCmd(), - newVolumeCreateCmd(), + newVolumeCreateCmd(cfg), newVolumeDeleteCmd(), newVolumeDetachCmd(), newVolumeAttachCmd(), @@ -44,7 +47,7 @@ func newVolumeLsCmd() *cobra.Command { return volumeLsCmd } -func newVolumeCreateCmd() *cobra.Command { +func newVolumeCreateCmd(cfg *openevec.EdenSetupArgs) *cobra.Command { var registry, diskSize, volumeName, volumeType, datastoreOverride string var sftpLoad, directLoad bool @@ -55,8 +58,8 @@ func newVolumeCreateCmd() *cobra.Command { Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { appLink := args[0] - err := openevec.VolumeCreate(appLink, registry, diskSize, volumeName, - volumeType, datastoreOverride, sftpLoad, directLoad) + err := openevec.VolumeCreate(appLink, registry, cfg.Registry.IP, diskSize, volumeName, + volumeType, datastoreOverride, cfg.Registry.Port, sftpLoad, directLoad) if err != nil { log.Fatal(err) } diff --git a/cmd/root.go b/cmd/root.go index ff3ddf5a1..fbe20cc5c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -52,7 +52,7 @@ func NewEdenCommand() *cobra.Command { newUtilsCmd(&configName, &verbosity), newControllerCmd(&configName, &verbosity), newNetworkCmd(), - newVolumeCmd(), + newVolumeCmd(&configName, &verbosity), newDisksCmd(), newPacketCmd(&configName, &verbosity), newRolCmd(&configName, &verbosity), diff --git a/pkg/openevec/edenVolume.go b/pkg/openevec/edenVolume.go index f6a6cb3c9..33c94b699 100644 --- a/pkg/openevec/edenVolume.go +++ b/pkg/openevec/edenVolume.go @@ -13,7 +13,6 @@ import ( "github.com/lf-edge/eve/api/go/config" uuid "github.com/satori/go.uuid" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" ) func VolumeLs() error { @@ -35,7 +34,7 @@ func VolumeLs() error { return nil } -func VolumeCreate(appLink, registry, diskSize, volumeName, volumeType, datastoreOverride string, sftpLoad, directLoad bool) error { +func VolumeCreate(appLink, registry, registryIp, diskSize, volumeName, volumeType, datastoreOverride string, registryPort int, sftpLoad, directLoad bool) error { changer := &adamChanger{} ctrl, dev, err := changer.getControllerAndDev() if err != nil { @@ -82,7 +81,7 @@ func VolumeCreate(appLink, registry, diskSize, volumeName, volumeType, datastore registryToUse := registry switch registry { case "local": - registryToUse = fmt.Sprintf("%s:%d", viper.GetString("registry.ip"), viper.GetInt("registry.port")) + registryToUse = fmt.Sprintf("%s:%d", registryIp, registryPort) case "remote": registryToUse = "" } From 4f0f61f02b5c5d11a0fb848d73b84fd8887f4f12 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 14:41:46 +0200 Subject: [PATCH 07/20] Add viper config read for packet command Signed-off-by: Pavel Abramov --- cmd/edenPacket.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/edenPacket.go b/cmd/edenPacket.go index a9558c170..6b15c5523 100644 --- a/cmd/edenPacket.go +++ b/cmd/edenPacket.go @@ -12,8 +12,9 @@ func newPacketCmd(configName, verbosity *string) *cobra.Command { var packetProjectName string var packetCmd = &cobra.Command{ - Use: "packet", - Short: `Manage VMs in Equinix Metal Platform`, + Use: "packet", + Short: `Manage VMs in Equinix Metal Platform`, + PersistentPreRunE: preRunViperLoadFunction(cfg, configName, verbosity), } packetCmd.AddCommand(newPacketVMCmd(cfg, &cfg.Packet.Key, &packetProjectName)) From 828b5f0de72b373e6f291bea045adcf6be107b50 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 27 Mar 2023 14:47:51 +0200 Subject: [PATCH 08/20] Remove unused stopAdam function Signed-off-by: Pavel Abramov --- pkg/openevec/start.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/openevec/start.go b/pkg/openevec/start.go index d64dd974b..e0aaa179a 100644 --- a/pkg/openevec/start.go +++ b/pkg/openevec/start.go @@ -6,7 +6,6 @@ import ( "github.com/lf-edge/eden/pkg/eden" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" ) func StartAdam(cfg EdenSetupArgs) error { @@ -27,15 +26,6 @@ func StartAdam(cfg EdenSetupArgs) error { return nil } -func stopAdam(_ string) error { - adamRm := viper.GetBool("adam-rm") - - if err := eden.StopAdam(adamRm); err != nil { - return fmt.Errorf("cannot stop adam: %w", err) - } - return nil -} - func GetAdamStatus() (string, error) { statusAdam, err := eden.StatusAdam() if err != nil { From e01eff6f351df3e30be8d2f68413706f6a72ec40 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Wed, 5 Apr 2023 14:59:44 +0200 Subject: [PATCH 09/20] Add ConfigWrite function Signed-off-by: Pavel Abramov --- .gitignore | 4 ++ pkg/openevec/config.go | 53 ++++++++++++++++-- pkg/openevec/config_test.go | 104 ++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 pkg/openevec/config_test.go diff --git a/.gitignore b/.gitignore index f70e55765..ff14fd159 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,7 @@ tests/workflow/workflow.large.txt eve-config-dir/* export + +# vim swap files +*.swp +*.swo diff --git a/pkg/openevec/config.go b/pkg/openevec/config.go index 81e824f1a..3b9c0c58b 100644 --- a/pkg/openevec/config.go +++ b/pkg/openevec/config.go @@ -2,6 +2,7 @@ package openevec import ( "fmt" + "io" "os" "path" "path/filepath" @@ -21,6 +22,12 @@ type EServerConfig struct { Tag string `mapstructure:"tag" cobraflag:"eserver-tag"` IP string `mapstructure:"ip"` Images ImagesConfig `mapstructure:"images"` + EVEIP string `mapstructure:"eve-ip"` +} + +type EClientConfig struct { + Tag string `mapstructure: "tag"` + Image string `mapstructure: "image"` } type ImagesConfig struct { @@ -40,8 +47,8 @@ type EdenConfig struct { Tests string `mapstructure:"tests" resolvepath:""` EServer EServerConfig `mapstructure:"eserver"` - - Images ImagesConfig `mapstructure:"images"` + EClient EClientConfig `mapstructure:"eclient"` + Images ImagesConfig `mapstructure:"images"` } type RedisConfig struct { @@ -50,7 +57,8 @@ type RedisConfig struct { Port int `mapstructure:"port" cobraflag:"redis-port"` Dist string `mapstructure:"dist" cobraflag:"redis-dist" resolvepath:""` Force bool `mapstructure:"force" cobraflag:"redis-force"` - Eden string `mapstructure:"eden"` + Eden string `mapstructure:"eden"` // TODO: belongs to ADAM Redis + Adam string `mapstructure:"adam"` // TODO: belongs to ADAM Redis } type RemoteConfig struct { @@ -74,8 +82,10 @@ type AdamConfig struct { CertsEVEIP string `mapstructure:"eve-ip" cobraflag:"eve-ip"` APIv1 bool `mapstructure:"v1" cobrafalg:"force"` Force bool `mapstructure:"force" cobraflag:"force"` + CA string `mapstructure:"ca"` + Domain string `mapstructure:"domain"` - Redis RedisConfig `mapstructure:"redis"` + Redis RedisConfig `mapstructure:"redis"` // TODO: this should be separate config from EdenSetupArgs.Redis Remote RemoteConfig `mapstructure:"remote"` Caching CachingConfig `mapstructure:"caching"` } @@ -300,6 +310,41 @@ func LoadConfig(configFile string) (*EdenSetupArgs, error) { return cfg, nil } +func WriteConfig(dst reflect.Value, writer io.Writer, nestLevel int) { + for i := 0; i < dst.NumField(); i++ { + if structTag := dst.Type().Field(i).Tag.Get("mapstructure"); structTag != "" { + io.WriteString(writer, strings.Repeat(" ", nestLevel)) + switch dst.Field(i).Kind() { + case reflect.Struct: + io.WriteString(writer, structTag+":\n") + WriteConfig(dst.Field(i), writer, nestLevel+1) + case reflect.Map: + io.WriteString(writer, structTag+":\n") + iter := dst.Field(i).MapRange() + for iter.Next() { + k := iter.Key() + v := iter.Value() + io.WriteString(writer, strings.Repeat(" ", nestLevel+1)) + // We assume that only map we are using is map[string]string + // in case if we want to expand this check should be made as separate function + io.WriteString(writer, fmt.Sprintf("%v: '%v'\n", k.Interface(), v.Interface())) + } + case reflect.Slice: + io.WriteString(writer, structTag+":\n") + for j := 0; j < dst.Field(i).Len(); j++ { + io.WriteString(writer, strings.Repeat(" ", nestLevel+1)) + elem := dst.Field(i).Index(j) + io.WriteString(writer, fmt.Sprintf("- %v\n", elem.Interface())) + } + case reflect.String: // we need to wrap string in quotes + io.WriteString(writer, fmt.Sprintf("%s: '%v'\n", structTag, dst.Field(i))) + default: + io.WriteString(writer, fmt.Sprintf("%s: %v\n", structTag, dst.Field(i))) + } + } + } +} + func resolvePath(v reflect.Value, edenRoot string) { for i := 0; i < v.NumField(); i++ { f := v.Field(i) diff --git a/pkg/openevec/config_test.go b/pkg/openevec/config_test.go new file mode 100644 index 000000000..31740064e --- /dev/null +++ b/pkg/openevec/config_test.go @@ -0,0 +1,104 @@ +package openevec_test + +import ( + "bytes" + "fmt" + "reflect" + "testing" + + "github.com/lf-edge/eden/pkg/openevec" + "github.com/spf13/viper" +) + +type ServerConfig struct { + Field string `mapstructure:"field"` + Access int `mapstructure:"access"` + HostFwd map[string]string `mapstructure:"hostfwd"` +} + +type Config struct { + Names []string `mapstructure:"names"` + IsSpecial bool `mapstructure:"special"` + + Server ServerConfig `mapstructure:"server"` +} + +func (lhs *Config) IsEqual(rhs Config) bool { + for _, lname := range lhs.Names { + contains := false + for _, rname := range rhs.Names { + if lname == rname { + contains = true + break + } + } + if !contains { + //fmt.Println("Missing ", lname) + return false + } + } + + if lhs.IsSpecial != rhs.IsSpecial { + //fmt.Println("IsSpecial missmatch") + return false + } + + if lhs.Server.Field != rhs.Server.Field { + //fmt.Println("Server Field missmatch") + return false + } + + if lhs.Server.Access != rhs.Server.Access { + //fmt.Println("Server Access missmatch") + return false + } + + for k, lval := range lhs.Server.HostFwd { + if rval, ok := rhs.Server.HostFwd[k]; ok { + if lval != rval { + //fmt.Println("Key %v missmatch. Have %v got %v", k, lhs, rhs) + return false + } + } else { + //fmt.Println("Missing hostfwd key ", k) + return false + } + } + + return true +} + +func TestViperSerializeFromWriteConfig(t *testing.T) { + cfg := Config{ + Names: []string{"test1", "test2"}, + IsSpecial: false, + + Server: ServerConfig{ + Field: "ServerField", + Access: 42, + + HostFwd: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + }, + } + + var buf bytes.Buffer + openevec.WriteConfig(reflect.ValueOf(cfg), &buf, 0) + + v := viper.New() + v.SetConfigType("yaml") + err := v.ReadConfig(&buf) + if err != nil { + fmt.Println("error reading config:", err) + return + } + + // Unmarshal the configuration into the Config struct. + gotCfg := &Config{} + err = v.Unmarshal(&gotCfg) + if !gotCfg.IsEqual(cfg) { + t.Errorf("Generated config is = %v; want %v", gotCfg, cfg) + } +} From 1bc9bd73dca610e499b1d52029dd365f3bb34289 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Wed, 12 Apr 2023 09:28:28 +0200 Subject: [PATCH 10/20] Remove unused CobraToViper variable Signed-off-by: Pavel Abramov --- pkg/defaults/defaults.go | 89 ---------------------------------------- 1 file changed, 89 deletions(-) diff --git a/pkg/defaults/defaults.go b/pkg/defaults/defaults.go index 00d739dee..374bb8d96 100644 --- a/pkg/defaults/defaults.go +++ b/pkg/defaults/defaults.go @@ -203,93 +203,4 @@ const ( var ( //DefaultQemuHostFwd represents port forward for ssh DefaultQemuHostFwd = map[string]string{strconv.Itoa(DefaultSSHPort): "22"} - //DefaultCobraToViper represents mapping values between cobra (cli) and viper (yml) - DefaultCobraToViper = map[string]string{ - "redis.dist": "redis-dist", - "redis.tag": "redis-tag", - "redis.port": "redis-port", - "redis.force": "redis-force", - - "adam.dist": "adam-dist", - "adam.tag": "adam-tag", - "adam.port": "adam-port", - "adam.domain": "domain", - "adam.ip": "ip", - "adam.eve-ip": "eve-ip", - "adam.force": "adam-force", - "adam.v1": "api-v1", - "adam.redis.adam": "adam-redis-url", - "adam.remote.redis": "adam-redis", - - "registry.tag": "registry-tag", - "registry.port": "registry-port", - "registry.dist": "registry-dist", - - "eve.arch": "eve-arch", - "eve.os": "eve-os", - "eve.accel": "eve-accel", - "eve.hv": "eve-hv", - "eve.serial": "eve-serial", - "eve.pid": "eve-pid", - "eve.log": "eve-log", - "eve.firmware": "eve-firmware", - "eve.repo": "eve-repo", - "eve.registry": "eve-registry", - "eve.tag": "eve-tag", - "eve.hostfwd": "eve-hostfwd", - "eve.dist": "eve-dist", - "eve.base-dist": "eve-base-dist", - "eve.qemu-config": "qemu-config", - "eve.uuid": "uuid", - "eve.image-file": "image-file", - "eve.dtb-part": "dtb-part", - "eve.config-part": "config-part", - "eve.base-version": "os-version", - "eve.devmodel": "devmodel", - "eve.devmodelfile": "devmodel-file", - "eve.telnet-port": "eve-telnet-port", - "eve.cpu": "cpus", - "eve.ram": "memory", - "eve.tpm": "tpm", - "eve.disks": "eve-disks", - - "eve.custom-installer.path": "custom-installer-path", - "eve.custom-installer.format": "custom-installer-format", - - "eve.bootstrap-file": "eve-bootstrap-file", - "eve.usbnetconf-file": "eve-usbnetconf-file", - - "eve.qemu.monitor-port": "qemu-monitor-port", - "eve.qemu.netdev-socket-port": "qemu-netdev-socket-port", - - "eden.images.dist": "image-dist", - "eden.images.docker": "docker-yml", - "eden.images.vm": "vm-yml", - "eden.download": "download", - "eden.eserver.ip": "eserver-ip", - "eden.eserver.port": "eserver-port", - "eden.eserver.tag": "eserver-tag", - "eden.eserver.force": "eserver-force", - "eden.certs-dist": "certs-dist", - "eden.bin-dist": "bin-dist", - "eden.ssh-key": "ssh-key", - "eden.test-bin": "prog", - "eden.test-scenario": "scenario", - - "config": "config", - - "sdn.disable": "sdn-disable", - "sdn.source-dir": "sdn-source-dir", - "sdn.config-dir": "sdn-config-dir", - "sdn.image-file": "sdn-image-file", - "sdn.linuxkit-bin": "sdn-linuxkit-bin", - "sdn.cpu": "sdn-cpu", - "sdn.ram": "sdn-ram", - "sdn.pid": "sdn-pid", - "sdn.console-log": "sdn-console-log", - "sdn.telnet-port": "sdn-telnet-port", - "sdn.ssh-port": "sdn-ssh-port", - "sdn.mgmt-port": "sdn-mgmt-port", - "sdn.network-model": "sdn-network-model", - } ) From ae089d727bf2fd74e57faf7eb87a0d39e6ef2db9 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Wed, 12 Apr 2023 09:29:32 +0200 Subject: [PATCH 11/20] Rename Merge to MergeFlagSet Signed-off-by: Pavel Abramov --- cmd/root.go | 2 +- pkg/openevec/config.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index fbe20cc5c..727ee809e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -74,7 +74,7 @@ func preRunViperLoadFunction(cfg *openevec.EdenSetupArgs, configName, verbosity if err != nil { return err } - openevec.Merge(reflect.ValueOf(viperCfg).Elem(), reflect.ValueOf(*cfg), cmd.Flags()) + openevec.MergeFlagSet(reflect.ValueOf(viperCfg).Elem(), reflect.ValueOf(*cfg), cmd.Flags()) *cfg = *viperCfg return nil } diff --git a/pkg/openevec/config.go b/pkg/openevec/config.go index 3b9c0c58b..916ffdea5 100644 --- a/pkg/openevec/config.go +++ b/pkg/openevec/config.go @@ -222,10 +222,10 @@ type PodConfig struct { ACLOnlyHost bool } -func Merge(dst, src reflect.Value, flags *pflag.FlagSet) { +func MergeFlagSet(dst, src reflect.Value, flags *pflag.FlagSet) { for i := 0; i < dst.NumField(); i++ { if dst.Field(i).Kind() == reflect.Struct { - Merge(dst.Field(i), src.Field(i), flags) + MergeFlagSet(dst.Field(i), src.Field(i), flags) } if dst.Type().Field(i).Tag != "" { cobraFlagTag := dst.Type().Field(i).Tag.Get("cobraflag") From c8c19fa5a7c44cea03fd11091df6fe0004a3079e Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Thu, 25 May 2023 11:15:49 +0200 Subject: [PATCH 12/20] openevec/config minor fixes to config elements Signed-off-by: Pavel Abramov --- pkg/openevec/config.go | 34 ++++++++++++++++++++-------------- pkg/openevec/config_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/pkg/openevec/config.go b/pkg/openevec/config.go index 916ffdea5..f7b39b3cd 100644 --- a/pkg/openevec/config.go +++ b/pkg/openevec/config.go @@ -26,8 +26,8 @@ type EServerConfig struct { } type EClientConfig struct { - Tag string `mapstructure: "tag"` - Image string `mapstructure: "image"` + Tag string `mapstructure:"tag"` + Image string `mapstructure:"image"` } type ImagesConfig struct { @@ -36,11 +36,11 @@ type ImagesConfig struct { type EdenConfig struct { Download bool `mapstructure:"download" cobraflag:"download"` - BinDir string `mapstructure:"bin-dist" cobraflag:"bin-dist" resolvepath:""` + BinDir string `mapstructure:"bin-dist" cobraflag:"bin-dist"` CertsDir string `mapstructure:"certs-dist" cobraflag:"certs-dist" resolvepath:""` Dist string `mapstructure:"dist"` Root string `mapstructure:"root"` - SSHKey string `mapstructure:"ssh-key" cobraflag:"ssh-key" resolvepath:""` + SSHKey string `mapstructure:"ssh-key" cobraflag:"ssh-key"` EdenBin string `mapstructure:"eden-bin"` TestBin string `mapstructure:"test-bin"` TestScenario string `mapstructure:"test-scenario"` @@ -52,13 +52,12 @@ type EdenConfig struct { } type RedisConfig struct { - RemoteURL string `mapstructure:"adam" cobraflag:"adam-redis-url"` + RemoteURL string `mapstructure:"adam" cobraflag:"adam-redis-url"` // TODO: belongs to ADAM Redis Tag string `mapstructure:"tag" cobraflag:"redis-tag"` Port int `mapstructure:"port" cobraflag:"redis-port"` Dist string `mapstructure:"dist" cobraflag:"redis-dist" resolvepath:""` Force bool `mapstructure:"force" cobraflag:"redis-force"` Eden string `mapstructure:"eden"` // TODO: belongs to ADAM Redis - Adam string `mapstructure:"adam"` // TODO: belongs to ADAM Redis } type RemoteConfig struct { @@ -83,7 +82,6 @@ type AdamConfig struct { APIv1 bool `mapstructure:"v1" cobrafalg:"force"` Force bool `mapstructure:"force" cobraflag:"force"` CA string `mapstructure:"ca"` - Domain string `mapstructure:"domain"` Redis RedisConfig `mapstructure:"redis"` // TODO: this should be separate config from EdenSetupArgs.Redis Remote RemoteConfig `mapstructure:"remote"` @@ -105,7 +103,7 @@ type EveConfig struct { QemuConfig QemuConfig `mapstructure:"qemu"` QemuFirmware []string `mapstructure:"firmware" cobraflag:"eve-firmware"` - QemuConfigPath string `mapstructure:"config-part" cobraflag:"config-path" resolvepath:""` + QemuConfigPath string `mapstructure:"config-part" cobraflag:"config-path"` QemuDTBPath string `mapstructure:"dtb-part" cobraflag:"dtb-part" resolvepath:""` QemuOS string `mapstructure:"os" cobraflag:"eve-os"` ImageFile string `mapstructure:"image-file" cobraflag:"image-file" resolvepath:""` @@ -123,7 +121,6 @@ type EveConfig struct { QemuMemory int `mapstructure:"ram" cobraflag:"memory"` ImageSizeMB int `mapstructure:"disk" cobraflag:"image-size"` DevModel string `mapstructure:"devmodel" cobraflag:"devmodel"` - DevModelFile string `mapstructure:"devmodelfile"` Ssid string `mapstructure:"ssid" cobraflag:"ssid"` Password string `mapstructure:"password" cobraflag:"password"` Serial string `mapstructure:"serial" cobraflag:"eve-serial"` @@ -144,6 +141,7 @@ type EveConfig struct { BootstrapFile string `mapstructure:"bootstrap-file" cobraflag:"eve-bootstrap-file"` UsbNetConfFile string `mapstructure:"usbnetconf-file" cobraflag:"eve-usbnetconf-file"` TPM bool `mapstructure:"tpm" cobraflag:"tpm"` + Platform string `mapstructure:"platform"` } type RegistryConfig struct { @@ -162,7 +160,7 @@ type GcpConfig struct { } type SdnConfig struct { - ImageFile string `mapstructure:"image-file" cobraflag:"sdn-image-file" resolvepath:""` + ImageFile string `mapstructure:"image-file" cobraflag:"sdn-image-file"` SourceDir string `mapstructure:"source-dir" cobraflag:"sdn-source-dir" resolvepath:""` RAM int `mapstructure:"ram" cobraflag:"sdn-ram"` CPU int `mapstructure:"cpu" cobraflag:"sdn-cpu"` @@ -189,6 +187,7 @@ type EdenSetupArgs struct { ConfigFile string ConfigName string + EdenDir string } // PodConfig store configuration for Pod deployment @@ -310,6 +309,14 @@ func LoadConfig(configFile string) (*EdenSetupArgs, error) { return cfg, nil } +func getValStrRepr(v reflect.Value) string { + if v.Kind() == reflect.String { + return fmt.Sprintf("'%v'", v.Interface()) + } else { + return fmt.Sprintf("%v", v.Interface()) + } +} + func WriteConfig(dst reflect.Value, writer io.Writer, nestLevel int) { for i := 0; i < dst.NumField(); i++ { if structTag := dst.Type().Field(i).Tag.Get("mapstructure"); structTag != "" { @@ -325,16 +332,15 @@ func WriteConfig(dst reflect.Value, writer io.Writer, nestLevel int) { k := iter.Key() v := iter.Value() io.WriteString(writer, strings.Repeat(" ", nestLevel+1)) - // We assume that only map we are using is map[string]string - // in case if we want to expand this check should be made as separate function - io.WriteString(writer, fmt.Sprintf("%v: '%v'\n", k.Interface(), v.Interface())) + // We assume that map cannot have structure as value + io.WriteString(writer, fmt.Sprintf("%v: %s\n", k.Interface(), getValStrRepr(v))) } case reflect.Slice: io.WriteString(writer, structTag+":\n") for j := 0; j < dst.Field(i).Len(); j++ { io.WriteString(writer, strings.Repeat(" ", nestLevel+1)) elem := dst.Field(i).Index(j) - io.WriteString(writer, fmt.Sprintf("- %v\n", elem.Interface())) + io.WriteString(writer, fmt.Sprintf("- %v\n", getValStrRepr(elem))) } case reflect.String: // we need to wrap string in quotes io.WriteString(writer, fmt.Sprintf("%s: '%v'\n", structTag, dst.Field(i))) diff --git a/pkg/openevec/config_test.go b/pkg/openevec/config_test.go index 31740064e..e3285c1e9 100644 --- a/pkg/openevec/config_test.go +++ b/pkg/openevec/config_test.go @@ -8,12 +8,19 @@ import ( "github.com/lf-edge/eden/pkg/openevec" "github.com/spf13/viper" + "gotest.tools/assert" ) +type NestedConfig struct { + NumField int `mapstructure:"numfield"` +} + type ServerConfig struct { Field string `mapstructure:"field"` Access int `mapstructure:"access"` HostFwd map[string]string `mapstructure:"hostfwd"` + + NestedField NestedConfig `mapstructure:"nested"` } type Config struct { @@ -81,6 +88,10 @@ func TestViperSerializeFromWriteConfig(t *testing.T) { "key1": "value1", "key2": "value2", }, + + NestedField: NestedConfig{ + NumField: 21, + }, }, } @@ -98,7 +109,29 @@ func TestViperSerializeFromWriteConfig(t *testing.T) { // Unmarshal the configuration into the Config struct. gotCfg := &Config{} err = v.Unmarshal(&gotCfg) + if !gotCfg.IsEqual(cfg) { t.Errorf("Generated config is = %v; want %v", gotCfg, cfg) } } + +func TestConfigSliceType(t *testing.T) { + cfg := Config{ + Names: []string{"test1", "test2"}, + } + + var buf bytes.Buffer + openevec.WriteConfig(reflect.ValueOf(cfg), &buf, 0) + + v := viper.New() + v.SetConfigType("yaml") + err := v.ReadConfig(&buf) + if err != nil { + fmt.Println("error reading config:", err) + return + } + + gotCfg := &Config{} + err = v.Unmarshal(&gotCfg) + assert.Equal(t, reflect.String, reflect.TypeOf(cfg.Names[0]).Kind(), "Name type should be string") +} From 655ca3dbf4cf113b60c628cdcdb4a7ef18f955d2 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Thu, 25 May 2023 11:25:20 +0200 Subject: [PATCH 13/20] openevec/eden interpret firmware parameter as list Signed-off-by: Pavel Abramov --- pkg/openevec/eden.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/openevec/eden.go b/pkg/openevec/eden.go index 06e3bc604..d0e838ebe 100644 --- a/pkg/openevec/eden.go +++ b/pkg/openevec/eden.go @@ -118,10 +118,8 @@ func setupQemuConfig(cfg EdenSetupArgs) error { } } var qemuFirmwareParam []string - for _, line := range cfg.Eve.QemuFirmware { - for _, el := range strings.Split(line, " ") { - qemuFirmwareParam = append(qemuFirmwareParam, utils.ResolveAbsPath(el)) - } + for _, el := range cfg.Eve.QemuFirmware { + qemuFirmwareParam = append(qemuFirmwareParam, utils.ResolveAbsPath(el)) } if cfg.Eve.CustomInstaller.Path != "" && cfg.Eve.Disks == 0 { return fmt.Errorf("EVE installer requires at least one disK") From 0bf46eb7c6ff6a954a32b1960f80b4cec9abe599 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Thu, 25 May 2023 11:30:03 +0200 Subject: [PATCH 14/20] openevec/defaults fix default config generation Signed-off-by: Pavel Abramov --- pkg/openevec/defaults.go | 168 ++++++++++++++++++++++++++++++++------- 1 file changed, 138 insertions(+), 30 deletions(-) diff --git a/pkg/openevec/defaults.go b/pkg/openevec/defaults.go index 17ab318e4..2f8fa819d 100644 --- a/pkg/openevec/defaults.go +++ b/pkg/openevec/defaults.go @@ -5,91 +5,199 @@ import ( "path/filepath" "reflect" "runtime" + "strconv" + "strings" "github.com/dustin/go-humanize" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/utils" + uuid "github.com/satori/go.uuid" ) func GetDefaultConfig(currentPath string) *EdenSetupArgs { + ip, err := utils.GetIPForDockerAccess() + if err != nil { + return nil + } + + edenDir, err := utils.DefaultEdenDir() + if err != nil { + return nil + } + + id, err := uuid.NewV4() + if err != nil { + return nil + } + + imageDist := fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultImageDist) + certsDist := fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultCertsDist) + + firmware := []string{filepath.Join(imageDist, "eve", "OVMF.fd")} + if runtime.GOARCH == "amd64" { + firmware = []string{ + filepath.Join(imageDist, "eve", "OVMF_CODE.fd"), + filepath.Join(imageDist, "eve", "OVMF_VARS.fd")} + } + defaultEdenConfig := &EdenSetupArgs{ Eden: EdenConfig{ - Download: true, - BinDir: filepath.Join(currentPath, defaults.DefaultDist, defaults.DefaultBinDist), - SSHKey: filepath.Join(currentPath, defaults.DefaultCertsDist, "id_rsa"), - Root: filepath.Join(currentPath, defaults.DefaultDist), - CertsDir: filepath.Join(fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultCertsDist)), + Root: filepath.Join(currentPath, defaults.DefaultDist), + Tests: filepath.Join(currentPath, defaults.DefaultDist, "tests"), + Download: true, + BinDir: filepath.Join(defaults.DefaultDist, defaults.DefaultBinDist), + SSHKey: fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultSSHKey), + CertsDir: filepath.Join(fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultCertsDist)), + TestBin: defaults.DefaultBinDist, + EdenBin: "eden.escript.test", + TestScenario: defaults.DefaultTestScenario, + + Images: ImagesConfig{ + EServerImageDist: defaults.DefaultEserverDist, + }, EServer: EServerConfig{ + IP: ip, + EVEIP: defaults.DefaultDomain, + Port: defaults.DefaultEserverPort, - Force: false, + Force: true, Tag: defaults.DefaultEServerTag, }, + + EClient: EClientConfig{ + Tag: defaults.DefaultEClientTag, + Image: defaults.DefaultEClientContainerRef, + }, }, Adam: AdamConfig{ - Tag: defaults.DefaultAdamTag, - Port: defaults.DefaultAdamPort, - CertsIP: defaults.DefaultIP, - CertsEVEIP: defaults.DefaultEVEIP, + Tag: defaults.DefaultAdamTag, + Port: defaults.DefaultAdamPort, + Dist: defaults.DefaultAdamDist, + CertsDomain: defaults.DefaultDomain, + CertsIP: ip, + CertsEVEIP: ip, + Force: true, + CA: filepath.Join(certsDist, "root-certificate.pem"), + APIv1: false, Redis: RedisConfig{ - Tag: defaults.DefaultRedisTag, - Port: defaults.DefaultRedisPort, + RemoteURL: fmt.Sprintf("%s:%d", defaults.DefaultRedisContainerName, defaults.DefaultRedisPort), + Tag: defaults.DefaultRedisTag, + Port: defaults.DefaultRedisPort, + Eden: fmt.Sprintf("%s:%d", ip, defaults.DefaultRedisPort), + }, + + Remote: RemoteConfig{ + Enabled: true, + Redis: true, + }, + + Caching: CachingConfig{ + Enabled: false, + Redis: false, + Prefix: "cache", }, }, Eve: EveConfig{ - QemuConfig: QemuConfig{ - MonitorPort: defaults.DefaultQemuMonitorPort, - NetDevSocketPort: defaults.DefaultQemuNetdevSocketPort, - }, - CertsUUID: defaults.DefaultUUID, - Dist: filepath.Join(currentPath, defaults.DefaultDist, defaults.DefaultEVEDist), - Repo: defaults.DefaultEveRepo, - Registry: defaults.DefaultEveRegistry, - Tag: defaults.DefaultEVETag, - UefiTag: defaults.DefaultEVETag, - HV: defaults.DefaultEVEHV, - Arch: runtime.GOARCH, - HostFwd: defaults.DefaultQemuHostFwd, + Name: strings.ToLower(defaults.DefaultContext), + DevModel: defaults.DefaultQemuModel, + ModelFile: "", + Arch: runtime.GOARCH, + QemuOS: runtime.GOOS, + Accel: true, + HV: defaults.DefaultEVEHV, + CertsUUID: id.String(), + Cert: filepath.Join(certsDist, "onboard.cert.pem"), + DeviceCert: filepath.Join(certsDist, "device.cert.pem"), + QemuFirmware: firmware, + Dist: fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultEVEDist), + Repo: defaults.DefaultEveRepo, + Registry: defaults.DefaultEveRegistry, + Tag: defaults.DefaultEVETag, + UefiTag: defaults.DefaultEVETag, + HostFwd: map[string]string{ + strconv.Itoa(defaults.DefaultSSHPort): "22", + "5911": "5901", + "5912": "5902", + "8027": "8027", + "8028": "8028"}, QemuFileToSave: defaults.DefaultQemuFileToSave, QemuCpus: defaults.DefaultCpus, QemuMemory: defaults.DefaultMemory, ImageSizeMB: defaults.DefaultEVEImageSize, - DevModel: defaults.DefaultQemuModel, Serial: defaults.DefaultEVESerial, - Pid: filepath.Join(currentPath, defaults.DefaultDist), - Log: filepath.Join(currentPath, defaults.DefaultDist), + Pid: fmt.Sprintf("%s-eve.pid", strings.ToLower(defaults.DefaultContext)), + Log: fmt.Sprintf("%s-eve.log", strings.ToLower(defaults.DefaultContext)), TelnetPort: defaults.DefaultTelnetPort, TPM: defaults.DefaultTPMEnabled, - ImageFile: "default-images/eve/live.img", + ImageFile: filepath.Join(imageDist, "eve", "live.img"), + QemuDTBPath: "", + QemuConfigPath: certsDist, + Remote: defaults.DefaultEVERemote, + RemoteAddr: defaults.DefaultEVEHost, + LogLevel: defaults.DefaultEveLogLevel, + AdamLogLevel: defaults.DefaultAdamLogLevel, + Ssid: "", + Disks: defaults.DefaultAdditionalDisks, + BootstrapFile: "", + UsbNetConfFile: "", + Platform: "none", + + CustomInstaller: CustomInstallerConfig{ + Path: "", + Format: "", + }, + + QemuConfig: QemuConfig{ + MonitorPort: defaults.DefaultQemuMonitorPort, + NetDevSocketPort: defaults.DefaultQemuNetdevSocketPort, + }, }, Redis: RedisConfig{ Tag: defaults.DefaultRedisTag, Port: defaults.DefaultRedisPort, + Dist: defaults.DefaultRedisDist, }, Registry: RegistryConfig{ Tag: defaults.DefaultRegistryTag, Port: defaults.DefaultRegistryPort, + IP: ip, + Dist: defaults.DefaultRegistryDist, }, Sdn: SdnConfig{ RAM: defaults.DefaultSdnMemory, CPU: defaults.DefaultSdnCpus, ConsoleLogFile: filepath.Join(currentPath, defaults.DefaultDist, "sdn-console.log"), - Disable: false, + Disable: true, TelnetPort: defaults.DefaultSdnTelnetPort, MgmtPort: defaults.DefaultSdnMgmtPort, PidFile: filepath.Join(currentPath, defaults.DefaultDist, "sdn.pid"), SSHPort: defaults.DefaultSdnSSHPort, + SourceDir: filepath.Join(currentPath, "sdn"), + ConfigDir: filepath.Join(edenDir, fmt.Sprintf("%s-sdn", "default")), + ImageFile: filepath.Join(imageDist, "eden", "sdn-efi.qcow2"), + LinuxkitBin: filepath.Join(currentPath, defaults.DefaultBuildtoolsDir, "linuxkit"), + NetModelFile: "", + }, + + Gcp: GcpConfig{ + Key: "", + }, + + Packet: PacketConfig{ + Key: "", }, ConfigName: defaults.DefaultContext, ConfigFile: utils.GetConfig(defaults.DefaultContext), + EdenDir: edenDir, } resolvePath(reflect.ValueOf(defaultEdenConfig).Elem(), defaultEdenConfig.Eden.Root) From 8066850df8453f059cc1d72e6b2d6ecd87f15a9d Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Thu, 25 May 2023 11:31:01 +0200 Subject: [PATCH 15/20] cmd/edenConfig refactor ConfigAdd Signed-off-by: Pavel Abramov --- cmd/edenConfig.go | 27 ++++++---- pkg/openevec/edenConfig.go | 106 +++++++------------------------------ 2 files changed, 35 insertions(+), 98 deletions(-) diff --git a/cmd/edenConfig.go b/cmd/edenConfig.go index 88014793b..2737f78eb 100644 --- a/cmd/edenConfig.go +++ b/cmd/edenConfig.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "os" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/openevec" @@ -10,7 +11,12 @@ import ( ) func newConfigCmd(configName, verbosity *string) *cobra.Command { - cfg := &openevec.EdenSetupArgs{} + currentPath, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + cfg := openevec.GetDefaultConfig(currentPath) var configCmd = &cobra.Command{ Use: "config", Short: "work with config", @@ -69,17 +75,16 @@ func newConfigAddCmd(cfg *openevec.EdenSetupArgs) *cobra.Command { fmt.Sprintf("device model (%s/%s/%s/%s)", defaults.DefaultQemuModel, defaults.DefaultRPIModel, defaults.DefaultGCPModel, defaults.DefaultGeneralModel)) configAddCmd.Flags().StringVar(&contextFile, "file", "", "file with config to add") - //not used in function configAddCmd.Flags().StringVarP(&cfg.Eve.QemuFileToSave, "qemu-config", "", defaults.DefaultQemuFileToSave, "file to save config") - configAddCmd.Flags().IntVarP(&cfg.Eve.QemuCpus, "cpus", "", defaults.DefaultCpus, "cpus") - configAddCmd.Flags().IntVarP(&cfg.Eve.QemuMemory, "memory", "", defaults.DefaultMemory, "memory (MB)") - configAddCmd.Flags().StringSliceVarP(&cfg.Eve.QemuFirmware, "eve-firmware", "", nil, "firmware path") - configAddCmd.Flags().StringVarP(&cfg.Eve.QemuConfigPath, "config-part", "", "", "path for config drive") - configAddCmd.Flags().StringVarP(&cfg.Eve.QemuDTBPath, "dtb-part", "", "", "path for device tree drive (for arm)") - configAddCmd.Flags().StringToStringVarP(&cfg.Eve.HostFwd, "eve-hostfwd", "", defaults.DefaultQemuHostFwd, "port forward map") - configAddCmd.Flags().StringVar(&cfg.Eve.Ssid, "ssid", "", "set ssid of wifi for rpi") - configAddCmd.Flags().StringVar(&cfg.Eve.Arch, "arch", "", "arch of EVE (amd64 or arm64)") - configAddCmd.Flags().StringVar(&cfg.Eve.ModelFile, "devmodel-file", "", "File to use for overwrite of model defaults") + configAddCmd.Flags().IntVarP(&cfg.Eve.QemuCpus, "cpus", "", cfg.Eve.QemuCpus, "cpus") + configAddCmd.Flags().IntVarP(&cfg.Eve.QemuMemory, "memory", "", cfg.Eve.QemuMemory, "memory (MB)") + configAddCmd.Flags().StringSliceVarP(&cfg.Eve.QemuFirmware, "eve-firmware", "", cfg.Eve.QemuFirmware, "firmware path") + configAddCmd.Flags().StringVarP(&cfg.Eve.QemuConfigPath, "config-part", "", cfg.Eve.QemuConfigPath, "path for config drive") + configAddCmd.Flags().StringVarP(&cfg.Eve.QemuDTBPath, "dtb-part", "", cfg.Eve.QemuDTBPath, "path for device tree drive (for arm)") + configAddCmd.Flags().StringToStringVarP(&cfg.Eve.HostFwd, "eve-hostfwd", "", cfg.Eve.HostFwd, "port forward map") + configAddCmd.Flags().StringVar(&cfg.Eve.Ssid, "ssid", cfg.Eve.Ssid, "set ssid of wifi for rpi") + configAddCmd.Flags().StringVar(&cfg.Eve.Arch, "arch", cfg.Eve.Arch, "arch of EVE (amd64 or arm64)") + configAddCmd.Flags().StringVar(&cfg.Eve.ModelFile, "devmodel-file", cfg.Eve.ModelFile, "File to use for overwrite of model defaults") configAddCmd.Flags().BoolVarP(&force, "force", "", false, "force overwrite config file") return configAddCmd diff --git a/pkg/openevec/edenConfig.go b/pkg/openevec/edenConfig.go index ea5ed5de1..44599161a 100644 --- a/pkg/openevec/edenConfig.go +++ b/pkg/openevec/edenConfig.go @@ -6,9 +6,9 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "github.com/lf-edge/eden/pkg/defaults" - "github.com/lf-edge/eden/pkg/models" "github.com/lf-edge/eden/pkg/utils" log "github.com/sirupsen/logrus" "github.com/spf13/viper" @@ -27,34 +27,6 @@ func isEncodingNeeded(contextKeySet string) bool { return false } -func ReloadConfigDetails(cfg *EdenSetupArgs) error { - viperLoaded, err := utils.LoadConfigFile(cfg.ConfigFile) - if err != nil { - return fmt.Errorf("error reading config: %w", err) - } - if viperLoaded { - cfg.Eve.QemuFirmware = viper.GetStringSlice("eve.firmware") - cfg.Eve.QemuConfigPath = utils.ResolveAbsPath(viper.GetString("eve.config-part")) - cfg.Eve.QemuDTBPath = utils.ResolveAbsPath(viper.GetString("eve.dtb-part")) - cfg.Eve.ImageFile = utils.ResolveAbsPath(viper.GetString("eve.image-file")) - cfg.Eve.HostFwd = viper.GetStringMapString("eve.hostfwd") - cfg.Eve.QemuFileToSave = utils.ResolveAbsPath(viper.GetString("eve.qemu-config")) - cfg.Eve.DevModel = viper.GetString("eve.devmodel") - cfg.Eve.Remote = viper.GetBool("eve.remote") - cfg.Eve.ModelFile = viper.GetString("eve.devmodelfile") - if cfg.Eve.ModelFile != "" { - filePath, err := filepath.Abs(cfg.Eve.ModelFile) - if err != nil { - return fmt.Errorf("cannot get absolute path for devmodelfile (%s): %w", cfg.Eve.ModelFile, err) - } - if _, err := os.Stat(filePath); err != nil { - return fmt.Errorf("cannot parse devmodelfile (%s): %w", cfg.Eve.ModelFile, err) - } - } - } - return nil -} - func ConfigAdd(cfg *EdenSetupArgs, currentContext, contextFile string, force bool) error { var err error if cfg.ConfigFile == "" { @@ -63,10 +35,6 @@ func ConfigAdd(cfg *EdenSetupArgs, currentContext, contextFile string, force boo return fmt.Errorf("fail in DefaultConfigPath: %w", err) } } - model, err := models.GetDevModelByName(cfg.Eve.DevModel) - if err != nil { - return fmt.Errorf("GetDevModelByName: %w", err) - } if _, err := os.Stat(cfg.ConfigFile); !os.IsNotExist(err) { if force { if err := os.Remove(cfg.ConfigFile); err != nil { @@ -76,21 +44,27 @@ func ConfigAdd(cfg *EdenSetupArgs, currentContext, contextFile string, force boo log.Debugf("current config already exists: %s", cfg.ConfigFile) } } - if _, err = os.Stat(cfg.ConfigFile); os.IsNotExist(err) { - if err = utils.GenerateConfigFile(cfg.ConfigFile); err != nil { - return fmt.Errorf("fail in generate yaml: %w", err) + + context, err := utils.ContextInit() + if err != nil { + return fmt.Errorf("Load context error: %w", err) + } + + if _, err := os.Stat(cfg.ConfigFile); os.IsNotExist(err) { + if err := os.MkdirAll(filepath.Dir(cfg.ConfigFile), 0755); err != nil { + return fmt.Errorf("Error creating folders: %v", err) + } + file, err := os.Create(cfg.ConfigFile) + if err != nil { + return fmt.Errorf("Error creating file %v", err) } + defer file.Close() + + WriteConfig(reflect.ValueOf(*cfg), file, 0) + log.Infof("Config file generated: %s", cfg.ConfigFile) } - if err := ReloadConfigDetails(cfg); err != nil { - return err - } - context, err := utils.ContextLoad() - if err != nil { - return fmt.Errorf("load context error: %w", err) - } - currentContextName := context.Current if currentContext != "" { context.Current = currentContext } else { @@ -102,48 +76,9 @@ func ConfigAdd(cfg *EdenSetupArgs, currentContext, contextFile string, force boo return fmt.Errorf("cannot copy file: %w", err) } log.Infof("Context file generated: %s", contextFile) - } else { - if _, err := os.Stat(cfg.ConfigFile); os.IsNotExist(err) { - if err = utils.GenerateConfigFileDiff(cfg.ConfigFile, context); err != nil { - return fmt.Errorf("error generate config: %w", err) - } - log.Infof("Context file generated: %s", cfg.ConfigFile) - } else { - log.Infof("Config file already exists %s", cfg.ConfigFile) - } - } - context.SetContext(context.Current) - if err := ReloadConfigDetails(cfg); err != nil { - return err } - // we prepare viper config here from EdenSetupArgs - // to feed into GenerateConfigFileFromViper - - if cfg.Eve.Arch != "" { - viper.Set("eve.arch", cfg.Eve.Arch) - imageDist := fmt.Sprintf("%s-%s", context.Current, defaults.DefaultImageDist) - switch cfg.Eve.Arch { - case "amd64": - viper.Set("eve.firmware", []string{filepath.Join(imageDist, "eve", "OVMF_CODE.fd"), - filepath.Join(imageDist, "eve", "OVMF_VARS.fd")}) - case "arm64": - viper.Set("eve.firmware", []string{filepath.Join(imageDist, "eve", "OVMF.fd")}) - } - } - if cfg.Eve.Ssid != "" { - viper.Set("eve.ssid", cfg.Eve.Ssid) - } - - for k, v := range model.Config() { - viper.Set(k, v) - } - - if err = utils.GenerateConfigFileFromViper(); err != nil { - return fmt.Errorf("error writing config: %w", err) - } - context.SetContext(currentContextName) - + context.Save() return nil } @@ -347,9 +282,6 @@ func ConfigDelete(target string, cfg *EdenSetupArgs) error { } context.Current = target configFile := context.GetCurrentConfig() - if err := ReloadConfigDetails(cfg); err != nil { - log.Infof("Failed to ReloadConfigDetails: %s", err.Error()) - } if _, err := os.Stat(cfg.Eve.QemuFileToSave); !os.IsNotExist(err) { if err := os.Remove(cfg.Eve.QemuFileToSave); err == nil { log.Infof("deleted qemu config %s", cfg.Eve.QemuFileToSave) From adbe4a59b3be01d5b44ab64e8c69fa84821f2ac9 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 12 Jun 2023 13:56:48 +0200 Subject: [PATCH 16/20] Create cli folder under cmd Following golang bestpractices eden CLI is moved into its own folder under cmd folder. That way we can create other applications using eden packages for instance integration tests Signed-off-by: Pavel Abramov --- Makefile | 2 +- cmd/{ => cli}/adam.go | 0 cmd/{ => cli}/certs.go | 0 cmd/{ => cli}/commandGroup.go | 0 cmd/{ => cli}/debug.go | 0 cmd/{ => cli}/disks.go | 0 cmd/{ => cli}/downloader.go | 0 cmd/{ => cli}/edenClean.go | 0 cmd/{ => cli}/edenConfig.go | 0 cmd/{ => cli}/edenController.go | 0 cmd/{ => cli}/edenGcp.go | 0 cmd/{ => cli}/edenNetwork.go | 0 cmd/{ => cli}/edenPacket.go | 0 cmd/{ => cli}/edenPod.go | 0 cmd/{ => cli}/edenRol.go | 0 cmd/{ => cli}/edenSetup.go | 0 cmd/{ => cli}/edenStart.go | 0 cmd/{ => cli}/edenStatus.go | 0 cmd/{ => cli}/edenStop.go | 0 cmd/{ => cli}/edenTest.go | 0 cmd/{ => cli}/edenUtils.go | 0 cmd/{ => cli}/edenVolume.go | 0 cmd/{ => cli}/eserver.go | 0 cmd/{ => cli}/eve.go | 0 cmd/{ => cli}/flowlog.go | 0 cmd/{ => cli}/info.go | 0 cmd/{ => cli}/log.go | 0 cmd/{ => cli}/metric.go | 0 cmd/{ => cli}/ociimage.go | 0 cmd/{ => cli}/redis.go | 0 cmd/{ => cli}/registry.go | 0 cmd/{ => cli}/root.go | 0 cmd/{ => cli}/sdn.go | 0 main.go | 2 +- 34 files changed, 2 insertions(+), 2 deletions(-) rename cmd/{ => cli}/adam.go (100%) rename cmd/{ => cli}/certs.go (100%) rename cmd/{ => cli}/commandGroup.go (100%) rename cmd/{ => cli}/debug.go (100%) rename cmd/{ => cli}/disks.go (100%) rename cmd/{ => cli}/downloader.go (100%) rename cmd/{ => cli}/edenClean.go (100%) rename cmd/{ => cli}/edenConfig.go (100%) rename cmd/{ => cli}/edenController.go (100%) rename cmd/{ => cli}/edenGcp.go (100%) rename cmd/{ => cli}/edenNetwork.go (100%) rename cmd/{ => cli}/edenPacket.go (100%) rename cmd/{ => cli}/edenPod.go (100%) rename cmd/{ => cli}/edenRol.go (100%) rename cmd/{ => cli}/edenSetup.go (100%) rename cmd/{ => cli}/edenStart.go (100%) rename cmd/{ => cli}/edenStatus.go (100%) rename cmd/{ => cli}/edenStop.go (100%) rename cmd/{ => cli}/edenTest.go (100%) rename cmd/{ => cli}/edenUtils.go (100%) rename cmd/{ => cli}/edenVolume.go (100%) rename cmd/{ => cli}/eserver.go (100%) rename cmd/{ => cli}/eve.go (100%) rename cmd/{ => cli}/flowlog.go (100%) rename cmd/{ => cli}/info.go (100%) rename cmd/{ => cli}/log.go (100%) rename cmd/{ => cli}/metric.go (100%) rename cmd/{ => cli}/ociimage.go (100%) rename cmd/{ => cli}/redis.go (100%) rename cmd/{ => cli}/registry.go (100%) rename cmd/{ => cli}/root.go (100%) rename cmd/{ => cli}/sdn.go (100%) diff --git a/Makefile b/Makefile index 2c9187649..be6fd4744 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,7 @@ install: build CGO_ENABLED=0 go install . build: $(BIN) $(EMPTY_DRIVE).raw $(EMPTY_DRIVE).qcow2 $(EMPTY_DRIVE).qcow $(EMPTY_DRIVE).vmdk $(EMPTY_DRIVE).vhdx $(LINUXKIT) -$(LOCALBIN): $(BINDIR) cmd/*.go pkg/*/*.go pkg/*/*/*.go +$(LOCALBIN): $(BINDIR) cmd/cli/*.go pkg/*/*.go pkg/*/*/*.go CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -ldflags "-s -w" -o $@ . mkdir -p dist/scripts/shell cp -r shell-scripts/* dist/scripts/shell/ diff --git a/cmd/adam.go b/cmd/cli/adam.go similarity index 100% rename from cmd/adam.go rename to cmd/cli/adam.go diff --git a/cmd/certs.go b/cmd/cli/certs.go similarity index 100% rename from cmd/certs.go rename to cmd/cli/certs.go diff --git a/cmd/commandGroup.go b/cmd/cli/commandGroup.go similarity index 100% rename from cmd/commandGroup.go rename to cmd/cli/commandGroup.go diff --git a/cmd/debug.go b/cmd/cli/debug.go similarity index 100% rename from cmd/debug.go rename to cmd/cli/debug.go diff --git a/cmd/disks.go b/cmd/cli/disks.go similarity index 100% rename from cmd/disks.go rename to cmd/cli/disks.go diff --git a/cmd/downloader.go b/cmd/cli/downloader.go similarity index 100% rename from cmd/downloader.go rename to cmd/cli/downloader.go diff --git a/cmd/edenClean.go b/cmd/cli/edenClean.go similarity index 100% rename from cmd/edenClean.go rename to cmd/cli/edenClean.go diff --git a/cmd/edenConfig.go b/cmd/cli/edenConfig.go similarity index 100% rename from cmd/edenConfig.go rename to cmd/cli/edenConfig.go diff --git a/cmd/edenController.go b/cmd/cli/edenController.go similarity index 100% rename from cmd/edenController.go rename to cmd/cli/edenController.go diff --git a/cmd/edenGcp.go b/cmd/cli/edenGcp.go similarity index 100% rename from cmd/edenGcp.go rename to cmd/cli/edenGcp.go diff --git a/cmd/edenNetwork.go b/cmd/cli/edenNetwork.go similarity index 100% rename from cmd/edenNetwork.go rename to cmd/cli/edenNetwork.go diff --git a/cmd/edenPacket.go b/cmd/cli/edenPacket.go similarity index 100% rename from cmd/edenPacket.go rename to cmd/cli/edenPacket.go diff --git a/cmd/edenPod.go b/cmd/cli/edenPod.go similarity index 100% rename from cmd/edenPod.go rename to cmd/cli/edenPod.go diff --git a/cmd/edenRol.go b/cmd/cli/edenRol.go similarity index 100% rename from cmd/edenRol.go rename to cmd/cli/edenRol.go diff --git a/cmd/edenSetup.go b/cmd/cli/edenSetup.go similarity index 100% rename from cmd/edenSetup.go rename to cmd/cli/edenSetup.go diff --git a/cmd/edenStart.go b/cmd/cli/edenStart.go similarity index 100% rename from cmd/edenStart.go rename to cmd/cli/edenStart.go diff --git a/cmd/edenStatus.go b/cmd/cli/edenStatus.go similarity index 100% rename from cmd/edenStatus.go rename to cmd/cli/edenStatus.go diff --git a/cmd/edenStop.go b/cmd/cli/edenStop.go similarity index 100% rename from cmd/edenStop.go rename to cmd/cli/edenStop.go diff --git a/cmd/edenTest.go b/cmd/cli/edenTest.go similarity index 100% rename from cmd/edenTest.go rename to cmd/cli/edenTest.go diff --git a/cmd/edenUtils.go b/cmd/cli/edenUtils.go similarity index 100% rename from cmd/edenUtils.go rename to cmd/cli/edenUtils.go diff --git a/cmd/edenVolume.go b/cmd/cli/edenVolume.go similarity index 100% rename from cmd/edenVolume.go rename to cmd/cli/edenVolume.go diff --git a/cmd/eserver.go b/cmd/cli/eserver.go similarity index 100% rename from cmd/eserver.go rename to cmd/cli/eserver.go diff --git a/cmd/eve.go b/cmd/cli/eve.go similarity index 100% rename from cmd/eve.go rename to cmd/cli/eve.go diff --git a/cmd/flowlog.go b/cmd/cli/flowlog.go similarity index 100% rename from cmd/flowlog.go rename to cmd/cli/flowlog.go diff --git a/cmd/info.go b/cmd/cli/info.go similarity index 100% rename from cmd/info.go rename to cmd/cli/info.go diff --git a/cmd/log.go b/cmd/cli/log.go similarity index 100% rename from cmd/log.go rename to cmd/cli/log.go diff --git a/cmd/metric.go b/cmd/cli/metric.go similarity index 100% rename from cmd/metric.go rename to cmd/cli/metric.go diff --git a/cmd/ociimage.go b/cmd/cli/ociimage.go similarity index 100% rename from cmd/ociimage.go rename to cmd/cli/ociimage.go diff --git a/cmd/redis.go b/cmd/cli/redis.go similarity index 100% rename from cmd/redis.go rename to cmd/cli/redis.go diff --git a/cmd/registry.go b/cmd/cli/registry.go similarity index 100% rename from cmd/registry.go rename to cmd/cli/registry.go diff --git a/cmd/root.go b/cmd/cli/root.go similarity index 100% rename from cmd/root.go rename to cmd/cli/root.go diff --git a/cmd/sdn.go b/cmd/cli/sdn.go similarity index 100% rename from cmd/sdn.go rename to cmd/cli/sdn.go diff --git a/main.go b/main.go index 356ee8d3f..0f5ae434d 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/lf-edge/eden/cmd" + cmd "github.com/lf-edge/eden/cmd/cli" ) func main() { From 5cf017e6edb7e7b808d7ba405f1ddebda19fe17b Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Mon, 12 Jun 2023 13:58:36 +0200 Subject: [PATCH 17/20] Move tests into its cmd Integration tests will have their own binary and files used since it will all be stored in its own cmd folder Signed-off-by: Pavel Abramov --- {pkg/openevec => cmd/patchwork}/main_test.go | 0 {pkg/openevec => cmd/patchwork}/mount_test.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {pkg/openevec => cmd/patchwork}/main_test.go (100%) rename {pkg/openevec => cmd/patchwork}/mount_test.go (100%) diff --git a/pkg/openevec/main_test.go b/cmd/patchwork/main_test.go similarity index 100% rename from pkg/openevec/main_test.go rename to cmd/patchwork/main_test.go diff --git a/pkg/openevec/mount_test.go b/cmd/patchwork/mount_test.go similarity index 100% rename from pkg/openevec/mount_test.go rename to cmd/patchwork/mount_test.go From d748e9e06e61403f897bebaf789303f37c6a3d01 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Wed, 5 Jul 2023 09:48:57 +0200 Subject: [PATCH 18/20] Move redis cmd to openevec Signed-off-by: Pavel Abramov --- cmd/cli/redis.go | 2 +- cmd/patchwork/main_test.go | 67 ++++++++++++++++++++++++---------- cmd/patchwork/mount_test.go | 30 +++++++++------- cmd/patchwork/utils.go | 72 +++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 32 deletions(-) create mode 100644 cmd/patchwork/utils.go diff --git a/cmd/cli/redis.go b/cmd/cli/redis.go index dd4319601..f29d9b0c5 100644 --- a/cmd/cli/redis.go +++ b/cmd/cli/redis.go @@ -45,7 +45,7 @@ func newStartRedisCmd(cfg *openevec.EdenSetupArgs) *cobra.Command { log.Fatalf("cannot obtain executable path: %s", err) } log.Infof("Executable path: %s", command) - if err := eden.StartRedis(cfg.Redis.Port, cfg.Redis.Dist, cfg.Redis.Force, cfg.Redis.Tag); err != nil { + if err := openevec.StartRedis(*cfg); err != nil { log.Errorf("cannot start redis: %s", err) } else { log.Infof("Redis is running and accessible on port %d", cfg.Redis.Port) diff --git a/cmd/patchwork/main_test.go b/cmd/patchwork/main_test.go index 55c6284ce..ac3cf1f1b 100644 --- a/cmd/patchwork/main_test.go +++ b/cmd/patchwork/main_test.go @@ -1,53 +1,82 @@ -package openevec +package patchwork import ( + "errors" + "fmt" "os" "path/filepath" "testing" "github.com/lf-edge/eden/pkg/defaults" + "github.com/lf-edge/eden/pkg/eden" + ec "github.com/lf-edge/eden/pkg/openevec" "github.com/lf-edge/eden/pkg/utils" ) -func setup() { - cfg := GetDefaultConfig(curPath) +func setup(cfg *ec.EdenSetupArgs) error { - err := SetupEden(&cfg.ConfigName, - filepath.Join(curPath, "eve-config-dir"), + edenDir, err := utils.DefaultEdenDir() + if err != nil { + return err + } + + // We need eden dir since we are storing certificates there + if _, err := os.Stat(edenDir); errors.Is(err, os.ErrNotExist) { + err := os.Mkdir(edenDir, os.ModePerm) + if err != nil { + return err + } + } + + err = ec.SetupEden(cfg.ConfigName, filepath.Join(cfg.Eden.Root, "eve-config-dir"), - "", "", "", []string{}, false, false, cfg) + "", "", "", []string{}, false, false, *cfg) if err != nil { - panic("Setup Failed") + return err } - if err = StartEden(cfg, defaults.DefaultVBoxVMName, "", ""); err != nil { - panic("Start failed") + if err = ec.StartEden(cfg, defaults.DefaultVBoxVMName, "", ""); err != nil { + return err } - if err = OnboardEve(cfg.Eve.CertsUUID); err != nil { - panic("Onboard failed") + if err = ec.OnboardEve(cfg.Eve.CertsUUID); err != nil { + return err } + return nil } -func teardown() { - cfg := GetDefaultConfig() - StopEden(false, false, false, false, cfg.Eve.Remote, cfg.Eve.Pid, swtpmPidFile(cfg), cfg.Sdn.PidFile, cfg.Eve.DevModel, defautls.DefaultVBoxVMName) +func teardown(cfg *ec.EdenSetupArgs) error { + eden.StopEden(false, false, false, false, cfg.Eve.Remote, cfg.Eve.Pid, ec.SwtpmPidFile(cfg), cfg.Sdn.PidFile, cfg.Eve.DevModel, defaults.DefaultVBoxVMName) configDist, err := utils.DefaultEdenDir() if err != nil { - panic() + return err } - err = EdenClean(cfg, cfg.ConfigName, configDist, defaults.DefaultVBoxVMName, false) + err = ec.EdenClean(*cfg, cfg.ConfigName, configDist, defaults.DefaultVBoxVMName, false) if err != nil { - panic() + return err } + return nil } func TestMain(m *testing.M) { - setup() + curPath, err := os.Getwd() + if err != nil { + // Getwd failed + os.Exit(1) + } + cfg := ec.GetDefaultConfig(curPath) + + if err = setup(cfg); err != nil { + fmt.Printf("Error setup %v", err) + os.Exit(1) + } code := m.Run() - teardown() + if err = teardown(cfg); err != nil { + fmt.Printf("Error setup %v", err) + os.Exit(1) + } os.Exit(code) } diff --git a/cmd/patchwork/mount_test.go b/cmd/patchwork/mount_test.go index c37a967b5..3d2c680c7 100644 --- a/cmd/patchwork/mount_test.go +++ b/cmd/patchwork/mount_test.go @@ -1,7 +1,8 @@ -package openevec +package patchwork import ( "fmt" + "os" "path/filepath" "testing" "time" @@ -9,6 +10,7 @@ import ( "github.com/lf-edge/eden/pkg/controller" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/eve" + ec "github.com/lf-edge/eden/pkg/openevec" ) func TestEclientMount(t *testing.T) { @@ -25,8 +27,12 @@ func TestEclientMount(t *testing.T) { devUUID := devFirst.GetID() port := 2223 - cfg := GetDefaultConfig() - pc := GetDefaultPodConfig() + curPath, err := os.Getwd() + if err != nil { + t.Errorf("Getwd error: %v", err) + } + cfg := ec.GetDefaultConfig(curPath) + pc := ec.GetDefaultPodConfig() pc.PortPublish = []string{fmt.Sprint(port)} podName := "eclient-mount" pc.Mount = []string{ @@ -35,7 +41,7 @@ func TestEclientMount(t *testing.T) { } appLink := fmt.Sprintf("docker://%s:%s", defaults.DefaultEClientTag, defaults.DefaultEClientContainerRef) - if err = PodDeploy(appLink, *pc, cfg); err != nil { + if err = ec.PodDeploy(appLink, *pc, cfg); err != nil { t.Errorf("PodDeploy error: %v", err) return } @@ -50,7 +56,7 @@ func TestEclientMount(t *testing.T) { ETestsFolder := filepath.Join(cfg.Eden.Root, "tests") sshCmd := fmt.Sprintf("ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o PasswordAuthentication=no -i %s/eclient/image/cert/id_rsa root@FWD_IP -p FWD_PORT ls", ETestsFolder) sshOut, err := withCapturingStdout(func() error { - if err := SdnForwardCmd("", "eth0", port, sshCmd+"/tst", cfg); err != nil { + if err := ec.SdnForwardCmd("", "eth0", port, sshCmd+"/tst", cfg); err != nil { return fmt.Errorf("ssh to tst failed") } return nil @@ -63,7 +69,7 @@ func TestEclientMount(t *testing.T) { } sshOut, err = withCapturingStdout(func() error { - if err := SdnForwardCmd("", "eth0", port, sshCmd+"/dir", cfg); err != nil { + if err := ec.SdnForwardCmd("", "eth0", port, sshCmd+"/dir", cfg); err != nil { return fmt.Errorf("ssh to dir failed") } return nil @@ -76,7 +82,7 @@ func TestEclientMount(t *testing.T) { } sshOut, err = withCapturingStdout(func() error { - return VolumeLs() + return ec.VolumeLs() }) if err != nil { t.Error(err) @@ -86,7 +92,7 @@ func TestEclientMount(t *testing.T) { } volumeName := "eclient-mount_1_m_0" - if err := VolumeDetach(volumeName); err != nil { + if err := ec.VolumeDetach(volumeName); err != nil { t.Errorf("Volume detach failed") return } @@ -97,7 +103,7 @@ func TestEclientMount(t *testing.T) { } sshOut, err = withCapturingStdout(func() error { - if err := SdnForwardCmd("", "eth0", port, sshCmd+"/dst", cfg); err != nil { + if err := ec.SdnForwardCmd("", "eth0", port, sshCmd+"/dst", cfg); err != nil { return fmt.Errorf("ssh to dst failed") } return nil @@ -110,7 +116,7 @@ func TestEclientMount(t *testing.T) { } sshOut, err = withCapturingStdout(func() error { - return VolumeLs() + return ec.VolumeLs() }) if err != nil { t.Error(err) @@ -119,13 +125,13 @@ func TestEclientMount(t *testing.T) { t.Errorf("Volume ls failed") } - if _, err := PodDelete(podName, true); err != nil { + if _, err := ec.PodDelete(podName, true); err != nil { t.Errorf("PodDelete failed") return } // check that podName was deleted - if err := ResetEve(cfg.Eve.CertsUUID); err != nil { + if err := ec.ResetEve(cfg.Eve.CertsUUID); err != nil { t.Errorf("Resetting EVE failed") return } diff --git a/cmd/patchwork/utils.go b/cmd/patchwork/utils.go new file mode 100644 index 000000000..a5a2a3173 --- /dev/null +++ b/cmd/patchwork/utils.go @@ -0,0 +1,72 @@ +package patchwork + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "strings" + "time" + + "github.com/lf-edge/eden/pkg/controller" + "github.com/lf-edge/eden/pkg/controller/einfo" + "github.com/lf-edge/eden/pkg/eve" + "github.com/lf-edge/eve/api/go/info" + uuid "github.com/satori/go.uuid" +) + +func checkAppState(ctrl controller.Cloud, devUUID uuid.UUID, appName string, eveState *eve.State, expState string, timeout time.Duration) error { + startTime := time.Now() + + // Waiting for 15 min maximum to get eclient-mount app in state running + handleInfo := func(im *info.ZInfoMsg) bool { + eveState.InfoCallback()(im) + for _, s := range eveState.Applications() { + if s.Name == appName { + if s.EVEState == expState { + return true + } + } + } + if time.Now().After(startTime.Add(timeout)) { + log.Fatal("eclient-mount timeout") + } + return false + } + + if err := ctrl.InfoChecker(devUUID, nil, handleInfo, einfo.InfoNew, 0); err != nil { + return fmt.Errorf("eclient-mount RUNNING state InfoChecker: %w", err) + } + + return nil +} + +func withCapturingStdout(f func() error) ([]byte, error) { + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + err := f() + + w.Close() + out, _ := ioutil.ReadAll(r) + os.Stdout = rescueStdout + + return out, err +} + +func checkOutput(input string, shouldHave, shouldNotHave []string) error { + for _, str := range shouldHave { + if !strings.Contains(input, str) { + return fmt.Errorf("Input does not contain %v", str) + } + } + + for _, str := range shouldNotHave { + if strings.Contains(input, str) { + return fmt.Errorf("Input contains %v", str) + } + } + + return nil +} From 1ddffa283620738ce432b33dbb854ad3040ffcec Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Wed, 5 Jul 2023 09:49:50 +0200 Subject: [PATCH 19/20] Temp commit for pkg Signed-off-by: Pavel Abramov --- pkg/eden/eden.go | 143 +-------------------------------- pkg/openevec/adam.go | 96 +++++++++++++++++++++- pkg/openevec/config.go | 9 ++- pkg/openevec/config_context.go | 23 ++++++ pkg/openevec/config_test.go | 2 +- pkg/openevec/defaults.go | 2 +- pkg/openevec/eden.go | 56 ++++++++----- pkg/openevec/eden_test.go | 41 ++++++++++ pkg/openevec/onboard.go | 6 +- pkg/openevec/start.go | 54 +++++++++++-- pkg/openevec/utils.go | 62 -------------- pkg/utils/context.go | 7 +- 12 files changed, 260 insertions(+), 241 deletions(-) create mode 100644 pkg/openevec/config_context.go create mode 100644 pkg/openevec/eden_test.go diff --git a/pkg/eden/eden.go b/pkg/eden/eden.go index 56c844f6a..e3f9710f9 100644 --- a/pkg/eden/eden.go +++ b/pkg/eden/eden.go @@ -37,52 +37,6 @@ import ( const bootstrapFilename = "bootstrap-config.pb" -// StartRedis function run redis in docker with mounted redisPath:/data -// if redisForce is set, it recreates container -func StartRedis(redisPort int, redisPath string, redisForce bool, redisTag string) (err error) { - portMap := map[string]string{"6379": strconv.Itoa(redisPort)} - volumeMap := map[string]string{"/data": redisPath} - redisServerCommand := strings.Fields("redis-server --appendonly yes") - edenHome, err := utils.DefaultEdenDir() - if err != nil { - return err - } - globalCertsDir := filepath.Join(edenHome, defaults.DefaultCertsDist) - redisPasswordFile := filepath.Join(globalCertsDir, defaults.DefaultRedisPasswordFile) - pwd, err := ioutil.ReadFile(redisPasswordFile) - if err == nil { - redisServerCommand = append(redisServerCommand, strings.Fields(fmt.Sprintf("--requirepass %s", string(pwd)))...) - } else { - log.Errorf("cannot read redis password: %v", err) - } - if redisPath != "" { - if err = os.MkdirAll(redisPath, 0755); err != nil { - return fmt.Errorf("StartRedis: Cannot create directory for redis (%s): %s", redisPath, err) - } - } - if redisForce { - _ = utils.StopContainer(defaults.DefaultRedisContainerName, true) - if err := utils.CreateAndRunContainer(defaults.DefaultRedisContainerName, defaults.DefaultRedisContainerRef+":"+redisTag, portMap, volumeMap, redisServerCommand, nil); err != nil { - return fmt.Errorf("StartRedis: error in create redis container: %s", err) - } - } else { - state, err := utils.StateContainer(defaults.DefaultRedisContainerName) - if err != nil { - return fmt.Errorf("StartRedis: error in get state of redis container: %s", err) - } - if state == "" { - if err := utils.CreateAndRunContainer(defaults.DefaultRedisContainerName, defaults.DefaultRedisContainerRef+":"+redisTag, portMap, volumeMap, redisServerCommand, nil); err != nil { - return fmt.Errorf("StartRedis: error in create redis container: %s", err) - } - } else if !strings.Contains(state, "running") { - if err := utils.StartContainer(defaults.DefaultRedisContainerName); err != nil { - return fmt.Errorf("StartRedis: error in restart redis container: %s", err) - } - } - } - return nil -} - // StopRedis function stop redis container func StopRedis(redisRm bool) (err error) { state, err := utils.StateContainer(defaults.DefaultRedisContainerName) @@ -123,97 +77,6 @@ func StatusRedis() (status string, err error) { return state, nil } -// StartAdam function run adam in docker with mounted adamPath/run:/adam/run -// if adamForce is set, it recreates container -func StartAdam(adamPort int, adamPath string, adamForce bool, adamTag string, adamRemoteRedisURL string, apiV1 bool, opts ...string) (err error) { - edenHome, err := utils.DefaultEdenDir() - if err != nil { - return err - } - globalCertsDir := filepath.Join(edenHome, defaults.DefaultCertsDist) - serverCertPath := filepath.Join(globalCertsDir, "server.pem") - serverKeyPath := filepath.Join(globalCertsDir, "server-key.pem") - cert, err := ioutil.ReadFile(serverCertPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", serverCertPath, err) - } - key, err := ioutil.ReadFile(serverKeyPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", serverKeyPath, err) - } - envs := []string{ - fmt.Sprintf("SERVER_CERT=%s", cert), - fmt.Sprintf("SERVER_KEY=%s", key), - } - if !apiV1 { - signingCertPath := filepath.Join(globalCertsDir, "signing.pem") - signingKeyPath := filepath.Join(globalCertsDir, "signing-key.pem") - signingCert, err := ioutil.ReadFile(signingCertPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", signingCertPath, err) - } - signingKey, err := ioutil.ReadFile(signingKeyPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", signingKeyPath, err) - } - envs = append(envs, fmt.Sprintf("SIGNING_CERT=%s", signingCert)) - envs = append(envs, fmt.Sprintf("SIGNING_KEY=%s", signingKey)) - - encryptCertPath := filepath.Join(globalCertsDir, "encrypt.pem") - encryptKeyPath := filepath.Join(globalCertsDir, "encrypt-key.pem") - encryptCert, err := ioutil.ReadFile(encryptCertPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", encryptCertPath, err) - } - encryptKey, err := ioutil.ReadFile(encryptKeyPath) - if err != nil { - return fmt.Errorf("StartAdam: cannot load %s: %s", encryptKeyPath, err) - } - envs = append(envs, fmt.Sprintf("ENCRYPT_CERT=%s", encryptCert)) - envs = append(envs, fmt.Sprintf("ENCRYPT_KEY=%s", encryptKey)) - } - portMap := map[string]string{"8080": strconv.Itoa(adamPort)} - volumeMap := map[string]string{"/adam/run": fmt.Sprintf("%s/run", adamPath)} - adamServerCommand := strings.Fields("server --conf-dir ./run/conf") - if adamPath == "" { - volumeMap = map[string]string{"/adam/run": ""} - adamServerCommand = strings.Fields("server") - } - if adamRemoteRedisURL != "" { - redisPasswordFile := filepath.Join(globalCertsDir, defaults.DefaultRedisPasswordFile) - pwd, err := ioutil.ReadFile(redisPasswordFile) - if err == nil { - adamRemoteRedisURL = fmt.Sprintf("redis://%s:%s@%s", string(pwd), string(pwd), adamRemoteRedisURL) - } else { - log.Errorf("cannot read redis password: %v", err) - adamRemoteRedisURL = fmt.Sprintf("redis://%s", adamRemoteRedisURL) - } - adamServerCommand = append(adamServerCommand, strings.Fields(fmt.Sprintf("--db-url %s", adamRemoteRedisURL))...) - } - adamServerCommand = append(adamServerCommand, opts...) - if adamForce { - _ = utils.StopContainer(defaults.DefaultAdamContainerName, true) - if err := utils.CreateAndRunContainer(defaults.DefaultAdamContainerName, defaults.DefaultAdamContainerRef+":"+adamTag, portMap, volumeMap, adamServerCommand, envs); err != nil { - return fmt.Errorf("StartAdam: error in create adam container: %s", err) - } - } else { - state, err := utils.StateContainer(defaults.DefaultAdamContainerName) - if err != nil { - return fmt.Errorf("StartAdam: error in get state of adam container: %s", err) - } - if state == "" { - if err := utils.CreateAndRunContainer(defaults.DefaultAdamContainerName, defaults.DefaultAdamContainerRef+":"+adamTag, portMap, volumeMap, adamServerCommand, envs); err != nil { - return fmt.Errorf("StartAdam: error in create adam container: %s", err) - } - } else if !strings.Contains(state, "running") { - if err := utils.StartContainer(defaults.DefaultAdamContainerName); err != nil { - return fmt.Errorf("StartAdam: error in restart adam container: %s", err) - } - } - } - return nil -} - // StopAdam function stop adam container func StopAdam(adamRm bool) (err error) { state, err := utils.StateContainer(defaults.DefaultAdamContainerName) @@ -407,11 +270,7 @@ func GenerateEveCerts(certsDir, domain, ip, eveIP, uuid, devModel, ssid, passwor return fmt.Errorf("GenerateEveCerts: %s", err) } } - edenHome, err := utils.DefaultEdenDir() - if err != nil { - return fmt.Errorf("GenerateEveCerts: %s", err) - } - globalCertsDir := filepath.Join(edenHome, defaults.DefaultCertsDist) + globalCertsDir := filepath.Join(certsDir, defaults.DefaultCertsDist) if _, err := os.Stat(globalCertsDir); os.IsNotExist(err) { if err = os.MkdirAll(globalCertsDir, 0755); err != nil { return fmt.Errorf("GenerateEveCerts: %s", err) diff --git a/pkg/openevec/adam.go b/pkg/openevec/adam.go index b8a76851a..0385ade56 100644 --- a/pkg/openevec/adam.go +++ b/pkg/openevec/adam.go @@ -2,9 +2,14 @@ package openevec import ( "fmt" + "io/ioutil" "os" + "path/filepath" + "strconv" + "strings" - "github.com/lf-edge/eden/pkg/eden" + "github.com/lf-edge/eden/pkg/defaults" + "github.com/lf-edge/eden/pkg/utils" log "github.com/sirupsen/logrus" ) @@ -17,10 +22,97 @@ func AdamStart(cfg *EdenSetupArgs) error { if !cfg.Adam.Remote.Redis { cfg.Adam.Redis.RemoteURL = "" } - if err := eden.StartAdam(cfg.Adam.Port, cfg.Adam.Dist, cfg.Adam.Force, cfg.Adam.Tag, cfg.Adam.Redis.RemoteURL, cfg.Adam.APIv1); err != nil { + if err := StartAdam(cfg.Eden.CertsDir, cfg.Adam); err != nil { log.Errorf("cannot start adam: %s", err.Error()) } else { log.Infof("Adam is running and accessible on port %d", cfg.Adam.Port) } return nil } + +// StartAdam function run adam in docker with mounted adamPath/run:/adam/run +// if adamForce is set, it recreates container +func StartAdam(certsDir string, cfg AdamConfig, opts ...string) (err error) { + globalCertsDir := filepath.Join(certsDir, defaults.DefaultCertsDist) + serverCertPath := filepath.Join(globalCertsDir, "server.pem") + serverKeyPath := filepath.Join(globalCertsDir, "server-key.pem") + cert, err := ioutil.ReadFile(serverCertPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", serverCertPath, err) + } + key, err := ioutil.ReadFile(serverKeyPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", serverKeyPath, err) + } + envs := []string{ + fmt.Sprintf("SERVER_CERT=%s", cert), + fmt.Sprintf("SERVER_KEY=%s", key), + } + if !cfg.APIv1 { + signingCertPath := filepath.Join(globalCertsDir, "signing.pem") + signingKeyPath := filepath.Join(globalCertsDir, "signing-key.pem") + signingCert, err := ioutil.ReadFile(signingCertPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", signingCertPath, err) + } + signingKey, err := ioutil.ReadFile(signingKeyPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", signingKeyPath, err) + } + envs = append(envs, fmt.Sprintf("SIGNING_CERT=%s", signingCert)) + envs = append(envs, fmt.Sprintf("SIGNING_KEY=%s", signingKey)) + + encryptCertPath := filepath.Join(globalCertsDir, "encrypt.pem") + encryptKeyPath := filepath.Join(globalCertsDir, "encrypt-key.pem") + encryptCert, err := ioutil.ReadFile(encryptCertPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", encryptCertPath, err) + } + encryptKey, err := ioutil.ReadFile(encryptKeyPath) + if err != nil { + return fmt.Errorf("StartAdam: cannot load %s: %s", encryptKeyPath, err) + } + envs = append(envs, fmt.Sprintf("ENCRYPT_CERT=%s", encryptCert)) + envs = append(envs, fmt.Sprintf("ENCRYPT_KEY=%s", encryptKey)) + } + portMap := map[string]string{"8080": strconv.Itoa(cfg.Port)} + volumeMap := map[string]string{"/adam/run": fmt.Sprintf("%s/run", cfg.Dist)} + adamServerCommand := strings.Fields("server --conf-dir ./run/conf") + if cfg.Dist == "" { + volumeMap = map[string]string{"/adam/run": ""} + adamServerCommand = strings.Fields("server") + } + if cfg.Redis.RemoteURL != "" { + redisPasswordFile := filepath.Join(globalCertsDir, defaults.DefaultRedisPasswordFile) + pwd, err := ioutil.ReadFile(redisPasswordFile) + if err == nil { + cfg.Redis.RemoteURL = fmt.Sprintf("redis://%s:%s@%s", string(pwd), string(pwd), cfg.Redis.RemoteURL) + } else { + log.Errorf("cannot read redis password: %v", err) + cfg.Redis.RemoteURL = fmt.Sprintf("redis://%s", cfg.Redis.RemoteURL) + } + adamServerCommand = append(adamServerCommand, strings.Fields(fmt.Sprintf("--db-url %s", cfg.Redis.RemoteURL))...) + } + adamServerCommand = append(adamServerCommand, opts...) + if cfg.Force { + _ = utils.StopContainer(defaults.DefaultAdamContainerName, true) + if err := utils.CreateAndRunContainer(defaults.DefaultAdamContainerName, defaults.DefaultAdamContainerRef+":"+cfg.Tag, portMap, volumeMap, adamServerCommand, envs); err != nil { + return fmt.Errorf("StartAdam: error in create adam container: %s", err) + } + } else { + state, err := utils.StateContainer(defaults.DefaultAdamContainerName) + if err != nil { + return fmt.Errorf("StartAdam: error in get state of adam container: %s", err) + } + if state == "" { + if err := utils.CreateAndRunContainer(defaults.DefaultAdamContainerName, defaults.DefaultAdamContainerRef+":"+cfg.Tag, portMap, volumeMap, adamServerCommand, envs); err != nil { + return fmt.Errorf("StartAdam: error in create adam container: %s", err) + } + } else if !strings.Contains(state, "running") { + if err := utils.StartContainer(defaults.DefaultAdamContainerName); err != nil { + return fmt.Errorf("StartAdam: error in restart adam container: %s", err) + } + } + } + return nil +} diff --git a/pkg/openevec/config.go b/pkg/openevec/config.go index f7b39b3cd..b4e9c3108 100644 --- a/pkg/openevec/config.go +++ b/pkg/openevec/config.go @@ -37,7 +37,7 @@ type ImagesConfig struct { type EdenConfig struct { Download bool `mapstructure:"download" cobraflag:"download"` BinDir string `mapstructure:"bin-dist" cobraflag:"bin-dist"` - CertsDir string `mapstructure:"certs-dist" cobraflag:"certs-dist" resolvepath:""` + CertsDir string `mapstructure:"certs-dist" cobraflag:"certs-dist" resolvepath:"global"` Dist string `mapstructure:"dist"` Root string `mapstructure:"root"` SSHKey string `mapstructure:"ssh-key" cobraflag:"ssh-key"` @@ -352,12 +352,17 @@ func WriteConfig(dst reflect.Value, writer io.Writer, nestLevel int) { } func resolvePath(v reflect.Value, edenRoot string) { + edenDir, _ := utils.DefaultEdenDir() for i := 0; i < v.NumField(); i++ { f := v.Field(i) if _, ok := v.Type().Field(i).Tag.Lookup("resolvepath"); ok { if f.IsValid() && f.CanSet() && f.Kind() == reflect.String { val := f.Interface().(string) - f.SetString(utils.ResolveAbsPathWithRoot(val, edenRoot)) + if v.Type().Field(i).Tag.Get("resolvepath") == "global" { + f.SetString(utils.ResolveAbsPathWithRoot(val, edenDir)) + } else { + f.SetString(utils.ResolveAbsPathWithRoot(val, edenRoot)) + } } } if f.Kind() == reflect.Struct { diff --git a/pkg/openevec/config_context.go b/pkg/openevec/config_context.go new file mode 100644 index 000000000..7f85e4903 --- /dev/null +++ b/pkg/openevec/config_context.go @@ -0,0 +1,23 @@ +package openevec + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/lf-edge/eden/pkg/defaults" + "github.com/lf-edge/eden/pkg/utils" +) + +func (cfg EdenSetupArgs) WithContext(name string) EdenSetupArgs { + cfg.Eden.SSHKey = fmt.Sprintf("%s-%s", name, defaults.DefaultSSHKey) + cfg.Eve.Name = strings.ToLower(name) + cfg.Eve.Dist = fmt.Sprintf("%s-%s", name, defaults.DefaultEVEDist) + cfg.Eve.QemuFileToSave = filepath.Join(cfg.EdenDir, fmt.Sprintf("%s-%s", name, defaults.DefaultQemuFileToSave)) + cfg.Eve.Pid = fmt.Sprintf("%s-eve.pid", strings.ToLower(name)) + cfg.Eve.Log = fmt.Sprintf("%s-eve.log", strings.ToLower(name)) + cfg.ConfigName = name + cfg.ConfigFile = utils.GetConfig(name) + + return cfg +} diff --git a/pkg/openevec/config_test.go b/pkg/openevec/config_test.go index e3285c1e9..656332f43 100644 --- a/pkg/openevec/config_test.go +++ b/pkg/openevec/config_test.go @@ -102,7 +102,7 @@ func TestViperSerializeFromWriteConfig(t *testing.T) { v.SetConfigType("yaml") err := v.ReadConfig(&buf) if err != nil { - fmt.Println("error reading config:", err) + t.Errorf("error reading config: %v", err) return } diff --git a/pkg/openevec/defaults.go b/pkg/openevec/defaults.go index 2f8fa819d..08a63562b 100644 --- a/pkg/openevec/defaults.go +++ b/pkg/openevec/defaults.go @@ -48,7 +48,7 @@ func GetDefaultConfig(currentPath string) *EdenSetupArgs { Download: true, BinDir: filepath.Join(defaults.DefaultDist, defaults.DefaultBinDist), SSHKey: fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultSSHKey), - CertsDir: filepath.Join(fmt.Sprintf("%s-%s", defaults.DefaultContext, defaults.DefaultCertsDist)), + CertsDir: fmt.Sprintf("%s", defaults.DefaultCertsDist), TestBin: defaults.DefaultBinDist, EdenBin: "eden.escript.test", TestScenario: defaults.DefaultTestScenario, diff --git a/pkg/openevec/eden.go b/pkg/openevec/eden.go index d0e838ebe..2b4a980ae 100644 --- a/pkg/openevec/eden.go +++ b/pkg/openevec/eden.go @@ -14,6 +14,7 @@ import ( "regexp" "strconv" "strings" + "text/template" "github.com/lf-edge/eden/pkg/controller" "github.com/lf-edge/eden/pkg/controller/eflowlog" @@ -44,28 +45,31 @@ func SwtpmPidFile(cfg *EdenSetupArgs) string { return "" } -func generateScripts(in string, out string, configFile string) error { - tmpl, err := ioutil.ReadFile(in) +// ParseTemplateFile fills EdenSetupArgs variable into +// template stored in file and writes result to io.Writer +func ParseTemplateFile(path string, cfg EdenSetupArgs, w io.Writer) error { + t, err := ioutil.ReadFile(path) if err != nil { return err } - script, err := utils.RenderTemplate(configFile, string(tmpl)) - if err != nil { - return err - } - err = ioutil.WriteFile(out, []byte(script), 0644) + + tmpl, err := template.New("").Parse(string(t)) + if err != nil { return err } + + err = tmpl.Execute(w, cfg) + return nil } func SetupEden(configName, configDir, softSerial, zedControlURL, ipxeOverride string, grubOptions []string, netboot, installer bool, cfg EdenSetupArgs) error { - if err := configCheck(configName); err != nil { - return err - } + //if err := configCheck(configName); err != nil { + // return err + //} if netboot && installer { return fmt.Errorf("please use netboot or installer flag, not both") @@ -363,14 +367,25 @@ func setupEdenScripts(cfg EdenSetupArgs) error { cfgDir, err) } else { shPath := cfg.Eden.Root + "/scripts/shell/" - if err := generateScripts(shPath+"activate.sh.tmpl", - cfgDir+"activate.sh", cfg.ConfigName); err != nil { + + f, err := os.Create(cfgDir + "activate.sh") + if err != nil { return err } - if err := generateScripts(shPath+"activate.csh.tmpl", - cfgDir+"activate.csh", cfg.ConfigName); err != nil { + if err = ParseTemplateFile(shPath+"activate.sh.tmpl", cfg, f); err != nil { return err } + f.Close() + + f, err = os.Create(cfgDir + "activate.csh") + if err != nil { + return err + } + if err = ParseTemplateFile(shPath+"activate.csh.tmpl", cfg, f); err != nil { + return err + } + f.Close() + fmt.Println("To activate EDEN settings run:") fmt.Println("* for BASH/ZSH -- `source ~/.eden/activate.sh`") fmt.Println("* for TCSH -- `source ~/.eden/activate.csh`") @@ -520,7 +535,7 @@ func EdenClean(cfg EdenSetupArgs, configName, configDist, vmName string, current } else { log.Infof("Redis is running and accessible on port %d", cfg.Redis.Port) } - if err := StartAdam(cfg); err != nil { + if err := StartAdamCmd(cfg); err != nil { log.Errorf("cannot start adam: %s", err.Error()) } else { log.Infof("Adam is running and accessible on port %d", cfg.Adam.Port) @@ -723,12 +738,13 @@ func EdenMetric(cfg *EdenSetupArgs, outputFormat types.OutputFormat, follow bool func EdenExport(tarFile string, cfg *EdenSetupArgs) error { changer := &adamChanger{} // we need to obtain information about EVE from Adam - if err := eden.StartRedis(cfg.Redis.Port, cfg.Redis.Dist, false, cfg.Redis.Tag); err != nil { + // TODO: Force was false here + if err := StartRedis(*cfg); err != nil { return fmt.Errorf("cannot start redis: %w", err) } else { log.Infof("Redis is running and accessible on port %d", cfg.Redis.Port) } - if err := eden.StartAdam(cfg.Adam.Port, cfg.Adam.Dist, false, cfg.Adam.Tag, cfg.Adam.Redis.RemoteURL, cfg.Adam.APIv1); err != nil { + if err := StartAdam(cfg.Eden.CertsDir, cfg.Adam); err != nil { return fmt.Errorf("cannot start adam: %w", err) } else { log.Infof("Adam is running and accessible on port %d", cfg.Adam.Port) @@ -795,12 +811,14 @@ func EdenImport(tarFile string, rewriteRoot bool, cfg *EdenSetupArgs) error { } } // we need to put information about EVE into Adam - if err := eden.StartRedis(cfg.Redis.Port, cfg.Redis.Dist, false, cfg.Redis.Tag); err != nil { + // TODO: Force was false here + if err := StartRedis(*cfg); err != nil { log.Errorf("cannot start redis: %s", err.Error()) } else { log.Infof("Redis is running and accessible on port %d", cfg.Redis.Port) } - if err := eden.StartAdam(cfg.Adam.Port, cfg.Adam.Dist, false, cfg.Adam.Tag, cfg.Adam.Redis.RemoteURL, cfg.Adam.APIv1); err != nil { + // TODO here was false + if err := StartAdam(cfg.Eden.CertsDir, cfg.Adam); err != nil { log.Errorf("cannot start adam: %s", err.Error()) } else { log.Infof("Adam is running and accessible on port %d", cfg.Adam.Port) diff --git a/pkg/openevec/eden_test.go b/pkg/openevec/eden_test.go new file mode 100644 index 000000000..b04acc4fe --- /dev/null +++ b/pkg/openevec/eden_test.go @@ -0,0 +1,41 @@ +package openevec_test + +import ( + "bytes" + "fmt" + "os" + "testing" + + "github.com/lf-edge/eden/pkg/openevec" + "gotest.tools/assert" +) + +func TestParseTemplateFile(t *testing.T) { + var buf bytes.Buffer + + f, err := os.CreateTemp("", "template.*.tmpl") + if err != nil { + t.Errorf("CreateTemp failed %v", err) + return + } + defer f.Close() + + const tmpl = "{{.Eden.Root}} {{.Eden.BinDir}}" + f.Write([]byte(tmpl)) + + const rootVal = "rv" + const binDirVal = "bdv" + cfg := openevec.EdenSetupArgs{ + Eden: openevec.EdenConfig{ + Root: rootVal, + BinDir: binDirVal, + }, + } + + if err = openevec.ParseTemplateFile(f.Name(), cfg, &buf); err != nil { + t.Errorf("parseTemplateFile failed: %v", err) + return + } + + assert.Equal(t, buf.String(), fmt.Sprintf("%s %s", rootVal, binDirVal)) +} diff --git a/pkg/openevec/onboard.go b/pkg/openevec/onboard.go index dcc50c770..3ea037905 100644 --- a/pkg/openevec/onboard.go +++ b/pkg/openevec/onboard.go @@ -10,12 +10,12 @@ import ( ) func OnboardEve(eveUUID string) error { - edenDir, err := utils.DefaultEdenDir() if err != nil { - return fmt.Errorf("error getting default eden dir %w", err) + return err } - if err = utils.TouchFile(filepath.Join(edenDir, fmt.Sprintf("state-%s.yml", eveUUID))); err != nil { + + if err := utils.TouchFile(filepath.Join(edenDir, fmt.Sprintf("state-%s.yml", eveUUID))); err != nil { return fmt.Errorf("error getting file %w", err) } changer := &adamChanger{} diff --git a/pkg/openevec/start.go b/pkg/openevec/start.go index e0aaa179a..27811ecd3 100644 --- a/pkg/openevec/start.go +++ b/pkg/openevec/start.go @@ -2,13 +2,19 @@ package openevec import ( "fmt" + "io/ioutil" "os" + "path/filepath" + "strconv" + "strings" + "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/eden" + "github.com/lf-edge/eden/pkg/utils" log "github.com/sirupsen/logrus" ) -func StartAdam(cfg EdenSetupArgs) error { +func StartAdamCmd(cfg EdenSetupArgs) error { command, err := os.Executable() if err != nil { return fmt.Errorf("startAdam: cannot obtain executable path: %w", err) @@ -19,7 +25,7 @@ func StartAdam(cfg EdenSetupArgs) error { cfg.Adam.Redis.RemoteURL = "" } - if err := eden.StartAdam(cfg.Adam.Port, cfg.Adam.Dist, cfg.Adam.Force, cfg.Adam.Tag, cfg.Adam.Redis.RemoteURL, cfg.Adam.APIv1); err != nil { + if err := StartAdam(cfg.Eden.CertsDir, cfg.Adam); err != nil { return fmt.Errorf("cannot start adam: %w", err) } log.Infof("Adam is runnig and accessible on port %d", cfg.Adam.Port) @@ -36,10 +42,46 @@ func GetAdamStatus() (string, error) { } func StartRedis(cfg EdenSetupArgs) error { - if err := eden.StartRedis(cfg.Redis.Port, cfg.Adam.Redis.Dist, cfg.Redis.Force, cfg.Redis.Tag); err != nil { - return fmt.Errorf("cannot start redis: %w", err) + portMap := map[string]string{"6379": strconv.Itoa(cfg.Redis.Port)} + volumeMap := map[string]string{"/data": cfg.Redis.Dist} + redisServerCommand := strings.Fields("redis-server --appendonly yes") + edenHome, err := utils.DefaultEdenDir() + if err != nil { + return err + } + globalCertsDir := filepath.Join(edenHome, defaults.DefaultCertsDist) + redisPasswordFile := filepath.Join(globalCertsDir, defaults.DefaultRedisPasswordFile) + pwd, err := ioutil.ReadFile(redisPasswordFile) + if err == nil { + redisServerCommand = append(redisServerCommand, strings.Fields(fmt.Sprintf("--requirepass %s", string(pwd)))...) + } else { + log.Errorf("cannot read redis password: %v", err) + } + if cfg.Adam.Redis.Dist != "" { + if err = os.MkdirAll(cfg.Adam.Redis.Dist, 0755); err != nil { + return fmt.Errorf("StartRedis: Cannot create directory for redis (%s): %s", cfg.Adam.Redis.Dist, err) + } + } + if cfg.Redis.Force { + _ = utils.StopContainer(defaults.DefaultRedisContainerName, true) + if err := utils.CreateAndRunContainer(defaults.DefaultRedisContainerName, defaults.DefaultRedisContainerRef+":"+cfg.Redis.Tag, portMap, volumeMap, redisServerCommand, nil); err != nil { + return fmt.Errorf("StartRedis: error in create redis container: %s", err) + } + } else { + state, err := utils.StateContainer(defaults.DefaultRedisContainerName) + if err != nil { + return fmt.Errorf("StartRedis: error in get state of redis container: %s", err) + } + if state == "" { + if err := utils.CreateAndRunContainer(defaults.DefaultRedisContainerName, defaults.DefaultRedisContainerRef+":"+cfg.Redis.Tag, portMap, volumeMap, redisServerCommand, nil); err != nil { + return fmt.Errorf("StartRedis: error in create redis container: %s", err) + } + } else if !strings.Contains(state, "running") { + if err := utils.StartContainer(defaults.DefaultRedisContainerName); err != nil { + return fmt.Errorf("StartRedis: error in restart redis container: %s", err) + } + } } - log.Infof("Redis is running and accessible on port %d", cfg.Redis.Port) return nil } @@ -69,7 +111,7 @@ func StartEden(cfg *EdenSetupArgs, vmName, zedControlURL, tapInterface string) e return fmt.Errorf("cannot start redis %w", err) } - if err := StartAdam(*cfg); err != nil { + if err := StartAdamCmd(*cfg); err != nil { return fmt.Errorf("cannot start adam %w", err) } diff --git a/pkg/openevec/utils.go b/pkg/openevec/utils.go index a64792b1f..b8161d6e5 100644 --- a/pkg/openevec/utils.go +++ b/pkg/openevec/utils.go @@ -12,7 +12,6 @@ import ( "os" "path/filepath" "strings" - "time" "github.com/docker/docker/client" "github.com/google/go-containerregistry/pkg/name" @@ -20,16 +19,11 @@ import ( "github.com/google/go-containerregistry/pkg/v1/daemon" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/tarball" - "github.com/lf-edge/eden/pkg/controller" - "github.com/lf-edge/eden/pkg/controller/einfo" "github.com/lf-edge/eden/pkg/defaults" "github.com/lf-edge/eden/pkg/eden" - "github.com/lf-edge/eden/pkg/eve" "github.com/lf-edge/eden/pkg/models" "github.com/lf-edge/eden/pkg/tests" "github.com/lf-edge/eden/pkg/utils" - "github.com/lf-edge/eve/api/go/info" - uuid "github.com/satori/go.uuid" log "github.com/sirupsen/logrus" ) @@ -286,59 +280,3 @@ func Test(tstCfg *TestArgs) error { } return nil } - -func checkOutput(input string, shouldHave, shouldNotHave []string) error { - for _, str := range shouldHave { - if !strings.Contains(input, str) { - return fmt.Errorf("Input does not contain %v", str) - } - } - - for _, str := range shouldNotHave { - if strings.Contains(input, str) { - return fmt.Errorf("Input contains %v", str) - } - } - - return nil -} - -func checkAppState(ctrl controller.Cloud, devUUID uuid.UUID, appName string, eveState *eve.State, expState string, timeout time.Duration) error { - startTime := time.Now() - - // Waiting for 15 min maximum to get eclient-mount app in state running - handleInfo := func(im *info.ZInfoMsg) bool { - eveState.InfoCallback()(im) - for _, s := range eveState.Applications() { - if s.Name == appName { - if s.EVEState == expState { - return true - } - } - } - if time.Now().After(startTime.Add(timeout)) { - log.Fatal("eclient-mount timeout") - } - return false - } - - if err := ctrl.InfoChecker(devUUID, nil, handleInfo, einfo.InfoNew, 0); err != nil { - return fmt.Errorf("eclient-mount RUNNING state InfoChecker: %w", err) - } - - return nil -} - -func withCapturingStdout(f func() error) ([]byte, error) { - rescueStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - err := f() - - w.Close() - out, _ := ioutil.ReadAll(r) - os.Stdout = rescueStdout - - return out, err -} diff --git a/pkg/utils/context.go b/pkg/utils/context.go index 469976371..60053925e 100644 --- a/pkg/utils/context.go +++ b/pkg/utils/context.go @@ -2,13 +2,14 @@ package utils import ( "fmt" - "github.com/lf-edge/eden/pkg/defaults" - log "github.com/sirupsen/logrus" - "gopkg.in/yaml.v2" "io/ioutil" "os" "path/filepath" "strings" + + "github.com/lf-edge/eden/pkg/defaults" + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" ) //Context for use with multiple config files From 9795d8ef7f89999e06fa7cc77d35bdd2b9dea252 Mon Sep 17 00:00:00 2001 From: Pavel Abramov Date: Tue, 11 Jul 2023 14:27:01 +0200 Subject: [PATCH 20/20] Fix script templates to use config struct Signed-off-by: Pavel Abramov --- shell-scripts/activate.csh.tmpl | 4 ++-- shell-scripts/activate.sh.tmpl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shell-scripts/activate.csh.tmpl b/shell-scripts/activate.csh.tmpl index e0bfa8695..949be6134 100644 --- a/shell-scripts/activate.csh.tmpl +++ b/shell-scripts/activate.csh.tmpl @@ -14,10 +14,10 @@ alias eden-config 'eden config delete \!:1; eden_config default' # Unset irrelevant variables. eden_deactivate nondestructive -setenv EDEN_HOME "{{EdenConfig "eden.root"}}" +setenv EDEN_HOME "{{.Eden.Root}}" set _OLD_EDEN_PATH="$PATH:q" -setenv PATH "$EDEN_HOME/{{EdenConfig "eden.bin-dist"}}:$PATH:q" +setenv PATH "$EDEN_HOME/{{.Eden.BinDir}}:$PATH:q" if ( $?EDEN_DISABLE_PROMPT ) then if ( $EDEN_DISABLE_PROMPT == "" ) then diff --git a/shell-scripts/activate.sh.tmpl b/shell-scripts/activate.sh.tmpl index 631bce578..d5c97a528 100644 --- a/shell-scripts/activate.sh.tmpl +++ b/shell-scripts/activate.sh.tmpl @@ -75,8 +75,8 @@ eden-config () { # unset irrelevant variables eden_deactivate nondestructive -EDEN_HOME={{EdenConfig "eden.root"}} -EDEN_BIN="$EDEN_HOME/{{EdenConfig "eden.bin-dist"}}" +EDEN_HOME={{.Eden.Root}} +EDEN_BIN="$EDEN_HOME/{{.Eden.BinDir}}" export EDEN_HOME _OLD_EDEN_PATH="$PATH"