diff --git a/api/agent.yaml b/api/agent.yaml index 1d3a77f..da20853 100644 --- a/api/agent.yaml +++ b/api/agent.yaml @@ -44,6 +44,12 @@ paths: application/json: schema: $ref: "#/components/schemas/VPC" + "400": + description: Missing required field or invalid request body + content: + application/json: + schema: + $ref: "#/components/schemas/Error" "409": description: VPC already exists content: @@ -179,12 +185,6 @@ paths: $ref: "#/components/schemas/Subnet" "404": $ref: "#/components/responses/NotFound" - "409": - description: Subnet not in a deletable state - content: - application/json: - schema: - $ref: "#/components/schemas/Error" "500": $ref: "#/components/responses/InternalError" diff --git a/internal/api/agent/subnet_test.go b/internal/api/agent/subnet_test.go index 0fdd18b..23745a0 100644 --- a/internal/api/agent/subnet_test.go +++ b/internal/api/agent/subnet_test.go @@ -81,7 +81,7 @@ func TestPostSubnet_Created(t *testing.T) { func TestPostSubnet_MissingFields(t *testing.T) { s, _ := newTestServer(t) - body, _ := json.Marshal(SubnetCreateRequest{Name: "sn-1"}) // vpc, iface_type, gateway_ip, cidr manquants + body, _ := json.Marshal(SubnetCreateRequest{Name: "sn-1"}) // vpc, gateway_ip, cidr manquants w := httptest.NewRecorder() s.SubnetsHandler(w, httptest.NewRequest(http.MethodPost, "/subnets", bytes.NewReader(body))) if w.Code != http.StatusBadRequest { @@ -89,6 +89,24 @@ func TestPostSubnet_MissingFields(t *testing.T) { } } +func TestPostSubnet_IfaceTypeOptional(t *testing.T) { + s, db := newTestServer(t) + kv.AddInDB(db, "vpc/vpc-1/state", "created") + req := SubnetCreateRequest{ + Name: "sn-opt", + VPC: "vpc-1", + GatewayIP: "10.0.0.1", + CIDR: "10.0.0.0/24", + // IfaceType omis — doit utiliser default_interface + } + body, _ := json.Marshal(req) + w := httptest.NewRecorder() + s.SubnetsHandler(w, httptest.NewRequest(http.MethodPost, "/subnets", bytes.NewReader(body))) + if w.Code != http.StatusAccepted { + t.Fatalf("attendu 202, obtenu %d: %s", w.Code, w.Body.String()) + } +} + func TestPostSubnet_VPCNotFound(t *testing.T) { s, _ := newTestServer(t) req := SubnetCreateRequest{ @@ -101,8 +119,8 @@ func TestPostSubnet_VPCNotFound(t *testing.T) { body, _ := json.Marshal(req) w := httptest.NewRecorder() s.SubnetsHandler(w, httptest.NewRequest(http.MethodPost, "/subnets", bytes.NewReader(body))) - if w.Code != http.StatusConflict { - t.Errorf("attendu 409, obtenu %d", w.Code) + if w.Code != http.StatusUnprocessableEntity { + t.Errorf("attendu 422, obtenu %d", w.Code) } } @@ -138,8 +156,8 @@ func TestPostSubnet_VPCDeleting(t *testing.T) { body, _ := json.Marshal(req) w := httptest.NewRecorder() s.SubnetsHandler(w, httptest.NewRequest(http.MethodPost, "/subnets", bytes.NewReader(body))) - if w.Code != http.StatusConflict { - t.Errorf("attendu 409, obtenu %d", w.Code) + if w.Code != http.StatusUnprocessableEntity { + t.Errorf("attendu 422, obtenu %d", w.Code) } } diff --git a/internal/api/agent/subnets.go b/internal/api/agent/subnets.go index b0fb2fb..60467aa 100644 --- a/internal/api/agent/subnets.go +++ b/internal/api/agent/subnets.go @@ -69,9 +69,9 @@ func (s *Server) postSubnet(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(ErrorResponse{Error: "invalid request body"}) return } - if req.Name == "" || req.VPC == "" || req.IfaceType == "" || req.GatewayIP == "" || req.CIDR == "" { + if req.Name == "" || req.VPC == "" || req.GatewayIP == "" || req.CIDR == "" { w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(ErrorResponse{Error: "name, vpc, iface_type, gateway_ip and cidr are required"}) + json.NewEncoder(w).Encode(ErrorResponse{Error: "name, vpc, gateway_ip and cidr are required"}) return } cmd := dispatcher.CreateSubnetCommand{ @@ -83,7 +83,11 @@ func (s *Server) postSubnet(w http.ResponseWriter, r *http.Request) { CIDR: req.CIDR, } if err := s.dispatcher.Prepare(cmd); err != nil { - w.WriteHeader(http.StatusConflict) + if _, dbErr := kv.GetFromDB(s.db, "subnet/"+req.Name+"/state"); dbErr == nil { + w.WriteHeader(http.StatusConflict) + } else { + w.WriteHeader(http.StatusUnprocessableEntity) + } json.NewEncoder(w).Encode(ErrorResponse{Error: err.Error()}) return } diff --git a/internal/api/agent/vpc.go b/internal/api/agent/vpc.go index df2d47c..43cc33c 100644 --- a/internal/api/agent/vpc.go +++ b/internal/api/agent/vpc.go @@ -42,7 +42,11 @@ func (s *Server) getVpc(w http.ResponseWriter, _ *http.Request, name string) { func (s *Server) deleteVpc(w http.ResponseWriter, _ *http.Request, name string) { cmd := dispatcher.DeleteVPCCommand{Name: name} if err := s.dispatcher.Prepare(cmd); err != nil { - w.WriteHeader(http.StatusNotFound) + if _, dbErr := kv.GetFromDB(s.db, "vpc/"+name+"/state"); dbErr != nil { + w.WriteHeader(http.StatusNotFound) + } else { + w.WriteHeader(http.StatusConflict) + } json.NewEncoder(w).Encode(ErrorResponse{Error: err.Error()}) return } diff --git a/internal/api/agent/vpc_test.go b/internal/api/agent/vpc_test.go index 0edcd5b..01308a5 100644 --- a/internal/api/agent/vpc_test.go +++ b/internal/api/agent/vpc_test.go @@ -171,8 +171,8 @@ func TestDeleteVpc_BlockedByActiveSubnet(t *testing.T) { req := httptest.NewRequest(http.MethodDelete, "/vpcs/vpc-busy", nil) w := httptest.NewRecorder() s.VpcByNameHandler(w, req) - if w.Code != http.StatusNotFound { - t.Errorf("attendu 404 (Prepare échoue), obtenu %d: %s", w.Code, w.Body.String()) + if w.Code != http.StatusConflict { + t.Errorf("attendu 409, obtenu %d: %s", w.Code, w.Body.String()) } }