Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions modules/mysql/src/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type MySQL struct {
Version string `json:"version,omitempty" yaml:"version,omitempty"`
// The type of the MySQL instance.
InstanceType string `json:"instanceType,omitempty" yaml:"instanceType,omitempty"`
// The type of the MySQL volume.
VolumeType string
// The allocated storage size of the MySQL instance.
Size int `json:"size,omitempty" yaml:"size,omitempty"`
// The edition of the MySQL instance provided by the cloud vendor.
Expand All @@ -73,6 +75,8 @@ type MySQL struct {
Username string `json:"username,omitempty" yaml:"username,omitempty"`
// The list of IP addresses allowed to access the MySQL instance provided by the cloud vendor.
SecurityIPs []string `json:"securityIPs,omitempty" yaml:"securityIPs,omitempty"`
// The VPC ID associated with the cloud MySQL instance will be created in.
VPC string `json:"vpc,omitempty" yaml:"vpc,omitempty"`
// The virtual subnet ID associated with the VPC that the cloud MySQL instance will be created in.
SubnetID string `json:"subnetID,omitempty" yaml:"subnetID,omitempty"`
// Whether the host address of the cloud MySQL instance for the workload to connect with is via
Expand Down Expand Up @@ -131,6 +135,11 @@ func (mysql *MySQL) Generate(_ context.Context, request *module.GeneratorRequest
if err != nil {
return nil, err
}
case "viettelcloud":
resources, patcher, err = mysql.GenerateViettelCloudResources(request)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported cloud provider type: %s", providerType)
}
Expand Down Expand Up @@ -200,6 +209,14 @@ func (mysql *MySQL) GetCompleteConfig(devConfig apiv1.Accessory, platformConfig
mysql.InstanceType = instanceType.(string)
}

if volumeType, ok := platformConfig["volumeType"]; ok {
mysql.VolumeType = volumeType.(string)
}

if vpc, ok := platformConfig["vpc"]; ok {
mysql.VPC = vpc.(string)
}

if subnetID, ok := platformConfig["subnetID"]; ok {
mysql.SubnetID = subnetID.(string)
}
Expand Down
16 changes: 16 additions & 0 deletions modules/mysql/src/mysql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ func TestMySQLModule_Generator(t *testing.T) {
},
expectedErr: nil,
},
{
name: "Generate ViettelCloud MySQL DBaaS",
devModuleConfig: apiv1.Accessory{
"type": "cloud",
"version": "8.0",
},
platformConfig: apiv1.GenericConfig{
"cloud": "viettelcloud",
"size": 20,
"instanceType": "DBAAS_1vCPU_1_RAM",
"volumeType": "ssd",
"vpc": "vpc-test-name",
"subnetID": "subnet-test-name",
},
expectedErr: nil,
},
{
name: "Unsupported MySQL type",
devModuleConfig: apiv1.Accessory{
Expand Down
98 changes: 98 additions & 0 deletions modules/mysql/src/viettelcloud_dbaas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package main

import (
"os"

"kusionstack.io/kusion-module-framework/pkg/module"
apiv1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
"kusionstack.io/kusion/pkg/modules"
)

const (
DefaultViettelCloudRegion = "vn-central-1"
)

var (
viettelCloudRegionEnv = "VIETTEL_CLOUD_REGION"
viettelCloudDBInstance = "viettelcloud_db_instance"
)

var defaultViettelCloudProviderCfg = module.ProviderConfig{
Source: "hashicorp/viettelcloud",
Version: "1.0.0-dev",
}

// GenerateViettelCloudResources generates the ViettelCloud provided MySQL database instance.
func (mysql *MySQL) GenerateViettelCloudResources(request *module.GeneratorRequest) ([]apiv1.Resource, *apiv1.Patcher, error) {
var resources []apiv1.Resource

// Set the ViettelCloud provider with the default provider config.
viettelCloudProviderCfg := defaultViettelCloudProviderCfg

// Get the ViettelCloud Terraform provider region, which should not be empty.
var region string
if region = module.TerraformProviderRegion(viettelCloudProviderCfg); region == "" {
region = os.Getenv(viettelCloudRegionEnv)
}
if region == "" {
region = DefaultViettelCloudRegion
}

// Build random_password resource.
randomPasswordRes, randomPasswordID, err := mysql.GenerateTFRandomPassword(request)
if err != nil {
return nil, nil, err
}
resources = append(resources, *randomPasswordRes)

// Build viettelCloud_db_instance resource.
viettelCloudDBInstance, viettelCloudDBInstanceID, err := mysql.generateViettelCloudDBInstance(viettelCloudProviderCfg, region, randomPasswordID)
if err != nil {
return nil, nil, err
}
resources = append(resources, *viettelCloudDBInstance)

hostAddress := modules.KusionPathDependency(viettelCloudDBInstanceID, "private_url")
password := modules.KusionPathDependency(randomPasswordID, "result")

// Build Kubernetes Secret with the hostAddress, username and password of the ViettelCloud provided MySQL instance,
// and inject the credentials as the environment variable patcher.
dbSecret, patcher, err := mysql.GenerateDBSecret(request, hostAddress, mysql.Username, password)
if err != nil {
return nil, nil, err
}
resources = append(resources, *dbSecret)

return resources, patcher, nil
}

// generateViettelCloudDBInstance generates viettelCloud_db_instance resource for the ViettelCloud provided MySQL database instance.
func (mysql *MySQL) generateViettelCloudDBInstance(viettelCloudProviderCfg module.ProviderConfig, region, randomPasswordID string) (*apiv1.Resource, string, error) {
resAttrs := map[string]interface{}{
"database_type": dbEngine,
"region": region,
"name": mysql.DatabaseName,
"db_version": mysql.Version,
"flavor": mysql.InstanceType,
"volume_type": mysql.VolumeType,
"disk_size": mysql.Size,
"vpc_name": mysql.VPC,
"subnet": mysql.SubnetID,
"solution": mysql.Category,
"root_password": modules.KusionPathDependency(randomPasswordID, "result"),
"enable_auto_backup": false,
}

id, err := module.TerraformResourceID(viettelCloudProviderCfg, viettelCloudDBInstance, mysql.DatabaseName)
if err != nil {
return nil, "", err
}

viettelCloudProviderCfg.ProviderMeta = map[string]any{}
resource, err := module.WrapTFResourceToKusionResource(viettelCloudProviderCfg, viettelCloudDBInstance, id, resAttrs, nil)
if err != nil {
return nil, "", err
}

return resource, id, nil
}
69 changes: 69 additions & 0 deletions modules/mysql/src/viettelcloud_dbaas_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"github.com/bytedance/mockey"
"github.com/stretchr/testify/assert"
"kusionstack.io/kusion-module-framework/pkg/module"
v1 "kusionstack.io/kusion/pkg/apis/api.kusion.io/v1"
"os"
"testing"
)

func TestMySQLModule_GenerateViettelCloudResources(t *testing.T) {
r := &module.GeneratorRequest{
Project: "test-project",
Stack: "test-stack",
App: "test-app",
Workload: &v1.Workload{
Header: v1.Header{
Type: "Service",
},
Service: &v1.Service{},
},
}

mysql := &MySQL{
Type: "local",
Version: "8.0",
DatabaseName: "test-database",
Username: defaultUsername,
Category: defaultCategory,
Size: defaultSize,
InstanceType: "DBAAS_1vCPU_1_RAM",
VolumeType: "ssd",
VPC: "vpc-new",
SubnetID: "subnet",
}

mockey.PatchConvey("set viettelcloud region env", t, func() {
mockey.Mock(os.Getenv).Return("test-region").Build()

resources, patchers, err := mysql.GenerateViettelCloudResources(r)

assert.Equal(t, 3, len(resources))
assert.NotNil(t, patchers)
assert.NoError(t, err)
})
}

func TestMySQLModule_GenerateViettelCloudDBInstance(t *testing.T) {
mysql := &MySQL{
Type: "local",
Version: "8.0",
DatabaseName: "test-database",
Username: defaultUsername,
Category: defaultCategory,
Size: defaultSize,
InstanceType: "DBAAS_1vCPU_1_RAM",
VolumeType: "ssd",
VPC: "vpc-new",
SubnetID: "subnet",
}

res, id, err := mysql.generateViettelCloudDBInstance(defaultViettelCloudProviderCfg, "test-region",
"random_password_id")

assert.NotNil(t, res)
assert.NotEqual(t, id, "")
assert.NoError(t, err)
}