Compare commits

...

5 Commits

Author SHA1 Message Date
admju
4bce096e1f test 2024-09-10 17:01:54 +00:00
admju
75b7b94a50 test 2024-09-10 13:05:48 +00:00
admju
13025746e6 test 2024-09-09 14:17:02 +00:00
admju
550675a4aa StringInSlice 2024-09-09 10:11:44 +00:00
admju
a1af83689d test 2024-09-09 10:11:10 +00:00
58 changed files with 2221 additions and 767 deletions

View File

@ -70,6 +70,10 @@ clean:
@rm -rf workspace_* @rm -rf workspace_*
.PHONY: test .PHONY: test
test_%:
go test oc-deploy/$(subst test_,,$@) -coverprofile=.coverage.out -v
@go tool cover -html=.coverage.out -o .coverage.html
test: test:
@go test ./... -coverprofile=.coverage.out -v @go test ./... -coverprofile=.coverage.out -v
go tool cover -html=.coverage.out -o .coverage.html go tool cover -html=.coverage.out -o .coverage.html

View File

@ -16,58 +16,70 @@ var (
modules []string modules []string
) )
func cobraInstallCmd() *cobra.Command {
return &cobra.Command{
Use: "install",
Short: "install",
Long: `deploy Charts`,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return InstallCmd(context, version, modules)
},
Example: "oc-deploy install --version 1.0 --context ex1",
}
}
func cobraUninstallCmd() *cobra.Command{
return &cobra.Command{
Use: "uninstall",
Short: "undeploy",
Long: `Undeploy`,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return UninstallCmd(context)
},
Example: "oc-deploy uninstall --context ex1",
}
}
func cobraGenerateCmd() *cobra.Command{
return &cobra.Command{
Use: "generate",
Short: "generate",
Long: "Value",
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return GenerateCmd(context, version)
},
Example: "oc-deploy generate --version 1.0 --context ex1",
}
}
func Execute() { func Execute() {
log.Log().Debug().Msg("Execute") log.Log().Debug().Msg("Execute")
var rootCmd = &cobra.Command{Use: "oc-deploy"} var rootCmd = &cobra.Command{Use: "oc-deploy"}
var cmdInstall = &cobra.Command{ var cmdInstall = cobraInstallCmd()
Use: "install", var cmdUninstall = cobraUninstallCmd()
Short: "deploy", var cmdGenerate = cobraGenerateCmd()
Long: `deploy Charts`,
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
InstallCmd(context, version, modules)
},
Example: "oc-deploy install --version 1.0 --context ex1",
}
var cmdUninstall = &cobra.Command{ cmdInstall.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context")
Use: "uninstall", cmdInstall.Flags().StringVarP(&version, "version", "v", "latest", "Version")
Short: "undeploy", cmdInstall.Flags().StringArrayVarP(&modules, "modules", "m", []string{}, "modules, ...")
Long: `Undeploy`,
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
UninstallCmd(context)
},
Example: "oc-deploy uninstall --context ex1",
}
var cmdGenerate = &cobra.Command{ cmdUninstall.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context")
Use: "generate",
Short: "generate",
Long: "Value",
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
GenerateCmd(context, version)
},
Example: "oc-deploy generate --version 1.0 --context ex1",
}
cmdInstall.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context") cmdGenerate.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context")
cmdInstall.Flags().StringVarP(&version, "version", "v", "latest", "Version") cmdGenerate.Flags().StringVarP(&version, "version", "v", "latest", "Version")
cmdInstall.Flags().StringArrayVarP(&modules, "modules", "m", []string{}, "modules, ...")
cmdUninstall.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context") rootCmd.AddCommand(cmdInstall)
rootCmd.AddCommand(cmdUninstall)
rootCmd.AddCommand(cmdGenerate)
cmdGenerate.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context") cobra.CheckErr(rootCmd.Execute())
cmdGenerate.Flags().StringVarP(&version, "version", "v", "latest", "Version")
rootCmd.AddCommand(cmdInstall)
rootCmd.AddCommand(cmdUninstall)
rootCmd.AddCommand(cmdGenerate)
cobra.CheckErr(rootCmd.Execute())
} }

9
src/cmd/args_test.go Normal file
View File

@ -0,0 +1,9 @@
package cmd
import (
"testing"
)
func TestExecute(t *testing.T) {
Execute()
}

View File

@ -8,7 +8,7 @@ import (
"oc-deploy/generate" "oc-deploy/generate"
) )
func GenerateCmd(project string, version string) { func GenerateCmd(project string, version string) error {
log.Log().Info().Msg("Generate >> ") log.Log().Info().Msg("Generate >> ")
version, err := versionOc.GetFromFile(version) version, err := versionOc.GetFromFile(version)
@ -24,4 +24,5 @@ func GenerateCmd(project string, version string) {
} }
log.Log().Info().Msg(" >> Value : " + fic) log.Log().Info().Msg(" >> Value : " + fic)
return err
} }

View File

@ -7,7 +7,7 @@ import (
"oc-deploy/install" "oc-deploy/install"
) )
func InstallCmd(context string, version string, modules []string) { func InstallCmd(context string, version string, modules []string) error {
log.Log().Info().Msg("Install >> ") log.Log().Info().Msg("Install >> ")
log.Log().Info().Msg(" << Contexte : " + context) log.Log().Info().Msg(" << Contexte : " + context)
@ -47,4 +47,5 @@ func InstallCmd(context string, version string, modules []string) {
log.Log().Fatal().Msg(" >> " + err.Error()) log.Log().Fatal().Msg(" >> " + err.Error())
} }
return err
} }

View File

@ -0,0 +1,41 @@
package cmd
import (
"bytes"
"github.com/spf13/cobra"
"testing"
"github.com/stretchr/testify/assert"
)
func TestInstallCommand(t *testing.T) {
cmd := cobraInstallCmd()
inMock := false
cmd.RunE = func(cmd *cobra.Command, args []string) error {
inMock = true
return nil
}
cmd.Execute()
assert.Truef(t, inMock, "TestInstallCommand")
}
func TestInstallCommandErr(t *testing.T) {
cmd := cobraUninstallCmd()
inMock := false
cmd.RunE = func(cmd *cobra.Command, args []string) error {
inMock = true
return nil
}
cmd.SetArgs([]string{"bad"})
b := bytes.NewBufferString("")
cmd.SetOut(b)
err := cmd.Execute()
assert.Falsef(t, inMock, "TestInstallCommand args")
assert.NotNilf(t, err, "TestInstallCommand args")
}

View File

@ -11,8 +11,8 @@ import (
"oc-deploy/install" "oc-deploy/install"
) )
func UninstallCmd(context string) { func UninstallCmd(context string) error {
log.Log().Info().Msg("Unnstall >> ") log.Log().Info().Msg("Uninstall >> ")
log.Log().Info().Msg(" << Contexte : " + context) log.Log().Info().Msg(" << Contexte : " + context)
@ -40,4 +40,6 @@ func UninstallCmd(context string) {
if err != nil { if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error()) log.Log().Fatal().Msg(" >> " + err.Error())
} }
return err
} }

View File

@ -0,0 +1,41 @@
package cmd
import (
"bytes"
"github.com/spf13/cobra"
"testing"
"github.com/stretchr/testify/assert"
)
func TestUninstallCommand(t *testing.T) {
cmd := cobraUninstallCmd()
inMock := false
cmd.RunE = func(cmd *cobra.Command, args []string) error {
inMock = true
return nil
}
cmd.Execute()
assert.Truef(t, inMock, "TestUninstallCommand")
}
func TestUninstallCommandErr(t *testing.T) {
cmd := cobraUninstallCmd()
inMock := false
cmd.RunE = func(cmd *cobra.Command, args []string) error {
inMock = true
return nil
}
cmd.SetArgs([]string{"bad"})
b := bytes.NewBufferString("")
cmd.SetOut(b)
err := cmd.Execute()
assert.Falsef(t, inMock, "TestUninstallCommand args")
assert.NotNilf(t, err, "TestUninstallCommand args")
}

View File

@ -1,159 +1,162 @@
package helm package helm
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"os" "os"
"os/exec" "strings"
"strings" "errors"
"errors" "path/filepath"
"path/filepath" "encoding/json"
"encoding/json" log "oc-deploy/log_wrapper"
log "oc-deploy/log_wrapper" )
)
type HelmChart struct {
type HelmChart struct { Bin string
Bin string Name string
Name string Chart string
Chart string Version string
Version string Url string
Url string
Workspace string
Workspace string Opts string
Opts string Values string
Values string FileValues string
FileValues string }
}
type installInfoOutput struct {
type installInfoOutput struct { Description string `json:"description"`
Description string `json:"description"` Notes string `json:"notes"`
Notes string `json:"notes"` Status string `json:"status"`
Status string `json:"status"` }
}
type installOutput struct {
type installOutput struct { Info installInfoOutput `json:"info"`
Info installInfoOutput `json:"info"` }
}
func (this HelmCommand) ChartInstall(data HelmChart) (string, error) {
func (this HelmChart) Install() (string, error) { bin := this.Bin
bin := this.Bin
existe, err := this.chartExists(data)
existe, err := this.exists() if err != nil {
if err != nil { return "", err
return "", err }
}
if existe {
if existe { return "Existe déjà", nil
return "Existe déjà", nil }
}
ficChart := data.Chart
ficChart := this.Chart // Recherche locale
// Recherche locale if _, err := os.Stat(ficChart); err != nil {
if _, err := os.Stat(ficChart); err != nil { } else {
} else { // Recherche voa le Workspace
// Recherche voa le Workspace ficChart := filepath.Join(data.Workspace, data.Chart)
ficChart := filepath.Join(this.Workspace, this.Chart) if _, err := os.Stat(ficChart); err == nil {
if _, err := os.Stat(ficChart); err == nil { } else {
} else { if data.Url != "" {
if this.Url != "" { fmt.Println("============ 52 Télechargement", data.Url)
fmt.Println("============ 52 Télechargement", this.Url) }
} }
} }
}
msg := fmt.Sprintf("%s install %s %s %s --output json", bin, data.Name, ficChart, data.Opts)
msg := fmt.Sprintf("%s install %s %s %s --output json", bin, this.Name, ficChart, this.Opts)
if data.Version != "" {
if this.Version != "" { msg = fmt.Sprintf("%s --version %s", msg, data.Version)
msg = fmt.Sprintf("%s --version %s", msg, this.Version) }
}
if data.FileValues != "" {
if this.FileValues != "" { fic := filepath.Join(data.Workspace, data.FileValues)
fic := filepath.Join(this.Workspace, this.FileValues) if _, err := os.Stat(fic); err != nil {
if _, err := os.Stat(fic); err != nil { log.Log().Warn().Msg(fic)
log.Log().Warn().Msg(fic) } else {
} else { msg = fmt.Sprintf("%s --values %s", msg, fic)
msg = fmt.Sprintf("%s --values %s", msg, fic) }
} }
}
msg = strings.Replace(msg, " ", " ", -1)
msg = strings.Replace(msg, " ", " ", -1)
log.Log().Debug().Msg(msg)
log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ")
cmd_args := strings.Split(msg, " ") cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput()
cmd := exec.Command(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() if err != nil {
res := string(stdout)
if err != nil { res = strings.TrimSuffix(res, "\n")
res := string(stdout) return "", errors.New(res)
res = strings.TrimSuffix(res, "\n") }
return "", errors.New(res)
} var objmap installOutput
var objmap installOutput err = json.Unmarshal(stdout, &objmap)
if err != nil {
err = json.Unmarshal(stdout, &objmap) return "", err
if err != nil { }
return "", err
} res := objmap.Info.Status
res := objmap.Info.Status return res, nil
}
return res, nil
} func (this HelmCommand) ChartUninstall(data HelmChart) (string, error) {
bin := this.Bin
func (this HelmChart) Uninstall() (string, error) {
bin := this.Bin log.Log().Info().Msg(" >> Chart : " + data.Name)
log.Log().Info().Msg(" >> Chart : " + this.Name) existe, err := this.chartExists(data)
if err != nil {
existe, err := this.exists() return "", err
if err != nil { }
return "", err if ! existe {
} return "Non présent", nil
if ! existe { }
return "Non présent", nil
} msg := fmt.Sprintf("%s uninstall %s", bin, data.Name)
log.Log().Debug().Msg(msg)
msg := fmt.Sprintf("%s uninstall %s", bin, this.Name)
log.Log().Debug().Msg(msg) cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
cmd := exec.Command(bin, "uninstall", this.Name) stdout, err := cmd.CombinedOutput()
stdout, err := cmd.CombinedOutput()
res := string(stdout)
return string(stdout), err res = strings.TrimSuffix(res, "\n")
}
log.Log().Debug().Msg(res)
// ../bin/helm list --filter phpmyadminm --short
func (this HelmChart) exists() (bool, error) { return res, err
bin := this.Bin }
msg := fmt.Sprintf("%s list --filter %s --no-headers", bin, this.Name) // ../bin/helm list --filter phpmyadminm --short
log.Log().Debug().Msg(msg) func (this HelmCommand) chartExists(data HelmChart) (bool, error) {
bin := this.Bin
cmd_args := strings.Split(msg, " ")
msg := fmt.Sprintf("%s list --filter %s --no-headers", bin, data.Name)
cmd := exec.Command(cmd_args[0], cmd_args[1:]...) log.Log().Debug().Msg(msg)
stdout, err := cmd.CombinedOutput()
if err != nil { cmd_args := strings.Split(msg, " ")
log.Log().Debug().Msg(string(stdout)) cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
return false, errors.New(string(stdout)) stdout, err := cmd.CombinedOutput()
} if err != nil {
log.Log().Debug().Msg(string(stdout))
res := string(stdout) return false, errors.New(string(stdout))
res = strings.TrimSuffix(res, "\n") }
log.Log().Debug().Msg(string(stdout)) res := string(stdout)
log.Log().Debug().Msg(strconv.FormatBool(res != "")) res = strings.TrimSuffix(res, "\n")
return res != "", nil log.Log().Debug().Msg(string(stdout))
} log.Log().Debug().Msg(strconv.FormatBool(res != ""))
func (this HelmChart) GetRessources() (map[string]string, error) { return res != "", nil
hs := HelmStatus{Name: this.Name} }
hs.New(this.Bin)
data, _ := hs.getRessources() // func (this HelmChart) GetRessources() (map[string]string, error) {
// hs := HelmStatus{Name: this.Name}
return data, nil // hs.New(this.Bin)
} // data, _ := hs.getRessources()
// return data, nil
// }

30
src/helm/chart_test.go Normal file
View File

@ -0,0 +1,30 @@
package helm
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestHelmChartExists(t *testing.T){
cmd := getCmdHelm(true, `oc-catalog default 1 2024-09-06 16:01:49.17368605 +0200 CEST deployed oc-catalog-0.1.0 1.0`)
data := HelmChart{Name: "oc-catalog"}
res, err := cmd.chartExists(data)
assert.Nilf(t, err, "error message %s", err)
assert.Truef(t, res, "TestHelmVersion error")
}
func TestHelmChartNotExists(t *testing.T){
cmd := getCmdHelm(true, "\n")
data := HelmChart{Name: "phpmyadmin"}
res, err := cmd.chartExists(data)
assert.Nilf(t, err, "error message %s", err)
assert.Falsef(t, res, "TestHelmVersion error")
}

View File

@ -1,16 +0,0 @@
package helm
import (
)
type HelmCommandInterface interface {
Status(string) (string, error)
AddRepository(HelmRepo) (string, error)
}
type HelmCommandData struct {
Bin string
}
type RealHelmCommand HelmCommandData

22
src/helm/helm.go Normal file
View File

@ -0,0 +1,22 @@
package helm
import (
"os/exec"
)
type HelmCommand struct {
Bin string
Exec func(string,...string) commandExecutor
}
////
type commandExecutor interface {
Output() ([]byte, error)
CombinedOutput() ([]byte, error)
}
func (this *HelmCommand) New() {
this.Exec = func(name string, arg ...string) commandExecutor {
return exec.Command(name, arg...)
}
}

17
src/helm/helm_test.go Normal file
View File

@ -0,0 +1,17 @@
package helm
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestHelm(t *testing.T) {
cmd := HelmCommand{}
cmd.New()
assert.NotNilf(t, cmd.Exec, "TestHelm %s", "New")
cmd.Exec("pwd")
}

View File

@ -1,8 +1,9 @@
package helm package helm
import ( import (
"os" "os"
"testing" "strings"
"testing"
"path/filepath" "path/filepath"
) )
@ -11,14 +12,73 @@ var TEST_SRC_DIR = filepath.Join("../../test", "helm")
var TEST_BIN_DIR = filepath.Join("../../test", "bin") var TEST_BIN_DIR = filepath.Join("../../test", "bin")
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
folderPath := TEST_DEST_DIR folderPath := TEST_DEST_DIR
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.MkdirAll(folderPath, os.ModePerm) os.MkdirAll(folderPath, os.ModePerm)
// call flag.Parse() here if TestMain uses flags // call flag.Parse() here if TestMain uses flags
exitCode := m.Run() exitCode := m.Run()
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.Exit(exitCode) os.Exit(exitCode)
} }
// Mock
type MockCommandExecutor struct {
// Used to stub the return of the Output method
// Could add other properties depending on testing needs
output string
}
// Implements the commandExecutor interface
func (m *MockCommandExecutor) Output() ([]byte, error) {
return []byte(m.output), nil
}
func (m *MockCommandExecutor) CombinedOutput() ([]byte, error) {
return []byte(m.output), nil
}
//
func getCmdHelm(mock bool, output string) (HelmCommand) {
if mock == true {
mock := func(name string, args ...string) commandExecutor {
return &MockCommandExecutor{output: output}
}
cmd := HelmCommand{Bin: "mock", Exec: mock}
return cmd
} else {
bin := filepath.Join(TEST_BIN_DIR, "helm")
os.Chmod(bin, 0700)
cmd := HelmCommand{Bin: bin}
cmd.New()
return cmd
}
}
func getCmdsHelm(mock bool, outputs map[string]string) (HelmCommand) {
if mock == true {
mock := func(name string, args ...string) commandExecutor {
cmd := strings.TrimSuffix(strings.Join(args," "), " ")
output := outputs[cmd]
return &MockCommandExecutor{output: output}
}
cmd := HelmCommand{Bin: "mock", Exec: mock}
return cmd
} else {
bin := filepath.Join(TEST_BIN_DIR, "helm")
os.Chmod(bin, 0700)
cmd := HelmCommand{Bin: bin}
cmd.New()
return cmd
}
}

View File

@ -1,96 +1,98 @@
package helm package helm
import ( import (
"fmt" "fmt"
"strings" "strings"
"os/exec" "encoding/json"
"encoding/json"
log "oc-deploy/log_wrapper"
log "oc-deploy/log_wrapper" "oc-deploy/utils"
"oc-deploy/utils" )
)
type HelmRepo struct {
type HelmRepo struct { Name string
Name string Repository string // Url du dépôt
Repository string // Url du dépôt ForceUpdate bool
ForceUpdate bool Opts string
Opts string }
}
func (this HelmCommand) AddRepository(repo HelmRepo) (string, error) {
func (this RealHelmCommand) AddRepository(repo HelmRepo) (string, error) {
helm_bin := this.Bin
helm_bin := this.Bin
force_update := "--force-update=false"
force_update := "--force-update=false" if repo.ForceUpdate {
if repo.ForceUpdate { force_update = "--force-update=true"
force_update = "--force-update=true" } else {
} else { list, _ := this.ListRepository()
list, _ := this.ListRepository() if utils.StringInSlice(repo.Name, list) {
if utils.StringInSlice(repo.Name, list) { return "Existe déjà", nil
return "Existe déjà", nil }
} }
}
msg := fmt.Sprintf("%s repo add %s %s %s %s", helm_bin, repo.Name, repo.Repository, force_update, repo.Opts)
msg := fmt.Sprintf("%s repo add %s %s %s %s", helm_bin, repo.Name, repo.Repository, force_update, repo.Opts) log.Log().Debug().Msg(msg)
log.Log().Debug().Msg(msg)
msg = strings.TrimSuffix(msg, " ")
cmd_args := strings.Split(msg, " ")
cmd_args := strings.Split(msg, " ")
cmd := exec.Command(cmd_args[0], cmd_args[1:]...) cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
res := string(stdout) res := string(stdout)
res = strings.TrimSuffix(res, "\n") res = strings.TrimSuffix(res, "\n")
return res, err return res, err
} }
type parseList struct { type parseList struct {
Name string `json:"name"` Name string `json:"name"`
} }
func (this RealHelmCommand) ListRepository() ([]string, error) { func (this HelmCommand) ListRepository() ([]string, error) {
helm_bin := this.Bin helm_bin := this.Bin
res := make([]string, 0, 0) res := make([]string, 0, 0)
msg := fmt.Sprintf("%s repo list -o json", helm_bin) msg := fmt.Sprintf("%s repo list -o json", helm_bin)
log.Log().Debug().Msg(msg) log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ") cmd_args := strings.Split(msg, " ")
cmd := exec.Command(cmd_args[0], cmd_args[1:]...) cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return res, err return res, err
} }
var objmap []parseList var objmap []parseList
err = json.Unmarshal([]byte(stdout), &objmap) err = json.Unmarshal(stdout, &objmap)
if err != nil { if err != nil {
return res, err return res, err
} }
for _, ele := range objmap { for _, ele := range objmap {
res = append(res, ele.Name) res = append(res, ele.Name)
} }
return res, err return res, err
} }
// helm repo remove [NAME] // helm repo remove [NAME]
func (this RealHelmCommand) RemoveRepository(repo HelmRepo) (string, error) { func (this HelmCommand) RemoveRepository(repo HelmRepo) (string, error) {
helm_bin := this.Bin helm_bin := this.Bin
msg := fmt.Sprintf("%s repo remove %s", helm_bin, repo.Name) msg := fmt.Sprintf("%s repo remove %s", helm_bin, repo.Name)
log.Log().Debug().Msg(msg) log.Log().Debug().Msg(msg)
cmd := exec.Command(helm_bin, "repo", "remove", repo.Name) cmd_args := strings.Split(msg, " ")
stdout, err := cmd.CombinedOutput()
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
res := string(stdout) stdout, err := cmd.CombinedOutput()
res = strings.TrimSuffix(res, "\n")
res := string(stdout)
return res, err res = strings.TrimSuffix(res, "\n")
}
return res, err
}

View File

@ -1,39 +1,72 @@
package helm package helm
import ( import (
"fmt" "testing"
// "os"
// "path/filepath" "github.com/stretchr/testify/assert"
)
"testing"
func TestHelmListRepository(t *testing.T){
"github.com/stretchr/testify/assert"
) cmd := getCmdHelm(true, `[{"name":"bitnami","url":"https://charts.bitnami.com/bitnami"}]`)
func TestHelmRepoAdd(t *testing.T) { res, err := cmd.ListRepository()
repo := HelmRepo{ assert.Nilf(t, err, "error message %s", err)
Bin: "./helm", assert.Equal(t, "bitnami", res[0], "TestHelmVersion error")
Name: "repooc", }
Repository: "https://url",
ForceUpdate: true, func TestHelmRemoveRepository(t *testing.T){
Opts: ""}
fmt.Println(" TestHelmRepoAdd ", repo) cmd := getCmdHelm(true, `"bitnami" has been removed from your repositories`)
res, err := repo.AddRepository() repo := HelmRepo{Name: "bitnami"}
fmt.Println("TestHelmRepoAdd.24", res, err) res, err := cmd.RemoveRepository(repo)
}
assert.Nilf(t, err, "error message %s", err)
// helm : not found assert.Equal(t, `"bitnami" has been removed from your repositories`, res, "TestHelmRemoveRepository error")
func TestHelmRepoAddErr(t *testing.T) { }
repo := HelmRepo{ func TestHelmRemoveRepository2(t *testing.T){
Bin: "./helm",
Name: "repooc", cmd := getCmdHelm(true, `Error: no repositories configured`)
Repository: "https://url",
ForceUpdate: true, repo := HelmRepo{Name: "bitnami"}
Opts: ""} res, err := cmd.RemoveRepository(repo)
_, err := repo.AddRepository() assert.Nilf(t, err, "error message %s", err)
assert.NotNilf(t, err, "error message %s", "./helm") assert.Equal(t, `Error: no repositories configured`, res, "TestHelmRemoveRepository error")
} }
func TestHelmAddRepositoryNew(t *testing.T){
cmd_output := map[string]string{
"repo list -o json": `[{"name":"repo1","url":"https://repo.com"}]`,
"repo add repo2 https://repo2.com --force-update=false": `"repo2" has been added to your repositories"`,
}
cmd := getCmdsHelm(true, cmd_output)
repo := HelmRepo{Name: "repo2", Repository: "https://repo2.com", ForceUpdate: false}
res, err := cmd.AddRepository(repo)
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, `"repo2" has been added to your repositories"`, res, "TestHelmAddRepositoryNew error")
}
func TestHelmAddRepositoryExists(t *testing.T){
cmd_output := map[string]string{
"repo list -o json": `[{"name":"repo1","url":"https://repo.com"}]`,
"version --short": "v3.15.4+gfa9efb0",
}
cmd := getCmdsHelm(true, cmd_output)
repo := HelmRepo{Name: "repo1", Repository: "https://repo.com", ForceUpdate: false}
res, err := cmd.AddRepository(repo)
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, `Existe déjà`, res, "TestHelmRemoveRepository error")
}

View File

@ -4,20 +4,6 @@ import (
// "fmt" // "fmt"
"encoding/json" "encoding/json"
) )
type HelmStatus struct {
Name string // Nom
command HelmCommandInterface
}
func (this *HelmStatus) New(bin string) {
this.command = RealHelmCommand{Bin: bin}
}
func (this *HelmStatus) NewMock(mock HelmCommandInterface) {
this.command = mock
}
//// ////
type parseStatusInfoResourcesMetadata struct { type parseStatusInfoResourcesMetadata struct {
@ -57,11 +43,11 @@ type parseStatus struct {
Info parseStatusInfo `json:"info"` Info parseStatusInfo `json:"info"`
} }
func (this HelmStatus) getRessources() (map[string]string, error) { func (this HelmCommand) GetRessources(data HelmChart) (map[string]string, error) {
res := make(map[string]string) res := make(map[string]string)
status, err := this.command.Status(this.Name) status, err := this.Status(data)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -9,20 +9,16 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type MockCommandStatus HelmCommandData func TestHelmRessources(t *testing.T){
func TestHelmStatus(t *testing.T){
hs := HelmStatus{Name: "oc-catalog"}
hs.NewMock(MockCommandStatus{})
data, _ := hs.getRessources()
assert.Equal(t, "StatefulSet", data["oc-catalog-oc-catalog"], "TestHelmStatus error")
}
// Mock
func (this MockCommandStatus) Status(name string) (string, error) {
fileName := filepath.Join(TEST_SRC_DIR, "helm_status.json") fileName := filepath.Join(TEST_SRC_DIR, "helm_status.json")
data, _ := os.ReadFile(fileName) res_json, _ := os.ReadFile(fileName)
return string(data), nil
} cmd := getCmdHelm(true, string(res_json))
data := HelmChart{Name: "test1"}
res, err := cmd.GetRessources(data)
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "StatefulSet", res["oc-catalog-oc-catalog"], "TestHelmStatus error")
}

View File

@ -3,22 +3,25 @@ package helm
import ( import (
"fmt" "fmt"
"strings" "strings"
"errors" "errors"
"os/exec"
log "oc-deploy/log_wrapper" log "oc-deploy/log_wrapper"
) )
func (this RealHelmCommand) Status(name string) (string, error) { // type HelmData struct {
// Name string
// }
func (this HelmCommand) Status(data HelmChart) (string, error) {
helm_bin := this.Bin helm_bin := this.Bin
msg := fmt.Sprintf("%s status %s --show-resources -o json", helm_bin, name) msg := fmt.Sprintf("%s status %s --show-resources -o json", helm_bin, data.Name)
log.Log().Debug().Msg(msg) log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ") cmd_args := strings.Split(msg, " ")
cmd := exec.Command(cmd_args[0], cmd_args[1:]...) cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Log().Debug().Msg(string(stdout)) log.Log().Debug().Msg(string(stdout))
@ -27,4 +30,3 @@ func (this RealHelmCommand) Status(name string) (string, error) {
return string(stdout), nil return string(stdout), nil
} }

View File

@ -1,20 +1,20 @@
package helm package helm
import ( import (
"strings" "strings"
"os/exec" )
)
func Version(path string) (string, error) { func (this HelmCommand) GetVersion() (string, error) {
cmd := exec.Command(path, "version", "--short") cmd := this.Exec(this.Bin, "version", "--short")
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return "", err return "", err
} }
res := string(stdout) res := string(stdout)
res = strings.TrimSuffix(res, "\n") res = strings.TrimSuffix(res, "\n")
return res, nil return res, nil
} }

View File

@ -1,22 +1,18 @@
package helm package helm
import ( import (
"os" "testing"
"path/filepath"
"github.com/stretchr/testify/assert"
"testing" )
"github.com/stretchr/testify/assert" func TestHelmVersion(t *testing.T){
)
cmd := getCmdHelm(true, "v3.15.4+gfa9efb0\n")
func TestHelmVersion(t *testing.T){
version, err := cmd.GetVersion()
bin := filepath.Join(TEST_BIN_DIR, "helm")
os.Chmod(bin, 0700) assert.Nilf(t, err, "error message %s", err)
assert.FileExists(t, bin, "TestHelmVersion error") assert.Equal(t, "v3.15.4+gfa9efb0", version, "TestHelmVersion error")
}
version, err := Version(bin)
assert.Nilf(t, err, "error message %s", bin)
assert.Equal(t, "v3.15.4+gfa9efb0", version, "TestHelmVersion error")
}

View File

@ -51,15 +51,17 @@ func (this *InstallClass) Tools() (error) {
func (this *InstallClass) SetCommands() { func (this *InstallClass) SetCommands() {
helm_bin, _ := this.getToolBin("helm") helm_bin, _ := this.getToolBin("helm")
this.commandHelm = helm.RealHelmCommand{Bin: helm_bin} this.commandHelm = helm.HelmCommand{Bin: helm_bin}
this.commandHelm.New()
// kubectl_bin, _ := this.getToolBin("kubectl") kubectl_bin, _ := this.getToolBin("kubectl")
// this.commandKubectl = helm.RealHelmCommand{Bin: kubectl_bin} this.commandKubectl = kubectl.KubectlCommand{Bin: kubectl_bin}
this.commandKubectl.New()
} }
func (this *InstallClass) SetCommandsMock(mock helm.HelmCommandInterface) { // func (this *InstallClass) SetCommandsMock(mock helm.HelmCommandInterface) {
this.commandHelm = mock // this.commandHelm = mock
} // }
func (this *InstallClass) getToolBin(name string) (string, error) { func (this *InstallClass) getToolBin(name string) (string, error) {
for key, value := range this.toolsBin { for key, value := range this.toolsBin {
@ -72,9 +74,8 @@ func (this *InstallClass) getToolBin(name string) (string, error) {
} }
func (this *InstallClass) K8s(context string) (error) { func (this *InstallClass) K8s(context string) (error) {
bin_path, _ := this.getToolBin("kubectl")
kube := kubectl.KubeContext{Bin: bin_path} kube := this.commandKubectl
err := kube.UseContext(context) err := kube.UseContext(context)
if err != nil { if err != nil {

View File

@ -22,7 +22,8 @@ type InstallClass struct {
toolsBin map[string]string toolsBin map[string]string
charts []chart.ChartRepoData charts []chart.ChartRepoData
commandHelm helm.HelmCommandInterface commandHelm helm.HelmCommand
commandKubectl kubectl.KubectlCommand
} }
func (this *InstallClass) NewInstall() (string, error) { func (this *InstallClass) NewInstall() (string, error) {
@ -91,19 +92,19 @@ func (this *InstallClass) ChartRepo() (error) {
func (this *InstallClass) InstallCharts(modules []string) (error) { func (this *InstallClass) InstallCharts(modules []string) (error) {
helm_bin, _ := this.getToolBin("helm") // helm_bin, _ := this.getToolBin("helm")
kubectl_bin, _ := this.getToolBin("kubectl") // kubectl_bin, _ := this.getToolBin("kubectl")
var wg sync.WaitGroup var wg sync.WaitGroup
for _, v := range this.charts { for _, v := range this.charts {
for _, v1 := range v.Charts { for _, v1 := range v.Charts {
if len(modules) == 0 || stringInSlice(v1.Name, modules) { if len(modules) == 0 || utils.StringInSlice(v1.Name, modules) {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
this.installChart(helm_bin, kubectl_bin, v1) this.installChart(v1)
} () } ()
} }
} }
@ -112,45 +113,32 @@ func (this *InstallClass) InstallCharts(modules []string) (error) {
return nil return nil
} }
func stringInSlice(a string, list []string) bool { func (this *InstallClass) installChart(chart chart.ChartData) {
for _, b := range list {
if b == a {
return true
}
}
return false
}
func (this *InstallClass) installChart(helm_bin string, kubectl_bin string, chart chart.ChartData) {
log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name)) log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name))
helmchart := helm.HelmChart{Bin: helm_bin, data := helm.HelmChart{Name: chart.Name,
Name: chart.Name, Chart: chart.Chart,
Chart: chart.Chart, Url: chart.Url,
Url: chart.Url, Version: chart.Version,
Version: chart.Version, Workspace: this.Workspace,
Workspace: this.Workspace, Opts: chart.Opts,
Opts: chart.Opts, Values: chart.Values,
Values: chart.Values, FileValues: chart.FileValues}
FileValues: chart.FileValues}
res, err := helmchart.Install() res, err := this.commandHelm.ChartInstall(data)
if err != nil { if err != nil {
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", helmchart.Name, "KO", err)) log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", data.Name, "KO", err))
return return
} }
log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", helmchart.Name, res)) log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", data.Name, res))
ressources, _ := helmchart.GetRessources() ressources, _ := this.commandHelm.GetRessources(data)
for key, value := range ressources { for key, value := range ressources {
obj := kubectl.KubeObject{Bin: kubectl_bin, obj := kubectl.KubectlObject{Name: key, Kind: value}
Kind: value, err := this.commandKubectl.Wait(obj)
Name: key}
err := obj.Wait()
if err != nil { if err != nil {
log.Log().Error().Msg(fmt.Sprintf(" >> %s/%s KO (%s)", chart.Name, key, err)) log.Log().Error().Msg(fmt.Sprintf(" >> %s/%s KO (%s)", chart.Name, key, err))
} else { } else {

View File

@ -63,13 +63,19 @@ func (this *InstallClass) uninstallChart(helm_bin string, kubectl_bin string, ch
log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name)) log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name))
helmchart := helm.HelmChart{Bin: helm_bin,
Name: chart.Name}
res, err := helmchart.Uninstall() helm_cmd := helm.HelmCommand{Bin: helm_bin}
helm_cmd.New()
data := helm.HelmChart{Name: chart.Name}
// helmchart := helm.HelmChart{Bin: helm_bin,
// Name: chart.Name}
res, err := helm_cmd.ChartUninstall(data)
if err != nil { if err != nil {
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", helmchart.Name, "KO", err)) log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", data.Name, "KO", err))
return return
} }
log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", helmchart.Name, res)) log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", data.Name, res))
} }

View File

@ -1,29 +0,0 @@
package kubectl
// import (
// "fmt"
// )
// type KubectlCommandInterface interface {
// // GetDeployment() (string, error)
// GetDeployment() (string, error)
// }
// type KubectlCommandData struct {
// bin string
// command string
// }
// type Real KubectlCommandStatus KubectlCommandData
// // func (this KubectlCommandStatus) Status() (string, error) {
// // fmt.Println("BIN ", this.bin)
// // fmt.Println("COMMAND status")
// // return "Res de KubectlCommandStatus", nil
// // }
// func (this KubectlCommandStatus) GetDeployment() (string, error) {
// fmt.Println("BIN ", this.bin)
// fmt.Println("COMMAND status")
// return "Res de GetDeployment", nil
// }

View File

@ -1,18 +1,14 @@
package kubectl package kubectl
import ( import (
// "fmt" "fmt"
"strings" "strings"
"errors" "errors"
"os/exec"
"encoding/json" "encoding/json"
log "oc-deploy/log_wrapper" log "oc-deploy/log_wrapper"
) )
type KubeContext struct {
Bin string // Chemin vers le binaire
}
type kubeConfig struct { type kubeConfig struct {
CurrentContext string `json:"current-context"` CurrentContext string `json:"current-context"`
@ -40,9 +36,14 @@ type kubeConfigClusters struct {
Cluster kubeConfigCluster `json:"cluster"` Cluster kubeConfigCluster `json:"cluster"`
} }
func (this KubeContext) GetCurrentContext() (string, error) { func (this KubectlCommand) GetCurrentContext() (string, error) {
bin := this.Bin
cmd := exec.Command(this.Bin, "config", "current-context") msg := fmt.Sprintf("%s config current-context", bin)
log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
res := string(stdout) res := string(stdout)
@ -51,16 +52,24 @@ func (this KubeContext) GetCurrentContext() (string, error) {
return res, err return res, err
} }
// Current Context // currentContext, currentNamespace, currentServer
// namespace, server func (this KubectlCommand) GetContext() (string, string, string, error) {
func (this KubeContext) GetContext() (string, string, string, error) {
cmd := exec.Command(this.Bin, "config", "view", "-o", "json") bin := this.Bin
stdout, _ := cmd.CombinedOutput()
msg := fmt.Sprintf("%s config view -o json", bin)
log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput()
if err != nil {
return "", "", "", errors.New(string(stdout))
}
var objmap kubeConfig var objmap kubeConfig
err := json.Unmarshal(stdout, &objmap) err = json.Unmarshal(stdout, &objmap)
if err != nil { if err != nil {
return "", "", "", err return "", "", "", err
} }
@ -85,11 +94,16 @@ func (this KubeContext) GetContext() (string, string, string, error) {
return currentContext, currentNamespace, currentServer, nil return currentContext, currentNamespace, currentServer, nil
} }
func (this KubeContext) UseContext(newContext string) (error) { func (this KubectlCommand) UseContext(newContext string) (error) {
cmd := exec.Command(this.Bin, "config", "use-context", newContext) bin := this.Bin
msg := fmt.Sprintf("%s config use-context %s", bin, newContext)
log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Log().Debug().Msg(string(stdout)) log.Log().Debug().Msg(string(stdout))
return errors.New(string(stdout)) return errors.New(string(stdout))
@ -98,9 +112,14 @@ func (this KubeContext) UseContext(newContext string) (error) {
return nil return nil
} }
func (this KubeContext) Check() (error) { func (this KubectlCommand) Check() (error) {
bin := this.Bin
cmd := exec.Command(this.Bin, "cluster-info") msg := fmt.Sprintf("%s cluster-info", bin)
log.Log().Debug().Msg(msg)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Log().Debug().Msg(string(stdout)) log.Log().Debug().Msg(string(stdout))

View File

@ -0,0 +1,86 @@
package kubectl
import (
"os"
"path/filepath"
"errors"
"testing"
"github.com/stretchr/testify/assert"
)
var MOCK_ENABLE = true
func TestKubectCurrentContext(t *testing.T) {
cmd := getCmdKubectl(MOCK_ENABLE, "minikube")
res, err := cmd.GetCurrentContext()
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "minikube", res, "TestKubectCurrentContext error")
}
func TestKubectContext(t *testing.T) {
fileName := filepath.Join(TEST_SRC_DIR, "context.json")
cmd_json, _ := os.ReadFile(fileName)
cmd := getCmdKubectl(MOCK_ENABLE, string(cmd_json))
currentContext, currentNamespace, currentServer, err := cmd.GetContext()
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "minikube", currentContext, "TestKubectContext error")
assert.Equal(t, "default", currentNamespace, "TestKubectContext error")
assert.Equal(t, "https://127.0.0.1:38039", currentServer, "TestKubectContext error")
}
func TestKubectUseContext(t *testing.T) {
cmd := getCmdKubectl(MOCK_ENABLE, `Switched to context "minikube".`)
err := cmd.UseContext("minikube")
assert.Nilf(t, err, "error message %s", err)
}
func TestKubectUseContextErr(t *testing.T) {
error := errors.New("exit 1")
cmd := getCmdKubectlError(MOCK_ENABLE, `error: no context exists with the name: "minikube2"`, error)
err := cmd.UseContext("minikube2")
assert.NotNilf(t, err, "error message %s", err)
}
func TestKubectCheck(t *testing.T) {
cmd_txt := `
Kubernetes control plane is running at https://127.0.0.1:38039
CoreDNS is running at https://127.0.0.1:38039/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
`
// error := errors.New("exit 1")
cmd := getCmdKubectl(MOCK_ENABLE, cmd_txt)
err := cmd.Check()
assert.Nilf(t, err, "error message %s", err)
}
func TestKubectCheckErr(t *testing.T) {
cmd_txt := ""
error := errors.New("exit 1")
cmd := getCmdKubectlError(MOCK_ENABLE, cmd_txt, error)
err := cmd.Check()
assert.NotNilf(t, err, "error message %s", "TestKubectCheckErr")
}

40
src/kubectl/deployment.go Normal file
View File

@ -0,0 +1,40 @@
package kubectl
import (
"fmt"
"strings"
"errors"
"encoding/json"
log "oc-deploy/log_wrapper"
)
func (this KubectlCommand) getDeployment(data KubectlObject) (map[string]any, error) {
bin := this.Bin
msg := fmt.Sprintf("%s get deployment %s -o json", bin, data.Name)
log.Log().Debug().Msg(msg)
m := make(map[string]any)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput()
if err != nil {
return m, errors.New(string(stdout))
}
var objmap getOutput
json.Unmarshal(stdout, &objmap)
kind := objmap.Kind
status := objmap.Status
m["name"] = data.Name
m["kind"] = kind
m["replicas"] = status.Replicas
m["UnavailableReplicas"] = status.UnavailableReplicas
return m, nil
}

View File

@ -0,0 +1,29 @@
package kubectl
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKubectDeployment(t *testing.T) {
fileName := filepath.Join(TEST_SRC_DIR, "deployment.json")
cmd_json, _ := os.ReadFile(fileName)
cmd := getCmdKubectl(true, string(cmd_json))
data := KubectlObject{Name: "dep1", Kind: "Deployment"}
res, err := cmd.getDeployment(data)
// map[string]interface {}(map[string]interface {}{"UnavailableReplicas":0, "kind":"Deployment", "name":"dep1", "replicas":1})
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "Deployment", res["kind"], "TestKubectDeployment error")
assert.Equal(t, 1, res["replicas"], "TestKubectDeployment error")
}

22
src/kubectl/kubectl.go Normal file
View File

@ -0,0 +1,22 @@
package kubectl
import (
"os/exec"
)
type KubectlCommand struct {
Bin string
Exec func(string,...string) commandExecutor
}
////
type commandExecutor interface {
Output() ([]byte, error)
CombinedOutput() ([]byte, error)
}
func (this *KubectlCommand) New() {
this.Exec = func(name string, arg ...string) commandExecutor {
return exec.Command(name, arg...)
}
}

View File

@ -0,0 +1,17 @@
package kubectl
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestKubectl(t *testing.T) {
cmd := KubectlCommand{}
cmd.New()
assert.NotNilf(t, cmd.Exec, "TestKubectl %s", "New")
cmd.Exec("pwd")
}

View File

@ -1,8 +1,9 @@
package kubectl package kubectl
import ( import (
"os" "os"
"testing" "strings"
"testing"
"path/filepath" "path/filepath"
) )
@ -11,14 +12,93 @@ var TEST_SRC_DIR = filepath.Join("../../test", "kubectl")
var TEST_BIN_DIR = filepath.Join("../../test", "bin") var TEST_BIN_DIR = filepath.Join("../../test", "bin")
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
folderPath := TEST_DEST_DIR folderPath := TEST_DEST_DIR
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.MkdirAll(folderPath, os.ModePerm) os.MkdirAll(folderPath, os.ModePerm)
// call flag.Parse() here if TestMain uses flags // call flag.Parse() here if TestMain uses flags
exitCode := m.Run() exitCode := m.Run()
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.Exit(exitCode) os.Exit(exitCode)
} }
// Mock
type MockCommandExecutor struct {
// Used to stub the return of the Output method
// Could add other properties depending on testing needs
output string
err error
}
// Implements the commandExecutor interface
func (m *MockCommandExecutor) Output() ([]byte, error) {
return []byte(m.output), m.err
}
func (m *MockCommandExecutor) CombinedOutput() ([]byte, error) {
return []byte(m.output), m.err
}
//
func getCmdKubectl(mock bool, output string) (KubectlCommand) {
if mock == true {
mock := func(name string, args ...string) commandExecutor {
return &MockCommandExecutor{output: output}
}
cmd := KubectlCommand{Bin: "mock", Exec: mock}
return cmd
} else {
bin := filepath.Join(TEST_BIN_DIR, "kubectl")
os.Chmod(bin, 0700)
cmd := KubectlCommand{Bin: bin}
cmd.New()
return cmd
}
}
func getCmdsKubectl(mock bool, outputs map[string]string) (KubectlCommand) {
if mock == true {
mock := func(name string, args ...string) commandExecutor {
cmd := strings.TrimSuffix(strings.Join(args," "), " ")
output := outputs[cmd]
return &MockCommandExecutor{output: output}
}
cmd := KubectlCommand{Bin: "mock", Exec: mock}
return cmd
} else {
bin := filepath.Join(TEST_BIN_DIR, "kubectl")
os.Chmod(bin, 0700)
cmd := KubectlCommand{Bin: bin}
cmd.New()
return cmd
}
}
func getCmdKubectlError(mock bool, output string, err error) (KubectlCommand) {
if mock == true {
mock := func(name string, args ...string) commandExecutor {
return &MockCommandExecutor{output: output, err: err}
}
cmd := KubectlCommand{Bin: "mock", Exec: mock}
return cmd
} else {
bin := filepath.Join(TEST_BIN_DIR, "kubectl")
os.Chmod(bin, 0700)
cmd := KubectlCommand{Bin: bin}
cmd.New()
return cmd
}
}

View File

@ -1,122 +1,56 @@
package kubectl package kubectl
import ( import (
"fmt" "fmt"
"strings" "time"
"errors" "errors"
"time"
"os/exec" log "oc-deploy/log_wrapper"
"encoding/json" )
log "oc-deploy/log_wrapper"
)
type KubectlObject struct {
type KubeObject struct { Name string
Bin string // Chemin vers le binaire Kind string
Name string }
Kind string
} type getOutput struct {
Kind string `json:"kind"`
type getOutput struct { Status getStatusOutput `json:"status"`
Kind string `json:"kind"` }
Status getStatusOutput `json:"status"`
} type getStatusOutput struct {
Replicas int `json:"replicas"`
type getStatusOutput struct { UnavailableReplicas int `json:"unavailableReplicas"`
Replicas int `json:"replicas"` }
UnavailableReplicas int `json:"unavailableReplicas"`
} func (this KubectlCommand) Get(data KubectlObject) (map[string]any, error) {
if data.Kind == "Deployment" {return this.getDeployment(data)}
func (this KubeObject) Get() (map[string]any, error) { if data.Kind == "StatefulSet" {return this.getStatefulSet(data)}
if this.Kind == "Deployment" {return this.getDeployment()} return make(map[string]any), fmt.Errorf("Kind %s inconnu", data.Kind)
if this.Kind == "StatefulSet" {return this.getStatefulSet()} }
return make(map[string]any), fmt.Errorf("Kind %s inconnu", this.Kind)
} func (this KubectlCommand) Wait(data KubectlObject) (error) {
func (this KubeObject) getDeployment() (map[string]any, error) { boucle := 10
bin := this.Bin sleep := 10000 * time.Millisecond
name := this.Name
for _ = range boucle {
msg := fmt.Sprintf("%s get deployment %s -o json", bin, name)
log.Log().Debug().Msg(msg) log.Log().Debug().Msg(fmt.Sprintf("Check Deployement %s", data.Name))
m := make(map[string]any) m, err := this.Get(data)
if err != nil {
cmd_args := strings.Split(msg, " ") return err
}
cmd := exec.Command(cmd_args[0], cmd_args[1:]...) ko := m["UnavailableReplicas"].(int)
stdout, err := cmd.CombinedOutput() if ko == 0 {
if err != nil { return nil
return m, errors.New(string(stdout)) }
}
log.Log().Info().Msg(fmt.Sprintf(" >> %s (Unavailable : %d)...", data.Name, ko))
var objmap getOutput time.Sleep(sleep)
json.Unmarshal(stdout, &objmap) }
return errors.New("Temps d'attente dépassé")
kind := objmap.Kind
status := objmap.Status
m["name"] = name
m["kind"] = kind
m["replicas"] = status.Replicas
m["UnavailableReplicas"] = status.UnavailableReplicas
return m, nil
}
func (this KubeObject) getStatefulSet() (map[string]any, error) {
bin := this.Bin
name := this.Name
msg := fmt.Sprintf("%s get statefulset %s -o json", bin, name)
log.Log().Debug().Msg(msg)
m := make(map[string]any)
cmd_args := strings.Split(msg, " ")
cmd := exec.Command(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput()
if err != nil {
return m, errors.New(string(stdout))
}
var objmap getOutput
json.Unmarshal(stdout, &objmap)
kind := objmap.Kind
status := objmap.Status
m["name"] = name
m["kind"] = kind
m["replicas"] = status.Replicas
m["UnavailableReplicas"] = status.UnavailableReplicas
return m, nil
}
func (this KubeObject) Wait() (error) {
boucle := 10
sleep := 10000 * time.Millisecond
for _ = range boucle {
log.Log().Debug().Msg(fmt.Sprintf("Check Deployement %s", this.Name))
m, err := this.Get()
if err != nil {
return err
}
ko := m["UnavailableReplicas"].(int)
if ko == 0 {
return nil
}
log.Log().Info().Msg(fmt.Sprintf(" >> %s (Unavailable : %d)...", this.Name, ko))
time.Sleep(sleep)
}
return errors.New("Temps d'attente dépassé")
} }

View File

@ -0,0 +1,28 @@
package kubectl
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKubectStatefulset(t *testing.T) {
fileName := filepath.Join(TEST_SRC_DIR, "statefulset.json")
cmd_json, _ := os.ReadFile(fileName)
cmd := getCmdKubectl(true, string(cmd_json))
data := KubectlObject{Name: "dep1", Kind: "Statefulset"}
res, err := cmd.getDeployment(data)
// map[string]interface {}(map[string]interface {}{"UnavailableReplicas":0, "kind":"StatefulSet", "name":"dep1", "replicas":1})
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "StatefulSet", res["kind"], "TestKubectDeployment error")
assert.Equal(t, 1, res["replicas"], "TestKubectDeployment error")
}

View File

@ -0,0 +1,43 @@
package kubectl
import (
"fmt"
"strings"
"errors"
"encoding/json"
log "oc-deploy/log_wrapper"
)
func (this KubectlCommand) getStatefulSet(data KubectlObject) (map[string]any, error) {
bin := this.Bin
name := data.Name
msg := fmt.Sprintf("%s get statefulset %s -o json", bin, name)
log.Log().Debug().Msg(msg)
m := make(map[string]any)
cmd_args := strings.Split(msg, " ")
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
stdout, err := cmd.CombinedOutput()
if err != nil {
return m, errors.New(string(stdout))
}
var objmap getOutput
json.Unmarshal(stdout, &objmap)
kind := objmap.Kind
status := objmap.Status
m["name"] = name
m["kind"] = kind
m["replicas"] = status.Replicas
m["UnavailableReplicas"] = status.UnavailableReplicas
return m, nil
}

View File

@ -1,31 +1,29 @@
package kubectl package kubectl
import ( import (
"os/exec" "encoding/json"
"encoding/json" )
)
type toolClientVersion struct {
type toolClientVersion struct { GitVersion string `json:"gitVersion"`
GitVersion string `json:"gitVersion"` }
}
type toolVersion struct {
type toolVersion struct { ClientVersion toolClientVersion `json:"clientVersion"`
ClientVersion toolClientVersion `json:"clientVersion"` }
}
func (this KubectlCommand) GetVersion() (string, error) {
func Version(path string) (string, error) {
cmd := this.Exec(this.Bin, "version", "-o", "json", "--client=true")
cmd := exec.Command(path, "version", "-o", "json", "--client=true") stdout, err := cmd.CombinedOutput()
stdout, err := cmd.CombinedOutput() if err != nil {
return "", err
if err != nil { }
return "", err
} var objmap toolVersion
var objmap toolVersion json.Unmarshal(stdout, &objmap)
res := objmap.ClientVersion.GitVersion
json.Unmarshal(stdout, &objmap)
res := objmap.ClientVersion.GitVersion return res, nil
}
return res, nil
}

View File

@ -1,22 +1,33 @@
package kubectl package kubectl
import ( import (
"os" "testing"
"path/filepath"
"github.com/stretchr/testify/assert"
"testing" )
"github.com/stretchr/testify/assert" func TestKubectlVersion(t *testing.T) {
)
cmd_json := `
func TestKubectlVersion(t *testing.T){ {
"clientVersion": {
bin := filepath.Join(TEST_BIN_DIR, "kubectl") "major": "1",
os.Chmod(bin, 0700) "minor": "30",
assert.FileExists(t, bin, "TestKubectlVersion error") "gitVersion": "v1.30.3",
"gitCommit": "6fc0a69044f1ac4c13841ec4391224a2df241460",
version, err := Version(bin) "gitTreeState": "clean",
"buildDate": "2024-07-16T23:54:40Z",
assert.Nilf(t, err, "error message %s", bin) "goVersion": "go1.22.5",
assert.Equal(t, "v1.30.3", version, "TestKubectlVersion error") "compiler": "gc",
} "platform": "linux/amd64"
},
"kustomizeVersion": "v5.0.4-0.20230601165947-6ce0bf390ce3"
}`
cmd := getCmdKubectl(true, cmd_json)
version, err := cmd.GetVersion()
assert.Nilf(t, err, "error message %s", err)
assert.Equal(t, "v1.30.3", version, "TestkubectlVersion error")
}

View File

@ -4,6 +4,7 @@ package log_wrapper
import ( import (
"os" "os"
"path/filepath"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
@ -28,9 +29,10 @@ func Log() *zerolog.Logger {
return &mainLogVar return &mainLogVar
} }
func InitLog(serverName string) bool { func InitLog(filename string) bool {
fAll, _ := os.OpenFile("./" + serverName + ".log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) ficlog := filepath.Join(filename + ".log")
fAll, _ := os.OpenFile(ficlog, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
output := zerolog.ConsoleWriter{Out: os.Stdout} output := zerolog.ConsoleWriter{Out: os.Stdout}
writerInfo := zerolog.MultiLevelWriter(output) writerInfo := zerolog.MultiLevelWriter(output)

View File

@ -0,0 +1,21 @@
package log_wrapper
import (
// "os"
"path/filepath"
// "errors"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLogWrapper(t *testing.T) {
ficlog := filepath.Join(TEST_DEST_DIR, "test")
InitLog(ficlog)
Log().Info().Msg("KKK")
Log().Error().Msg("KKK")
assert.FileExists(t, ficlog + ".log", "TestLogWrapper")
}

View File

@ -0,0 +1,21 @@
package log_wrapper
import (
"os"
"testing"
)
var TEST_DEST_DIR = "../wrk_log"
func TestMain(m *testing.M) {
folderPath := TEST_DEST_DIR
os.RemoveAll(folderPath)
os.MkdirAll(folderPath, os.ModePerm)
// call flag.Parse() here if TestMain uses flags
exitCode := m.Run()
os.RemoveAll(folderPath)
os.Exit(exitCode)
}

9
src/occonst/main_test.go Normal file
View File

@ -0,0 +1,9 @@
package occonst
import (
"testing"
)
func TestMain(m *testing.M) {
}

View File

@ -1,6 +1,6 @@
package occonst package occonst
const ONLINE_URL = "https://cloud.o-forge.io" var ONLINE_URL = "https://cloud.o-forge.io"
const ONLINE_VERSION = "core/oc-deploy" var ONLINE_VERSION = "core/oc-deploy"
var OFFLINE_DIR = "../../offline" var OFFLINE_DIR = "../../offline"

View File

@ -1,8 +1,6 @@
package tool package tool
import ( import (
"fmt"
// "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -15,7 +13,6 @@ func TestToolConf(t *testing.T) {
src := filepath.Join(TEST_SRC_DIR, "oc.yml") src := filepath.Join(TEST_SRC_DIR, "oc.yml")
data, err := FromConfigFile(src) data, err := FromConfigFile(src)
fmt.Println("data", src, data, err)
assert.Equal(t, "kubectl", data[0].Name, "TestToolConf error") assert.Equal(t, "kubectl", data[0].Name, "TestToolConf error")
assert.Nilf(t, err, "error message %s", src) assert.Nilf(t, err, "error message %s", src)
} }

View File

@ -8,16 +8,16 @@ import (
"oc-deploy/helm" "oc-deploy/helm"
) )
type HelmInstallData struct { type HelmInstall struct {
obj ToolData obj ToolData
tmp string tmp string
} }
func (this HelmInstallData) Get() (ToolData) { func (this HelmInstall) Get() (ToolData) {
return this.obj return this.obj
} }
func (this HelmInstallData) Download() (error) { func (this HelmInstall) Download() (error) {
bin_dir := this.obj.Bin bin_dir := this.obj.Bin
err2 := os.MkdirAll(bin_dir, os.ModePerm) err2 := os.MkdirAll(bin_dir, os.ModePerm)
@ -35,7 +35,9 @@ func (this HelmInstallData) Download() (error) {
r, _ := os.Open(tmp_file) r, _ := os.Open(tmp_file)
err1 := utils.ExtractTarGz(bin_dir, r) err1 := utils.ExtractTarGz(bin_dir, r)
if err1 != nil {return err1} if err1 != nil {
return err1
}
os.Remove(tmp_file) os.Remove(tmp_file)
@ -48,6 +50,8 @@ func (this HelmInstallData) Download() (error) {
} }
/////////////// ///////////////
func (this HelmInstallData) Version(path string) (string, error) { func (this HelmInstall) Version(path string) (string, error) {
return helm.Version(path) cmd := helm.HelmCommand{Bin: path}
cmd.New()
return cmd.GetVersion()
} }

View File

@ -1 +1,62 @@
package tool package tool
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/jarcoal/httpmock"
)
func TestToolHelm(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
data := ToolData{Bin: TEST_DEST_DIR,
Name: "helm",
Version: "1.0",
Url: "http://test/%s"}
fileName := filepath.Join(TEST_SRC_DIR, "helm.tgz")
httpRes, _ := os.ReadFile(fileName)
httpmock.RegisterResponder("GET", "http://test/1.0",
httpmock.NewBytesResponder(200, httpRes))
install := HelmInstall{obj: data, tmp: TEST_DEST_DIR}
data2 := install.Get()
assert.Equal(t, data.Name, data2.Name, "TestToolHelm error")
assert.Equal(t, data.Version, data2.Version, "TestToolHelm error")
err := install.Download()
assert.Nilf(t, err, "error message %s", "Download")
dest := filepath.Join(TEST_DEST_DIR, "helm")
assert.FileExists(t, dest, "TestToolHelm Download error")
version, _ := install.Version(dest)
assert.Equal(t, "1.0", version, "TestToolHelm error")
}
func TestToolHelmErr(t *testing.T) {
data := ToolData{Bin: TEST_DEST_DIR,
Name: "test",
Version: "1.0",
Url: "http://test/%s"}
install := HelmInstall{obj: data}
data2 := install.Get()
assert.Equal(t, data.Name, data2.Name, "TestToolHelm error")
err := install.Download()
assert.NotNilf(t, err, "error message %s", "Download")
}

View File

@ -10,15 +10,15 @@ import (
"oc-deploy/kubectl" "oc-deploy/kubectl"
) )
type KubecltInstallData struct { type KubectlInstall struct {
obj ToolData obj ToolData
} }
func (this KubecltInstallData) Get() (ToolData) { func (this KubectlInstall) Get() (ToolData) {
return this.obj return this.obj
} }
func (this KubecltInstallData) Download() (error) { func (this KubectlInstall) Download() (error) {
bin_dir := this.obj.Bin bin_dir := this.obj.Bin
bin := filepath.Join(bin_dir, this.obj.Name) bin := filepath.Join(bin_dir, this.obj.Name)
@ -36,6 +36,8 @@ func (this KubecltInstallData) Download() (error) {
} }
/////////////// ///////////////
func (this KubecltInstallData) Version(path string) (string, error) { func (this KubectlInstall) Version(path string) (string, error) {
return kubectl.Version(path) cmd := kubectl.KubectlCommand{Bin: path}
cmd.New()
return cmd.GetVersion()
} }

79
src/tool/kubectl_test.go Normal file
View File

@ -0,0 +1,79 @@
package tool
import (
"fmt"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/jarcoal/httpmock"
)
func TestToolKubectl(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
data := ToolData{Bin: TEST_DEST_DIR,
Name: "kubectl",
Version: "1.0",
Url: "http://test/%s"}
binContent := `#!/bin/sh
cat <<EOF
{
"clientVersion": {
"major": "1",
"minor": "30",
"gitVersion": "v1.30.3",
"gitCommit": "6fc0a69044f1ac4c13841ec4391224a2df241460",
"gitTreeState": "clean",
"buildDate": "2024-07-16T23:54:40Z",
"goVersion": "go1.22.5",
"compiler": "gc",
"platform": "linux/amd64"
},
"kustomizeVersion": "v5.0.4-0.20230601165947-6ce0bf390ce3"
}
EOF
`
httpmock.RegisterResponder("GET", "http://test/1.0",
httpmock.NewStringResponder(200, binContent))
install := KubectlInstall{obj: data}
data2 := install.Get()
assert.Equal(t, data.Name, data2.Name, "TestToolKubectl error")
assert.Equal(t, data.Version, data2.Version, "TestToolKubectl error")
err := install.Download()
assert.Nilf(t, err, "error message %s", "Download")
dest := filepath.Join(TEST_DEST_DIR, "kubectl")
assert.FileExists(t, dest, "TestToolKubectl Download error")
version, err1 := install.Version(dest)
assert.Equal(t, "v1.30.3", version, "TestToolKubectl error")
fmt.Println(" err1 ", err1)
}
func TestToolKubectlErr(t *testing.T) {
data := ToolData{Bin: TEST_DEST_DIR,
Name: "test",
Version: "1.0",
Url: "http://test/%s"}
install := KubectlInstall{obj: data}
data2 := install.Get()
assert.Equal(t, data.Name, data2.Name, "TestToolKubectl error")
err := install.Download()
assert.NotNilf(t, err, "error message %s", "Download")
}

View File

@ -1,24 +1,23 @@
package tool package tool
import ( import (
"os" "os"
"testing" "testing"
"path/filepath" "path/filepath"
) )
var TEST_DEST_DIR = "../wrk_tool" var TEST_DEST_DIR = "../wrk_tool"
var TEST_SRC_DIR = filepath.Join("../../test", "tool") var TEST_SRC_DIR = filepath.Join("../../test", "tool")
var TEST_BIN_DIR = filepath.Join("../../test", "bin")
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
folderPath := TEST_DEST_DIR folderPath := TEST_DEST_DIR
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.MkdirAll(folderPath, os.ModePerm) os.MkdirAll(folderPath, os.ModePerm)
// call flag.Parse() here if TestMain uses flags // call flag.Parse() here if TestMain uses flags
exitCode := m.Run() exitCode := m.Run()
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.Exit(exitCode) os.Exit(exitCode)
} }

View File

@ -68,9 +68,9 @@ func factory(data ToolData) (Forme, error) {
switch data.Name { switch data.Name {
case "kubectl": case "kubectl":
f = KubecltInstallData{obj: data} f = KubectlInstall{obj: data}
case "helm": case "helm":
f = HelmInstallData{obj: data, tmp: "/tmp"} f = HelmInstall{obj: data, tmp: "/tmp"}
default: default:
return f, fmt.Errorf("Outil Inconnu : %s", data.Name) return f, fmt.Errorf("Outil Inconnu : %s", data.Name)
} }

View File

@ -1,7 +1,6 @@
package utils package utils
import ( import (
// "fmt"
"os" "os"
"io" "io"
"path" "path"
@ -56,7 +55,7 @@ func ExtractTarGz(dest string, gzipStream io.Reader) error {
// return err // return err
// } // }
case tar.TypeReg: case tar.TypeReg:
outName := dest + "/" + path.Base( header.Name) outName := dest + "/" + path.Base(header.Name)
outFile, _ := os.Create(outName) outFile, _ := os.Create(outName)
if err != nil { if err != nil {
return err return err

View File

@ -1,8 +1,7 @@
package utils package utils
// https://pkg.go.dev/github.com/stretchr/testify/assert#Nilf
import ( import (
"os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -26,3 +25,27 @@ func TestDownload(t *testing.T) {
assert.Nilf(t, err, "error message %s", url) assert.Nilf(t, err, "error message %s", url)
assert.FileExists(t, dest, "DownloadFromUrl error") assert.FileExists(t, dest, "DownloadFromUrl error")
} }
func TestExtractTarGz(t *testing.T) {
dest := filepath.Join(TEST_DEST_DIR, "extract")
os.MkdirAll(dest, os.ModePerm)
src := filepath.Join(TEST_SRC_DIR, "fichier1.tgz")
file, _ := os.Open(src)
err := ExtractTarGz(dest, file)
assert.Nilf(t, err, "error message %s", src)
assert.FileExists(t, filepath.Join(dest, "fichier1"), "TestExtractTarGz error")
}
func TestExtractTarGzErr(t *testing.T) {
dest := filepath.Join(TEST_DEST_DIR, "extract")
src := filepath.Join(TEST_SRC_DIR, "fichier1")
file, _ := os.Open(src)
err := ExtractTarGz(dest, file)
assert.NotNilf(t, err, "error message %s", src)
}

View File

@ -1,23 +1,25 @@
package utils package utils
// https://pkg.go.dev/github.com/stretchr/testify/assert
import ( import (
"os" "os"
"testing" "testing"
"path/filepath" "path/filepath"
) )
var TEST_DEST_DIR = "../wrk_utils" var TEST_DEST_DIR = "../wrk_utils"
var TEST_SRC_DIR = filepath.Join("../../test", "utils") var TEST_SRC_DIR = filepath.Join("../../test", "utils")
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
folderPath := TEST_DEST_DIR folderPath := TEST_DEST_DIR
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.MkdirAll(folderPath, os.ModePerm) os.MkdirAll(folderPath, os.ModePerm)
// call flag.Parse() here if TestMain uses flags // call flag.Parse() here if TestMain uses flags
exitCode := m.Run() exitCode := m.Run()
os.RemoveAll(folderPath) os.RemoveAll(folderPath)
os.Exit(exitCode) os.Exit(exitCode)
} }

22
src/utils/slice_test.go Normal file
View File

@ -0,0 +1,22 @@
package utils
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSliceInStringExist(t *testing.T) {
liste := []string{"text1", "text2"}
res := StringInSlice("text1", liste)
assert.Truef(t, res, "error message %s", "text1")
}
func TestSliceInStringNotExist(t *testing.T) {
liste := []string{"text1", "text2"}
res := StringInSlice("text3", liste)
assert.Falsef(t, res, "error message %s", "text3")
}

54
test/kubectl/context.json Normal file
View File

@ -0,0 +1,54 @@
{
"kind": "Config",
"apiVersion": "v1",
"preferences": {},
"clusters": [
{
"name": "minikube",
"cluster": {
"server": "https://127.0.0.1:38039",
"certificate-authority": "/home/admeju/.minikube/ca.crt",
"extensions": [
{
"name": "cluster_info",
"extension": {
"last-update": "Tue, 10 Sep 2024 10:32:04 UTC",
"provider": "minikube.sigs.k8s.io",
"version": "v1.33.1"
}
}
]
}
}
],
"users": [
{
"name": "minikube",
"user": {
"client-certificate": "/home/admeju/.minikube/profiles/minikube/client.crt",
"client-key": "/home/admeju/.minikube/profiles/minikube/client.key"
}
}
],
"contexts": [
{
"name": "minikube",
"context": {
"cluster": "minikube",
"user": "minikube",
"namespace": "default",
"extensions": [
{
"name": "context_info",
"extension": {
"last-update": "Tue, 10 Sep 2024 10:32:04 UTC",
"provider": "minikube.sigs.k8s.io",
"version": "v1.33.1"
}
}
]
}
}
],
"current-context": "minikube"
}

View File

@ -0,0 +1,312 @@
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"annotations": {
"deployment.kubernetes.io/revision": "1",
"meta.helm.sh/release-name": "phpmyadmin",
"meta.helm.sh/release-namespace": "default"
},
"creationTimestamp": "2024-09-06T12:29:16Z",
"generation": 1,
"labels": {
"app.kubernetes.io/instance": "phpmyadmin",
"app.kubernetes.io/managed-by": "Helm",
"app.kubernetes.io/name": "phpmyadmin",
"app.kubernetes.io/version": "5.2.1",
"helm.sh/chart": "phpmyadmin-17.0.4"
},
"name": "phpmyadmin",
"namespace": "default",
"resourceVersion": "87308",
"uid": "b8518be1-1dd0-45a1-80f3-ddb835a56a5d"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/instance": "phpmyadmin",
"app.kubernetes.io/name": "phpmyadmin"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app.kubernetes.io/instance": "phpmyadmin",
"app.kubernetes.io/managed-by": "Helm",
"app.kubernetes.io/name": "phpmyadmin",
"app.kubernetes.io/version": "5.2.1",
"helm.sh/chart": "phpmyadmin-17.0.4"
}
},
"spec": {
"affinity": {
"podAntiAffinity": {
"preferredDuringSchedulingIgnoredDuringExecution": [
{
"podAffinityTerm": {
"labelSelector": {
"matchLabels": {
"app.kubernetes.io/instance": "phpmyadmin",
"app.kubernetes.io/name": "phpmyadmin"
}
},
"topologyKey": "kubernetes.io/hostname"
},
"weight": 1
}
]
}
},
"automountServiceAccountToken": false,
"containers": [
{
"env": [
{
"name": "BITNAMI_DEBUG",
"value": "false"
},
{
"name": "DATABASE_PORT_NUMBER",
"value": "3306"
},
{
"name": "DATABASE_HOST"
},
{
"name": "PHPMYADMIN_ALLOW_NO_PASSWORD",
"value": "true"
},
{
"name": "PHPMYADMIN_ALLOW_ARBITRARY_SERVER",
"value": "true"
},
{
"name": "DATABASE_ENABLE_SSL",
"value": "no"
}
],
"image": "docker.io/bitnami/phpmyadmin:5.2.1-debian-12-r36",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"failureThreshold": 6,
"initialDelaySeconds": 30,
"periodSeconds": 10,
"successThreshold": 1,
"tcpSocket": {
"port": "http"
},
"timeoutSeconds": 30
},
"name": "phpmyadmin",
"ports": [
{
"containerPort": 8080,
"name": "http",
"protocol": "TCP"
},
{
"containerPort": 8443,
"name": "https",
"protocol": "TCP"
}
],
"readinessProbe": {
"failureThreshold": 6,
"httpGet": {
"path": "/",
"port": "http",
"scheme": "HTTP"
},
"initialDelaySeconds": 30,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 30
},
"resources": {
"limits": {
"cpu": "375m",
"ephemeral-storage": "2Gi",
"memory": "384Mi"
},
"requests": {
"cpu": "250m",
"ephemeral-storage": "50Mi",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"privileged": false,
"readOnlyRootFilesystem": true,
"runAsGroup": 1001,
"runAsNonRoot": true,
"runAsUser": 1001,
"seccompProfile": {
"type": "RuntimeDefault"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/opt/bitnami/apache/conf",
"name": "empty-dir",
"subPath": "apache-conf-dir"
},
{
"mountPath": "/opt/bitnami/apache/logs",
"name": "empty-dir",
"subPath": "apache-logs-dir"
},
{
"mountPath": "/opt/bitnami/apache/var/run",
"name": "empty-dir",
"subPath": "apache-tmp-dir"
},
{
"mountPath": "/opt/bitnami/php/etc",
"name": "empty-dir",
"subPath": "php-conf-dir"
},
{
"mountPath": "/opt/bitnami/php/tmp",
"name": "empty-dir",
"subPath": "php-tmp-dir"
},
{
"mountPath": "/opt/bitnami/php/var",
"name": "empty-dir",
"subPath": "php-var-dir"
},
{
"mountPath": "/tmp",
"name": "empty-dir",
"subPath": "tmp-dir"
},
{
"mountPath": "/opt/bitnami/phpmyadmin",
"name": "empty-dir",
"subPath": "app-base-dir"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"hostAliases": [
{
"hostnames": [
"status.localhost"
],
"ip": "127.0.0.1"
}
],
"initContainers": [
{
"args": [
"-ec",
"#!/bin/bash\n\n. /opt/bitnami/scripts/liblog.sh\n. /opt/bitnami/scripts/libfs.sh\n\ninfo \"Copying base dir to empty dir\"\n# In order to not break the application functionality (such as upgrades or plugins) we need\n# to make the base directory writable, so we need to copy it to an empty dir volume\ncp -r --preserve=mode /opt/bitnami/phpmyadmin /emptydir/app-base-dir\n\ninfo \"Copying symlinks to stdout/stderr\"\n# We copy the logs folder because it has symlinks to stdout and stderr\nif ! is_dir_empty /opt/bitnami/apache/logs; then\n cp -r /opt/bitnami/apache/logs /emptydir/apache-logs-dir\nfi\ninfo \"Copying php var directory\"\n# PhpMyAdmin will fail to start if the php var folder is not populated\nif ! is_dir_empty /opt/bitnami/php/var; then\n cp -r /opt/bitnami/php/var /emptydir/php-var-dir\nfi\ninfo \"Copy operation completed\"\n"
],
"command": [
"/bin/bash"
],
"image": "docker.io/bitnami/phpmyadmin:5.2.1-debian-12-r36",
"imagePullPolicy": "IfNotPresent",
"name": "prepare-base-dir",
"resources": {
"limits": {
"cpu": "375m",
"ephemeral-storage": "2Gi",
"memory": "384Mi"
},
"requests": {
"cpu": "250m",
"ephemeral-storage": "50Mi",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"privileged": false,
"readOnlyRootFilesystem": true,
"runAsGroup": 1001,
"runAsNonRoot": true,
"runAsUser": 1001,
"seccompProfile": {
"type": "RuntimeDefault"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/emptydir",
"name": "empty-dir"
}
]
}
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1001,
"fsGroupChangePolicy": "Always"
},
"serviceAccount": "phpmyadmin",
"serviceAccountName": "phpmyadmin",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"emptyDir": {},
"name": "empty-dir"
}
]
}
}
},
"status": {
"availableReplicas": 1,
"conditions": [
{
"lastTransitionTime": "2024-09-06T12:29:17Z",
"lastUpdateTime": "2024-09-06T12:30:08Z",
"message": "ReplicaSet \"phpmyadmin-7f7bbf7bd7\" has successfully progressed.",
"reason": "NewReplicaSetAvailable",
"status": "True",
"type": "Progressing"
},
{
"lastTransitionTime": "2024-09-09T11:54:00Z",
"lastUpdateTime": "2024-09-09T11:54:00Z",
"message": "Deployment has minimum availability.",
"reason": "MinimumReplicasAvailable",
"status": "True",
"type": "Available"
}
],
"observedGeneration": 1,
"readyReplicas": 1,
"replicas": 1,
"updatedReplicas": 1
}
}

View File

@ -0,0 +1,332 @@
{
"apiVersion": "apps/v1",
"kind": "StatefulSet",
"metadata": {
"annotations": {
"meta.helm.sh/release-name": "wordpress",
"meta.helm.sh/release-namespace": "default"
},
"creationTimestamp": "2024-09-09T12:29:35Z",
"generation": 1,
"labels": {
"app.kubernetes.io/component": "primary",
"app.kubernetes.io/instance": "wordpress",
"app.kubernetes.io/managed-by": "Helm",
"app.kubernetes.io/name": "mariadb",
"app.kubernetes.io/version": "11.4.2",
"helm.sh/chart": "mariadb-19.0.3"
},
"name": "wordpress-mariadb",
"namespace": "default",
"resourceVersion": "92784",
"uid": "82197de7-3b4f-4225-b1a2-58e8ac0fad44"
},
"spec": {
"persistentVolumeClaimRetentionPolicy": {
"whenDeleted": "Retain",
"whenScaled": "Retain"
},
"podManagementPolicy": "OrderedReady",
"replicas": 1,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app.kubernetes.io/component": "primary",
"app.kubernetes.io/instance": "wordpress",
"app.kubernetes.io/name": "mariadb"
}
},
"serviceName": "wordpress-mariadb",
"template": {
"metadata": {
"annotations": {
"checksum/configuration": "0fdca6295cb246435ed7edb5801c3445ca97c878dcce94b652f2fec128efd78a"
},
"creationTimestamp": null,
"labels": {
"app.kubernetes.io/component": "primary",
"app.kubernetes.io/instance": "wordpress",
"app.kubernetes.io/managed-by": "Helm",
"app.kubernetes.io/name": "mariadb",
"app.kubernetes.io/version": "11.4.2",
"helm.sh/chart": "mariadb-19.0.3"
}
},
"spec": {
"affinity": {
"podAntiAffinity": {
"preferredDuringSchedulingIgnoredDuringExecution": [
{
"podAffinityTerm": {
"labelSelector": {
"matchLabels": {
"app.kubernetes.io/component": "primary",
"app.kubernetes.io/instance": "wordpress",
"app.kubernetes.io/name": "mariadb"
}
},
"topologyKey": "kubernetes.io/hostname"
},
"weight": 1
}
]
}
},
"automountServiceAccountToken": false,
"containers": [
{
"env": [
{
"name": "BITNAMI_DEBUG",
"value": "false"
},
{
"name": "MARIADB_ROOT_PASSWORD",
"valueFrom": {
"secretKeyRef": {
"key": "mariadb-root-password",
"name": "wordpress-mariadb"
}
}
},
{
"name": "MARIADB_USER",
"value": "bn_wordpress"
},
{
"name": "MARIADB_PASSWORD",
"valueFrom": {
"secretKeyRef": {
"key": "mariadb-password",
"name": "wordpress-mariadb"
}
}
},
{
"name": "MARIADB_DATABASE",
"value": "bitnami_wordpress"
}
],
"image": "docker.io/bitnami/mariadb:11.4.2-debian-12-r2",
"imagePullPolicy": "IfNotPresent",
"livenessProbe": {
"exec": {
"command": [
"/bin/bash",
"-ec",
"password_aux=\"${MARIADB_ROOT_PASSWORD:-}\"\nif [[ -f \"${MARIADB_ROOT_PASSWORD_FILE:-}\" ]]; then\n password_aux=$(cat \"$MARIADB_ROOT_PASSWORD_FILE\")\nfi\nmysqladmin status -uroot -p\"${password_aux}\"\n"
]
},
"failureThreshold": 3,
"initialDelaySeconds": 120,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"name": "mariadb",
"ports": [
{
"containerPort": 3306,
"name": "mysql",
"protocol": "TCP"
}
],
"readinessProbe": {
"exec": {
"command": [
"/bin/bash",
"-ec",
"password_aux=\"${MARIADB_ROOT_PASSWORD:-}\"\nif [[ -f \"${MARIADB_ROOT_PASSWORD_FILE:-}\" ]]; then\n password_aux=$(cat \"$MARIADB_ROOT_PASSWORD_FILE\")\nfi\nmysqladmin ping -uroot -p\"${password_aux}\"\n"
]
},
"failureThreshold": 3,
"initialDelaySeconds": 30,
"periodSeconds": 10,
"successThreshold": 1,
"timeoutSeconds": 1
},
"resources": {
"limits": {
"cpu": "375m",
"ephemeral-storage": "2Gi",
"memory": "384Mi"
},
"requests": {
"cpu": "250m",
"ephemeral-storage": "50Mi",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"privileged": false,
"readOnlyRootFilesystem": true,
"runAsGroup": 1001,
"runAsNonRoot": true,
"runAsUser": 1001,
"seLinuxOptions": {},
"seccompProfile": {
"type": "RuntimeDefault"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/bitnami/mariadb",
"name": "data"
},
{
"mountPath": "/opt/bitnami/mariadb/conf/my.cnf",
"name": "config",
"subPath": "my.cnf"
},
{
"mountPath": "/tmp",
"name": "empty-dir",
"subPath": "tmp-dir"
},
{
"mountPath": "/opt/bitnami/mariadb/conf",
"name": "empty-dir",
"subPath": "app-conf-dir"
},
{
"mountPath": "/opt/bitnami/mariadb/tmp",
"name": "empty-dir",
"subPath": "app-tmp-dir"
},
{
"mountPath": "/opt/bitnami/mariadb/logs",
"name": "empty-dir",
"subPath": "app-logs-dir"
}
]
}
],
"dnsPolicy": "ClusterFirst",
"initContainers": [
{
"args": [
"-ec",
"#!/bin/bash\n\n. /opt/bitnami/scripts/libfs.sh\n# We copy the logs folder because it has symlinks to stdout and stderr\nif ! is_dir_empty /opt/bitnami/mariadb/logs; then\n cp -r /opt/bitnami/mariadb/logs /emptydir/app-logs-dir\nfi\n"
],
"command": [
"/bin/bash"
],
"image": "docker.io/bitnami/mariadb:11.4.2-debian-12-r2",
"imagePullPolicy": "IfNotPresent",
"name": "preserve-logs-symlinks",
"resources": {
"limits": {
"cpu": "375m",
"ephemeral-storage": "2Gi",
"memory": "384Mi"
},
"requests": {
"cpu": "250m",
"ephemeral-storage": "50Mi",
"memory": "256Mi"
}
},
"securityContext": {
"allowPrivilegeEscalation": false,
"capabilities": {
"drop": [
"ALL"
]
},
"privileged": false,
"readOnlyRootFilesystem": true,
"runAsGroup": 1001,
"runAsNonRoot": true,
"runAsUser": 1001,
"seLinuxOptions": {},
"seccompProfile": {
"type": "RuntimeDefault"
}
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"volumeMounts": [
{
"mountPath": "/emptydir",
"name": "empty-dir"
}
]
}
],
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {
"fsGroup": 1001,
"fsGroupChangePolicy": "Always"
},
"serviceAccount": "wordpress-mariadb",
"serviceAccountName": "wordpress-mariadb",
"terminationGracePeriodSeconds": 30,
"volumes": [
{
"emptyDir": {},
"name": "empty-dir"
},
{
"configMap": {
"defaultMode": 420,
"name": "wordpress-mariadb"
},
"name": "config"
}
]
}
},
"updateStrategy": {
"type": "RollingUpdate"
},
"volumeClaimTemplates": [
{
"apiVersion": "v1",
"kind": "PersistentVolumeClaim",
"metadata": {
"creationTimestamp": null,
"labels": {
"app.kubernetes.io/component": "primary",
"app.kubernetes.io/instance": "wordpress",
"app.kubernetes.io/name": "mariadb"
},
"name": "data"
},
"spec": {
"accessModes": [
"ReadWriteOnce"
],
"resources": {
"requests": {
"storage": "8Gi"
}
},
"volumeMode": "Filesystem"
},
"status": {
"phase": "Pending"
}
}
]
},
"status": {
"availableReplicas": 1,
"collisionCount": 0,
"currentReplicas": 1,
"currentRevision": "wordpress-mariadb-599b74c5bc",
"observedGeneration": 1,
"readyReplicas": 1,
"replicas": 1,
"updateRevision": "wordpress-mariadb-599b74c5bc",
"updatedReplicas": 1
}
}

BIN
test/tool/helm.tgz Normal file

Binary file not shown.

BIN
test/utils/fichier1.tgz Normal file

Binary file not shown.