Skip to content

Commit

Permalink
implemented first version of launch command
Browse files Browse the repository at this point in the history
  • Loading branch information
Omar El Malak committed Oct 16, 2024
1 parent a6b9d9d commit 8aa111e
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 22 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ The mipy cli makes use of a configmap file as this one:
"templates": [
{
"type": "enum",
"path": "string"
"id": "string",
"cicdProvider": "string", // for now only "azure" is supported
"cicdProviderBaseUrl": "string",
"azureOrganization": "string",
"azureProject": "string",
"terraformPipelineId": "string"
}
],
"logLevel": "string"
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require github.com/mia-platform/miactl v0.15.0
require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mia-platform/miactl v0.15.0 h1:tCvFnkqMjit+Y7giZaF3ZVPXKvz1eG3Cen/CsXA4QfI=
github.com/mia-platform/miactl v0.15.0/go.mod h1:QOflNDd0wdfmB6TvTe7XWG8KTDo7R5RVIlQvMqQY9DU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand Down
9 changes: 7 additions & 2 deletions internal/cliconfig/cliconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ type Config struct {
}

type Template struct {
Type string `json:"type"`
Id string `json:"id"`
Type string `json:"type"`
Id string `json:"id"`
CICDProvider string `json:"cicdProvider"`
CICDBaseUrl string `json:"cicdProviderBaseUrl"`
AzureOrganization string `json:"azureOrganization"`
AzureProject string `json:"azureProject"`
TerraformPipelineID string `json:"terraformPipelineId"`
}

func loadPreferredConfigPath() (string, error) {
Expand Down
162 changes: 143 additions & 19 deletions internal/cmd/launch.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package cmd

import (
"errors"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/fs"
"log"
"net/http"
"os"
"path/filepath"

"github.com/joho/godotenv"
"github.com/mia-platform/mipy/internal/cliconfig"
"github.com/spf13/cobra"
)
Expand All @@ -17,36 +23,136 @@ var errorCode int
var debug bool
var dryRun bool
var environment string
var username string
var password string

type CRInfo struct {
Path string
TemplateType string
Path string
TemplateType string
CICDProvider string
CICDBaseUrl string
CICDOrganization string
CICDProject string
TerraformPipelineID string
}

func handleTerraformCR(cr CRInfo) error {
fmt.Println("Handle template %s", cr.Path)
configFilePath := filepath.Join(cr.Path, "config.tf")
type TerraformRequestBody struct {
Resources struct {
Repositories struct {
Self struct {
RefName string `json:"refName"`
} `json:"self"`
} `json:"repositories"`
} `json:"resources"`
TemplateParameters struct {
DebugMode bool `json:"DEBUG_MODE"`
TerraformAutoApprove string `json:"TERRAFORM_AUTO_APPROVE"`
TerraformAction string `json:"TERRAFORM_ACTION"`
} `json:"templateParameters"`
Variables struct {
AzureSubscriptionID struct {
IsSecret bool `json:"isSecret"`
Value string `json:"value"`
} `json:"AZURE_SUBSCRIPTION_ID"`
AzureTenantID struct {
IsSecret bool `json:"isSecret"`
Value string `json:"value"`
} `json:"AZURE_TENANT_ID"`
TerraformVariables struct {
IsSecret bool `json:"isSecret"`
Value string `json:"value"`
} `json:"TERRAFORM_VARIABLES"`
} `json:"variables"`
}

func azureTerraformCR(cr CRInfo, user string, password string, configContent string, envVars map[string]string) error {
azSubscriptionID := envVars["AZURE_SUBSCRIPTION_ID"]
azTenantID := envVars["AZURE_TENANT_ID"]
terraformAction := envVars["ACTION"]
terraformAutoApprove := envVars["AUTO_APPROVE"]

requestBody := TerraformRequestBody{}
requestBody.Resources.Repositories.Self.RefName = "refs/heads/{branch}" // TODO default 'main'
requestBody.TemplateParameters.DebugMode = true
requestBody.TemplateParameters.TerraformAutoApprove = terraformAutoApprove
requestBody.TemplateParameters.TerraformAction = terraformAction
requestBody.Variables.AzureSubscriptionID.IsSecret = false
requestBody.Variables.AzureSubscriptionID.Value = azSubscriptionID
requestBody.Variables.AzureTenantID.IsSecret = false
requestBody.Variables.AzureTenantID.Value = azTenantID
requestBody.Variables.TerraformVariables.IsSecret = false
requestBody.Variables.TerraformVariables.Value = configContent

jsonData, err := json.Marshal(requestBody)
if err != nil {
fmt.Println("Error mashal error")
return err
}
auth := base64.StdEncoding.EncodeToString([]byte(user + ":" + password))

url := fmt.Sprintf("%s/%s/%s/_apis/pipelines/%s/runs?api-version=7.1", cr.CICDBaseUrl, cr.CICDOrganization, cr.CICDProject, cr.TerraformPipelineID)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
log.Fatalf("Error creating request: %v", err)
return err
}

// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Basic "+auth)

// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalf("Error sending request: %v", err)
return err
}
defer resp.Body.Close()

// Print the status code
fmt.Printf("Response Status Code: %d\n", resp.StatusCode)

responseBody, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error reading response body: %v", err)
}
fmt.Println("Response Body:", string(responseBody))
return nil
}

func handleTerraformCR(cr CRInfo, user string, password string) error {
fmt.Printf("Handle template %s\n", cr.Path)
configFilePath := filepath.Join(cr.Path, "configs.tf")
variablesFilePath := filepath.Join(cr.Path, "variables.env")

configContent, err := os.ReadFile(configFilePath)
if err != nil {
return fmt.Errorf("error reading config.tf: %v", err)
}

encodedConfigContent := base64.StdEncoding.EncodeToString(configContent)

// Read the variables.env file
variablesContent, err := os.ReadFile(variablesFilePath)
envVars, err := godotenv.Read(variablesFilePath)
if err != nil {
return fmt.Errorf("error reading variables.env: %v", err)
}
fmt.Println(configContent, variablesContent)
return nil

if cr.CICDProvider != "azure" {
return fmt.Errorf("CICD provider not supported")
}
return azureTerraformCR(cr, user, password, encodedConfigContent, envVars)
}

func launchCR(cr CRInfo) error {
func launchCR(cr CRInfo, user string, password string) error {
if cr.TemplateType == "terraform" {
handleTerraformCR(cr)
err := handleTerraformCR(cr, user, password)
if err != nil {
return err
}
} else {
fmt.Println("Template type not implemented")
fmt.Println("Template type %s not implemented", cr.TemplateType)
return fmt.Errorf("Template type not implemented")
}

Expand All @@ -64,8 +170,17 @@ func getCRInfos(basePath string, template cliconfig.Template, environment string

if d.IsDir() && path != searchPath {
crInfo := CRInfo{
Path: path,
TemplateType: template.Type,
Path: path,
TemplateType: template.Type,
CICDProvider: template.CICDProvider,
CICDBaseUrl: template.CICDBaseUrl,
TerraformPipelineID: template.TerraformPipelineID,
}

if template.CICDProvider == "azure" {
crInfo.CICDOrganization = template.AzureOrganization
crInfo.CICDProject = template.AzureProject

}
crInfos = append(crInfos, crInfo)
}
Expand Down Expand Up @@ -108,19 +223,28 @@ func LaunchCmd() *cobra.Command {
return nil
}

launchCR(crInfos[1])
for _, crInfo := range crInfos {
err = launchCR(crInfo, username, password)
if err != nil {
fmt.Println(err)
}
}

// get all cr for each template id in config
return errors.New("command not implemented")
return nil
},
}

cmd.Flags().StringSliceVar(&crList, "cr-list", []string{}, "List of CRs to launch")
cmd.Flags().BoolVar(&parallel, "parallel", false, "Launch CRs in parallel")
cmd.Flags().StringVarP(&username, "username", "u", "", "Username for auth to cicd provider")
cmd.Flags().StringVarP(&password, "password", "p", "", "Password for auth to cicd provider")
cmd.Flags().StringSliceVar(&crList, "cr-list", []string{}, "NOT IMPLEMENTED YET: List of CRs to launch")
cmd.Flags().BoolVar(&parallel, "parallel", false, "NOT IMPLEMENTED YET: Launch CRs in parallel")
cmd.Flags().IntVar(&errorCode, "error-code", 500, "Error code to trigger on failure")
cmd.Flags().BoolVar(&debug, "debug", false, "Enable debug mode")
cmd.Flags().BoolVar(&debug, "debug", false, "NOT IMPLEMENTED YET: Enable debug mode")
cmd.Flags().BoolVar(&dryRun, "dry-run", false, "Preview CRs without executing")
cmd.Flags().StringVarP(&environment, "environment", "e", "", "Environment to deploy")
cmd.MarkFlagRequired("environment")
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
return cmd
}

0 comments on commit 8aa111e

Please sign in to comment.