diff --git a/server/README.md b/server/README.md index 09b49df..d2c31ed 100644 --- a/server/README.md +++ b/server/README.md @@ -18,10 +18,7 @@ Server-side implementation for shoes-lxd-multi ``` ### Optional values -- `LXD_MULTI_IMAGE_ALIAS` - - set runner image alias - - default: `ubuntu:bionic` - - e.g.) for remote image server: `https://192.0.2.110:8443/ubuntu-custom` + - `LXD_MULTI_RESOURCE_TYPE_MAPPING` - mapping `resource_type` and CPU / Memory. - need JSON format. keys is `resource_type_name`, `cpu`, `memory`. diff --git a/server/go.mod b/server/go.mod index a88201f..7897e24 100644 --- a/server/go.mod +++ b/server/go.mod @@ -7,8 +7,6 @@ require ( github.com/lxc/lxd v0.0.0-20211202222358-a293da71aeb0 github.com/prometheus/client_golang v1.11.0 github.com/whywaita/myshoes v1.10.4 - github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2 + github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161 google.golang.org/grpc v1.42.0 ) - -//replace github.com/flosch/pongo2 => github.com/flosch/pongo2/v4 v4.0.2 diff --git a/server/go.sum b/server/go.sum index 21e4fee..5174fe1 100644 --- a/server/go.sum +++ b/server/go.sum @@ -809,6 +809,8 @@ github.com/whywaita/myshoes v1.10.4 h1:4EeoOKnwN2HpCe8KaLRQhQPWDvqYlNSPjIc94z5WC github.com/whywaita/myshoes v1.10.4/go.mod h1:1HsvGV2VRtOtagjo0S0XhYM9dJdOHzX2+XXJ1yQAG04= github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2 h1:bidYeGz7agcdZMjO1yk2GhjhZMuVZmszfu40StCblmc= github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2/go.mod h1:xLARbdd13u1aMMBI0xRc8FVv4RRoCFf5f7+E/HaNs7o= +github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161 h1:p8niwHC6nWbg0uoX3pd3aI5ZwVxgtHXGDzSKx49zcfg= +github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161/go.mod h1:xLARbdd13u1aMMBI0xRc8FVv4RRoCFf5f7+E/HaNs7o= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= diff --git a/server/main.go b/server/main.go index 55de364..cee2d64 100644 --- a/server/main.go +++ b/server/main.go @@ -25,14 +25,14 @@ func main() { } func run() error { - hostConfigs, mapping, instanceSource, listenPort, overCommitPercent, err := config.Load() + hostConfigs, mapping, listenPort, overCommitPercent, err := config.Load() if err != nil { return fmt.Errorf("failed to create server: %w", err) } go serveMetrics(context.Background(), hostConfigs) - server, err := api.New(hostConfigs, mapping, instanceSource, overCommitPercent) + server, err := api.New(hostConfigs, mapping, overCommitPercent) if err != nil { return fmt.Errorf("failed to create server: %w", err) } diff --git a/server/pkg/api/server.go b/server/pkg/api/server.go index 5629b10..ff6b96c 100644 --- a/server/pkg/api/server.go +++ b/server/pkg/api/server.go @@ -5,8 +5,6 @@ import ( "log" "net" - "github.com/lxc/lxd/shared/api" - pb "github.com/whywaita/shoes-lxd-multi/proto.go" "github.com/whywaita/shoes-lxd-multi/server/pkg/config" "github.com/whywaita/shoes-lxd-multi/server/pkg/lxdclient" @@ -19,17 +17,15 @@ type ShoesLXDMultiServer struct { hostConfigs *config.HostConfigMap resourceMapping map[pb.ResourceType]config.Mapping - instanceSource *api.InstanceSource overCommitPercent uint64 } // New create gRPC server -func New(hostConfigs *config.HostConfigMap, mapping map[pb.ResourceType]config.Mapping, instanceSource *api.InstanceSource, overCommitPercent uint64) (*ShoesLXDMultiServer, error) { +func New(hostConfigs *config.HostConfigMap, mapping map[pb.ResourceType]config.Mapping, overCommitPercent uint64) (*ShoesLXDMultiServer, error) { return &ShoesLXDMultiServer{ hostConfigs: hostConfigs, resourceMapping: mapping, - instanceSource: instanceSource, overCommitPercent: overCommitPercent, }, nil } diff --git a/server/pkg/api/server_add_instance.go b/server/pkg/api/server_add_instance.go index 0fac663..d4848ba 100644 --- a/server/pkg/api/server_add_instance.go +++ b/server/pkg/api/server_add_instance.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "math/rand" + "net/url" "sort" "strconv" "strings" @@ -26,6 +27,12 @@ func (s *ShoesLXDMultiServer) AddInstance(ctx context.Context, req *pb.AddInstan return nil, status.Errorf(codes.InvalidArgument, "failed to parse request name: %+v", err) } instanceName := req.RunnerName + + instanceSource, err := parseAlias(req.ImageAlias) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "failed to parse image alias: %+v", err) + } + targetLXDHosts, err := s.validateTargetHosts(req.TargetHosts) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to validate target hosts: %+v", err) @@ -45,7 +52,7 @@ func (s *ShoesLXDMultiServer) AddInstance(ctx context.Context, req *pb.AddInstan Config: s.getInstanceConfig(req.SetupScript, req.ResourceType), }, Name: instanceName, - Source: *s.instanceSource, + Source: *instanceSource, } client = host.Client @@ -161,3 +168,40 @@ func schedule(targets []targetHost, limitOverCommit uint64) (*targetHost, error) index := rand.Intn(len(schedulableTargets)) return &schedulableTargets[index], nil } + +// parseAlias parse user input +func parseAlias(input string) (*api.InstanceSource, error) { + if strings.EqualFold(input, "") { + // default value is ubuntu:bionic + return &api.InstanceSource{ + Type: "image", + Properties: map[string]string{ + "os": "ubuntu", + "release": "bionic", + }, + }, nil + } + + if strings.HasPrefix(input, "http") { + // https://:8443/ + u, err := url.Parse(input) + if err != nil { + return nil, fmt.Errorf("failed to parse alias: %w", err) + } + + urlImageServer := fmt.Sprintf("%s://%s", u.Scheme, u.Host) + alias := strings.TrimPrefix(u.Path, "/") + + return &api.InstanceSource{ + Type: "image", + Mode: "pull", + Server: urlImageServer, + Alias: alias, + }, nil + } + + return &api.InstanceSource{ + Type: "image", + Alias: input, + }, nil +} diff --git a/server/pkg/config/config.go b/server/pkg/config/config.go index f4b08c0..e76da0f 100644 --- a/server/pkg/config/config.go +++ b/server/pkg/config/config.go @@ -8,7 +8,6 @@ import ( pb "github.com/whywaita/shoes-lxd-multi/proto.go" - "github.com/lxc/lxd/shared/api" "github.com/whywaita/myshoes/pkg/datastore" ) @@ -16,8 +15,6 @@ const ( // EnvLXDHosts is json of lxd hosts EnvLXDHosts = "LXD_MULTI_HOSTS" - // EnvLXDImageAlias is alias in lxd - EnvLXDImageAlias = "LXD_MULTI_IMAGE_ALIAS" // EnvLXDResourceTypeMapping is mapping resource in lxd EnvLXDResourceTypeMapping = "LXD_MULTI_RESOURCE_TYPE_MAPPING" // EnvPort will listen port @@ -34,10 +31,10 @@ type Mapping struct { } // Load load config from Environment values -func Load() (*HostConfigMap, map[pb.ResourceType]Mapping, *api.InstanceSource, int, uint64, error) { +func Load() (*HostConfigMap, map[pb.ResourceType]Mapping, int, uint64, error) { hostConfigs, err := loadHostConfigs() if err != nil { - return nil, nil, nil, -1, 0, fmt.Errorf("failed to load host config: %w", err) + return nil, nil, -1, 0, fmt.Errorf("failed to load host config: %w", err) } envMappingJSON := os.Getenv(EnvLXDResourceTypeMapping) @@ -45,15 +42,10 @@ func Load() (*HostConfigMap, map[pb.ResourceType]Mapping, *api.InstanceSource, i if envMappingJSON != "" { m, err = readResourceTypeMapping(envMappingJSON) if err != nil { - return nil, nil, nil, -1, 0, fmt.Errorf("failed to read %s: %w", EnvLXDResourceTypeMapping, err) + return nil, nil, -1, 0, fmt.Errorf("failed to read %s: %w", EnvLXDResourceTypeMapping, err) } } - alias, err := parseAlias(os.Getenv(EnvLXDImageAlias)) - if err != nil { - return nil, nil, nil, -1, 0, fmt.Errorf("failed to parse alias %s: %w", EnvLXDImageAlias, err) - } - envPort := os.Getenv(EnvPort) var port int if envPort == "" { @@ -61,7 +53,7 @@ func Load() (*HostConfigMap, map[pb.ResourceType]Mapping, *api.InstanceSource, i } else { port, err = strconv.Atoi(envPort) if err != nil { - return nil, nil, nil, -1, 0, fmt.Errorf("failed to parse %s, need to int: %w", EnvPort, err) + return nil, nil, -1, 0, fmt.Errorf("failed to parse %s, need to int: %w", EnvPort, err) } } @@ -72,11 +64,11 @@ func Load() (*HostConfigMap, map[pb.ResourceType]Mapping, *api.InstanceSource, i } else { overCommitPercent, err = strconv.ParseUint(envOCP, 10, 64) if err != nil { - return nil, nil, nil, -1, 0, fmt.Errorf("failed to parse %s, need to uint: %w", EnvOverCommit, err) + return nil, nil, -1, 0, fmt.Errorf("failed to parse %s, need to uint: %w", EnvOverCommit, err) } } - return hostConfigs, m, alias, port, overCommitPercent, nil + return hostConfigs, m, port, overCommitPercent, nil } func readResourceTypeMapping(env string) (map[pb.ResourceType]Mapping, error) { diff --git a/server/pkg/config/config_alias.go b/server/pkg/config/config_alias.go deleted file mode 100644 index 7aa43da..0000000 --- a/server/pkg/config/config_alias.go +++ /dev/null @@ -1,46 +0,0 @@ -package config - -import ( - "fmt" - "net/url" - "strings" - - "github.com/lxc/lxd/shared/api" -) - -// parseAlias parse user input -func parseAlias(input string) (*api.InstanceSource, error) { - if strings.EqualFold(input, "") { - // default value is ubuntu:bionic - return &api.InstanceSource{ - Type: "image", - Properties: map[string]string{ - "os": "ubuntu", - "release": "bionic", - }, - }, nil - } - - if strings.HasPrefix(input, "http") { - // https://:8443/ - u, err := url.Parse(input) - if err != nil { - return nil, fmt.Errorf("failed to parse alias: %w", err) - } - - urlImageServer := fmt.Sprintf("%s://%s", u.Scheme, u.Host) - alias := strings.TrimPrefix(u.Path, "/") - - return &api.InstanceSource{ - Type: "image", - Mode: "pull", - Server: urlImageServer, - Alias: alias, - }, nil - } - - return &api.InstanceSource{ - Type: "image", - Alias: input, - }, nil -} diff --git a/shoes-lxd-multi/README.md b/shoes-lxd-multi/README.md index 30f196f..f3813ea 100644 --- a/shoes-lxd-multi/README.md +++ b/shoes-lxd-multi/README.md @@ -17,4 +17,11 @@ shoes-provider implementation for shoes-lxd-multi ] ``` -- `LXD_MULTI_SERVER_ENDPOINT`: Endpoint of Server-side Application \ No newline at end of file +- `LXD_MULTI_SERVER_ENDPOINT`: Endpoint of Server-side Application + +### Optional values + +- `LXD_MULTI_IMAGE_ALIAS` + - set runner image alias + - default: `ubuntu:bionic` + - e.g.) for remote image server: `https://192.0.2.110:8443/ubuntu-custom` diff --git a/shoes-lxd-multi/go.mod b/shoes-lxd-multi/go.mod index 0169c00..5a959df 100644 --- a/shoes-lxd-multi/go.mod +++ b/shoes-lxd-multi/go.mod @@ -5,6 +5,6 @@ go 1.16 require ( github.com/hashicorp/go-plugin v1.4.3 github.com/whywaita/myshoes v1.10.4 - github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2 + github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161 google.golang.org/grpc v1.33.2 ) diff --git a/shoes-lxd-multi/go.sum b/shoes-lxd-multi/go.sum index a330f1a..341477b 100644 --- a/shoes-lxd-multi/go.sum +++ b/shoes-lxd-multi/go.sum @@ -190,6 +190,8 @@ github.com/whywaita/myshoes v1.10.4 h1:4EeoOKnwN2HpCe8KaLRQhQPWDvqYlNSPjIc94z5WC github.com/whywaita/myshoes v1.10.4/go.mod h1:1HsvGV2VRtOtagjo0S0XhYM9dJdOHzX2+XXJ1yQAG04= github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2 h1:bidYeGz7agcdZMjO1yk2GhjhZMuVZmszfu40StCblmc= github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211203151606-53728ef694c2/go.mod h1:xLARbdd13u1aMMBI0xRc8FVv4RRoCFf5f7+E/HaNs7o= +github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161 h1:p8niwHC6nWbg0uoX3pd3aI5ZwVxgtHXGDzSKx49zcfg= +github.com/whywaita/shoes-lxd-multi/proto.go v0.0.0-20211208053634-b26d9a26e161/go.mod h1:xLARbdd13u1aMMBI0xRc8FVv4RRoCFf5f7+E/HaNs7o= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/shoes-lxd-multi/main.go b/shoes-lxd-multi/main.go index 152863d..f6a6d8f 100644 --- a/shoes-lxd-multi/main.go +++ b/shoes-lxd-multi/main.go @@ -21,6 +21,9 @@ const ( EnvTargetHosts = "LXD_MULTI_TARGET_HOSTS" // EnvServerEndpoint is endpoint of server EnvServerEndpoint = "LXD_MULTI_SERVER_ENDPOINT" + + // EnvLXDImageAlias is alias in lxd + EnvLXDImageAlias = "LXD_MULTI_IMAGE_ALIAS" ) func main() { @@ -53,24 +56,29 @@ type LXDMultiPlugin struct { plugin.Plugin } -func loadConfig() ([]string, string, error) { +func loadConfig() ([]string, string, string, error) { var targetHosts []string envTargetHosts := os.Getenv(EnvTargetHosts) if err := json.Unmarshal([]byte(envTargetHosts), &targetHosts); err != nil { - return nil, "", fmt.Errorf("failed to unmarshal JSON from %s: %w", envTargetHosts, err) + return nil, "", "", fmt.Errorf("failed to unmarshal JSON from %s: %w", envTargetHosts, err) } envServerEndpoint := os.Getenv(EnvServerEndpoint) if envServerEndpoint == "" { - return nil, "", fmt.Errorf("must set %s", EnvServerEndpoint) + return nil, "", "", fmt.Errorf("must set %s", EnvServerEndpoint) + } + + alias := os.Getenv(EnvLXDImageAlias) + if alias == "" { + alias = "ubuntu:bionic" } - return targetHosts, envServerEndpoint, nil + return targetHosts, envServerEndpoint, alias, nil } // GRPCServer is implement gRPC Server. func (l *LXDMultiPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { - targetHosts, serverEndpoint, err := loadConfig() + targetHosts, serverEndpoint, imageAlias, err := loadConfig() if err != nil { return fmt.Errorf("failed to load config: %w", err) } @@ -83,7 +91,7 @@ func (l *LXDMultiPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) e if err != nil { return fmt.Errorf("failed to dial to server: %w", err) } - client := NewClient(targetHosts, grpcConn) + client := NewClient(targetHosts, grpcConn, imageAlias) pb.RegisterShoesServer(s, client) return nil @@ -101,13 +109,15 @@ type Client struct { targetHosts []string conn *grpc.ClientConn + imageAlias string } // NewClient create Client -func NewClient(targetHosts []string, conn *grpc.ClientConn) *Client { +func NewClient(targetHosts []string, conn *grpc.ClientConn, imageAlias string) *Client { return &Client{ targetHosts: targetHosts, conn: conn, + imageAlias: imageAlias, } } @@ -119,6 +129,7 @@ func (l Client) AddInstance(ctx context.Context, req *pb.AddInstanceRequest) (*p SetupScript: req.SetupScript, ResourceType: shoeslxdpb.ResourceTypeToShoesLXDMultiPb(req.ResourceType), TargetHosts: l.targetHosts, + ImageAlias: l.imageAlias, } slResp, err := slClient.AddInstance(ctx, slReq)