diff --git a/.gitignore b/.gitignore index e0f702c..688c37f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,6 @@ cmd/cm-damselfly/cm-damselfly # Ignore DB file (it's temporally used) -db/* +*.db + +container-volume/ diff --git a/Dockerfile b/Dockerfile index fdc4010..9cecc48 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,11 +37,11 @@ RUN rm /bin/sh && ln -s /bin/bash /bin/sh # Set the Current Working Directory inside the container WORKDIR /app -# Installing necessary packages and cleaning up -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* +# # Installing necessary packages and cleaning up +# RUN apt-get update && apt-get install -y --no-install-recommends \ +# ca-certificates \ +# && apt-get clean \ +# && rm -rf /var/lib/apt/lists/* ## Copy the Pre-built binary and necessary files from the previous stage COPY --from=builder /go/src/github.com/cloud-barista/cm-damselfly/api/ /app/api/ diff --git a/api/docs.go b/api/docs.go index 3e4bbce..ad79b9c 100644 --- a/api/docs.go +++ b/api/docs.go @@ -697,7 +697,7 @@ const docTemplate = `{ "type": "boolean" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "userId": { "type": "string" @@ -738,7 +738,7 @@ const docTemplate = `{ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -865,7 +865,7 @@ const docTemplate = `{ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -930,7 +930,7 @@ const docTemplate = `{ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "region": { "type": "string" @@ -991,7 +991,7 @@ const docTemplate = `{ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -1127,7 +1127,7 @@ const docTemplate = `{ "type": "boolean" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "userId": { "type": "string" @@ -1168,7 +1168,7 @@ const docTemplate = `{ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -1184,112 +1184,7 @@ const docTemplate = `{ } } }, - "model.TbMciDynamicReq": { - "type": "object", - "required": [ - "name", - "vm" - ], - "properties": { - "description": { - "type": "string", - "example": "Made in CB-TB" - }, - "installMonAgent": { - "description": "InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] default:yes)", - "type": "string", - "default": "no", - "enum": [ - "yes", - "no" - ], - "example": "no" - }, - "label": { - "description": "Label is for describing the object by keywords", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "name": { - "type": "string", - "example": "mci01" - }, - "systemLabel": { - "description": "SystemLabel is for describing the mci in a keyword (any string can be used) for special System purpose", - "type": "string", - "example": "" - }, - "vm": { - "type": "array", - "items": { - "$ref": "#/definitions/model.TbVmDynamicReq" - } - } - } - }, - "model.TbVmDynamicReq": { - "type": "object", - "required": [ - "commonImage", - "commonSpec" - ], - "properties": { - "commonImage": { - "description": "CommonImage is field for id of a image in common namespace", - "type": "string", - "example": "ubuntu18.04" - }, - "commonSpec": { - "description": "CommonSpec is field for id of a spec in common namespace", - "type": "string", - "example": "aws+ap-northeast-2+t2.small" - }, - "connectionName": { - "description": "if ConnectionName is given, the VM tries to use associtated credential.\nif not, it will use predefined ConnectionName in Spec objects", - "type": "string" - }, - "description": { - "type": "string", - "example": "Description" - }, - "label": { - "description": "Label is for describing the object by keywords", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "name": { - "description": "VM name or subGroup name if is (not empty) \u0026\u0026 (\u003e 0). If it is a group, actual VM name will be generated with -N postfix.", - "type": "string", - "example": "g1-1" - }, - "rootDiskSize": { - "description": "\"default\", Integer (GB): [\"50\", ..., \"1000\"]", - "type": "string", - "default": "default", - "example": "default, 30, 42, ..." - }, - "rootDiskType": { - "description": "\"\", \"default\", \"TYPE1\", AWS: [\"standard\", \"gp2\", \"gp3\"], Azure: [\"PremiumSSD\", \"StandardSSD\", \"StandardHDD\"], GCP: [\"pd-standard\", \"pd-balanced\", \"pd-ssd\", \"pd-extreme\"], ALIBABA: [\"cloud_efficiency\", \"cloud\", \"cloud_essd\"], TENCENT: [\"CLOUD_PREMIUM\", \"CLOUD_SSD\"]", - "type": "string", - "default": "default", - "example": "default, TYPE1, ..." - }, - "subGroupSize": { - "description": "if subGroupSize is (not empty) \u0026\u0026 (\u003e 0), subGroup will be generated. VMs will be created accordingly.", - "type": "string", - "default": "1", - "example": "3" - }, - "vmUserPassword": { - "type": "string" - } - } - }, - "onprem.CpuProperty": { + "inframodel.CpuProperty": { "type": "object", "required": [ "cores", @@ -1331,7 +1226,7 @@ const docTemplate = `{ } } }, - "onprem.DiskProperty": { + "inframodel.DiskProperty": { "type": "object", "required": [ "label", @@ -1362,7 +1257,7 @@ const docTemplate = `{ } } }, - "onprem.MemoryProperty": { + "inframodel.MemoryProperty": { "type": "object", "required": [ "totalSize", @@ -1388,7 +1283,7 @@ const docTemplate = `{ } } }, - "onprem.NetworkInterfaceProperty": { + "inframodel.NetworkInterfaceProperty": { "type": "object", "required": [ "name" @@ -1426,7 +1321,7 @@ const docTemplate = `{ } } }, - "onprem.NetworkProperty": { + "inframodel.NetworkProperty": { "type": "object", "properties": { "ipv4Networks": { @@ -1447,24 +1342,24 @@ const docTemplate = `{ } } }, - "onprem.OnPremInfra": { + "inframodel.OnpremInfra": { "type": "object", "required": [ "servers" ], "properties": { "network": { - "$ref": "#/definitions/onprem.NetworkProperty" + "$ref": "#/definitions/inframodel.NetworkProperty" }, "servers": { "type": "array", "items": { - "$ref": "#/definitions/onprem.ServerProperty" + "$ref": "#/definitions/inframodel.ServerProperty" } } } }, - "onprem.OsProperty": { + "inframodel.OsProperty": { "type": "object", "required": [ "prettyName" @@ -1502,7 +1397,7 @@ const docTemplate = `{ } } }, - "onprem.RouteProperty": { + "inframodel.RouteProperty": { "type": "object", "properties": { "destination": { @@ -1539,16 +1434,16 @@ const docTemplate = `{ } } }, - "onprem.ServerProperty": { + "inframodel.ServerProperty": { "type": "object", "properties": { "cpu": { - "$ref": "#/definitions/onprem.CpuProperty" + "$ref": "#/definitions/inframodel.CpuProperty" }, "dataDisks": { "type": "array", "items": { - "$ref": "#/definitions/onprem.DiskProperty" + "$ref": "#/definitions/inframodel.DiskProperty" } }, "hostname": { @@ -1557,25 +1452,130 @@ const docTemplate = `{ "interfaces": { "type": "array", "items": { - "$ref": "#/definitions/onprem.NetworkInterfaceProperty" + "$ref": "#/definitions/inframodel.NetworkInterfaceProperty" } }, "memory": { - "$ref": "#/definitions/onprem.MemoryProperty" + "$ref": "#/definitions/inframodel.MemoryProperty" }, "os": { - "$ref": "#/definitions/onprem.OsProperty" + "$ref": "#/definitions/inframodel.OsProperty" }, "rootDisk": { - "$ref": "#/definitions/onprem.DiskProperty" + "$ref": "#/definitions/inframodel.DiskProperty" }, "routingTable": { "type": "array", "items": { - "$ref": "#/definitions/onprem.RouteProperty" + "$ref": "#/definitions/inframodel.RouteProperty" } } } + }, + "model.TbMciDynamicReq": { + "type": "object", + "required": [ + "name", + "vm" + ], + "properties": { + "description": { + "type": "string", + "example": "Made in CB-TB" + }, + "installMonAgent": { + "description": "InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] default:yes)", + "type": "string", + "default": "no", + "enum": [ + "yes", + "no" + ], + "example": "no" + }, + "label": { + "description": "Label is for describing the object by keywords", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "type": "string", + "example": "mci01" + }, + "systemLabel": { + "description": "SystemLabel is for describing the mci in a keyword (any string can be used) for special System purpose", + "type": "string", + "example": "" + }, + "vm": { + "type": "array", + "items": { + "$ref": "#/definitions/model.TbVmDynamicReq" + } + } + } + }, + "model.TbVmDynamicReq": { + "type": "object", + "required": [ + "commonImage", + "commonSpec" + ], + "properties": { + "commonImage": { + "description": "CommonImage is field for id of a image in common namespace", + "type": "string", + "example": "ubuntu18.04" + }, + "commonSpec": { + "description": "CommonSpec is field for id of a spec in common namespace", + "type": "string", + "example": "aws+ap-northeast-2+t2.small" + }, + "connectionName": { + "description": "if ConnectionName is given, the VM tries to use associtated credential.\nif not, it will use predefined ConnectionName in Spec objects", + "type": "string" + }, + "description": { + "type": "string", + "example": "Description" + }, + "label": { + "description": "Label is for describing the object by keywords", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "description": "VM name or subGroup name if is (not empty) \u0026\u0026 (\u003e 0). If it is a group, actual VM name will be generated with -N postfix.", + "type": "string", + "example": "g1-1" + }, + "rootDiskSize": { + "description": "\"default\", Integer (GB): [\"50\", ..., \"1000\"]", + "type": "string", + "default": "default", + "example": "default, 30, 42, ..." + }, + "rootDiskType": { + "description": "\"\", \"default\", \"TYPE1\", AWS: [\"standard\", \"gp2\", \"gp3\"], Azure: [\"PremiumSSD\", \"StandardSSD\", \"StandardHDD\"], GCP: [\"pd-standard\", \"pd-balanced\", \"pd-ssd\", \"pd-extreme\"], ALIBABA: [\"cloud_efficiency\", \"cloud\", \"cloud_essd\"], TENCENT: [\"CLOUD_PREMIUM\", \"CLOUD_SSD\"]", + "type": "string", + "default": "default", + "example": "default, TYPE1, ..." + }, + "subGroupSize": { + "description": "if subGroupSize is (not empty) \u0026\u0026 (\u003e 0), subGroup will be generated. VMs will be created accordingly.", + "type": "string", + "default": "1", + "example": "3" + }, + "vmUserPassword": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/api/swagger.json b/api/swagger.json index 4056b3b..5ca90a9 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -690,7 +690,7 @@ "type": "boolean" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "userId": { "type": "string" @@ -731,7 +731,7 @@ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -858,7 +858,7 @@ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -923,7 +923,7 @@ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "region": { "type": "string" @@ -984,7 +984,7 @@ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -1120,7 +1120,7 @@ "type": "boolean" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "userId": { "type": "string" @@ -1161,7 +1161,7 @@ "type": "string" }, "onpremiseInfraModel": { - "$ref": "#/definitions/onprem.OnPremInfra" + "$ref": "#/definitions/inframodel.OnpremInfra" }, "updateTime": { "type": "string" @@ -1177,112 +1177,7 @@ } } }, - "model.TbMciDynamicReq": { - "type": "object", - "required": [ - "name", - "vm" - ], - "properties": { - "description": { - "type": "string", - "example": "Made in CB-TB" - }, - "installMonAgent": { - "description": "InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] default:yes)", - "type": "string", - "default": "no", - "enum": [ - "yes", - "no" - ], - "example": "no" - }, - "label": { - "description": "Label is for describing the object by keywords", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "name": { - "type": "string", - "example": "mci01" - }, - "systemLabel": { - "description": "SystemLabel is for describing the mci in a keyword (any string can be used) for special System purpose", - "type": "string", - "example": "" - }, - "vm": { - "type": "array", - "items": { - "$ref": "#/definitions/model.TbVmDynamicReq" - } - } - } - }, - "model.TbVmDynamicReq": { - "type": "object", - "required": [ - "commonImage", - "commonSpec" - ], - "properties": { - "commonImage": { - "description": "CommonImage is field for id of a image in common namespace", - "type": "string", - "example": "ubuntu18.04" - }, - "commonSpec": { - "description": "CommonSpec is field for id of a spec in common namespace", - "type": "string", - "example": "aws+ap-northeast-2+t2.small" - }, - "connectionName": { - "description": "if ConnectionName is given, the VM tries to use associtated credential.\nif not, it will use predefined ConnectionName in Spec objects", - "type": "string" - }, - "description": { - "type": "string", - "example": "Description" - }, - "label": { - "description": "Label is for describing the object by keywords", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "name": { - "description": "VM name or subGroup name if is (not empty) \u0026\u0026 (\u003e 0). If it is a group, actual VM name will be generated with -N postfix.", - "type": "string", - "example": "g1-1" - }, - "rootDiskSize": { - "description": "\"default\", Integer (GB): [\"50\", ..., \"1000\"]", - "type": "string", - "default": "default", - "example": "default, 30, 42, ..." - }, - "rootDiskType": { - "description": "\"\", \"default\", \"TYPE1\", AWS: [\"standard\", \"gp2\", \"gp3\"], Azure: [\"PremiumSSD\", \"StandardSSD\", \"StandardHDD\"], GCP: [\"pd-standard\", \"pd-balanced\", \"pd-ssd\", \"pd-extreme\"], ALIBABA: [\"cloud_efficiency\", \"cloud\", \"cloud_essd\"], TENCENT: [\"CLOUD_PREMIUM\", \"CLOUD_SSD\"]", - "type": "string", - "default": "default", - "example": "default, TYPE1, ..." - }, - "subGroupSize": { - "description": "if subGroupSize is (not empty) \u0026\u0026 (\u003e 0), subGroup will be generated. VMs will be created accordingly.", - "type": "string", - "default": "1", - "example": "3" - }, - "vmUserPassword": { - "type": "string" - } - } - }, - "onprem.CpuProperty": { + "inframodel.CpuProperty": { "type": "object", "required": [ "cores", @@ -1324,7 +1219,7 @@ } } }, - "onprem.DiskProperty": { + "inframodel.DiskProperty": { "type": "object", "required": [ "label", @@ -1355,7 +1250,7 @@ } } }, - "onprem.MemoryProperty": { + "inframodel.MemoryProperty": { "type": "object", "required": [ "totalSize", @@ -1381,7 +1276,7 @@ } } }, - "onprem.NetworkInterfaceProperty": { + "inframodel.NetworkInterfaceProperty": { "type": "object", "required": [ "name" @@ -1419,7 +1314,7 @@ } } }, - "onprem.NetworkProperty": { + "inframodel.NetworkProperty": { "type": "object", "properties": { "ipv4Networks": { @@ -1440,24 +1335,24 @@ } } }, - "onprem.OnPremInfra": { + "inframodel.OnpremInfra": { "type": "object", "required": [ "servers" ], "properties": { "network": { - "$ref": "#/definitions/onprem.NetworkProperty" + "$ref": "#/definitions/inframodel.NetworkProperty" }, "servers": { "type": "array", "items": { - "$ref": "#/definitions/onprem.ServerProperty" + "$ref": "#/definitions/inframodel.ServerProperty" } } } }, - "onprem.OsProperty": { + "inframodel.OsProperty": { "type": "object", "required": [ "prettyName" @@ -1495,7 +1390,7 @@ } } }, - "onprem.RouteProperty": { + "inframodel.RouteProperty": { "type": "object", "properties": { "destination": { @@ -1532,16 +1427,16 @@ } } }, - "onprem.ServerProperty": { + "inframodel.ServerProperty": { "type": "object", "properties": { "cpu": { - "$ref": "#/definitions/onprem.CpuProperty" + "$ref": "#/definitions/inframodel.CpuProperty" }, "dataDisks": { "type": "array", "items": { - "$ref": "#/definitions/onprem.DiskProperty" + "$ref": "#/definitions/inframodel.DiskProperty" } }, "hostname": { @@ -1550,25 +1445,130 @@ "interfaces": { "type": "array", "items": { - "$ref": "#/definitions/onprem.NetworkInterfaceProperty" + "$ref": "#/definitions/inframodel.NetworkInterfaceProperty" } }, "memory": { - "$ref": "#/definitions/onprem.MemoryProperty" + "$ref": "#/definitions/inframodel.MemoryProperty" }, "os": { - "$ref": "#/definitions/onprem.OsProperty" + "$ref": "#/definitions/inframodel.OsProperty" }, "rootDisk": { - "$ref": "#/definitions/onprem.DiskProperty" + "$ref": "#/definitions/inframodel.DiskProperty" }, "routingTable": { "type": "array", "items": { - "$ref": "#/definitions/onprem.RouteProperty" + "$ref": "#/definitions/inframodel.RouteProperty" } } } + }, + "model.TbMciDynamicReq": { + "type": "object", + "required": [ + "name", + "vm" + ], + "properties": { + "description": { + "type": "string", + "example": "Made in CB-TB" + }, + "installMonAgent": { + "description": "InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] default:yes)", + "type": "string", + "default": "no", + "enum": [ + "yes", + "no" + ], + "example": "no" + }, + "label": { + "description": "Label is for describing the object by keywords", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "type": "string", + "example": "mci01" + }, + "systemLabel": { + "description": "SystemLabel is for describing the mci in a keyword (any string can be used) for special System purpose", + "type": "string", + "example": "" + }, + "vm": { + "type": "array", + "items": { + "$ref": "#/definitions/model.TbVmDynamicReq" + } + } + } + }, + "model.TbVmDynamicReq": { + "type": "object", + "required": [ + "commonImage", + "commonSpec" + ], + "properties": { + "commonImage": { + "description": "CommonImage is field for id of a image in common namespace", + "type": "string", + "example": "ubuntu18.04" + }, + "commonSpec": { + "description": "CommonSpec is field for id of a spec in common namespace", + "type": "string", + "example": "aws+ap-northeast-2+t2.small" + }, + "connectionName": { + "description": "if ConnectionName is given, the VM tries to use associtated credential.\nif not, it will use predefined ConnectionName in Spec objects", + "type": "string" + }, + "description": { + "type": "string", + "example": "Description" + }, + "label": { + "description": "Label is for describing the object by keywords", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "description": "VM name or subGroup name if is (not empty) \u0026\u0026 (\u003e 0). If it is a group, actual VM name will be generated with -N postfix.", + "type": "string", + "example": "g1-1" + }, + "rootDiskSize": { + "description": "\"default\", Integer (GB): [\"50\", ..., \"1000\"]", + "type": "string", + "default": "default", + "example": "default, 30, 42, ..." + }, + "rootDiskType": { + "description": "\"\", \"default\", \"TYPE1\", AWS: [\"standard\", \"gp2\", \"gp3\"], Azure: [\"PremiumSSD\", \"StandardSSD\", \"StandardHDD\"], GCP: [\"pd-standard\", \"pd-balanced\", \"pd-ssd\", \"pd-extreme\"], ALIBABA: [\"cloud_efficiency\", \"cloud\", \"cloud_essd\"], TENCENT: [\"CLOUD_PREMIUM\", \"CLOUD_SSD\"]", + "type": "string", + "default": "default", + "example": "default, TYPE1, ..." + }, + "subGroupSize": { + "description": "if subGroupSize is (not empty) \u0026\u0026 (\u003e 0), subGroup will be generated. VMs will be created accordingly.", + "type": "string", + "default": "1", + "example": "3" + }, + "vmUserPassword": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/api/swagger.yaml b/api/swagger.yaml index 214a057..a214b3b 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -102,7 +102,7 @@ definitions: isInitUserModel: type: boolean onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' userId: type: string userModelName: @@ -129,7 +129,7 @@ definitions: onpremModelVersion: type: string onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' updateTime: type: string userId: @@ -212,7 +212,7 @@ definitions: onpremModelVersion: type: string onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' updateTime: type: string userId: @@ -254,7 +254,7 @@ definitions: onpremModelVersion: type: string onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' region: type: string updateTime: @@ -295,7 +295,7 @@ definitions: onpremModelVersion: type: string onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' updateTime: type: string userId: @@ -384,7 +384,7 @@ definitions: isInitUserModel: type: boolean onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' userId: type: string userModelName: @@ -411,7 +411,7 @@ definitions: onpremModelVersion: type: string onpremiseInfraModel: - $ref: '#/definitions/onprem.OnPremInfra' + $ref: '#/definitions/inframodel.OnpremInfra' updateTime: type: string userId: @@ -423,95 +423,7 @@ definitions: required: - onpremiseInfraModel type: object - model.TbMciDynamicReq: - properties: - description: - example: Made in CB-TB - type: string - installMonAgent: - default: "no" - description: InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] - default:yes) - enum: - - "yes" - - "no" - example: "no" - type: string - label: - additionalProperties: - type: string - description: Label is for describing the object by keywords - type: object - name: - example: mci01 - type: string - systemLabel: - description: SystemLabel is for describing the mci in a keyword (any string - can be used) for special System purpose - example: "" - type: string - vm: - items: - $ref: '#/definitions/model.TbVmDynamicReq' - type: array - required: - - name - - vm - type: object - model.TbVmDynamicReq: - properties: - commonImage: - description: CommonImage is field for id of a image in common namespace - example: ubuntu18.04 - type: string - commonSpec: - description: CommonSpec is field for id of a spec in common namespace - example: aws+ap-northeast-2+t2.small - type: string - connectionName: - description: |- - if ConnectionName is given, the VM tries to use associtated credential. - if not, it will use predefined ConnectionName in Spec objects - type: string - description: - example: Description - type: string - label: - additionalProperties: - type: string - description: Label is for describing the object by keywords - type: object - name: - description: VM name or subGroup name if is (not empty) && (> 0). If it is - a group, actual VM name will be generated with -N postfix. - example: g1-1 - type: string - rootDiskSize: - default: default - description: '"default", Integer (GB): ["50", ..., "1000"]' - example: default, 30, 42, ... - type: string - rootDiskType: - default: default - description: '"", "default", "TYPE1", AWS: ["standard", "gp2", "gp3"], Azure: - ["PremiumSSD", "StandardSSD", "StandardHDD"], GCP: ["pd-standard", "pd-balanced", - "pd-ssd", "pd-extreme"], ALIBABA: ["cloud_efficiency", "cloud", "cloud_essd"], - TENCENT: ["CLOUD_PREMIUM", "CLOUD_SSD"]' - example: default, TYPE1, ... - type: string - subGroupSize: - default: "1" - description: if subGroupSize is (not empty) && (> 0), subGroup will be generated. - VMs will be created accordingly. - example: "3" - type: string - vmUserPassword: - type: string - required: - - commonImage - - commonSpec - type: object - onprem.CpuProperty: + inframodel.CpuProperty: properties: architecture: example: x86_64 @@ -544,7 +456,7 @@ definitions: - cpus - threads type: object - onprem.DiskProperty: + inframodel.DiskProperty: properties: available: description: Unit GiB @@ -567,7 +479,7 @@ definitions: - totalSize - type type: object - onprem.MemoryProperty: + inframodel.MemoryProperty: properties: available: description: Unit GiB @@ -586,7 +498,7 @@ definitions: - totalSize - type type: object - onprem.NetworkInterfaceProperty: + inframodel.NetworkInterfaceProperty: properties: ipv4CidrBlocks: description: IPv4 address with prefix length (e.g., 192.168.0.21/24), instead @@ -614,7 +526,7 @@ definitions: required: - name type: object - onprem.NetworkProperty: + inframodel.NetworkProperty: properties: ipv4Networks: example: @@ -628,18 +540,18 @@ definitions: type: string type: array type: object - onprem.OnPremInfra: + inframodel.OnpremInfra: properties: network: - $ref: '#/definitions/onprem.NetworkProperty' + $ref: '#/definitions/inframodel.NetworkProperty' servers: items: - $ref: '#/definitions/onprem.ServerProperty' + $ref: '#/definitions/inframodel.ServerProperty' type: array required: - servers type: object - onprem.OsProperty: + inframodel.OsProperty: properties: id: example: ubuntu @@ -667,7 +579,7 @@ definitions: required: - prettyName type: object - onprem.RouteProperty: + inframodel.RouteProperty: properties: destination: description: Destination network, expressed in CIDR format @@ -694,31 +606,119 @@ definitions: description: Optionally stores the source address (used for policy-based routing) type: string type: object - onprem.ServerProperty: + inframodel.ServerProperty: properties: cpu: - $ref: '#/definitions/onprem.CpuProperty' + $ref: '#/definitions/inframodel.CpuProperty' dataDisks: items: - $ref: '#/definitions/onprem.DiskProperty' + $ref: '#/definitions/inframodel.DiskProperty' type: array hostname: type: string interfaces: items: - $ref: '#/definitions/onprem.NetworkInterfaceProperty' + $ref: '#/definitions/inframodel.NetworkInterfaceProperty' type: array memory: - $ref: '#/definitions/onprem.MemoryProperty' + $ref: '#/definitions/inframodel.MemoryProperty' os: - $ref: '#/definitions/onprem.OsProperty' + $ref: '#/definitions/inframodel.OsProperty' rootDisk: - $ref: '#/definitions/onprem.DiskProperty' + $ref: '#/definitions/inframodel.DiskProperty' routingTable: items: - $ref: '#/definitions/onprem.RouteProperty' + $ref: '#/definitions/inframodel.RouteProperty' type: array type: object + model.TbMciDynamicReq: + properties: + description: + example: Made in CB-TB + type: string + installMonAgent: + default: "no" + description: InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] + default:yes) + enum: + - "yes" + - "no" + example: "no" + type: string + label: + additionalProperties: + type: string + description: Label is for describing the object by keywords + type: object + name: + example: mci01 + type: string + systemLabel: + description: SystemLabel is for describing the mci in a keyword (any string + can be used) for special System purpose + example: "" + type: string + vm: + items: + $ref: '#/definitions/model.TbVmDynamicReq' + type: array + required: + - name + - vm + type: object + model.TbVmDynamicReq: + properties: + commonImage: + description: CommonImage is field for id of a image in common namespace + example: ubuntu18.04 + type: string + commonSpec: + description: CommonSpec is field for id of a spec in common namespace + example: aws+ap-northeast-2+t2.small + type: string + connectionName: + description: |- + if ConnectionName is given, the VM tries to use associtated credential. + if not, it will use predefined ConnectionName in Spec objects + type: string + description: + example: Description + type: string + label: + additionalProperties: + type: string + description: Label is for describing the object by keywords + type: object + name: + description: VM name or subGroup name if is (not empty) && (> 0). If it is + a group, actual VM name will be generated with -N postfix. + example: g1-1 + type: string + rootDiskSize: + default: default + description: '"default", Integer (GB): ["50", ..., "1000"]' + example: default, 30, 42, ... + type: string + rootDiskType: + default: default + description: '"", "default", "TYPE1", AWS: ["standard", "gp2", "gp3"], Azure: + ["PremiumSSD", "StandardSSD", "StandardHDD"], GCP: ["pd-standard", "pd-balanced", + "pd-ssd", "pd-extreme"], ALIBABA: ["cloud_efficiency", "cloud", "cloud_essd"], + TENCENT: ["CLOUD_PREMIUM", "CLOUD_SSD"]' + example: default, TYPE1, ... + type: string + subGroupSize: + default: "1" + description: if subGroupSize is (not empty) && (> 0), subGroup will be generated. + VMs will be created accordingly. + example: "3" + type: string + vmUserPassword: + type: string + required: + - commonImage + - commonSpec + type: object info: contact: email: contact-to-cloud-barista@googlegroups.com diff --git a/cmd/cm-damselfly/main.go b/cmd/cm-damselfly/main.go index 2901870..44dd81a 100644 --- a/cmd/cm-damselfly/main.go +++ b/cmd/cm-damselfly/main.go @@ -1,18 +1,20 @@ package main import ( - "os" "flag" "fmt" + "os" "strconv" "sync" + "path/filepath" + "github.com/cloud-barista/cm-damselfly/pkg/config" "github.com/cloud-barista/cm-damselfly/pkg/lkvstore" "github.com/cloud-barista/cm-damselfly/pkg/logger" + "github.com/fsnotify/fsnotify" "github.com/rs/zerolog/log" "github.com/spf13/viper" - "path/filepath" restServer "github.com/cloud-barista/cm-damselfly/pkg/api/rest" ) @@ -24,25 +26,23 @@ func init() { // Initialize the logger logger := logger.NewLogger(logger.Config{ - LogLevel: viper.GetString("damselfly.loglevel"), - LogWriter: viper.GetString("damselfly.logwriter"), - LogFilePath: viper.GetString("damselfly.logfile.path"), - MaxSize: viper.GetInt("damselfly.logfile.maxsize"), - MaxBackups: viper.GetInt("damselfly.logfile.maxbackups"), - MaxAge: viper.GetInt("damselfly.logfile.maxage"), - Compress: viper.GetBool("damselfly.logfile.compress"), + LogLevel: config.Damselfly.LogLevel, + LogWriter: config.Damselfly.LogWriter, + LogFilePath: config.Damselfly.LogFile.Path, + MaxSize: config.Damselfly.LogFile.MaxSize, + MaxBackups: config.Damselfly.LogFile.MaxBackups, + MaxAge: config.Damselfly.LogFile.MaxAge, + Compress: config.Damselfly.LogFile.Compress, }) // Set a global logger log.Logger = *logger // Initialize the local key-value store with the specified file path - prjRoot := viper.GetString("damselfly.root") - dbFilePath := viper.GetString("damselfly.lkvstore.path") - dbFileFullPath := prjRoot + dbFilePath // Caution) Need to Modify!! + dbFilePath := config.Damselfly.LKVStore.Path lkvstore.Init(lkvstore.Config{ - DbFilePath: dbFileFullPath, + DbFilePath: dbFilePath, }) } @@ -66,18 +66,15 @@ func main() { log.Info().Msg("Preparing to run CM-Damselfly") // Initialize the local key-value store with the specified file path - prjRoot := viper.GetString("damselfly.root") - - dbFilePath := viper.GetString("damselfly.lkvstore.path") - dbFileFullPath := prjRoot + dbFilePath // Caution) Need to Modify!! + dbFilePath := config.Damselfly.LKVStore.Path // Ensure the DB file directory exists before creating the log file - dir := filepath.Dir(dbFileFullPath) + dir := filepath.Dir(dbFilePath) if _, err := os.Stat(dir); os.IsNotExist(err) { // Create the directory if it does not exist err = os.MkdirAll(dir, 0755) // Set permissions as needed if err != nil { - log.Error().Msgf("Failed to Create the DB Directory: : [%v]", err) + log.Error().Msgf("Failed to Create the DB Directory: : [%v]", err) } } @@ -109,6 +106,23 @@ func main() { } log.Debug().Msgf("port number: %s", *port) + // Watch config file changes + go func() { + viper.WatchConfig() + viper.OnConfigChange(func(e fsnotify.Event) { + log.Debug().Str("file", e.Name).Msg("config file changed") + err := viper.ReadInConfig() + if err != nil { // Handle errors reading the config file + log.Fatal().Err(err).Msg("fatal error in config file") + } + err = viper.Unmarshal(&config.RuntimeConfig) + if err != nil { + log.Panic().Err(err).Msg("error unmarshaling runtime configuration") + } + config.Damselfly = config.RuntimeConfig.Damselfly + }) + }() + // Launch API servers (REST) wg := new(sync.WaitGroup) wg.Add(1) diff --git a/conf/config.yaml b/conf/config.yaml index ed813f6..85fdd42 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -4,13 +4,13 @@ damselfly: ## Set internal DB config (lkvstore: local key-value store) lkvstore: - path: /db/damselfly.db + path: ./db/damselfly.db ## Logger configuration logfile: # Set log file path (default logfile path: ./damselfly.log) path: ./log/damselfly.log - maxsize: 10 + maxsize: 1000 maxbackups: 3 maxage: 30 compress: false diff --git a/conf/setup.env b/conf/setup.env index 5b1b1d3..c0e0fd1 100644 --- a/conf/setup.env +++ b/conf/setup.env @@ -20,7 +20,7 @@ export DAMSELFLY_LKVSTORE_PATH=db/damselfly.db ## Logger configuration # Set log file path (default logfile path: ./damselfly.log) export DAMSELFLY_LOGFILE_PATH=log/damselfly.log -export DAMSELFLY_LOGFILE_MAXSIZE=10 +export DAMSELFLY_LOGFILE_MAXSIZE=1000 export DAMSELFLY_LOGFILE_MAXBACKUPS=3 export DAMSELFLY_LOGFILE_MAXAGE=30 export DAMSELFLY_LOGFILE_COMPRESS=false diff --git a/docker-compose.yaml b/docker-compose.yaml index db27e2a..d1fefe8 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,6 @@ services: cm-damselfly: + image: cloudbaristaorg/cm-damselfly:0.2.0 container_name: cm-damselfly pull_policy: missing restart: always @@ -11,43 +12,26 @@ services: - target: 8088 published: 8088 protocol: tcp - image: cloudbaristaorg/cm-damselfly:latest volumes: - # - ./.damselfly/lkvstore.db:/app/db/lkvstore.db:rw - # - ./log/damselfly.log:/app/log/damselfly.log:rw - - ./.damselfly/:/app/db/ - - ./log/:/app/log/ - network_mode: "host" + - ./container-volume/cb-damselfly-container/db/:/app/db/ + - ./container-volume/cb-damselfly-container/log/:/app/log/ environment: - # - DAMSELFLY_ROOT=/app - ## Set API access config - # DAMSELFLY_API_ALLOW_ORIGINS (ex: https://cloud-barista.org,http://localhost:8080 or * for all) - - DAMSELFLY_API_ALLOW_ORIGINS=* - # Set DAMSELFLY_API_AUTH_ENABLED=true currently for basic auth for all routes (i.e., url or path) - - DAMSELFLY_API_AUTH_ENABLED=true - - DAMSELFLY_API_USERNAME=default - - DAMSELFLY_API_PASSWORD=default - # Set DAMSELFLY_SELF_ENDPOINT, to access Swagger API dashboard outside (Ex: export SELF_ENDPOINT=x.x.x.x:8056) - - DAMSELFLY_SELF_ENDPOINT=localhost:8088 - ## Logger configuration - # Set log file path (default logfile path: ./damselfly.log) - - DAMSELFLY_LOGFILE_PATH=/app/log/damselfly.log - - DAMSELFLY_LOGFILE_MAXSIZE=10 - - DAMSELFLY_LOGFILE_MAXBACKUPS=3 - - DAMSELFLY_LOGFILE_MAXAGE=30 - - DAMSELFLY_LOGFILE_COMPRESS=false - # Set log level, such as trace, debug info, warn, error, fatal, and panic + - DAMSELFLY_ROOT=/app + # - DAMSELFLY_API_ALLOW_ORIGINS=* + # - DAMSELFLY_API_AUTH_ENABLED=true + # - DAMSELFLY_API_USERNAME=default + # - DAMSELFLY_API_PASSWORD=default + # - DAMSELFLY_SELF_ENDPOINT=localhost:8088 + # - DAMSELFLY_LOGFILE_PATH=/app/log/damselfly.log + # - DAMSELFLY_LOGFILE_MAXSIZE=1000 + # - DAMSELFLY_LOGFILE_MAXBACKUPS=3 + # - DAMSELFLY_LOGFILE_MAXAGE=30 + # - DAMSELFLY_LOGFILE_COMPRESS=false - DAMSELFLY_LOGLEVEL=debug - # Set log writer, such as file, stdout, or both - - DAMSELFLY_LOGWRITER=both - - # Set DB file path - - DAMSELFLY_LKVSTORE_PATH=/app/db/damselfly.db - - # Set execution environment, such as development or production - - DAMSELFLY_NODE_ENV=development - ## Set period for auto control goroutine invocation - - DAMSELFLY_AUTOCONTROL_DURATION_MS=10000 + # - DAMSELFLY_LOGWRITER=both + # - DAMSELFLY_LKVSTORE_PATH=/app/db/damselfly.db + # - DAMSELFLY_NODE_ENV=production + # - DAMSELFLY_AUTOCONTROL_DURATION_MS=10000 healthcheck: # for CM-Beetle test: [ "CMD", "curl", "-f", "http://localhost:8088/damselfly/readyz" ] interval: 1m diff --git a/go.mod b/go.mod index 191adab..54ac299 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,8 @@ go 1.23.0 require ( github.com/cloud-barista/cb-tumblebug v0.9.16 - github.com/cloud-barista/cm-model v0.0.2 + github.com/cloud-barista/cm-model v0.0.3 + github.com/fsnotify/fsnotify v1.7.0 github.com/labstack/echo/v4 v4.12.0 github.com/rs/zerolog v1.33.0 github.com/spf13/viper v1.19.0 @@ -16,7 +17,6 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect diff --git a/go.sum b/go.sum index e779305..5edd99b 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,8 @@ github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86c github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cloud-barista/cb-tumblebug v0.9.16 h1:BRpYn+HOpJzC20oD5VMipyslMqePSc0Dx/GR/tefmOc= github.com/cloud-barista/cb-tumblebug v0.9.16/go.mod h1:NId135dY2nPhzV69+v1AFLlIjFTD400smoht73lG58c= -github.com/cloud-barista/cm-model v0.0.2 h1:6qxrkENlGurVs20rywKoT7L8OlvK4KWegIpJHaPJN3M= -github.com/cloud-barista/cm-model v0.0.2/go.mod h1:gSuMhQxD813KIdSvkp8uGptYOeyDik749sYcICZjhj8= +github.com/cloud-barista/cm-model v0.0.3 h1:sYowqaUMw77j2Hmz8nt/pjEA6lfMkGkZ31jNDDPN0Tk= +github.com/cloud-barista/cm-model v0.0.3/go.mod h1:gSuMhQxD813KIdSvkp8uGptYOeyDik749sYcICZjhj8= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= diff --git a/go.work.sum b/go.work.sum index 8b2b888..db3646a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -8,6 +8,8 @@ cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/cloud-barista/cm-model v0.0.3 h1:sYowqaUMw77j2Hmz8nt/pjEA6lfMkGkZ31jNDDPN0Tk= +github.com/cloud-barista/cm-model v0.0.3/go.mod h1:gSuMhQxD813KIdSvkp8uGptYOeyDik749sYcICZjhj8= github.com/cloud-barista/mc-terrarium v0.0.7/go.mod h1:qey9GFrJidyJ3tVfeL/gcImgWLqsF64j/fVmBfaddDI= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= diff --git a/pkg/api/rest/handler/common.go b/pkg/api/rest/handler/common.go index 59f0190..88c800b 100644 --- a/pkg/api/rest/handler/common.go +++ b/pkg/api/rest/handler/common.go @@ -1,127 +1,130 @@ package handler import ( - "fmt" - "time" - "math/big" + "bufio" "crypto/rand" "encoding/base64" - "bufio" + "fmt" + "math/big" + "net" "os" + "path/filepath" "strings" - "github.com/rs/zerolog/log" - "path/filepath" - "net" + "time" + + "github.com/cloud-barista/cm-damselfly/pkg/config" + "github.com/rs/zerolog/log" ) const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" func generateRandomString(n int) (string, error) { - b := make([]byte, n) - _, err := rand.Read(b) - if err != nil { - return "", err - } - - // Encode to base64 and trim to the desired length - return base64.URLEncoding.EncodeToString(b)[:n], nil + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + return "", err + } + + // Encode to base64 and trim to the desired length + return base64.URLEncoding.EncodeToString(b)[:n], nil } func generateUnique15DigitInt() (int, error) { - // The maximum value for a 15-digit number - max := new(big.Int) - max.SetString("999999999999999", 10) // 15-digit maximum value + // The maximum value for a 15-digit number + max := new(big.Int) + max.SetString("999999999999999", 10) // 15-digit maximum value // Get *big.Int type of num. - bigNum, err := rand.Int(rand.Reader, max) - if err != nil { - return 0, err - } - - result, err := bigIntToInt(bigNum) - if err != nil { - fmt.Println("Error:", err) - } else { - fmt.Println("Converted int:", result) - } - - return result, nil + bigNum, err := rand.Int(rand.Reader, max) + if err != nil { + return 0, err + } + + result, err := bigIntToInt(bigNum) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Converted int:", result) + } + + return result, nil } func bigIntToInt(b *big.Int) (int, error) { - // Convert big.Int to int64 - if !b.IsInt64() { - return 0, fmt.Errorf("value out of int64 range") - } - // Ensure it's within int range - i := b.Int64() - if i > int64(^uint(0)>>1) || i < int64(^int(0)) { - return 0, fmt.Errorf("value out of int range") - } - return int(i), nil + // Convert big.Int to int64 + if !b.IsInt64() { + return 0, fmt.Errorf("value out of int64 range") + } + // Ensure it's within int range + i := b.Int64() + if i > int64(^uint(0)>>1) || i < int64(^int(0)) { + return 0, fmt.Errorf("value out of int range") + } + return int(i), nil } func generateUnique15DigitString() (int, error) { - // The maximum value for a 15-digit number - max := new(big.Int) - max.SetString("999999999999999", 10) // 15-digit maximum value + // The maximum value for a 15-digit number + max := new(big.Int) + max.SetString("999999999999999", 10) // 15-digit maximum value // Get *big.Int type of num. - bigNum, err := rand.Int(rand.Reader, max) - if err != nil { - return 0, err - } - - result, err := bigIntToInt(bigNum) - if err != nil { - fmt.Println("Error:", err) - } else { - fmt.Println("Converted int:", result) - } - - return result, nil + bigNum, err := rand.Int(rand.Reader, max) + if err != nil { + return 0, err + } + + result, err := bigIntToInt(bigNum) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Converted int:", result) + } + + return result, nil } func getSeoulCurrentTime() string { loc, err := time.LoadLocation("Asia/Seoul") - if err != nil { - log.Error().Msgf("Failed to Get the Time Value of the Location : [%v]", err) - } + if err != nil { + log.Error().Msgf("Failed to Get the Time Value of the Location : [%v]", err) + } - currentTime := time.Now().In(loc) + currentTime := time.Now().In(loc) return currentTime.Format("2006-01-02 15:04:05") } func getModuleVersion(moduleName string) (string, error) { - var goFile *os.File - if isRunningInContainer() { - wd, err := os.Getwd() - if err != nil { - return "", err - } - goModPath := filepath.Join(wd, "go.mod") - - log.Debug().Msgf("go.mod file path : [%s]", goModPath) - - var openErr error - goFile, openErr = os.Open(goModPath) - if openErr != nil { - return "", openErr - } - defer goFile.Close() - } else { - var openErr error - goFile, openErr = os.Open("./../../go.mod") - if openErr != nil { - return "", openErr - } - defer goFile.Close() - } + var goFile *os.File + if isRunningInContainer() { + wd, err := os.Getwd() + if err != nil { + return "", err + } + goModPath := filepath.Join(wd, "go.mod") + + log.Debug().Msgf("go.mod file path : [%s]", goModPath) + + var openErr error + goFile, openErr = os.Open(goModPath) + if openErr != nil { + return "", openErr + } + defer goFile.Close() + } else { + var openErr error + projectRoot := config.Damselfly.Root + goFile, openErr = os.Open(projectRoot + "/go.mod") + if openErr != nil { + return "", openErr + } + defer goFile.Close() + } scanner := bufio.NewScanner(goFile) for scanner.Scan() { line := scanner.Text() - // log.Debug().Msgf("go.mod line : [%s]", line) + // log.Debug().Msgf("go.mod line : [%s]", line) if strings.Contains(line, moduleName) { parts := strings.Fields(line) @@ -134,26 +137,26 @@ func getModuleVersion(moduleName string) (string, error) { } func isRunningInContainer() bool { - interfaces, _ := net.Interfaces() - for _, iface := range interfaces { - // log.Debug().Msgf("iface.Name: [%v]", iface.Name) - if strings.HasPrefix(iface.Name, "docker") { - return true - } - } - return false - - // file, err := os.Open("/proc/1/cgroup") - // if err != nil { - // return false - // } - // defer file.Close() - - // scanner := bufio.NewScanner(file) - // for scanner.Scan() { - // if strings.Contains(scanner.Text(), "docker") || strings.Contains(scanner.Text(), "kubepods") { - // return true - // } - // } - // return false + interfaces, _ := net.Interfaces() + for _, iface := range interfaces { + // log.Debug().Msgf("iface.Name: [%v]", iface.Name) + if strings.HasPrefix(iface.Name, "docker") { + return true + } + } + return false + + // file, err := os.Open("/proc/1/cgroup") + // if err != nil { + // return false + // } + // defer file.Close() + + // scanner := bufio.NewScanner(file) + // for scanner.Scan() { + // if strings.Contains(scanner.Text(), "docker") || strings.Contains(scanner.Text(), "kubepods") { + // return true + // } + // } + // return false } diff --git a/pkg/api/rest/handler/model.go b/pkg/api/rest/handler/model.go index d6ff892..1794f25 100644 --- a/pkg/api/rest/handler/model.go +++ b/pkg/api/rest/handler/model.go @@ -3,14 +3,17 @@ package handler import ( "fmt" "net/http" + // "reflect" // "encoding/json" "strconv" "strings" + "github.com/labstack/echo/v4" + // "github.com/davecgh/go-spew/spew" - "github.com/rs/zerolog/log" "github.com/cloud-barista/cm-damselfly/pkg/lkvstore" + "github.com/rs/zerolog/log" tbmodel "github.com/cloud-barista/cb-tumblebug/src/core/model" onprem "github.com/cloud-barista/cm-model/infra/onprem" @@ -21,24 +24,25 @@ import ( // ############################################################################################## type ModelRespInfo struct { - Id string `json:"id"` - UserId string `json:"userId"` - IsInitUserModel bool `json:"isInitUserModel"` - UserModelName string `json:"userModelName"` - Description string `json:"description"` - UserModelVer string `json:"userModelVersion"` - CreateTime string `json:"createTime"` - UpdateTime string `json:"updateTime"` - IsTargetModel bool `json:"isTargetModel"` - IsCloudModel bool `json:"isCloudModel"` - OnPremModelVer string `json:"onpremModelVersion"` - CloudModelVer string `json:"cloudModelVersion"` - CSP string `json:"csp"` - Region string `json:"region"` - Zone string `json:"zone"` - OnPremInfraModel onprem.OnPremInfra `json:"onpremiseInfraModel" validate:"required"` - CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` + Id string `json:"id"` + UserId string `json:"userId"` + IsInitUserModel bool `json:"isInitUserModel"` + UserModelName string `json:"userModelName"` + Description string `json:"description"` + UserModelVer string `json:"userModelVersion"` + CreateTime string `json:"createTime"` + UpdateTime string `json:"updateTime"` + IsTargetModel bool `json:"isTargetModel"` + IsCloudModel bool `json:"isCloudModel"` + OnPremModelVer string `json:"onpremModelVersion"` + CloudModelVer string `json:"cloudModelVersion"` + CSP string `json:"csp"` + Region string `json:"region"` + Zone string `json:"zone"` + OnpremInfraModel onprem.OnpremInfra `json:"onpremiseInfraModel" validate:"required"` + CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` } + // Caution!!) // Init Swagger : ]# swag init --parseDependency --parseInternal // Need to add '--parseDependency --parseInternal' in order to apply imported structures @@ -59,14 +63,14 @@ type GetModelsResp struct { // @Router /model/{isTargetModel} [get] func GetModels(c echo.Context) error { param := c.Param("isTargetModel") - // fmt.Printf("# The value of 'isTargetModel' parameter : [%v]", isTargetModel) + // fmt.Printf("# The value of 'isTargetModel' parameter : [%v]", isTargetModel) if strings.EqualFold(param, "true") || strings.EqualFold(param, "false") { // if strings.EqualFold(param, "true") { // fmt.Printf("# Models to Get : Target models") // } else { // fmt.Printf("# Models to Get : Source models") - // } + // } } else { return c.JSON(http.StatusBadRequest, "Invalid type of parameter!!") } @@ -98,7 +102,7 @@ func GetModels(c echo.Context) error { } } - if len(models) < 1 { + if len(models) < 1 { msg := "Failed to Find Any Model" log.Debug().Msg(msg) @@ -114,8 +118,8 @@ func GetModels(c echo.Context) error { } type ModelsVersionRespInfo struct { - OnPremModelVer string `json:"onpremModelVersion"` - CloudModelVer string `json:"cloudModelVersion"` + OnPremModelVer string `json:"onpremModelVersion"` + CloudModelVer string `json:"cloudModelVersion"` } type GetModelsVersionResp struct { @@ -135,7 +139,7 @@ func GetModelsVersion(c echo.Context) error { onpremModelVer, err := getModuleVersion("github.com/cloud-barista/cm-model") if err != nil { - log.Error().Msgf("Failed to Get the Module Version : [%v]", err) + log.Error().Msgf("Failed to Get the Module Version : [%v]", err) } cloudModelVer, err := getModuleVersion("github.com/cloud-barista/cb-tumblebug") @@ -160,28 +164,29 @@ func GetModelsVersion(c echo.Context) error { // ############################################################################################## type OnPremModelReqInfo struct { - UserId string `json:"userId"` - IsInitUserModel bool `json:"isInitUserModel"` - UserModelName string `json:"userModelName"` - Description string `json:"description"` - UserModelVer string `json:"userModelVersion"` - OnPremInfraModel onprem.OnPremInfra `json:"onpremiseInfraModel" validate:"required"` + UserId string `json:"userId"` + IsInitUserModel bool `json:"isInitUserModel"` + UserModelName string `json:"userModelName"` + Description string `json:"description"` + UserModelVer string `json:"userModelVersion"` + OnpremInfraModel onprem.OnpremInfra `json:"onpremiseInfraModel" validate:"required"` } type OnPremModelRespInfo struct { - Id string `json:"id"` - UserId string `json:"userId"` - IsInitUserModel bool `json:"isInitUserModel"` - UserModelName string `json:"userModelName"` - Description string `json:"description"` - UserModelVer string `json:"userModelVersion"` - OnPremModelVer string `json:"onpremModelVersion"` - CreateTime string `json:"createTime"` - UpdateTime string `json:"updateTime"` - IsTargetModel bool `json:"isTargetModel"` - IsCloudModel bool `json:"isCloudModel"` - OnPremInfraModel onprem.OnPremInfra `json:"onpremiseInfraModel" validate:"required"` + Id string `json:"id"` + UserId string `json:"userId"` + IsInitUserModel bool `json:"isInitUserModel"` + UserModelName string `json:"userModelName"` + Description string `json:"description"` + UserModelVer string `json:"userModelVersion"` + OnPremModelVer string `json:"onpremModelVersion"` + CreateTime string `json:"createTime"` + UpdateTime string `json:"updateTime"` + IsTargetModel bool `json:"isTargetModel"` + IsCloudModel bool `json:"isCloudModel"` + OnpremInfraModel onprem.OnpremInfra `json:"onpremiseInfraModel" validate:"required"` } + // Caution!!) // Init Swagger : ]# swag init --parseDependency --parseInternal // Need to add '--parseDependency --parseInternal' in order to apply imported structures @@ -210,7 +215,7 @@ func GetOnPremModels(c echo.Context) error { // if id, exists := model["id"]; exists { // // fmt.Printf("Loaded value-1 for [%s]: %v\n", c.Param("id"), model) - // if id, ok := id.(string); ok { + // if id, ok := id.(string); ok { // log.Debug().Msgf("# Model ID to Add : [%s]\n", id) // } else { // msg := ("'id' is not a string type") @@ -232,7 +237,7 @@ func GetOnPremModels(c echo.Context) error { } } - if len(onpremModels) < 1 { + if len(onpremModels) < 1 { msg := "Failed to Find Any Model" log.Debug().Msg(msg) @@ -267,108 +272,108 @@ func GetOnPremModel(c echo.Context) error { } fmt.Printf("# Model ID to Get : [%s]\n", c.Param("id")) -/* - // GetWithPrefix returns the values for a given key prefix. - modelList, exists := lkvstore.GetWithPrefix("") - if exists { - // # Returns Only On-prem Models - var onpremModel map[string]interface{} - for _, model := range modelList { - if model, ok := model.(map[string]interface{}); ok { - - if isCloudModel, exists := model["isCloudModel"]; exists && isCloudModel == false { - - if id, exists := model["id"]; exists { - // fmt.Printf("Loaded value-1 for [%s]: %v\n", c.Param("id"), model) - if id, ok := id.(string); ok { - if id == c.Param("id") { - // fmt.Printf("Loaded value-2 for [%s]: %v\n", c.Param("id"), model) - onpremModel = model - return c.JSON(http.StatusOK, onpremModel) - - // if isCloudModelBool { - // newErr := fmt.Errorf("The Given ID is Not a On-premise Model ID : [%s]", c.Param("id")) - // return c.JSON(http.StatusNotFound, newErr) - // } else { - // msg := "This model is a On-premise Model!!" - // log.Error().Msg(msg) - - // newErr := fmt.Errorf(msg) - // return c.JSON(http.StatusNotFound, newErr) - // } + /* + // GetWithPrefix returns the values for a given key prefix. + modelList, exists := lkvstore.GetWithPrefix("") + if exists { + // # Returns Only On-prem Models + var onpremModel map[string]interface{} + for _, model := range modelList { + if model, ok := model.(map[string]interface{}); ok { + if isCloudModel, exists := model["isCloudModel"]; exists && isCloudModel == false { + + if id, exists := model["id"]; exists { + // fmt.Printf("Loaded value-1 for [%s]: %v\n", c.Param("id"), model) + if id, ok := id.(string); ok { + if id == c.Param("id") { + // fmt.Printf("Loaded value-2 for [%s]: %v\n", c.Param("id"), model) + onpremModel = model + return c.JSON(http.StatusOK, onpremModel) + + // if isCloudModelBool { + // newErr := fmt.Errorf("The Given ID is Not a On-premise Model ID : [%s]", c.Param("id")) + // return c.JSON(http.StatusNotFound, newErr) + // } else { + // msg := "This model is a On-premise Model!!" + // log.Error().Msg(msg) + + // newErr := fmt.Errorf(msg) + // return c.JSON(http.StatusNotFound, newErr) + // } + + } + } else { + msg := ("'id' is not a string type") + log.Error().Msg(msg) + + newErr := fmt.Errorf("'id' is not a string type") + return c.JSON(http.StatusNotFound, newErr) } } else { - msg := ("'id' is not a string type") + msg := ("'id' does not exist") log.Error().Msg(msg) - newErr := fmt.Errorf("'id' is not a string type") + newErr := fmt.Errorf("'id' does not exist") return c.JSON(http.StatusNotFound, newErr) } - } else { - msg := ("'id' does not exist") - log.Error().Msg(msg) + } + // else { + // msg := ("'id' does not exist") + // log.Error().Msg(msg) - newErr := fmt.Errorf("'id' does not exist") - return c.JSON(http.StatusNotFound, newErr) - } - } - // else { - // msg := ("'id' does not exist") - // log.Error().Msg(msg) - - // newErr := fmt.Errorf("'isCloudModel' does not exist") - // return c.JSON(http.StatusNotFound, newErr) - // } - - // fmt.Printf("Loaded value-1 for [%s]: %v\n", c.Param("id"), model) - - // if Id, exists := model["id"]; exists && Id == c.Param("id") { - - // fmt.Printf("Loaded value-2 for [%s]: %v\n", c.Param("id"), model) - - // if isCloudModel, exists := model["isCloudModel"]; exists { - // if isCloudModelBool, ok := isCloudModel.(bool); ok { - // if isCloudModelBool { - // newErr := fmt.Errorf("The Given ID is Not a On-premise Model ID : [%s]", c.Param("id")) - // return c.JSON(http.StatusNotFound, newErr) - // } else { - // msg := "This model is a On-premise Model!!" - // log.Error().Msg(msg) - - // newErr := fmt.Errorf(msg) - // return c.JSON(http.StatusNotFound, newErr) - // } - // } else { - // msg := ("'isCloudModel' is not a boolean type") - // log.Error().Msg(msg) - - // newErr := fmt.Errorf("'isCloudModel' is not a boolean type") - // return c.JSON(http.StatusNotFound, newErr) - // } - // } else { - // msg := ("'isCloudModel' does not exist") - // log.Error().Msg(msg) - - // newErr := fmt.Errorf("'isCloudModel' does not exist") - // return c.JSON(http.StatusNotFound, newErr) - // } - // } else { - // onpremModel = model - // return c.JSON(http.StatusOK, onpremModel) - // } + // newErr := fmt.Errorf("'isCloudModel' does not exist") + // return c.JSON(http.StatusNotFound, newErr) + // } + + // fmt.Printf("Loaded value-1 for [%s]: %v\n", c.Param("id"), model) + + // if Id, exists := model["id"]; exists && Id == c.Param("id") { + + // fmt.Printf("Loaded value-2 for [%s]: %v\n", c.Param("id"), model) + + // if isCloudModel, exists := model["isCloudModel"]; exists { + // if isCloudModelBool, ok := isCloudModel.(bool); ok { + // if isCloudModelBool { + // newErr := fmt.Errorf("The Given ID is Not a On-premise Model ID : [%s]", c.Param("id")) + // return c.JSON(http.StatusNotFound, newErr) + // } else { + // msg := "This model is a On-premise Model!!" + // log.Error().Msg(msg) + + // newErr := fmt.Errorf(msg) + // return c.JSON(http.StatusNotFound, newErr) + // } + // } else { + // msg := ("'isCloudModel' is not a boolean type") + // log.Error().Msg(msg) + + // newErr := fmt.Errorf("'isCloudModel' is not a boolean type") + // return c.JSON(http.StatusNotFound, newErr) + // } + // } else { + // msg := ("'isCloudModel' does not exist") + // log.Error().Msg(msg) + + // newErr := fmt.Errorf("'isCloudModel' does not exist") + // return c.JSON(http.StatusNotFound, newErr) + // } + // } else { + // onpremModel = model + // return c.JSON(http.StatusOK, onpremModel) + // } + } } - } - // return c.JSON(http.StatusOK, onpremModel) + // return c.JSON(http.StatusOK, onpremModel) - newErr := fmt.Errorf("Failed to Find the Model : [%s]\n", c.Param("id")) - return c.JSON(http.StatusNotFound, newErr) + newErr := fmt.Errorf("Failed to Find the Model : [%s]\n", c.Param("id")) + return c.JSON(http.StatusNotFound, newErr) - } else { - newErr := fmt.Errorf("Failed to Find the Model : [%s]\n", c.Param("id")) - return c.JSON(http.StatusNotFound, newErr) - } -*/ + } else { + newErr := fmt.Errorf("Failed to Find the Model : [%s]\n", c.Param("id")) + return c.JSON(http.StatusNotFound, newErr) + } + */ model, exists := lkvstore.Get(c.Param("id")) if exists { @@ -401,7 +406,6 @@ func GetOnPremModel(c echo.Context) error { } } - // [Note] // Struct Embedding is used to inherit the fields of MyOnPremModel type CreateOnPremModelReq struct { @@ -433,12 +437,12 @@ func CreateOnPremModel(c echo.Context) error { // fmt.Println("### OnPremModel",) // spew.Dump(model) - randomStr, err := generateRandomString(15) - if err != nil { - fmt.Println("Error:", err) - } else { - fmt.Println("Random 15-length of string : ", randomStr) - } + randomStr, err := generateRandomString(15) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Random 15-length of string : ", randomStr) + } model.Id = randomStr model.CreateTime = getSeoulCurrentTime() @@ -465,7 +469,7 @@ func CreateOnPremModel(c echo.Context) error { } else { fmt.Println("Succeeded in Saving the lkvstore to file.") } - + return c.JSON(http.StatusCreated, model) } @@ -539,7 +543,7 @@ func UpdateOnPremModel(c echo.Context) error { if model, ok := model.(map[string]interface{}); ok { if onPremModelVer, exists := model["onpremModelVersion"]; exists { - if onpremModelVerStr, ok := onPremModelVer.(string); ok { + if onpremModelVerStr, ok := onPremModelVer.(string); ok { updateModel.OnPremModelVer = onpremModelVerStr fmt.Printf("### onpremModelVerStr : [%s]\n", onpremModelVerStr) } else { @@ -553,16 +557,15 @@ func UpdateOnPremModel(c echo.Context) error { msg := "'onpremModelVersion' does not exist" log.Error().Msg(msg) - fmt.Println("'onpremModelVersion' does not exist") + fmt.Println("'onpremModelVersion' does not exist") } - } + } // else { // msg := "Error!! Error!! Error!! Error!! Error!!" // log.Error().Msg(msg) // } - if model, ok := model.(map[string]interface{}); ok { if createTime, exists := model["createTime"]; exists { if createTimeStr, ok := createTime.(string); ok { @@ -608,19 +611,19 @@ func UpdateOnPremModel(c echo.Context) error { } else { fmt.Println("Succeeded in Saving the lkvstore to file.") } - + // return c.JSON(http.StatusCreated, updateModel) // => Not http.StatusCreated // Get the model from the DB model, exists := lkvstore.Get(reqId) if exists { - // fmt.Printf("Loaded value for [%s]: %v\n", c.Param("id"), model) + // fmt.Printf("Loaded value for [%s]: %v\n", c.Param("id"), model) return c.JSON(http.StatusOK, model) } else { newErr := fmt.Errorf("Failed to Find the Model from DB : [%s]", reqId) return c.JSON(http.StatusNotFound, newErr) - } + } } else { msg := "Failed to Find the Model from DB : [%s]\n" log.Error().Msg(msg) @@ -700,35 +703,36 @@ func DeleteOnPremModel(c echo.Context) error { // ############################################################################################## type CloudModelReqInfo struct { - UserId string `json:"userId"` - IsTargetModel bool `json:"isTargetModel"` - IsInitUserModel bool `json:"isInitUserModel"` - UserModelName string `json:"userModelName"` - Description string `json:"description"` - UserModelVer string `json:"userModelVersion"` - CSP string `json:"csp"` - Region string `json:"region"` - Zone string `json:"zone"` - CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` + UserId string `json:"userId"` + IsTargetModel bool `json:"isTargetModel"` + IsInitUserModel bool `json:"isInitUserModel"` + UserModelName string `json:"userModelName"` + Description string `json:"description"` + UserModelVer string `json:"userModelVersion"` + CSP string `json:"csp"` + Region string `json:"region"` + Zone string `json:"zone"` + CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` } type CloudModelRespInfo struct { - Id string `json:"id"` - UserId string `json:"userId"` - IsTargetModel bool `json:"isTargetModel"` - IsInitUserModel bool `json:"isInitUserModel"` - UserModelName string `json:"userModelName"` - Description string `json:"description"` - UserModelVer string `json:"userModelVersion"` - CreateTime string `json:"createTime"` - UpdateTime string `json:"updateTime"` - CSP string `json:"csp"` - Region string `json:"region"` - Zone string `json:"zone"` - IsCloudModel bool `json:"isCloudModel"` - CloudModelVer string `json:"cloudModelVersion"` - CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` + Id string `json:"id"` + UserId string `json:"userId"` + IsTargetModel bool `json:"isTargetModel"` + IsInitUserModel bool `json:"isInitUserModel"` + UserModelName string `json:"userModelName"` + Description string `json:"description"` + UserModelVer string `json:"userModelVersion"` + CreateTime string `json:"createTime"` + UpdateTime string `json:"updateTime"` + CSP string `json:"csp"` + Region string `json:"region"` + Zone string `json:"zone"` + IsCloudModel bool `json:"isCloudModel"` + CloudModelVer string `json:"cloudModelVersion"` + CloudInfraModel tbmodel.TbMciDynamicReq `json:"cloudInfraModel" validate:"required"` } + // Caution!!) // Init Swagger : ]# swag init --parseDependency --parseInternal // Need to add '--parseDependency --parseInternal' in order to apply imported structures @@ -757,7 +761,7 @@ func GetCloudModels(c echo.Context) error { if isCloudModel, exists := model["isCloudModel"]; exists && isCloudModel == true { cloudModels = append(cloudModels, model) } - } + } } if len(cloudModels) < 1 { @@ -804,7 +808,7 @@ func GetCloudModel(c echo.Context) error { if isCloudModel, exists := model["isCloudModel"]; exists { if isCloudModelBool, ok := isCloudModel.(bool); ok { if isCloudModelBool { - fmt.Println("This model is a Cloud Model!!") + fmt.Println("This model is a Cloud Model!!") } else { newErr := fmt.Errorf("The Given ID is Not a Cloud Model ID : [%s]", c.Param("id")) return c.JSON(http.StatusNotFound, newErr) @@ -826,7 +830,6 @@ func GetCloudModel(c echo.Context) error { } } - // [Note] // Struct Embedding is used to inherit the fields of MyCloudModel type CreateCloudModelReq struct { @@ -858,12 +861,12 @@ func CreateCloudModel(c echo.Context) error { // fmt.Println("### CreateCloudModelResp",) // spew.Dump(model) - randomStr, err := generateRandomString(15) - if err != nil { - fmt.Println("Error:", err) - } else { - fmt.Println("Random 15-lenght of string:", randomStr) - } + randomStr, err := generateRandomString(15) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Random 15-lenght of string:", randomStr) + } model.Id = randomStr model.CreateTime = getSeoulCurrentTime() @@ -934,7 +937,7 @@ func UpdateCloudModel(c echo.Context) error { if exists { fmt.Printf("Succeeded in Finding the model : [%s]\n", reqId) // fmt.Printf("# Cloud Model ID to Update : [%s]\n", reqId) - // fmt.Printf("Values from DB [%s]: %v\n\n", c.Param("id"), model) + // fmt.Printf("Values from DB [%s]: %v\n\n", c.Param("id"), model) if cloudModel, ok := model.(map[string]interface{}); ok { // Check if the model is a on-premise model @@ -943,7 +946,7 @@ func UpdateCloudModel(c echo.Context) error { fmt.Printf("The value of isCloudModel is: %v\n", isCloudModel) if isCloudModelBool { - fmt.Println("This model is a Cloud Model!!") + fmt.Println("This model is a Cloud Model!!") } else { newErr := fmt.Errorf("The Given ID is Not a Cloud Model ID : [%s]", reqId) return c.JSON(http.StatusNotFound, newErr) @@ -982,7 +985,7 @@ func UpdateCloudModel(c echo.Context) error { fmt.Println("'createTime' does not exist") } } - + // cloudModelVer, err := getModuleVersion("github.com/cloud-barista/cb-tumblebug") // if err != nil { // fmt.Println("Error:", err) @@ -995,7 +998,7 @@ func UpdateCloudModel(c echo.Context) error { updateModel.UpdateTime = getSeoulCurrentTime() updateModel.IsCloudModel = true - // fmt.Println("### updateModel",) + // fmt.Println("### updateModel",) // spew.Dump(updateModel) // Convert to String type @@ -1003,7 +1006,7 @@ func UpdateCloudModel(c echo.Context) error { // Save the model to the key-value store lkvstore.Put(reqId, updateModel) - + // # Save the current state of the key-value store to file if err := lkvstore.SaveLkvStore(); err != nil { newErr := fmt.Errorf("Failed to Save the lkvstore to file. : [%v]", err) @@ -1015,7 +1018,7 @@ func UpdateCloudModel(c echo.Context) error { // Get the model from the DB model, exists := lkvstore.Get(reqId) if exists { - // fmt.Printf("Loaded value for [%s]: %v\n", c.Param("id"), model) + // fmt.Printf("Loaded value for [%s]: %v\n", c.Param("id"), model) return c.JSON(http.StatusOK, model) } else { newErr := fmt.Errorf("Failed to Find the Model from DB : [%s]", reqId) diff --git a/pkg/api/rest/server.go b/pkg/api/rest/server.go index 2d322a8..4e54f9f 100644 --- a/pkg/api/rest/server.go +++ b/pkg/api/rest/server.go @@ -24,7 +24,7 @@ import ( "github.com/cloud-barista/cm-damselfly/pkg/api/rest/handler" mw "github.com/cloud-barista/cm-damselfly/pkg/api/rest/middleware" "github.com/cloud-barista/cm-damselfly/pkg/common" - "github.com/spf13/viper" + "github.com/cloud-barista/cm-damselfly/pkg/config" "crypto/subtle" "fmt" @@ -103,7 +103,7 @@ func RunServer(port string) { e.HideBanner = true //e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website)) - allowedOrigins := viper.GetString("damselfly.api.allow.origins") + allowedOrigins := config.Damselfly.API.Allow.Origins if allowedOrigins == "" { log.Fatal().Msg("allow_ORIGINS env variable for CORS is " + allowedOrigins + ". Please provide a proper value and source setup.env again. EXITING...") @@ -115,10 +115,10 @@ func RunServer(port string) { })) // Conditions to prevent abnormal operation due to typos (e.g., ture, falss, etc.) - enableAuth := viper.GetString("damselfly.api.auth.enabled") == "true" + enableAuth := config.Damselfly.API.Auth.Enabled - apiUser := viper.GetString("damselfly.api.username") - apiPass := viper.GetString("damselfly.api.password") + apiUser := config.Damselfly.API.Username + apiPass := config.Damselfly.API.Password if enableAuth { e.Use(middleware.BasicAuthWithConfig(middleware.BasicAuthConfig{ @@ -184,7 +184,7 @@ func RunServer(port string) { gModel.DELETE("/cloudmodel/:id", handler.DeleteCloudModel) // Run Damselfly API server - selfEndpoint := viper.GetString("damselfly.self.endpoint") + selfEndpoint := config.Damselfly.Self.Endpoint apidashboard := " http://" + selfEndpoint + "/damselfly/api" if enableAuth { diff --git a/pkg/config/config.go b/pkg/config/config.go index cf89039..6c6548f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -11,6 +11,65 @@ import ( "github.com/spf13/viper" ) +var ( + RuntimeConfig Config + Damselfly DamselflyConfig +) + +type Config struct { + Damselfly DamselflyConfig `mapstructure:"damselfly"` +} + +type DamselflyConfig struct { + Root string `mapstructure:"root"` + Self SelfConfig `mapstructure:"self"` + API ApiConfig `mapstructure:"api"` + LKVStore LkvStoreConfig `mapstructure:"lkvstore"` + LogFile LogfileConfig `mapstructure:"logfile"` + LogLevel string `mapstructure:"loglevel"` + LogWriter string `mapstructure:"logwriter"` + Node NodeConfig `mapstructure:"node"` + AutoControl AutoControlConfig `mapstructure:"autocontrol"` +} + +type SelfConfig struct { + Endpoint string `mapstructure:"endpoint"` +} + +type ApiConfig struct { + Allow AllowConfig `mapstructure:"allow"` + Auth AuthConfig `mapstructure:"auth"` + Username string `mapstructure:"username"` + Password string `mapstructure:"password"` +} + +type AllowConfig struct { + Origins string `mapstructure:"origins"` +} +type AuthConfig struct { + Enabled bool `mapstructure:"enabled"` +} + +type LkvStoreConfig struct { + Path string `mapstructure:"path"` +} + +type LogfileConfig struct { + Path string `mapstructure:"path"` + MaxSize int `mapstructure:"maxsize"` + MaxBackups int `mapstructure:"maxbackups"` + MaxAge int `mapstructure:"maxage"` + Compress bool `mapstructure:"compress"` +} + +type NodeConfig struct { + Env string `mapstructure:"env"` +} + +type AutoControlConfig struct { + DurationMilliSec int `mapstructure:"duration_ms"` +} + func Init() { viper.AddConfigPath("../../conf/") // config for development viper.AddConfigPath(".") // config for production optionally looking for the configuration in the working directory @@ -18,55 +77,63 @@ func Init() { viper.SetConfigType("yaml") viper.SetConfigName("config") - // Load main configuration - viper.SetConfigName("config") err := viper.ReadInConfig() if err != nil { fmt.Printf("no main config file, using default settings: %s\n", err) log.Printf("no main config file, using default settings: %s", err) } - // Map environment variable names to config file key names + // Explicitly bind environment variables to configuration keys + bindEnvironmentVariables() + replacer := strings.NewReplacer(".", "_") viper.SetEnvKeyReplacer(replacer) - - // NOTE - the environment variable has higher priority than the config file - // Automatically recognize environment variables viper.AutomaticEnv() - // Values set in runtime if viper.GetString("damselfly.root") == "" { - fmt.Println("find project root by using project name") - log.Println("find project root by using project name") - - projectName := "cm-damselfly" - // Get the executable path - execPath, err := os.Executable() - if err != nil { - fmt.Printf("Error getting executable path: %v\n", err) - log.Fatalf("Error getting executable path: %v", err) - } - execDir := filepath.Dir(execPath) - projectRoot, err := checkProjectRootInParentDirectory(projectName, execDir) - if err != nil { - fmt.Printf("set current directory as project root directory (%v)\n", err) - log.Printf("set current directory as project root directory (%v)", err) - projectRoot = execDir - } - fmt.Printf("project root directory: %s\n", projectRoot) - log.Printf("project root directory: %s\n", projectRoot) + log.Println("Finding project root by using project name") - // Set the binary path + projectRoot := findProjectRoot("cm-damselfly") viper.Set("damselfly.root", projectRoot) } - // Recursively print all keys and values in Viper - settings := viper.AllSettings() - if viper.GetString("damselfly.node.env") == "development" { + if err := viper.Unmarshal(&RuntimeConfig); err != nil { + log.Fatalf("Unable to decode into struct: %v", err) + } + Damselfly = RuntimeConfig.Damselfly + + // Print settings if in development mode + if Damselfly.Node.Env == "development" { + settings := viper.AllSettings() recursivePrintMap(settings, "") } } +// NVL is func for null value logic +func NVL(str string, def string) string { + if len(str) == 0 { + return def + } + return str +} + +func findProjectRoot(projectName string) string { + execPath, err := os.Executable() + if err != nil { + log.Fatalf("Error getting executable path: %v", err) + } + execDir := filepath.Dir(execPath) + projectRoot, err := checkProjectRootInParentDirectory(projectName, execDir) + if err != nil { + fmt.Printf("Set current directory as project root directory (%v)\n", err) + log.Printf("Set current directory as project root directory (%v)", err) + projectRoot = execDir + } + fmt.Printf("Project root directory: %s\n", projectRoot) + log.Printf("Project root directory: %s\n", projectRoot) + return projectRoot +} + func checkProjectRootInParentDirectory(projectName string, execDir string) (string, error) { // Append a path separator to the project name for accurate matching @@ -95,3 +162,23 @@ func recursivePrintMap(m map[string]interface{}, prefix string) { } } } + +func bindEnvironmentVariables() { + // Explicitly bind environment variables to configuration keys + viper.BindEnv("damselfly.root", "DAMSELFLY_ROOT") + viper.BindEnv("damselfly.self.endpoint", "DAMSELFLY_SELF_ENDPOINT") + viper.BindEnv("damselfly.api.allow.origins", "DAMSELFLY_API_ALLOW_ORIGINS") + viper.BindEnv("damselfly.api.auth.enabled", "DAMSELFLY_API_AUTH_ENABLED") + viper.BindEnv("damselfly.api.username", "DAMSELFLY_API_USERNAME") + viper.BindEnv("damselfly.api.password", "DAMSELFLY_API_PASSWORD") + viper.BindEnv("damselfly.lkvstore.path", "DAMSELFLY_LKVSTORE_PATH") + viper.BindEnv("damselfly.logfile.path", "DAMSELFLY_LOGFILE_PATH") + viper.BindEnv("damselfly.logfile.maxsize", "DAMSELFLY_LOGFILE_MAXSIZE") + viper.BindEnv("damselfly.logfile.maxbackups", "DAMSELFLY_LOGFILE_MAXBACKUPS") + viper.BindEnv("damselfly.logfile.maxage", "DAMSELFLY_LOGFILE_MAXAGE") + viper.BindEnv("damselfly.logfile.compress", "DAMSELFLY_LOGFILE_COMPRESS") + viper.BindEnv("damselfly.loglevel", "DAMSELFLY_LOGLEVEL") + viper.BindEnv("damselfly.logwriter", "DAMSELFLY_LOGWRITER") + viper.BindEnv("damselfly.node.env", "DAMSELFLY_NODE_ENV") + viper.BindEnv("damselfly.autocontrol.duration_ms", "DAMSELFLY_AUTOCONTROL_DURATION_MS") +}