f-28: generate metadata_port automatically at vm creation
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
1b56a42627
commit
b41b4f2518
4 changed files with 55 additions and 33 deletions
|
|
@ -402,14 +402,11 @@ components:
|
||||||
|
|
||||||
VMCreateRequest:
|
VMCreateRequest:
|
||||||
type: object
|
type: object
|
||||||
required: [name, metadata_port, interfaces, storage]
|
required: [name, interfaces, storage]
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
example: vm-00001
|
example: vm-00001
|
||||||
metadata_port:
|
|
||||||
type: string
|
|
||||||
example: "80"
|
|
||||||
memory:
|
memory:
|
||||||
type: integer
|
type: integer
|
||||||
description: Memory in MB (default 512)
|
description: Memory in MB (default 512)
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,13 @@ type VMStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMCreateRequest struct {
|
type VMCreateRequest struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
MetadataPort string `json:"metadata_port"`
|
Memory int `json:"memory"`
|
||||||
Memory int `json:"memory"`
|
CPUs int `json:"cpus"`
|
||||||
CPUs int `json:"cpus"`
|
Password string `json:"password"`
|
||||||
Password string `json:"password"`
|
SSHKey string `json:"sshkey"`
|
||||||
SSHKey string `json:"sshkey"`
|
Interfaces []VMInterface `json:"interfaces"`
|
||||||
Interfaces []VMInterface `json:"interfaces"`
|
Storage []VMStorage `json:"storage"`
|
||||||
Storage []VMStorage `json:"storage"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type VM struct {
|
type VM struct {
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ func (s *Server) startVM(w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid request body"})
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid request body"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.Name == "" || req.MetadataPort == "" || len(req.Interfaces) == 0 || len(req.Storage) == 0 {
|
if req.Name == "" || len(req.Interfaces) == 0 || len(req.Storage) == 0 {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
json.NewEncoder(w).Encode(ErrorResponse{Error: "name, metadata_port, interfaces and storage are required"})
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "name, interfaces and storage are required"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,15 +78,14 @@ func (s *Server) startVM(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := dispatcher.StartVMCommand{
|
cmd := dispatcher.StartVMCommand{
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Subnet: primary.Subnet,
|
Subnet: primary.Subnet,
|
||||||
IP: primary.IP,
|
IP: primary.IP,
|
||||||
MetadataPort: req.MetadataPort,
|
VolumePath: req.Storage[0].Path,
|
||||||
VolumePath: req.Storage[0].Path,
|
Memory: req.Memory,
|
||||||
Memory: req.Memory,
|
CPUs: req.CPUs,
|
||||||
CPUs: req.CPUs,
|
Password: req.Password,
|
||||||
Password: req.Password,
|
SSHKey: req.SSHKey,
|
||||||
SSHKey: req.SSHKey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dispatcher.Prepare(cmd); err != nil {
|
if err := s.dispatcher.Prepare(cmd); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
configuration "git.g3e.fr/syonad/two/internal/config/agent"
|
configuration "git.g3e.fr/syonad/two/internal/config/agent"
|
||||||
|
|
@ -12,15 +14,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type StartVMCommand struct {
|
type StartVMCommand struct {
|
||||||
Name string
|
Name string
|
||||||
Subnet string
|
Subnet string
|
||||||
IP string
|
IP string
|
||||||
MetadataPort string
|
VolumePath string
|
||||||
VolumePath string
|
Memory int
|
||||||
Memory int
|
CPUs int
|
||||||
CPUs int
|
Password string
|
||||||
Password string
|
SSHKey string
|
||||||
SSHKey string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c StartVMCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
func (c StartVMCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
||||||
|
|
@ -34,10 +35,14 @@ func (c StartVMCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
||||||
if subnetState == "deleting" || subnetState == "deleted" {
|
if subnetState == "deleting" || subnetState == "deleted" {
|
||||||
return fmt.Errorf("subnet %q is %s", c.Subnet, subnetState)
|
return fmt.Errorf("subnet %q is %s", c.Subnet, subnetState)
|
||||||
}
|
}
|
||||||
|
port, err := allocateMetadataPort(db)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("allocate metadata port: %w", err)
|
||||||
|
}
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/state", "starting")
|
kv.AddInDB(db, "vm/"+c.Name+"/state", "starting")
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/subnet", c.Subnet)
|
kv.AddInDB(db, "vm/"+c.Name+"/subnet", c.Subnet)
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/ip", c.IP)
|
kv.AddInDB(db, "vm/"+c.Name+"/ip", c.IP)
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/metadata_port", c.MetadataPort)
|
kv.AddInDB(db, "vm/"+c.Name+"/metadata_port", strconv.Itoa(port))
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/volume_path", c.VolumePath)
|
kv.AddInDB(db, "vm/"+c.Name+"/volume_path", c.VolumePath)
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/memory", strconv.Itoa(c.Memory))
|
kv.AddInDB(db, "vm/"+c.Name+"/memory", strconv.Itoa(c.Memory))
|
||||||
kv.AddInDB(db, "vm/"+c.Name+"/cpus", strconv.Itoa(c.CPUs))
|
kv.AddInDB(db, "vm/"+c.Name+"/cpus", strconv.Itoa(c.CPUs))
|
||||||
|
|
@ -50,6 +55,28 @@ func (c StartVMCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allocateMetadataPort(db *badger.DB) (int, error) {
|
||||||
|
entries, err := kv.ListByPrefix(db, "vm/")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
used := make(map[int]struct{})
|
||||||
|
for key, value := range entries {
|
||||||
|
if strings.HasSuffix(key, "/metadata_port") {
|
||||||
|
if p, err := strconv.Atoi(value); err == nil {
|
||||||
|
used[p] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for range 100 {
|
||||||
|
p := rand.Intn(9000) + 1000
|
||||||
|
if _, taken := used[p]; !taken {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("no free metadata port available in [1000, 9999]")
|
||||||
|
}
|
||||||
|
|
||||||
func (c StartVMCommand) Execute(db *badger.DB, cfg *configuration.Config) error {
|
func (c StartVMCommand) Execute(db *badger.DB, cfg *configuration.Config) error {
|
||||||
timeout := time.After(time.Duration(cfg.Dispatcher.TimeoutSeconds) * time.Second)
|
timeout := time.After(time.Duration(cfg.Dispatcher.TimeoutSeconds) * time.Second)
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue