diff --git a/src/api/rest/docs/docs.go b/src/api/rest/docs/docs.go index bdae8547c..12e576b9a 100644 --- a/src/api/rest/docs/docs.go +++ b/src/api/rest/docs/docs.go @@ -7974,6 +7974,98 @@ const docTemplate = `{ } } }, + "/util/net/design": { + "post": { + "description": "Design a hierarchical network configuration of a VPC network or multi-cloud network consisting of multiple VPC networks", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Utility] Multi-cloud network design" + ], + "summary": "Design a multi-cloud network configuration", + "parameters": [ + { + "description": "A root/main network CIDR block and subnetting rules", + "name": "subnettingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToDesignNetworkRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToDesignNetworkReponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, + "/util/net/validate": { + "post": { + "description": "Validate a hierarchical configuration of a VPC network or multi-cloud network consisting of multiple VPC networks", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Utility] Multi-cloud network design" + ], + "summary": "Validate a multi-cloud network configuration", + "parameters": [ + { + "description": "A hierarchical network configuration", + "name": "subnettingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToValidateNetworkRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, "/{nsId}/checkResource/{resourceType}/{resourceId}": { "get": { "description": "Check resources' existence", @@ -11928,6 +12020,91 @@ const docTemplate = `{ "$ref": "#/definitions/mcis.resourceOnTumblebug" } } + }, + "netutil.Network": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.Network" + } + } + } + }, + "netutil.RestPostUtilToDesignNetworkReponse": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.Network" + } + } + } + }, + "netutil.RestPostUtilToDesignNetworkRequest": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string", + "example": "192.168.0.0/16" + }, + "subnettingRules": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.SubnettingRule" + } + } + } + }, + "netutil.RestPostUtilToValidateNetworkRequest": { + "type": "object", + "properties": { + "networkConfiguration": { + "$ref": "#/definitions/netutil.Network" + } + } + }, + "netutil.SubnettingRule": { + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/definitions/netutil.SubnettingRuleType" + } + ], + "example": "minSubnets" + }, + "value": { + "type": "integer", + "example": 2 + } + } + }, + "netutil.SubnettingRuleType": { + "type": "string", + "enum": [ + "minSubnets", + "minHosts" + ], + "x-enum-varnames": [ + "SubnettingRuleTypeMinSubnets", + "SubnettingRuleTypeMinHosts" + ] } }, "securityDefinitions": { diff --git a/src/api/rest/docs/swagger.json b/src/api/rest/docs/swagger.json index 73215ce8d..a5e6db714 100644 --- a/src/api/rest/docs/swagger.json +++ b/src/api/rest/docs/swagger.json @@ -7967,6 +7967,98 @@ } } }, + "/util/net/design": { + "post": { + "description": "Design a hierarchical network configuration of a VPC network or multi-cloud network consisting of multiple VPC networks", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Utility] Multi-cloud network design" + ], + "summary": "Design a multi-cloud network configuration", + "parameters": [ + { + "description": "A root/main network CIDR block and subnetting rules", + "name": "subnettingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToDesignNetworkRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToDesignNetworkReponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, + "/util/net/validate": { + "post": { + "description": "Validate a hierarchical configuration of a VPC network or multi-cloud network consisting of multiple VPC networks", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Utility] Multi-cloud network design" + ], + "summary": "Validate a multi-cloud network configuration", + "parameters": [ + { + "description": "A hierarchical network configuration", + "name": "subnettingReq", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/netutil.RestPostUtilToValidateNetworkRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/common.SimpleMsg" + } + } + } + } + }, "/{nsId}/checkResource/{resourceType}/{resourceId}": { "get": { "description": "Check resources' existence", @@ -11921,6 +12013,91 @@ "$ref": "#/definitions/mcis.resourceOnTumblebug" } } + }, + "netutil.Network": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.Network" + } + } + } + }, + "netutil.RestPostUtilToDesignNetworkReponse": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subnets": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.Network" + } + } + } + }, + "netutil.RestPostUtilToDesignNetworkRequest": { + "type": "object", + "properties": { + "cidrBlock": { + "type": "string", + "example": "192.168.0.0/16" + }, + "subnettingRules": { + "type": "array", + "items": { + "$ref": "#/definitions/netutil.SubnettingRule" + } + } + } + }, + "netutil.RestPostUtilToValidateNetworkRequest": { + "type": "object", + "properties": { + "networkConfiguration": { + "$ref": "#/definitions/netutil.Network" + } + } + }, + "netutil.SubnettingRule": { + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/definitions/netutil.SubnettingRuleType" + } + ], + "example": "minSubnets" + }, + "value": { + "type": "integer", + "example": 2 + } + } + }, + "netutil.SubnettingRuleType": { + "type": "string", + "enum": [ + "minSubnets", + "minHosts" + ], + "x-enum-varnames": [ + "SubnettingRuleTypeMinSubnets", + "SubnettingRuleTypeMinHosts" + ] } }, "securityDefinitions": { diff --git a/src/api/rest/docs/swagger.yaml b/src/api/rest/docs/swagger.yaml index b65c8f9ce..f32e036a9 100644 --- a/src/api/rest/docs/swagger.yaml +++ b/src/api/rest/docs/swagger.yaml @@ -2718,6 +2718,61 @@ definitions: onTumblebug: $ref: '#/definitions/mcis.resourceOnTumblebug' type: object + netutil.Network: + properties: + cidrBlock: + type: string + name: + type: string + subnets: + items: + $ref: '#/definitions/netutil.Network' + type: array + type: object + netutil.RestPostUtilToDesignNetworkReponse: + properties: + cidrBlock: + type: string + name: + type: string + subnets: + items: + $ref: '#/definitions/netutil.Network' + type: array + type: object + netutil.RestPostUtilToDesignNetworkRequest: + properties: + cidrBlock: + example: 192.168.0.0/16 + type: string + subnettingRules: + items: + $ref: '#/definitions/netutil.SubnettingRule' + type: array + type: object + netutil.RestPostUtilToValidateNetworkRequest: + properties: + networkConfiguration: + $ref: '#/definitions/netutil.Network' + type: object + netutil.SubnettingRule: + properties: + type: + allOf: + - $ref: '#/definitions/netutil.SubnettingRuleType' + example: minSubnets + value: + example: 2 + type: integer + type: object + netutil.SubnettingRuleType: + enum: + - minSubnets + - minHosts + type: string + x-enum-varnames: + - SubnettingRuleTypeMinSubnets + - SubnettingRuleTypeMinHosts info: contact: email: contact-to-cloud-barista@googlegroups.com @@ -8120,6 +8175,68 @@ paths: summary: Create System MCIS Dynamically for Special Purpose in NS:system-purpose-common-ns tags: - '[Infra service] MCIS Provisioning management' + /util/net/design: + post: + consumes: + - application/json + description: Design a hierarchical network configuration of a VPC network or + multi-cloud network consisting of multiple VPC networks + parameters: + - description: A root/main network CIDR block and subnetting rules + in: body + name: subnettingReq + required: true + schema: + $ref: '#/definitions/netutil.RestPostUtilToDesignNetworkRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/netutil.RestPostUtilToDesignNetworkReponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/common.SimpleMsg' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/common.SimpleMsg' + summary: Design a multi-cloud network configuration + tags: + - '[Utility] Multi-cloud network design' + /util/net/validate: + post: + consumes: + - application/json + description: Validate a hierarchical configuration of a VPC network or multi-cloud + network consisting of multiple VPC networks + parameters: + - description: A hierarchical network configuration + in: body + name: subnettingReq + required: true + schema: + $ref: '#/definitions/netutil.RestPostUtilToValidateNetworkRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.SimpleMsg' + "400": + description: Bad Request + schema: + $ref: '#/definitions/common.SimpleMsg' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/common.SimpleMsg' + summary: Validate a multi-cloud network configuration + tags: + - '[Utility] Multi-cloud network design' securityDefinitions: BasicAuth: type: basic diff --git a/src/api/rest/server/server.go b/src/api/rest/server/server.go index 268f840c7..49a064529 100644 --- a/src/api/rest/server/server.go +++ b/src/api/rest/server/server.go @@ -27,6 +27,7 @@ import ( rest_common "github.com/cloud-barista/cb-tumblebug/src/api/rest/server/common" rest_mcir "github.com/cloud-barista/cb-tumblebug/src/api/rest/server/mcir" rest_mcis "github.com/cloud-barista/cb-tumblebug/src/api/rest/server/mcis" + rest_netutil "github.com/cloud-barista/cb-tumblebug/src/api/rest/server/util" "crypto/subtle" "fmt" @@ -192,6 +193,10 @@ func RunServer(port string) { e.POST("/tumblebug/forward/*", rest_common.RestForwardAnyReqToAny) + // Utility for network design + e.POST("/tumblebug/util/net/design", rest_netutil.RestPostUtilToDesignNetwork) + e.POST("/tumblebug/util/net/validate", rest_netutil.RestPostUtilToValidateNetwork) + // Route for NameSpace subgroup g := e.Group("/tumblebug/ns", common.NsValidation()) diff --git a/src/api/rest/server/util/netuil.go b/src/api/rest/server/util/netuil.go new file mode 100644 index 000000000..bd8d8ba78 --- /dev/null +++ b/src/api/rest/server/util/netuil.go @@ -0,0 +1,85 @@ +package netutil + +import ( + "github.com/cloud-barista/cb-tumblebug/src/core/common" + "github.com/cloud-barista/cb-tumblebug/src/core/common/netutil" + "github.com/labstack/echo/v4" +) + +type RestPostUtilToDesignNetworkRequest struct { + netutil.SubnettingRequest +} + +type RestPostUtilToDesignNetworkReponse struct { + netutil.Network +} + +// RestPostUtilToDesignNetwork godoc +// @Summary Design a multi-cloud network configuration +// @Description Design a hierarchical network configuration of a VPC network or multi-cloud network consisting of multiple VPC networks +// @Tags [Utility] Multi-cloud network design +// @Accept json +// @Produce json +// @Param subnettingReq body RestPostUtilToDesignNetworkRequest true "A root/main network CIDR block and subnetting rules" +// @Success 201 {object} RestPostUtilToDesignNetworkReponse +// @Failure 400 {object} common.SimpleMsg +// @Failure 500 {object} common.SimpleMsg +// @Router /util/net/design [post] +func RestPostUtilToDesignNetwork(c echo.Context) error { + + // ID for API request tracing + reqID := common.StartRequestWithLog(c) + + // Bind the request body to SubnettingRequest struct + subnettingReq := new(netutil.SubnettingRequest) + if err := c.Bind(subnettingReq); err != nil { + return common.EndRequestWithLog(c, reqID, err, nil) + } + + // Subnetting as many as requested rules + networkConfig, err := netutil.SubnettingBy(*subnettingReq) + if err != nil { + return common.EndRequestWithLog(c, reqID, err, nil) + } + + return common.EndRequestWithLog(c, reqID, err, networkConfig) +} + +type RestPostUtilToValidateNetworkRequest struct { + netutil.NetworkConfig +} + +// RestPostUtilToValidateNetwork godoc +// @Summary Validate a multi-cloud network configuration +// @Description Validate a hierarchical configuration of a VPC network or multi-cloud network consisting of multiple VPC networks +// @Tags [Utility] Multi-cloud network design +// @Accept json +// @Produce json +// @Param subnettingReq body RestPostUtilToValidateNetworkRequest true "A hierarchical network configuration" +// @Success 200 {object} common.SimpleMsg +// @Failure 400 {object} common.SimpleMsg +// @Failure 500 {object} common.SimpleMsg +// @Router /util/net/validate [post] +func RestPostUtilToValidateNetwork(c echo.Context) error { + + // ID for API request tracing + reqID := common.StartRequestWithLog(c) + + // Bind the request body to SubnettingRequest struct + req := new(netutil.NetworkConfig) + if err := c.Bind(req); err != nil { + return common.EndRequestWithLog(c, reqID, err, nil) + } + + // Validate the network configuration + netConf := req.NetworkConfiguration + err := netutil.ValidateNetwork(netConf) + if err != nil { + return common.EndRequestWithLog(c, reqID, err, nil) + } + + okMessage := common.SimpleMsg{} + okMessage.Message = "Network configuration is valid." + + return common.EndRequestWithLog(c, reqID, err, okMessage) +} diff --git a/src/core/common/netutil/netutil.go b/src/core/common/netutil/netutil.go index 52796d095..8e1efe490 100644 --- a/src/core/common/netutil/netutil.go +++ b/src/core/common/netutil/netutil.go @@ -229,15 +229,24 @@ func calculateHostCapacity(maskSize, bits int) (int, error) { } // /////////////////////////////////////////////////////////////////// +// SubnettingRuleType defines the type for subnetting rules. +type SubnettingRuleType string + +// SubnettingRuleType constants. +const ( + SubnettingRuleTypeMinSubnets SubnettingRuleType = "minSubnets" + SubnettingRuleTypeMinHosts SubnettingRuleType = "minHosts" +) + // Models for subnetting type SubnettingRequest struct { - CIDRBlock string `json:"cidrBlock"` + CIDRBlock string `json:"cidrBlock" example:"192.168.0.0/16"` SubnettingRules []SubnettingRule `json:"subnettingRules"` } type SubnettingRule struct { - Type string `json:"type"` - Value int `json:"value"` + Type SubnettingRuleType `json:"type" example:"minSubnets" enum:"minSubnets,minHosts"` + Value int `json:"value" example:"2"` } // Functions for subnetting @@ -267,9 +276,9 @@ func subnetting(network Network, rules []SubnettingRule) (Network, error) { // Subnetting by the given rule switch rule.Type { - case "minSubnets": + case SubnettingRuleTypeMinSubnets: subnetsStr, err = SubnettingByMinimumSubnetCount(network.CIDRBlock, rule.Value) - case "minHosts": + case SubnettingRuleTypeMinHosts: subnetsStr, err = SubnettingByMinimumHosts(network.CIDRBlock, rule.Value) default: return network, fmt.Errorf("unknown rule type: %s", rule.Type) @@ -466,7 +475,6 @@ func NextSubnet(currentSubnetCIDR string, baseNetworkCIDR string) (string, error return fmt.Sprintf("%s/%d", nextIP.String(), maskSize), nil } - // PreviousSubnet find and check the previous subnet based on the base/parent network. func PreviousSubnet(currentSubnet string, baseNetworkCIDR string) (string, error) { // Parse the current subnet @@ -500,4 +508,4 @@ func PreviousSubnet(currentSubnet string, baseNetworkCIDR string) (string, error } return fmt.Sprintf("%s/%d", previousIP.String(), maskSize), nil -} \ No newline at end of file +} diff --git a/src/examples/netutil/netutil.go b/src/examples/netutil/netutil.go index bd7880a29..4eeb2ac9f 100644 --- a/src/examples/netutil/netutil.go +++ b/src/examples/netutil/netutil.go @@ -189,21 +189,27 @@ func runExample(cmd *cobra.Command, args []string) { fmt.Printf("[Network configuration to validate]\n%s\n", string(pretty)) if err := netutil.ValidateNetwork(network); err != nil { - fmt.Println("Network configuration is valid.") - } else { fmt.Println("Network configuration is invalid.") } + fmt.Println("Network configuration is valid.") + /////////////////////////////////////////////////////////////////////////////////////////////////// fmt.Println("\nSubnetting a CIDR block by requests") request := netutil.SubnettingRequest{ CIDRBlock: cidrBlock, SubnettingRules: []netutil.SubnettingRule{ - {Type: "minSubnets", Value: minSubnets}, - {Type: "minHosts", Value: hostsPerSubnet}, + {Type: netutil.SubnettingRuleTypeMinSubnets, Value: minSubnets}, + {Type: netutil.SubnettingRuleTypeMinHosts, Value: hostsPerSubnet}, }, } + pretty, err = json.MarshalIndent(request, "", " ") + if err != nil { + fmt.Printf("marshaling error: %s\n", err) + } + fmt.Printf("[Subnetting request]\n%s\n", string(pretty)) + // Subnetting by requests networkConfig, err := netutil.SubnettingBy(request) if err != nil {