f-28: add vpc cidr field
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
2504b435a3
commit
76a840b80a
8 changed files with 98 additions and 17 deletions
|
|
@ -294,13 +294,17 @@ components:
|
||||||
|
|
||||||
VPCCreateRequest:
|
VPCCreateRequest:
|
||||||
type: object
|
type: object
|
||||||
required: [name]
|
required: [name, cidr]
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description: Unique name for the VPC, must follow the format vp-[id]
|
description: Unique name for the VPC, must follow the format vp-[id]
|
||||||
pattern: '^vp-.+'
|
pattern: '^vp-.+'
|
||||||
example: vp-00001
|
example: vp-00001
|
||||||
|
cidr:
|
||||||
|
type: string
|
||||||
|
description: CIDR block for the entire VPC address space
|
||||||
|
example: "10.0.0.0/16"
|
||||||
|
|
||||||
VPC:
|
VPC:
|
||||||
type: object
|
type: object
|
||||||
|
|
@ -312,6 +316,9 @@ components:
|
||||||
type: string
|
type: string
|
||||||
enum: [creating, created, deleting, deleted]
|
enum: [creating, created, deleting, deleted]
|
||||||
example: created
|
example: created
|
||||||
|
cidr:
|
||||||
|
type: string
|
||||||
|
example: "10.0.0.0/16"
|
||||||
|
|
||||||
SubnetCreateRequest:
|
SubnetCreateRequest:
|
||||||
type: object
|
type: object
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package agentapi
|
||||||
|
|
||||||
type VPCCreateRequest struct {
|
type VPCCreateRequest struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
CIDR string `json:"cidr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VPC struct {
|
type VPC struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
|
CIDR string `json:"cidr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubnetCreateRequest struct {
|
type SubnetCreateRequest struct {
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,9 @@ func (s *Server) getVpc(w http.ResponseWriter, _ *http.Request, name string) {
|
||||||
json.NewEncoder(w).Encode(ErrorResponse{Error: "vpc not found"})
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "vpc not found"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cidr, _ := kv.GetFromDB(s.db, "vpc/"+name+"/cidr")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(VPC{Name: name, State: state})
|
json.NewEncoder(w).Encode(VPC{Name: name, State: state, CIDR: cidr})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) deleteVpc(w http.ResponseWriter, _ *http.Request, name string) {
|
func (s *Server) deleteVpc(w http.ResponseWriter, _ *http.Request, name string) {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func TestListVpcs_InvalidMethod(t *testing.T) {
|
||||||
|
|
||||||
func TestPostVpc_Created(t *testing.T) {
|
func TestPostVpc_Created(t *testing.T) {
|
||||||
s, _ := newTestServer(t)
|
s, _ := newTestServer(t)
|
||||||
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-new"})
|
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-new", CIDR: "10.0.0.0/16"})
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
||||||
if w.Code != http.StatusAccepted {
|
if w.Code != http.StatusAccepted {
|
||||||
|
|
@ -67,11 +67,34 @@ func TestPostVpc_Created(t *testing.T) {
|
||||||
if result.State != "creating" {
|
if result.State != "creating" {
|
||||||
t.Errorf("state attendu creating, obtenu %q", result.State)
|
t.Errorf("state attendu creating, obtenu %q", result.State)
|
||||||
}
|
}
|
||||||
|
if result.CIDR != "10.0.0.0/16" {
|
||||||
|
t.Errorf("cidr attendu 10.0.0.0/16, obtenu %q", result.CIDR)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPostVpc_MissingName(t *testing.T) {
|
func TestPostVpc_MissingName(t *testing.T) {
|
||||||
s, _ := newTestServer(t)
|
s, _ := newTestServer(t)
|
||||||
body, _ := json.Marshal(VPCCreateRequest{})
|
body, _ := json.Marshal(VPCCreateRequest{CIDR: "10.0.0.0/16"})
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("attendu 400, obtenu %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostVpc_MissingCIDR(t *testing.T) {
|
||||||
|
s, _ := newTestServer(t)
|
||||||
|
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-new"})
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("attendu 400, obtenu %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostVpc_InvalidCIDR(t *testing.T) {
|
||||||
|
s, _ := newTestServer(t)
|
||||||
|
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-new", CIDR: "not-a-cidr"})
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
||||||
if w.Code != http.StatusBadRequest {
|
if w.Code != http.StatusBadRequest {
|
||||||
|
|
@ -82,7 +105,7 @@ func TestPostVpc_MissingName(t *testing.T) {
|
||||||
func TestPostVpc_Duplicate(t *testing.T) {
|
func TestPostVpc_Duplicate(t *testing.T) {
|
||||||
s, db := newTestServer(t)
|
s, db := newTestServer(t)
|
||||||
kv.AddInDB(db, "vpc/vpc-exist/state", "created")
|
kv.AddInDB(db, "vpc/vpc-exist/state", "created")
|
||||||
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-exist"})
|
body, _ := json.Marshal(VPCCreateRequest{Name: "vpc-exist", CIDR: "10.0.0.0/16"})
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
s.VpcsHandler(w, httptest.NewRequest(http.MethodPost, "/vpcs", bytes.NewReader(body)))
|
||||||
if w.Code != http.StatusConflict {
|
if w.Code != http.StatusConflict {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package agentapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -38,8 +39,11 @@ func (s *Server) listVpcs(w http.ResponseWriter, _ *http.Request) {
|
||||||
if _, ok := vpcs[name]; !ok {
|
if _, ok := vpcs[name]; !ok {
|
||||||
vpcs[name] = &VPC{Name: name}
|
vpcs[name] = &VPC{Name: name}
|
||||||
}
|
}
|
||||||
if parts[2] == "state" {
|
switch parts[2] {
|
||||||
|
case "state":
|
||||||
vpcs[name].State = value
|
vpcs[name].State = value
|
||||||
|
case "cidr":
|
||||||
|
vpcs[name].CIDR = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result := make([]VPC, 0, len(vpcs))
|
result := make([]VPC, 0, len(vpcs))
|
||||||
|
|
@ -62,7 +66,17 @@ func (s *Server) postVpc(w http.ResponseWriter, r *http.Request) {
|
||||||
json.NewEncoder(w).Encode(ErrorResponse{Error: "name is required"})
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "name is required"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cmd := dispatcher.CreateVPCCommand{Name: req.Name}
|
if req.CIDR == "" {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "cidr is required"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, _, err := net.ParseCIDR(req.CIDR); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid cidr"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd := dispatcher.CreateVPCCommand{Name: req.Name, CIDR: req.CIDR}
|
||||||
if err := s.dispatcher.Prepare(cmd); err != nil {
|
if err := s.dispatcher.Prepare(cmd); err != nil {
|
||||||
w.WriteHeader(http.StatusConflict)
|
w.WriteHeader(http.StatusConflict)
|
||||||
json.NewEncoder(w).Encode(ErrorResponse{Error: err.Error()})
|
json.NewEncoder(w).Encode(ErrorResponse{Error: err.Error()})
|
||||||
|
|
@ -76,5 +90,5 @@ func (s *Server) postVpc(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusAccepted)
|
w.WriteHeader(http.StatusAccepted)
|
||||||
json.NewEncoder(w).Encode(VPC{Name: req.Name, State: state})
|
json.NewEncoder(w).Encode(VPC{Name: req.Name, State: state, CIDR: req.CIDR})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package dispatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -13,12 +14,19 @@ import (
|
||||||
|
|
||||||
type CreateVPCCommand struct {
|
type CreateVPCCommand struct {
|
||||||
Name string
|
Name string
|
||||||
|
CIDR string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CreateVPCCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
func (c CreateVPCCommand) Prepare(db *badger.DB, _ *configuration.Config) error {
|
||||||
if _, err := kv.GetFromDB(db, "vpc/"+c.Name+"/state"); err == nil {
|
if _, err := kv.GetFromDB(db, "vpc/"+c.Name+"/state"); err == nil {
|
||||||
return fmt.Errorf("vpc %q already exists", c.Name)
|
return fmt.Errorf("vpc %q already exists", c.Name)
|
||||||
}
|
}
|
||||||
|
if _, _, err := net.ParseCIDR(c.CIDR); err != nil {
|
||||||
|
return fmt.Errorf("invalid cidr %q: %w", c.CIDR, err)
|
||||||
|
}
|
||||||
|
if err := kv.AddInDB(db, "vpc/"+c.Name+"/cidr", c.CIDR); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return kv.AddInDB(db, "vpc/"+c.Name+"/state", "creating")
|
return kv.AddInDB(db, "vpc/"+c.Name+"/state", "creating")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
func TestCreateVPCCommand_Prepare_NewVPC(t *testing.T) {
|
func TestCreateVPCCommand_Prepare_NewVPC(t *testing.T) {
|
||||||
_, db := newTestDispatcher(t)
|
_, db := newTestDispatcher(t)
|
||||||
cmd := CreateVPCCommand{Name: "vpc-1"}
|
cmd := CreateVPCCommand{Name: "vpc-1", CIDR: "10.0.0.0/16"}
|
||||||
if err := cmd.Prepare(db, nil); err != nil {
|
if err := cmd.Prepare(db, nil); err != nil {
|
||||||
t.Fatalf("Prepare a échoué : %v", err)
|
t.Fatalf("Prepare a échoué : %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -21,17 +21,32 @@ func TestCreateVPCCommand_Prepare_NewVPC(t *testing.T) {
|
||||||
if state != "creating" {
|
if state != "creating" {
|
||||||
t.Errorf("state attendu creating, obtenu %q", state)
|
t.Errorf("state attendu creating, obtenu %q", state)
|
||||||
}
|
}
|
||||||
|
cidr, err := kv.GetFromDB(db, "vpc/vpc-1/cidr")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cidr non écrit en DB : %v", err)
|
||||||
|
}
|
||||||
|
if cidr != "10.0.0.0/16" {
|
||||||
|
t.Errorf("cidr attendu 10.0.0.0/16, obtenu %q", cidr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateVPCCommand_Prepare_Duplicate(t *testing.T) {
|
func TestCreateVPCCommand_Prepare_Duplicate(t *testing.T) {
|
||||||
_, db := newTestDispatcher(t)
|
_, db := newTestDispatcher(t)
|
||||||
kv.AddInDB(db, "vpc/vpc-exist/state", "created")
|
kv.AddInDB(db, "vpc/vpc-exist/state", "created")
|
||||||
cmd := CreateVPCCommand{Name: "vpc-exist"}
|
cmd := CreateVPCCommand{Name: "vpc-exist", CIDR: "10.0.0.0/16"}
|
||||||
if err := cmd.Prepare(db, nil); err == nil {
|
if err := cmd.Prepare(db, nil); err == nil {
|
||||||
t.Error("Prepare devrait échouer sur un VPC déjà existant")
|
t.Error("Prepare devrait échouer sur un VPC déjà existant")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateVPCCommand_Prepare_InvalidCIDR(t *testing.T) {
|
||||||
|
_, db := newTestDispatcher(t)
|
||||||
|
cmd := CreateVPCCommand{Name: "vpc-bad", CIDR: "not-a-cidr"}
|
||||||
|
if err := cmd.Prepare(db, nil); err == nil {
|
||||||
|
t.Error("Prepare devrait échouer avec un CIDR invalide")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- DeleteVPCCommand.Prepare ---
|
// --- DeleteVPCCommand.Prepare ---
|
||||||
|
|
||||||
func TestDeleteVPCCommand_Prepare_Success(t *testing.T) {
|
func TestDeleteVPCCommand_Prepare_Success(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ type subnetData struct {
|
||||||
localIface string
|
localIface string
|
||||||
interfaceIP net.IP
|
interfaceIP net.IP
|
||||||
cidr *net.IPNet
|
cidr *net.IPNet
|
||||||
|
vpcCIDR *net.IPNet
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSubnet(db *badger.DB, name string) (subnetData, error) {
|
func loadSubnet(db *badger.DB, name string) (subnetData, error) {
|
||||||
|
|
@ -77,5 +78,15 @@ func loadSubnet(db *badger.DB, name string) (subnetData, error) {
|
||||||
}
|
}
|
||||||
d.cidr = ipNet
|
d.cidr = ipNet
|
||||||
|
|
||||||
|
vpcCIDRStr, err := kv.GetFromDB(db, "vpc/"+d.vpc+"/cidr")
|
||||||
|
if err != nil {
|
||||||
|
return d, fmt.Errorf("get vpc cidr: %w", err)
|
||||||
|
}
|
||||||
|
_, vpcIPNet, err := net.ParseCIDR(vpcCIDRStr)
|
||||||
|
if err != nil {
|
||||||
|
return d, fmt.Errorf("parse vpc cidr: %w", err)
|
||||||
|
}
|
||||||
|
d.vpcCIDR = vpcIPNet
|
||||||
|
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue