From f48a6516d3f8e6617df065c307556a1d1e57bd1e Mon Sep 17 00:00:00 2001 From: YuYang Date: Thu, 18 May 2023 11:31:40 +0800 Subject: [PATCH] refactor config and move Host to config --- cmd/cmd.go | 40 +++- cmd/guest/list.go | 7 +- cmd/host/add.go | 73 ------- cmd/host/get.go | 28 --- cmd/host/host.go | 25 --- cmd/maint/fasten.go | 5 +- cmd/run/run.go | 28 ++- configs/config.go | 245 ++++++++++++++---------- configs/config_test.go | 25 +++ configs/default-config.toml | 62 ++++++ go.mod | 1 + go.sum | 2 + internal/metrics/metric.go | 6 +- internal/models/host.go | 51 ++--- internal/models/host_test.go | 30 --- internal/server/calico.go | 2 +- internal/server/server.go | 2 +- internal/server/service.go | 9 +- internal/virt/guest/guest.go | 2 +- internal/virt/guest/network.go | 15 +- internal/vnet/calico/ipam.go | 7 +- internal/vnet/handler/calico/gateway.go | 11 +- pkg/utils/misc.go | 11 -- yavirtd.go | 58 +++++- 24 files changed, 361 insertions(+), 384 deletions(-) delete mode 100644 cmd/host/add.go delete mode 100644 cmd/host/get.go delete mode 100644 cmd/host/host.go create mode 100644 configs/config_test.go create mode 100644 configs/default-config.toml diff --git a/cmd/cmd.go b/cmd/cmd.go index 441a332..545effd 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -7,7 +7,6 @@ import ( "github.com/urfave/cli/v2" "github.com/projecteru2/yavirt/cmd/guest" - "github.com/projecteru2/yavirt/cmd/host" "github.com/projecteru2/yavirt/cmd/image" "github.com/projecteru2/yavirt/cmd/maint" "github.com/projecteru2/yavirt/cmd/network" @@ -22,21 +21,50 @@ func main() { app := &cli.App{ Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Value: "/etc/eru/yavirtd.toml", + Usage: "config file path for yavirt, in yaml", + EnvVars: []string{"ERU_YAVIRT_CONFIG_PATH"}, + }, + &cli.StringFlag{ + Name: "log-level", + Value: "INFO", + Usage: "set log level", + EnvVars: []string{"ERU_YAVIRT_LOG_LEVEL"}, + }, &cli.StringSliceFlag{ - Name: "config", - Usage: "config files", - Required: true, + Name: "core-addrs", + Value: cli.NewStringSlice(), + Usage: "core addresses", + EnvVars: []string{"ERU_YAVIRT_CORE_ADDRS"}, + }, + &cli.StringFlag{ + Name: "core-username", + Value: "", + Usage: "core username", + EnvVars: []string{"ERU_YAVIRT_CORE_USERNAME"}, + }, + &cli.StringFlag{ + Name: "core-password", + Value: "", + Usage: "core password", + EnvVars: []string{"ERU_YAVIRT_CORE_PASSWORD"}, + }, + &cli.StringFlag{ + Name: "hostname", + Value: "", + Usage: "change hostname", + EnvVars: []string{"ERU_HOSTNAME", "HOSTNAME"}, }, &cli.BoolFlag{ Name: "skip-setup-host", Value: false, }, }, - Commands: []*cli.Command{ guest.Command(), image.Command(), - host.Command(), network.Command(), maint.Command(), }, diff --git a/cmd/guest/list.go b/cmd/guest/list.go index bdab226..92cb62e 100644 --- a/cmd/guest/list.go +++ b/cmd/guest/list.go @@ -6,8 +6,8 @@ import ( "github.com/urfave/cli/v2" "github.com/projecteru2/yavirt/cmd/run" + "github.com/projecteru2/yavirt/configs" "github.com/projecteru2/yavirt/internal/models" - "github.com/projecteru2/yavirt/pkg/utils" ) func listFlags() []cli.Flag { @@ -31,10 +31,7 @@ func list(c *cli.Context, _ run.Runtime) error { } else { nodename := c.String("node") if len(nodename) < 1 { - nodename, err = utils.Hostname() - if err != nil { - return err - } + nodename = configs.Hostname() } guests, err = models.GetNodeGuests(nodename) } diff --git a/cmd/host/add.go b/cmd/host/add.go deleted file mode 100644 index 8544161..0000000 --- a/cmd/host/add.go +++ /dev/null @@ -1,73 +0,0 @@ -package host - -import ( - "fmt" - - "github.com/urfave/cli/v2" - - "github.com/projecteru2/yavirt/cmd/run" - "github.com/projecteru2/yavirt/internal/models" - "github.com/projecteru2/yavirt/internal/vnet" - "github.com/projecteru2/yavirt/pkg/errors" -) - -func addFlags() []cli.Flag { - return []cli.Flag{ - &cli.IntFlag{ - Name: "cpu", - }, - &cli.Int64Flag{ - Name: "memory", - }, - &cli.Int64Flag{ - Name: "storage", - }, - &cli.StringFlag{ - Name: "subnet", - }, - &cli.StringFlag{ - Name: "network", - }, - } -} - -func add(c *cli.Context, runtime run.Runtime) error { - hn := c.Args().First() - subnet := runtime.ConvDecimal(c.String("subnet")) - cpu := c.Int("cpu") - mem := c.Int64("memory") - storage := c.Int64("storage") - network := c.String("network") - - switch { - case len(hn) < 1: - return errors.New("host name is required") - case cpu < 1: - return errors.New("--cpu is required") - case mem < 1: - return errors.New("--memory is required") - case storage < 1: - return errors.New("--storage is required") - case network == vnet.NetworkVlan && subnet < 1: - return errors.New("--subnet is required") - case network != vnet.NetworkCalico && network != vnet.NetworkVlan: - return errors.Errorf("--network is invalid: %s", network) - } - - host := models.NewHost() - host.Name = hn - host.Type = models.HostVirtType - host.Subnet = subnet - host.CPU = cpu - host.Memory = mem - host.Storage = storage - host.NetworkMode = network - - if err := host.Create(); err != nil { - return errors.Trace(err) - } - - fmt.Printf("host (%d) %s created\n", host.ID, host.Name) - - return nil -} diff --git a/cmd/host/get.go b/cmd/host/get.go deleted file mode 100644 index 3d2ea03..0000000 --- a/cmd/host/get.go +++ /dev/null @@ -1,28 +0,0 @@ -package host - -import ( - "fmt" - - "github.com/urfave/cli/v2" - - "github.com/projecteru2/yavirt/cmd/run" - "github.com/projecteru2/yavirt/internal/models" - "github.com/projecteru2/yavirt/pkg/errors" -) - -func get(c *cli.Context, _ run.Runtime) error { - hn := c.Args().First() - if len(hn) < 1 { - return errors.New("host name is required") - } - - h, err := models.LoadHost(hn) - if err != nil { - return errors.Trace(err) - - } - - fmt.Println(h) - - return nil -} diff --git a/cmd/host/host.go b/cmd/host/host.go deleted file mode 100644 index 355b438..0000000 --- a/cmd/host/host.go +++ /dev/null @@ -1,25 +0,0 @@ -package host - -import ( - "github.com/urfave/cli/v2" - - "github.com/projecteru2/yavirt/cmd/run" -) - -// Command . -func Command() *cli.Command { - return &cli.Command{ - Name: "host", - Subcommands: []*cli.Command{ - { - Name: "add", - Flags: addFlags(), - Action: run.Run(add), - }, - { - Name: "get", - Action: run.Run(get), - }, - }, - } -} diff --git a/cmd/maint/fasten.go b/cmd/maint/fasten.go index 74c870a..9cae147 100644 --- a/cmd/maint/fasten.go +++ b/cmd/maint/fasten.go @@ -18,7 +18,6 @@ import ( "github.com/projecteru2/yavirt/pkg/libvirt" "github.com/projecteru2/yavirt/pkg/netx" "github.com/projecteru2/yavirt/pkg/store" - "github.com/projecteru2/yavirt/pkg/utils" ) var intIPSubnets = map[int64]int64{} @@ -154,9 +153,7 @@ func fastenDangling(id string, virt *libvirt.Libvirtee) error { if err != nil { return errors.Trace(err) } - if guest.HostName, err = utils.Hostname(); err != nil { - return errors.Trace(err) - } + guest.HostName = configs.Hostname() guest.ID = id guest.ImageName = "ubuntu1604-sto" diff --git a/cmd/run/run.go b/cmd/run/run.go index e0714b3..4b8ec87 100644 --- a/cmd/run/run.go +++ b/cmd/run/run.go @@ -21,7 +21,6 @@ import ( "github.com/projecteru2/yavirt/pkg/idgen" "github.com/projecteru2/yavirt/pkg/netx" "github.com/projecteru2/yavirt/pkg/store" - "github.com/projecteru2/yavirt/pkg/utils" ) var runtime Runtime @@ -31,7 +30,6 @@ type Runner func(*cli.Context, Runtime) error // Runtime . type Runtime struct { - ConfigFiles []string SkipSetupHost bool Host *models.Host Device *device.Driver @@ -62,7 +60,14 @@ func (r Runtime) ConvDecimal(ipv4 string) int64 { // Run . func Run(fn Runner) cli.ActionFunc { return func(c *cli.Context) error { - runtime.ConfigFiles = c.StringSlice("config") + cfg := &configs.Conf + + if err := cfg.Load([]string{c.String("config")}); err != nil { + return errors.Trace(err) + } + if err := cfg.Prepare(c); err != nil { + return err + } runtime.SkipSetupHost = c.Bool("skip-setup-host") runtime.Guest = manager.New() // when add host, we need skip host setup @@ -78,12 +83,6 @@ func Run(fn Runner) cli.ActionFunc { } func setup() error { - if len(runtime.ConfigFiles) > 0 { - if err := configs.Conf.Load(runtime.ConfigFiles); err != nil { - return errors.Trace(err) - } - } - if err := store.Setup("etcd"); err != nil { return errors.Trace(err) } @@ -107,16 +106,11 @@ func setup() error { return nil } -func setupHost() error { - hn, err := utils.Hostname() - if err != nil { +func setupHost() (err error) { + if runtime.Host, err = models.LoadHost(); err != nil { return errors.Trace(err) } - if runtime.Host, err = models.LoadHost(hn); err != nil { - return errors.Annotatef(err, "invalid hostname %s", hn) - } - return nil } @@ -136,7 +130,7 @@ func setupCalico() (err error) { } var outboundIP string - if outboundIP, err = netx.GetOutboundIP(configs.Conf.CoreAddr); err != nil { + if outboundIP, err = netx.GetOutboundIP(configs.Conf.Core.Addrs[0]); err != nil { return } diff --git a/configs/config.go b/configs/config.go index 493f053..48eed27 100644 --- a/configs/config.go +++ b/configs/config.go @@ -4,78 +4,80 @@ import ( "crypto/tls" "os" "path/filepath" + "strings" "time" + _ "embed" + clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/pkg/transport" + "github.com/dustin/go-humanize" "github.com/projecteru2/yavirt/pkg/errors" "github.com/projecteru2/yavirt/pkg/log" + "github.com/projecteru2/yavirt/pkg/netx" + "github.com/urfave/cli/v2" +) + +var ( + //go:embed default-config.toml + DefaultTemplate string + Conf = newDefault() ) -// DefaultTemplate . -const DefaultTemplate = ` -env = "dev" -prof_http_port = 9999 -bind_http_addr = "0.0.0.0:9696" -bind_grpc_addr = "0.0.0.0:9697" -graceful_timeout = "20s" -virt_timeout = "1h" -health_check_timeout = "2s" -qmp_connect_timeout = "8s" -cni_plugin_path = "/usr/bin/yavirt-cni" -cni_config_path = "/etc/cni/net.d/yavirt-cni.conf" - -resize_volume_min_ratio = 0.05 -resize_volume_min_size = 10737418240 - -min_cpu = 1 -max_cpu = 64 -min_memory = 1073741824 -max_memory = 68719476736 -min_volume = 1073741824 -max_volume = 1099511627776 -max_volumes_count = 8 -max_snapshots_count = 30 -snapshot_restorable_days = 7 - -meta_timeout = "1m" -meta_type = "etcd" - -virt_dir = "/tmp/virt" -virt_bridge = "virbr0" -virt_cpu_cache_passthrough = true - -calico_gateway = "yavirt-cali-gw" -calico_pools = ["clouddev"] -calico_etcd_env = "ETCD_ENDPOINTS" - -log_level = "info" - -etcd_prefix = "/yavirt-dev/v1" -etcd_endpoints = ["http://127.0.0.1:2379"] - -core_addr = "127.0.0.1:5001" -core_username = "admin" -core_password = "password" -core_status_check_interval = "64s" -core_nodestatus_ttl = "16m" - -ga_disk_timeout = "16m" -ga_boot_timeout = "30m" - -recovery_on = false -recovery_max_retries = 2 -recovery_retry_interval = "3m" -recovery_interval = "10m" -` - -// Conf . -var Conf = newDefault() +type sizeType int64 +type subnetType int64 + +type CoreConfig struct { + Addrs []string `toml:"addrs"` + Username string `toml:"username"` + Password string `toml:"password"` + StatusCheckInterval Duration `toml:"status_check_interval"` + NodeStatusTTL Duration `toml:"nodestatus_ttl"` + Nodename string `toml:"nodename"` +} + +func (a *sizeType) UnmarshalText(text []byte) error { + var err error + i, err := humanize.ParseBytes(string(text)) + if err != nil { + return err + } + *a = sizeType(i) + return nil +} + +func (a *subnetType) UnmarshalText(text []byte) error { + if len(text) < 1 { + return nil + } + + dec, err := netx.IPv4ToInt(string(text)) + if err != nil { + return err + } + *a = subnetType(dec) + return nil +} + +type HostConfig struct { + Name string `json:"name" toml:"name"` + Addr string `json:"addr" toml:"addr"` + Type string `json:"type" toml:"type"` + Subnet subnetType `json:"subnet" toml:"subnet"` + CPU int `json:"cpu" toml:"cpu"` + Memory sizeType `json:"memory" toml:"memory"` + Storage sizeType `json:"storage" toml:"storage"` + NetworkMode string `json:"network,omitempty" toml:"network"` +} // Config . type Config struct { - Env string `toml:"env"` + Env string `toml:"env"` + // host-related config + Host HostConfig `toml:"host"` + Core CoreConfig `toml:"core"` + ProfHTTPPort int `toml:"prof_http_port"` BindHTTPAddr string `toml:"bind_http_addr"` BindGRPCAddr string `toml:"bind_grpc_addr"` @@ -135,13 +137,6 @@ type Config struct { EtcdKey string `toml:"etcd_key"` EtcdCert string `toml:"etcd_cert"` - CoreAddr string `toml:"core_addr"` - CoreUsername string `toml:"core_username"` - CorePassword string `toml:"core_password"` - CoreStatusCheckInterval Duration `toml:"core_status_check_interval"` - CoreNodeStatusTTL Duration `toml:"core_nodestatus_ttl"` - CoreNodename string `toml:"core_nodename"` - Batches []*Batch `toml:"batches"` // system recovery @@ -151,50 +146,92 @@ type Config struct { RecoveryInterval Duration `toml:"recovery_interval"` } +func Hostname() string { + return Conf.Host.Name +} + func newDefault() Config { var conf Config if err := Decode(DefaultTemplate, &conf); err != nil { log.FatalStack(err) } - conf.loadVirtDirs() - return conf } // Dump . -func (c *Config) Dump() (string, error) { - return Encode(c) +func (cfg *Config) Dump() (string, error) { + return Encode(cfg) } // Load . -func (c *Config) Load(files []string) error { +func (cfg *Config) Load(files []string) error { for _, path := range files { - if err := c.load(path); err != nil { + if err := DecodeFile(path, cfg); err != nil { return errors.Trace(err) } } return nil } -func (c *Config) load(file string) error { - if err := DecodeFile(file, c); err != nil { - return errors.Trace(err) +func (cfg *Config) Prepare(c *cli.Context) (err error) { + // try to initialize Hostname + if c.String("addr") != "" { + cfg.Host.Addr = c.String("addr") + } + if c.String("hostname") != "" { + cfg.Host.Name = c.String("hostname") + } else if cfg.Host.Name == "" { + cfg.Host.Name, err = os.Hostname() + if err != nil { + return err + } } - if err := c.loadVirtDirs(); err != nil { - return err + if cfg.Host.Name == "" { + cfg.Host.Name = strings.ReplaceAll(cfg.Host.Addr, ".", "-") } - return nil + if c.String("log-level") != "" { + cfg.LogLevel = c.String("log-level") + } + + if len(c.StringSlice("core-addrs")) > 0 { + cfg.Core.Addrs = c.StringSlice("core-addrs") + } + if c.String("core-username") != "" { + cfg.Core.Username = c.String("core-username") + } + if c.String("core-password") != "" { + cfg.Core.Password = c.String("core-password") + } + // prepare ETCD_ENDPOINTS(Calico needs this environment variable) + if len(cfg.EtcdEndpoints) > 0 { + if err = os.Setenv("ETCD_ENDPOINTS", strings.Join(cfg.EtcdEndpoints, ",")); err != nil { + return err + } + } + + if cfg.Host.Addr == "" { + return errors.New("Address must be provided") + } + // validate config values + if cfg.Host.Name == "" { + return errors.New("Hostname must be provided") + } + if len(cfg.Core.Addrs) == 0 { + return errors.New("Core addresses are needed") + } + + return cfg.loadVirtDirs() } -func (c *Config) loadVirtDirs() error { - c.VirtFlockDir = filepath.Join(c.VirtDir, "flock") - c.VirtTmplDir = filepath.Join(c.VirtDir, "template") - c.VirtSockDir = filepath.Join(c.VirtDir, "sock") +func (cfg *Config) loadVirtDirs() error { + cfg.VirtFlockDir = filepath.Join(cfg.VirtDir, "flock") + cfg.VirtTmplDir = filepath.Join(cfg.VirtDir, "template") + cfg.VirtSockDir = filepath.Join(cfg.VirtDir, "sock") // ensure directories - for _, d := range []string{c.VirtFlockDir, c.VirtTmplDir, c.VirtSockDir} { + for _, d := range []string{cfg.VirtFlockDir, cfg.VirtTmplDir, cfg.VirtSockDir} { err := os.MkdirAll(d, 0755) if err != nil && !os.IsExist(err) { return err @@ -204,47 +241,47 @@ func (c *Config) loadVirtDirs() error { } // NewEtcdConfig . -func (c *Config) NewEtcdConfig() (etcdcnf clientv3.Config, err error) { - etcdcnf.Endpoints = c.EtcdEndpoints - etcdcnf.Username = c.EtcdUsername - etcdcnf.Password = c.EtcdPassword - etcdcnf.TLS, err = c.newEtcdTLSConfig() +func (cfg *Config) NewEtcdConfig() (etcdcnf clientv3.Config, err error) { + etcdcnf.Endpoints = cfg.EtcdEndpoints + etcdcnf.Username = cfg.EtcdUsername + etcdcnf.Password = cfg.EtcdPassword + etcdcnf.TLS, err = cfg.newEtcdTLSConfig() return } -func (c *Config) newEtcdTLSConfig() (*tls.Config, error) { - if len(c.EtcdCA) < 1 || len(c.EtcdKey) < 1 || len(c.EtcdCert) < 1 { +func (cfg *Config) newEtcdTLSConfig() (*tls.Config, error) { + if len(cfg.EtcdCA) < 1 || len(cfg.EtcdKey) < 1 || len(cfg.EtcdCert) < 1 { return nil, nil //nolint } return transport.TLSInfo{ - TrustedCAFile: c.EtcdCA, - KeyFile: c.EtcdKey, - CertFile: c.EtcdCert, + TrustedCAFile: cfg.EtcdCA, + KeyFile: cfg.EtcdKey, + CertFile: cfg.EtcdCert, }.ClientConfig() } // CoreGuestStatusTTL . -func (c *Config) CoreGuestStatusTTL() time.Duration { - return 3 * c.CoreStatusCheckInterval.Duration() //nolint:gomnd // TTL is 3 times the interval +func (cfg *Config) CoreGuestStatusTTL() time.Duration { + return 3 * cfg.Core.StatusCheckInterval.Duration() //nolint:gomnd // TTL is 3 times the interval } // CoreGuestStatusCheckInterval . -func (c *Config) CoreGuestStatusCheckInterval() time.Duration { - return c.CoreStatusCheckInterval.Duration() +func (cfg *Config) CoreGuestStatusCheckInterval() time.Duration { + return cfg.Core.StatusCheckInterval.Duration() } // CoreGRPCTimeout . -func (c *Config) CoreGRPCTimeout() time.Duration { - return c.CoreStatusReportInterval() / 3 //nolint:gomnd // report timeout 3 times per interval +func (cfg *Config) CoreGRPCTimeout() time.Duration { + return cfg.CoreStatusReportInterval() / 3 //nolint:gomnd // report timeout 3 times per interval } // CoreStatusReportInterval . -func (c *Config) CoreStatusReportInterval() time.Duration { - return c.CoreStatusCheckInterval.Duration() / 3 //nolint:gomnd // report 3 times every check +func (cfg *Config) CoreStatusReportInterval() time.Duration { + return cfg.Core.StatusCheckInterval.Duration() / 3 //nolint:gomnd // report 3 times every check } // HasImageHub indicates whether the config has ImageHub configurations. -func (c *Config) HasImageHub() bool { - return len(c.ImageHubDomain) > 0 && len(c.ImageHubNamespace) > 0 +func (cfg *Config) HasImageHub() bool { + return len(cfg.ImageHubDomain) > 0 && len(cfg.ImageHubNamespace) > 0 } diff --git a/configs/config_test.go b/configs/config_test.go new file mode 100644 index 0000000..282abbc --- /dev/null +++ b/configs/config_test.go @@ -0,0 +1,25 @@ +package configs + +import ( + "testing" + + "github.com/BurntSushi/toml" + "github.com/projecteru2/yavirt/pkg/test/assert" +) + +func TestHostConfig(t *testing.T) { + ss := ` +[host] +name = "host1" +subnet = "127.0.0.1" +cpu = 4 +memory = "1gib" +storage = "40gi" +network = "calico" + ` + cfg := Config{} + _, err := toml.Decode(ss, &cfg) + assert.Nil(t, err) + assert.Equal(t, cfg.Host.Memory, sizeType(1*1024*1024*1024)) + assert.Equal(t, cfg.Host.Storage, sizeType(40*1024*1024*1024)) +} diff --git a/configs/default-config.toml b/configs/default-config.toml new file mode 100644 index 0000000..aa64ef4 --- /dev/null +++ b/configs/default-config.toml @@ -0,0 +1,62 @@ +env = "dev" +prof_http_port = 9999 +bind_http_addr = "0.0.0.0:9696" +bind_grpc_addr = "0.0.0.0:9697" +graceful_timeout = "20s" +virt_timeout = "1h" +health_check_timeout = "2s" +qmp_connect_timeout = "8s" +cni_plugin_path = "/usr/bin/yavirt-cni" +cni_config_path = "/etc/cni/net.d/yavirt-cni.conf" + +resize_volume_min_ratio = 0.05 +resize_volume_min_size = 10737418240 + +min_cpu = 1 +max_cpu = 64 +min_memory = 1073741824 +max_memory = 68719476736 +min_volume = 1073741824 +max_volume = 1099511627776 +max_volumes_count = 8 +max_snapshots_count = 30 +snapshot_restorable_days = 7 + +meta_timeout = "1m" +meta_type = "etcd" + +virt_dir = "/tmp/virt" +virt_bridge = "virbr0" +virt_cpu_cache_passthrough = true + +calico_gateway = "yavirt-cali-gw" +calico_pools = ["clouddev"] +calico_etcd_env = "ETCD_ENDPOINTS" + +log_level = "info" + +etcd_prefix = "/yavirt-dev/v1" +etcd_endpoints = ["http://127.0.0.1:2379"] + +ga_disk_timeout = "16m" +ga_boot_timeout = "30m" + +recovery_on = false +recovery_max_retries = 2 +recovery_retry_interval = "3m" +recovery_interval = "10m" + +[host] +name = "host1" +subnet = "127.0.0.1" +cpu = 4 +memory = "1g" +storage = "40g" +network = "calico" + +[core] +addrs = ["127.0.0.1:5001"] +username = "admin" +password = "password" +status_check_interval = "64s" +nodestatus_ttl = "16m" diff --git a/go.mod b/go.mod index e571605..12eaa08 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/BurntSushi/toml v1.2.1 github.com/containernetworking/cni v1.1.2 + github.com/dustin/go-humanize v1.0.1 github.com/getsentry/sentry-go v0.20.0 github.com/gin-gonic/gin v1.9.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 4d80a97..7e0b8f4 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= diff --git a/internal/metrics/metric.go b/internal/metrics/metric.go index 6075ef0..192cf29 100644 --- a/internal/metrics/metric.go +++ b/internal/metrics/metric.go @@ -6,6 +6,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/projecteru2/yavirt/configs" "github.com/projecteru2/yavirt/pkg/errors" "github.com/projecteru2/yavirt/pkg/utils" ) @@ -23,10 +24,7 @@ var ( ) func init() { - hn, err := utils.Hostname() - if err != nil { - panic(err) - } + hn := configs.Hostname() metr = New(hn) metr.RegisterCounter(MetricErrorCount, "yavirt errors", nil) //nolint diff --git a/internal/models/host.go b/internal/models/host.go index d344753..47886a6 100644 --- a/internal/models/host.go +++ b/internal/models/host.go @@ -1,12 +1,11 @@ package models import ( - "context" "fmt" + "github.com/projecteru2/yavirt/configs" "github.com/projecteru2/yavirt/internal/meta" - "github.com/projecteru2/yavirt/pkg/errors" - "github.com/projecteru2/yavirt/pkg/store" + "github.com/projecteru2/yavirt/pkg/netx" ) // Host . @@ -28,13 +27,22 @@ type Host struct { } // LoadHost . -func LoadHost(hn string) (*Host, error) { - var host = NewHost() - host.Name = hn - - if err := meta.Load(host); err != nil { - return nil, errors.Trace(err) +func LoadHost() (*Host, error) { + host := &Host{ + Generic: newGeneric(), + Name: configs.Conf.Host.Name, + Type: HostVirtType, + Subnet: int64(configs.Conf.Host.Subnet), + CPU: configs.Conf.Host.CPU, + Memory: int64(configs.Conf.Host.Memory), + Storage: int64(configs.Conf.Host.Storage), + NetworkMode: configs.Conf.Host.NetworkMode, + } + dec, err := netx.IPv4ToInt(configs.Conf.Host.Addr) + if err != nil { + return nil, err } + host.ID = uint32(dec) return host, nil } @@ -49,36 +57,11 @@ func (h *Host) MetaKey() string { return meta.HostKey(h.Name) } -// Create . -func (h *Host) Create() error { - var id, err = genHostID() - if err != nil { - return errors.Trace(err) - } - - h.ID = id - h.Status = StatusRunning - - return meta.Create(meta.Resources{h}) -} - func (h *Host) String() string { return fmt.Sprintf("%d %s subnet: %d, cpu: %d, memory: %d, storage: %d", h.ID, h.Name, h.Subnet, h.CPU, h.Memory, h.Storage) } -func genHostID() (uint32, error) { - var ctx, cancel = meta.Context(context.Background()) - defer cancel() - - var id, err = store.IncrUint32(ctx, meta.HostCounterKey()) - if err != nil { - return 0, errors.Trace(err) - } - - return id, nil -} - type hostGuest struct { *meta.Ver HostName string `json:"-"` diff --git a/internal/models/host_test.go b/internal/models/host_test.go index a84f692..e18a307 100644 --- a/internal/models/host_test.go +++ b/internal/models/host_test.go @@ -1,41 +1,11 @@ package models import ( - "testing" "time" - "github.com/projecteru2/yavirt/pkg/errors" "github.com/projecteru2/yavirt/pkg/idgen" - "github.com/projecteru2/yavirt/pkg/store/mocks" - "github.com/projecteru2/yavirt/pkg/test/assert" - "github.com/projecteru2/yavirt/pkg/test/mock" ) func init() { idgen.Setup(0, time.Now()) } - -func TestCreateHost(t *testing.T) { - var meta, cancel = mocks.Mock() - defer cancel() - defer meta.AssertExpectations(t) - - var host = NewHost() - - meta.On("IncrUint32", mock.Anything, mock.Anything).Return(uint32(1), nil).Once() - meta.On("Create", mock.Anything, mock.Anything).Return(nil).Once() - assert.NilErr(t, host.Create()) - assert.Equal(t, StatusRunning, host.Status) -} - -func TestCreateHostFailedAsNameExists(t *testing.T) { - var meta, cancel = mocks.Mock() - defer cancel() - defer meta.AssertExpectations(t) - - var host = NewHost() - - meta.On("IncrUint32", mock.Anything, mock.Anything).Return(uint32(1), nil).Once() - meta.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(errors.ErrKeyExists).Once() - assert.Err(t, host.Create()) -} diff --git a/internal/server/calico.go b/internal/server/calico.go index 48b636a..59c89b9 100644 --- a/internal/server/calico.go +++ b/internal/server/calico.go @@ -42,7 +42,7 @@ func (svc *Service) setupCalicoHandler() error { return errors.Trace(err) } - outboundIP, err := netx.GetOutboundIP(configs.Conf.CoreAddr) + outboundIP, err := netx.GetOutboundIP(configs.Conf.Core.Addrs[0]) if err != nil { return errors.Trace(err) } diff --git a/internal/server/server.go b/internal/server/server.go index d2cae77..26a9962 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -42,7 +42,7 @@ func (s *Server) Listen(addr string) (lis net.Listener, ip string, err error) { return } - if ip, err = netx.GetOutboundIP(configs.Conf.CoreAddr); err != nil { + if ip, err = netx.GetOutboundIP(configs.Conf.Core.Addrs[0]); err != nil { return } diff --git a/internal/server/service.go b/internal/server/service.go index 294cee8..9e133da 100644 --- a/internal/server/service.go +++ b/internal/server/service.go @@ -45,13 +45,8 @@ func SetupYavirtdService() (*Service, error) { return svc, svc.setup() } -func (svc *Service) setup() error { - hn, err := utils.Hostname() - if err != nil { - return errors.Trace(err) - } - - if svc.Host, err = models.LoadHost(hn); err != nil { +func (svc *Service) setup() (err error) { + if svc.Host, err = models.LoadHost(); err != nil { return errors.Trace(err) } diff --git a/internal/virt/guest/guest.go b/internal/virt/guest/guest.go index 5fd0d71..7603a0b 100644 --- a/internal/virt/guest/guest.go +++ b/internal/virt/guest/guest.go @@ -54,7 +54,7 @@ func ListLocalIDs(virt.Context) ([]string, error) { // Load . func (g *Guest) Load() error { - host, err := models.LoadHost(g.HostName) + host, err := models.LoadHost() if err != nil { return errors.Trace(err) } diff --git a/internal/virt/guest/network.go b/internal/virt/guest/network.go index 6f06de8..35a4fa3 100644 --- a/internal/virt/guest/network.go +++ b/internal/virt/guest/network.go @@ -88,11 +88,7 @@ func (g *Guest) CreateEthernet() (rollback func() error, err error) { } func (g *Guest) createEndpoint() (rollback func() error, err error) { - var hn string - hn, err = utils.Hostname() - if err != nil { - return nil, errors.Trace(err) - } + hn := configs.Hostname() var hand handler.Handler hand, err = g.NetworkHandler(g.Host) @@ -147,9 +143,7 @@ func (g *Guest) joinEthernet() (err error) { args.MAC = g.MAC args.EndpointID = g.EndpointID - if args.Hostname, err = utils.Hostname(); err != nil { - return errors.Trace(err) - } + args.Hostname = configs.Hostname() if args.Device, err = hand.GetEndpointDevice(g.NetworkPair); err != nil { return errors.Trace(err) @@ -186,10 +180,7 @@ func (g *Guest) deleteEthernet() error { return g.calicoCNIDel() } - hn, err := utils.Hostname() - if err != nil { - return errors.Trace(err) - } + hn := configs.Hostname() hand, err := g.NetworkHandler(g.Host) if err != nil { diff --git a/internal/vnet/calico/ipam.go b/internal/vnet/calico/ipam.go index 8d54df6..5c4ba17 100644 --- a/internal/vnet/calico/ipam.go +++ b/internal/vnet/calico/ipam.go @@ -7,12 +7,12 @@ import ( libcaliipam "github.com/projectcalico/calico/libcalico-go/lib/ipam" libcalinet "github.com/projectcalico/calico/libcalico-go/lib/net" + "github.com/projecteru2/yavirt/configs" "github.com/projecteru2/yavirt/internal/meta" "github.com/projecteru2/yavirt/pkg/errors" "github.com/projecteru2/yavirt/pkg/log" "github.com/projecteru2/yavirt/pkg/netx" "github.com/projecteru2/yavirt/pkg/store/etcd" - "github.com/projecteru2/yavirt/pkg/utils" ) // Ipam . @@ -26,10 +26,7 @@ func newIpam(driver *Driver) *Ipam { // Assign . func (ipam *Ipam) Assign(_ context.Context) (meta.IP, error) { - hn, err := utils.Hostname() - if err != nil { - return nil, errors.Trace(err) - } + hn := configs.Hostname() ipam.Lock() defer ipam.Unlock() diff --git a/internal/vnet/handler/calico/gateway.go b/internal/vnet/handler/calico/gateway.go index 750da03..5ddd170 100644 --- a/internal/vnet/handler/calico/gateway.go +++ b/internal/vnet/handler/calico/gateway.go @@ -11,7 +11,6 @@ import ( "github.com/projecteru2/yavirt/internal/vnet/device" "github.com/projecteru2/yavirt/internal/vnet/types" "github.com/projecteru2/yavirt/pkg/errors" - "github.com/projecteru2/yavirt/pkg/utils" ) // InitGateway . @@ -95,10 +94,7 @@ func (h *Handler) bindGatewayIPs(ips ...meta.IP) error { } func (h *Handler) addGatewayEndpoint(ip meta.IP) error { - hn, err := utils.Hostname() - if err != nil { - return errors.Trace(err) - } + hn := configs.Hostname() var args types.EndpointArgs args.IPs = []meta.IP{ip} @@ -141,10 +137,7 @@ func (h *Handler) RefreshGateway() error { } func (h *Handler) loadGateway() error { - hn, err := utils.Hostname() - if err != nil { - return errors.Trace(err) - } + hn := configs.Hostname() var args types.EndpointArgs args.Hostname = hn diff --git a/pkg/utils/misc.go b/pkg/utils/misc.go index 8c6ce82..8effabf 100644 --- a/pkg/utils/misc.go +++ b/pkg/utils/misc.go @@ -1,7 +1,6 @@ package utils import ( - "os" "strconv" "github.com/projecteru2/core/utils" @@ -9,19 +8,9 @@ import ( ) const ( - hnEnv = "HOSTNAME" - biggestMultiple1024 int64 = 0x7ffffffffffffc00 ) -// Hostname . -func Hostname() (string, error) { - if hn := os.Getenv(hnEnv); len(hn) > 0 { - return hn, nil - } - return os.Hostname() -} - // Invoke . func Invoke(funcs []func() error) error { for _, fn := range funcs { diff --git a/yavirtd.go b/yavirtd.go index 63013ea..63f587b 100644 --- a/yavirtd.go +++ b/yavirtd.go @@ -40,7 +40,45 @@ func main() { Name: "yavirtd", Usage: "yavirt daemon", Version: "v", - Action: Run, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Value: "/etc/eru/yavirtd.toml", + Usage: "config file path for yavirt, in toml", + EnvVars: []string{"ERU_YAVIRT_CONFIG_PATH"}, + }, + &cli.StringFlag{ + Name: "log-level", + Value: "INFO", + Usage: "set log level", + EnvVars: []string{"ERU_YAVIRT_LOG_LEVEL"}, + }, + &cli.StringSliceFlag{ + Name: "core-addrs", + Value: cli.NewStringSlice(), + Usage: "core addresses", + EnvVars: []string{"ERU_YAVIRT_CORE_ADDRS"}, + }, + &cli.StringFlag{ + Name: "core-username", + Value: "", + Usage: "core username", + EnvVars: []string{"ERU_YAVIRT_CORE_USERNAME"}, + }, + &cli.StringFlag{ + Name: "core-password", + Value: "", + Usage: "core password", + EnvVars: []string{"ERU_YAVIRT_CORE_PASSWORD"}, + }, + &cli.StringFlag{ + Name: "hostname", + Value: "", + Usage: "change hostname", + EnvVars: []string{"ERU_HOSTNAME", "HOSTNAME"}, + }, + }, + Action: Run, } if err := app.Run(os.Args); err != nil { @@ -51,10 +89,20 @@ func main() { os.Exit(0) } +func initConfig(c *cli.Context) error { + cfg := &configs.Conf + if err := cfg.Load([]string{c.String("config")}); err != nil { + return err + } + return cfg.Prepare(c) +} // Run . func Run(c *cli.Context) error { - defers, svc, err := setup(c.Args().Slice()) + if err := initConfig(c); err != nil { + return err + } + defers, svc, err := setup() if err != nil { return errors.Trace(err) } @@ -147,11 +195,7 @@ func notify(servers []server.Serverable) { wg.Wait() } -func setup(configFiles []string) (deferSentry func(), svc *server.Service, err error) { - if err = configs.Conf.Load(configFiles); err != nil { - return - } - +func setup() (deferSentry func(), svc *server.Service, err error) { if deferSentry, err = log.Setup(configs.Conf.LogLevel, configs.Conf.LogFile, configs.Conf.LogSentry); err != nil { return }