This commit is contained in:
admju 2024-09-09 14:17:02 +00:00
parent 550675a4aa
commit 13025746e6
32 changed files with 1597 additions and 664 deletions

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...)
}
}

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,8 +92,8 @@ 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
@ -103,7 +104,7 @@ func (this *InstallClass) InstallCharts(modules []string) (error) {
go func() { go func() {
defer wg.Done() defer wg.Done()
this.installChart(helm_bin, kubectl_bin, v1) this.installChart(v1)
} () } ()
} }
} }
@ -112,35 +113,32 @@ func (this *InstallClass) InstallCharts(modules []string) (error) {
return nil return nil
} }
func (this *InstallClass) installChart(helm_bin string, kubectl_bin string, chart chart.ChartData) { func (this *InstallClass) installChart(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,7 +1,7 @@
package kubectl package kubectl
import ( import (
// "fmt" "fmt"
"strings" "strings"
"errors" "errors"
"os/exec" "os/exec"
@ -9,9 +9,9 @@ import (
log "oc-deploy/log_wrapper" log "oc-deploy/log_wrapper"
) )
type KubeContext struct { // type KubeContext struct {
Bin string // Chemin vers le binaire // Bin string // Chemin vers le binaire
} // }
type kubeConfig struct { type kubeConfig struct {
@ -40,9 +40,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 get 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)
@ -53,14 +58,23 @@ func (this KubeContext) GetCurrentContext() (string, error) {
// Current Context // Current Context
// namespace, server // namespace, server
func (this KubeContext) GetContext() (string, string, string, error) { func (this KubectlCommand) 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,7 +99,7 @@ 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) cmd := exec.Command(this.Bin, "config", "use-context", newContext)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
@ -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))

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

@ -1,8 +1,9 @@
package kubectl package kubectl
import ( import (
"os" "os"
"testing" "strings"
"testing"
"path/filepath" "path/filepath"
) )
@ -11,14 +12,73 @@ 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
}
// 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 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
}
}

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,31 @@
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 Version(path string) (string, error) { func (this KubectlCommand) GetVersion() (string, error) {
cmd := exec.Command(path, "version", "-o", "json", "--client=true") cmd := this.Exec(this.Bin, "version", "-o", "json", "--client=true")
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return "", err return "", err
} }
var objmap toolVersion var objmap toolVersion
json.Unmarshal(stdout, &objmap) json.Unmarshal(stdout, &objmap)
res := objmap.ClientVersion.GitVersion 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")
}

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

@ -49,5 +49,7 @@ func (this HelmInstallData) Download() (error) {
/////////////// ///////////////
func (this HelmInstallData) Version(path string) (string, error) { func (this HelmInstallData) Version(path string) (string, error) {
return helm.Version(path) cmd := helm.HelmCommand{Bin: path}
cmd.New()
return cmd.GetVersion()
} }

View File

@ -37,5 +37,7 @@ func (this KubecltInstallData) Download() (error) {
/////////////// ///////////////
func (this KubecltInstallData) Version(path string) (string, error) { func (this KubecltInstallData) Version(path string) (string, error) {
return kubectl.Version(path) cmd := kubectl.KubectlCommand{Bin: path}
cmd.New()
return cmd.GetVersion()
} }

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
}
}