diff --git a/.gitignore b/.gitignore index 376f5e735..1a7a77c28 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # General files for the project -pkg/* *.pyc bin/* **bin/ @@ -40,4 +39,4 @@ Session.vim .history # Ignore docs site created -**/site/ \ No newline at end of file +**/site/ diff --git a/cmd/starship/go.mod b/cmd/starship/go.mod index 58cd1c747..819208e8d 100644 --- a/cmd/starship/go.mod +++ b/cmd/starship/go.mod @@ -6,6 +6,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/urfave/cli/v2 v2.25.3 go.uber.org/zap v1.24.0 + gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.12.0 sigs.k8s.io/yaml v1.3.0 ) @@ -129,7 +130,6 @@ require ( google.golang.org/protobuf v1.29.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.27.1 // indirect k8s.io/apiextensions-apiserver v0.27.1 // indirect k8s.io/apimachinery v0.27.1 // indirect diff --git a/faucet/go.mod b/faucet/go.mod index ead92ddc1..ef5bda4c2 100644 --- a/faucet/go.mod +++ b/faucet/go.mod @@ -4,7 +4,6 @@ go 1.19 require ( github.com/go-chi/chi v1.5.4 - github.com/golang/protobuf v1.5.3 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 github.com/urfave/cli v1.22.12 @@ -18,6 +17,7 @@ require ( github.com/benbjohnson/clock v1.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/golang/glog v1.1.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/stretchr/testify v1.8.2 // indirect diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..866ac5430 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/cosmology-tech/starship + +go 1.21.0 + +require gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..a62c313c5 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work index 960d21613..aa09a2abd 100644 --- a/go.work +++ b/go.work @@ -1,13 +1,15 @@ -go 1.19 +go 1.21.0 use ( + + . ./clients/go/client ./cmd/starship ./examples/upgrade-test ./exposer - ./registry ./faucet + ./registry ./tests/e2e ./tools ) diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go new file mode 100644 index 000000000..2e491b166 --- /dev/null +++ b/pkg/loader/loader.go @@ -0,0 +1,7 @@ +package loader + +import "github.com/cosmology-tech/starship/pkg/types" + +type Loader interface { + LoadFile(files []string, defaultFile string) (types.StarshipObject, error) +} diff --git a/pkg/loader/starship/chain.go b/pkg/loader/starship/chain.go new file mode 100644 index 000000000..443e1f358 --- /dev/null +++ b/pkg/loader/starship/chain.go @@ -0,0 +1,67 @@ +package starship + +import ( + "github.com/cosmology-tech/starship/pkg/types" + "strings" +) + +func getChainPorts(chainConfig types.Chain) []types.Ports { + // default ports + ports := []types.Ports{ + {Name: "p2p", ContainerPort: 26656, Protocol: "TCP"}, + {Name: "rpc", ContainerPort: 26657, Protocol: "TCP"}, + {Name: "address", ContainerPort: 26658, Protocol: "TCP"}, + {Name: "grpc", ContainerPort: 9090, Protocol: "TCP"}, + {Name: "rest", ContainerPort: 1317, Protocol: "TCP"}, + } + + for i, port := range ports { + hostPort := chainConfig.Ports.GetPort(port.Name) + if hostPort != 0 { + ports[i].HostPort = int32(hostPort) + } + } + + return ports +} + +// convertChainToServiceConfig creates a list of serviceConfig objects based on chain defination in config +// when a chain is converted to NodeConfig, then these containers are created: +// - {chain}-genesis +// init: [init-genesis, init-config] +// sidecars: [exposer, faucet(optional)] +// - {chain}-validator +// dependson: genesis +// init: [init-validator, init-config] +// sidecars: [exposer] +// - {chain}-cometmock (optional) +// dependson: genesis, validator +// init: [init-cometmock] +func convertChainToServiceConfig(chainConfig types.Chain) ([]types.NodeConfig, error) { + allNodes := []types.NodeConfig{} + + // initialize genesis node + genesis := types.NodeConfig{ + Name: chainConfig.Name, + ContainerName: strings.Replace(chainConfig.Name, "_", "-", -1), + Controller: "statefulsets", // this is specific to k8s, and is ignored for others + Image: chainConfig.Image, + Port: getChainPorts(chainConfig), + Command: nil, + ScriptFiles: nil, + WorkingDir: "", + Init: nil, + DependsOn: nil, + Replicas: 0, + Labels: nil, + Annotations: nil, + Sidecars: nil, + Resources: types.Resource{}, + ImagePullPolicy: "", + Files: nil, + } + + allNodes = append(allNodes, genesis) + + return allNodes, nil +} diff --git a/pkg/loader/starship/starship.go b/pkg/loader/starship/starship.go new file mode 100644 index 000000000..d4fcc5b23 --- /dev/null +++ b/pkg/loader/starship/starship.go @@ -0,0 +1,46 @@ +package starship + +import ( + "errors" + "github.com/cosmology-tech/starship/pkg/types" + "gopkg.in/yaml.v3" + "os" +) + +// Starship is starship config file loader, implements Loader interface +type Starship struct { +} + +func (s *Starship) LoadFile(files []string, defaultFile string) (types.StarshipObject, error) { + if len(files) > 0 { + return types.StarshipObject{}, errors.New("loading from multiple files not supported, yet") + } + config, err := s.loadConfig(files[0]) + if err != nil { + return types.StarshipObject{}, nil + } + // todo: override defaults into config + + return convertConfigToObject(config) +} + +// loadConfig reads the file into config object +func (s *Starship) loadConfig(file string) (types.Config, error) { + config := types.Config{} + yamlFile, err := os.ReadFile(file) + if err != nil { + return types.Config{}, err + } + err = yaml.Unmarshal(yamlFile, config) + if err != nil { + return types.Config{}, err + } + + return config, nil +} + +// convertConfigToObject converts basic Config object into Starship object, this would prefill informations +// based on chains, relayers and explorers +func convertConfigToObject(config types.Config) (types.StarshipObject, error) { + return types.StarshipObject{}, nil +} diff --git a/pkg/transformer/kubernetes/kubernetes.go b/pkg/transformer/kubernetes/kubernetes.go new file mode 100644 index 000000000..b3c6e92c5 --- /dev/null +++ b/pkg/transformer/kubernetes/kubernetes.go @@ -0,0 +1,9 @@ +package kubernetes + +import "github.com/cosmology-tech/starship/pkg/types" + +// Kubernetes implements Transformer interface and represents Kubernetes transformer +type Kubernetes struct { + // the user provided options from the command line + Opt types.ConvertOptions +} diff --git a/pkg/transformer/transform.go b/pkg/transformer/transform.go new file mode 100644 index 000000000..17c22785a --- /dev/null +++ b/pkg/transformer/transform.go @@ -0,0 +1,14 @@ +package transformer + +import ( + "github.com/cosmology-tech/starship/pkg/types" +) + +type Object interface { + WriteToFile(dir string) error + Validate() error +} + +type Transformer interface { + Transform(types.StarshipObject, types.ConvertOptions) (Object, error) +} diff --git a/pkg/types/config.go b/pkg/types/config.go new file mode 100644 index 000000000..2c065b071 --- /dev/null +++ b/pkg/types/config.go @@ -0,0 +1,160 @@ +package types + +import ( + "fmt" + "strings" +) + +type Chain struct { + Name string `name:"name" json:"name,omitempty" yaml:"name"` + Type string `name:"type" json:"type,omitempty" yaml:"type"` + NumValidators int `name:"num-validators" json:"num_validators,omitempty" yaml:"numValidators"` + Image string `name:"image" json:"image,omitempty" yaml:"image,omitempty"` + // Chain specifics + Home string `name:"home" json:"home,omitempty" yaml:"home,omitempty"` + Binary string `name:"binary" json:"binary,omitempty" yaml:"binary,omitempty"` + Prefix string `name:"prefix" json:"prefix,omitempty" yaml:"prefix,omitempty"` + Denom string `name:"denom" json:"denom,omitempty" yaml:"denom,omitempty"` + PrettyName string `name:"pretty-name" json:"pretty_name,omitempty" yaml:"prettyName,omitempty"` + Coins string `name:"coins" json:"coins,omitempty" yaml:"coins,omitempty"` + HDPath string `name:"hd-path" json:"hd_path,omitempty" yaml:"hdPath,omitempty"` + CoinType string `name:"coin-type" json:"coin_type,omitempty" yaml:"coinType,omitempty"` + Repo string `name:"repo" json:"repo,omitempty" yaml:"repo,omitempty"` + // Custom modifications + Scripts map[string]ScriptData `name:"scripts" json:"scripts,omitempty" yaml:"scripts"` + Upgrade Upgrade `name:"upgrade" json:"upgrade,omitempty" yaml:"upgrade"` + Genesis map[string]interface{} `name:"genesis" json:"genesis,omitempty" yaml:"genesis"` + // Feature toggles + Build Build `name:"build" json:"build,omitempty" yaml:"build,omitempty"` + Cometmock *Feature `name:"cometmock" json:"cometmock,omitempty" yaml:"cometmock,omitempty"` + Faucet *Feature `name:"facuet" json:"faucet,omitempty" yaml:"faucet,omitempty"` + ICS *Feature `name:"ics" json:"ics,omitempty" yaml:"ics,omitempty"` + // Additional information + Ports HostPort `name:"ports" json:"ports,omitempty" yaml:"ports,omitempty"` + Resources Resource `name:"resource" json:"resources,omitempty" yaml:"resources,omitempty"` +} + +func (c *Chain) GetName() string { + return strings.Replace(c.Name, "_", "-", -1) +} + +func (c *Chain) GetChainID() string { + return c.Name +} + +func (c *Chain) GetRPCAddr() string { + return fmt.Sprintf("http://localhost:%d", c.Ports.Rpc) +} + +func (c *Chain) GetRESTAddr() string { + return fmt.Sprintf("http://localhost:%d", c.Ports.Rest) +} + +type ScriptData struct { + File string `name:"file" json:"file,omitempty" yaml:"file"` + Data string `name:"data" json:"data,omitempty" yaml:"data"` +} + +type Upgrade struct { + Enabled bool `name:"eanbled" json:"enabled" yaml:"enabled"` + Type string `name:"type" json:"type" yaml:"type"` + Genesis string `name:"genesis" json:"genesis" yaml:"genesis"` + Upgrades []struct { + Name string `name:"name" json:"name" yaml:"name"` + Version string `name:"version" json:"version" yaml:"version"` + } `name:"upgrades" json:"upgrades" yaml:"upgrades"` +} + +type Build struct { + Enabled bool `name:"enabled" json:"enabled,omitempty" yaml:"enabled,omitempty"` + Source string `name:"source" json:"source,omitempty" yaml:"source,omitempty"` +} + +type HostPort struct { + Rest int `name:"rest" json:"rest" yaml:"rest"` + Rpc int `name:"rpc" json:"rpc" yaml:"rpc"` + Grpc int `name:"grpc" json:"grpc" yaml:"grpc"` + Exposer int `name:"exposer" json:"exposer" yaml:"exposer"` + Faucet int `name:"faucet" json:"faucet" yaml:"faucet"` +} + +func (p HostPort) GetPort(port string) int { + switch port { + case "rpc": + return p.Rpc + case "rest": + return p.Rest + case "grpc": + return p.Grpc + case "exposer": + return p.Exposer + case "faucet": + return p.Faucet + default: + return 0 + } +} + +type Relayer struct { + Name string `name:"name" json:"name" yaml:"name"` + Type string `name:"type" json:"type" yaml:"type"` + Image string `name:"image" json:"image,omitempty" yaml:"image,omitempty"` + Replicas int `name:"replicas" json:"replicas" yaml:"replicas"` + Chains []string `name:"chains" json:"chains" yaml:"chains"` + Config interface{} `name:"config" json:"config,omitempty" yaml:"config,omitempty"` +} + +type Faucet struct { + Enabled bool `name:"enabled" json:"enabled" yaml:"enabled"` + Image string `name:"image" json:"image" yaml:"image"` + Ports HostPort `name:"ports" json:"ports" yaml:"ports"` + Concurrency int `name:"concurrency" json:"concurrency,omitempty" yaml:"concurrency,omitempty"` +} + +type Feature struct { + Enabled bool `name:"enabled" json:"enabled" yaml:"enabled"` + Image string `name:"image" json:"image" yaml:"image"` + Ports HostPort `name:"ports" json:"ports" yaml:"ports"` +} + +func (f *Feature) GetRPCAddr() string { + return fmt.Sprintf("http://localhost:%d", f.Ports.Rpc) +} + +func (f *Feature) GetRESTAddr() string { + return fmt.Sprintf("http://localhost:%d", f.Ports.Rest) +} + +// Config is the struct for the config.yaml setup file +// Need not be fully compatible with the values.schema.json file, just need +// parts of the config file for performing various functions, mainly port-forwarding +// todo: move this to a more common place, outside just tests +// todo: can be moved to proto defination +type Config struct { + Chains []*Chain `name:"chains" json:"chains" yaml:"chains"` + Relayers []*Relayer `name:"relayers" json:"relayers" yaml:"relayers"` + Explorer *Feature `name:"explorer" json:"explorer" yaml:"explorer"` + Registry *Feature `name:"registry" json:"registry" yaml:"registry"` +} + +// HasChainId returns true if chain id found in list of chains +func (c *Config) HasChainId(chainId string) bool { + for _, chain := range c.Chains { + if chain.Name == chainId { + return true + } + } + + return false +} + +// GetChain returns the Chain object pointer for the given chain id +func (c *Config) GetChain(chainId string) *Chain { + for _, chain := range c.Chains { + if chain.Name == chainId { + return chain + } + } + + return nil +} diff --git a/pkg/types/object.go b/pkg/types/object.go new file mode 100644 index 000000000..9812528b4 --- /dev/null +++ b/pkg/types/object.go @@ -0,0 +1,63 @@ +package types + +type StarshipObject struct { + ServiceConfigs map[string]NodeConfig +} + +type EnvVar struct { + Name string + Value string +} + +type Ports struct { + Name string + HostPort int32 + ContainerPort int32 + HostIP string + Protocol string +} + +// Init describes precontainer creation steps. These can be either as docker containers +// or just scripts. These are supposed to run to completion +type Init struct { + Name string + Image string // optional + Command []string + WorkingDir string + ScriptFiles []string +} + +type Resource struct { + CPU string `name:"cpu" json:"cpu,omitempty" yaml:"cpu,omitempty"` + Memory string `name:"memory" json:"memory,omitempty" yaml:"memory,omitempty"` +} + +type File struct { + Name string + Path string + Content []byte + MountPath string +} + +// NodeConfig describes containers and objects without specifics of underlying infra +type NodeConfig struct { + Name string + ContainerName string + Controller string + Image string + Environment []EnvVar + EnvFile []string + Port []Ports + Command []string + ScriptFiles []string + WorkingDir string + Init []Init + DependsOn []*NodeConfig // Pointer to serviceconfig this would depend on + Replicas int + Labels map[string]string + Annotations map[string]string + Sidecars []*NodeConfig // pointers to serviceconfig that are run as sidecars + Resources Resource + ImagePullPolicy string + Files []File +} diff --git a/pkg/types/options.go b/pkg/types/options.go new file mode 100644 index 000000000..3efdd078f --- /dev/null +++ b/pkg/types/options.go @@ -0,0 +1,4 @@ +package types + +type ConvertOptions struct { +}