1 Commits

Author SHA1 Message Date
admju
4ae5926b01 init bin 2024-09-02 07:09:46 +00:00
112 changed files with 1713 additions and 66 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
bin

View File

@@ -35,69 +35,5 @@ Install Talos
chmod 700 get_helm.sh
./get_helm.sh
--------------------------
# Create OpenCloud Chart
# `oc-deploy` Component
The `oc-deploy` component aims to simplify and automate the deployment of OpenCloud components on a Kubernetes cluster through the creation of Helm Charts.
## Prerequisites:
- Access to the OpenCloud forge and the associated Harbor registry: [https://registry.o-forge.io/](https://registry.o-forge.io/), which will allow pulling OpenCloud release images from the "stable" project.
- To test the connection to this registry from the Docker client:
```bash
docker login registry.o-forge.io
```
- A Kubernetes cluster: Minikube, K3s, RKE2, etc. See `KubernetesCluster`.
- Helm installed locally
## **To Be Defined:**
### Configuring a Docker Secret for Kubernetes
Kubernetes needs to know your credentials to pull images from the "registry.o-forge.io" registry. Create a Docker secret in Kubernetes:
```bash
kubectl create secret docker-registry regcred \
--docker-server=registry.o-forge.io \
--docker-username=<your_username> \
--docker-password=<your_password> \
--docker-email=<your_email>
```
## Checking if Helm Recognizes Your Local Kubernetes Cluster:
### 1. Verify Connection to Kubernetes:
Before checking Helm, ensure that your `kubectl` is properly configured to connect to your local Kubernetes cluster.
Run the following command to see if you can communicate with the cluster:
```bash
kubectl get nodes
```
If this command returns the list of nodes in your cluster, it means `kubectl` is properly connected.
### 2. Verify Helm Configuration:
Now, you can check if Helm can access the cluster by using the following command:
```bash
helm version
```
This command displays the Helm version and the Kubernetes version it is connected to.
## Deploying with Helm:
You can deploy the `oc-deploy` Chart with Helm:
```bash
helm install oc-deploy path/to/your/Helm/oc-deploy
```
## Checking Helm Releases:
You can also list the existing releases to see if Helm is properly connected to the cluster:
```bash
helm list
```
If all these commands execute without errors and give the expected results, your Helm installation is correctly configured to recognize and interact with your local Kubernetes cluster
helm create occhart

View File

@@ -1,4 +1,4 @@
@startuml Arch Diagram
@startuml
top to bottom direction

5
src/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
go.sum
*_
.coverage.*
.*.log
workspace_*

73
src/Makefile Normal file
View File

@@ -0,0 +1,73 @@
BIN_NAME := oc-deploy
BIN_OPTS :=
##################
SOURCES := $(wildcard *.go) $(wildcard */*.go)
BIN_DIR = ../bin/
PLUGINS := $(wildcard ../plugins/*/*.go)
OBJS := ${PLUGINS:.go=.so}
%.so: %.go
go build -buildmode=plugin -o $@ $<
help:
@echo
@echo 'Usage:'
@echo ' make build Génère les exécutables.'
@echo ' make get-deps runs dep ensure, mostly used for ci.'
@echo ' make run BIN_OPTS=... Go run'
@echo ' make run_install BIN_OPTS=... Go run'
@echo ' make run_uninstall BIN_OPTS=... Go run'
@echo ' make exec BIN_OPTS=... exécutable'
@echo ' make exec_install BIN_OPTS=... exécutable'
@echo ' make exec_uninstall BIN_OPTS=... exécutable'
@echo ' make test Test.'
@echo ' make test Test'
@echo ' make clean Clean the directory tree.'
@echo
${BIN_DIR}/${BIN_NAME}: ${SOURCES} $(OBJS)
go build -o ${BIN_DIR}/${BIN_NAME}
build: ${BIN_DIR}/${BIN_NAME}
run: $(OBJS)
@go run main.go ${BIN_OPTS}
run_generate: $(OBJS)
@go run main.go generate ${BIN_OPTS}
run_install: $(OBJS)
@go run main.go install ${BIN_OPTS}
run_uninstall: $(OBJS)
@go run main.go uninstall ${BIN_OPTS}
exec: ${BIN_DIR}/${BIN_NAME} $(OBJS)
@${BIN_DIR}/${BIN_NAME} ${BIN_OPTS}
exec_install: ${BIN_DIR}/${BIN_NAME} $(OBJS)
@${BIN_DIR}/${BIN_NAME} install ${BIN_OPTS}
exec_uninstall: ${BIN_DIR}/${BIN_NAME} $(OBJS)
@${BIN_DIR}/${BIN_NAME} uninstall ${BIN_OPTS}
clean:
@test ! -e ${BIN_DIR}/${BIN_NAME} || rm ${BIN_DIR}/${BIN_NAME}
@test ! -e .coverage.out || rm .coverage.out
@test ! -e .coverage.html || rm .coverage.html
@test ! -e go.sum || rm go.sum
@test ! -e .oc-deploy.log || rm .oc-deploy.log
@rm -rf workspace_*
@go mod tidy
.PHONY: test
test:
@go test ./... -coverprofile=.coverage.out -v
go tool cover -html=.coverage.out -o .coverage.html

75
src/README.md Normal file
View File

@@ -0,0 +1,75 @@
# Helm
[![Build Status](https://github.com/helm/helm/workflows/release/badge.svg)](https://github.com/helm/helm/actions?workflow=release)
[![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm)
[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131)
Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources.
Use Helm to:
- Find and use [popular software packaged as Helm Charts](https://artifacthub.io/packages/search?kind=0) to run in Kubernetes
- Share your own applications as Helm Charts
- Create reproducible builds of your Kubernetes applications
- Intelligently manage your Kubernetes manifest files
- Manage releases of Helm packages
## Helm in a Handbasket
Helm is a tool that streamlines installing and managing Kubernetes applications.
Think of it like apt/yum/homebrew for Kubernetes.
- Helm renders your templates and communicates with the Kubernetes API
- Helm runs on your laptop, CI/CD, or wherever you want it to run.
- Charts are Helm packages that contain at least two things:
- A description of the package (`Chart.yaml`)
- One or more templates, which contain Kubernetes manifest files
- Charts can be stored on disk, or fetched from remote chart repositories
(like Debian or RedHat packages)
## Install
Binary downloads of the Helm client can be found on [the Releases page](https://github.com/helm/helm/releases/latest).
Unpack the `helm` binary and add it to your PATH and you are good to go!
If you want to use a package manager:
- [Homebrew](https://brew.sh/) users can use `brew install helm`.
- [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`.
- [Scoop](https://scoop.sh/) users can use `scoop install helm`.
- [Snapcraft](https://snapcraft.io/) users can use `snap install helm --classic`
To rapidly get Helm up and running, start with the [Quick Start Guide](https://helm.sh/docs/intro/quickstart/).
See the [installation guide](https://helm.sh/docs/intro/install/) for more options,
including installing pre-releases.
## Docs
Get started with the [Quick Start guide](https://helm.sh/docs/intro/quickstart/) or plunge into the [complete documentation](https://helm.sh/docs)
## Roadmap
The [Helm roadmap uses GitHub milestones](https://github.com/helm/helm/milestones) to track the progress of the project.
## Community, discussion, contribution, and support
You can reach the Helm community and developers via the following channels:
- [Kubernetes Slack](https://kubernetes.slack.com):
- [#helm-users](https://kubernetes.slack.com/messages/helm-users)
- [#helm-dev](https://kubernetes.slack.com/messages/helm-dev)
- [#charts](https://kubernetes.slack.com/messages/charts)
- Mailing List:
- [Helm Mailing List](https://lists.cncf.io/g/cncf-helm)
- Developer Call: Thursdays at 9:30-10:00 Pacific ([meeting details](https://github.com/helm/community/blob/master/communication.md#meetings))
### Contribution
If you're interested in contributing, please refer to the [Contributing Guide](CONTRIBUTING.md) **before submitting a pull request**.
### Code of conduct
Participation in the Helm community is governed by the [Code of Conduct](code-of-conduct.md).

34
src/chart/conf.go Normal file
View File

@@ -0,0 +1,34 @@
package chart
import (
"os"
"gopkg.in/yaml.v2"
)
type ChartData struct {
Name string `yaml:"name"`
Chart string `yaml:"chart"`
Version string `yaml:"version"`
Opts string `yaml:"helm_opts"`
Values string `yaml:"helm_values"`
FileValues string `yaml:"helm_filevalues"`
}
type ChartRepoData struct {
Name string `yaml:"name"`
Repository string `yaml:"repository"`
Charts []ChartData `yaml:"charts"`
}
type chartsRepoData struct {
Charts []ChartRepoData `yaml:"opencloud"`
}
func FromConfigFile(filename string) ([]ChartRepoData) {
yamlFile, _ := os.ReadFile(filename)
var data chartsRepoData
yaml.Unmarshal(yamlFile, &data)
return data.Charts
}

30
src/chart/conf_test.go Normal file
View File

@@ -0,0 +1,30 @@
package chart
// https://pkg.go.dev/github.com/stretchr/testify/assert
import (
"testing"
"path/filepath"
"github.com/stretchr/testify/assert"
)
func TestReadConfChart(t *testing.T){
src := filepath.Join(TEST_SRC_DIR, "oc.yml")
assert.FileExists(t, src, "FromConfigFile error")
data := FromConfigFile(src)
assert.Equal(t, data[0].Name, "bitnami", "FromConfigFile error")
assert.Equal(t, data[0].Repository, "https://charts.bitnami.com/bitnami", "FromConfigFile error")
wordpress := data[0].Charts[0]
assert.Equal(t, wordpress.Name, "wordpress", "FromConfigFile error")
assert.Equal(t, wordpress.Chart, "bitnami/wordpress", "FromConfigFile error")
assert.Equal(t, wordpress.Version, "23.1.0", "FromConfigFile error")
phpmyadmin := data[0].Charts[1]
assert.Equal(t, phpmyadmin.Name, "phpmyadmin", "FromConfigFile error")
assert.Equal(t, phpmyadmin.Chart, "bitnami/phpmyadmin", "FromConfigFile error")
assert.Equal(t, phpmyadmin.Version, "17.0.4", "FromConfigFile error")
}

23
src/chart/main_test.go Normal file
View File

@@ -0,0 +1,23 @@
package chart
import (
"os"
"testing"
"path/filepath"
)
var TEST_DEST_DIR = "../wrk_chart"
var TEST_SRC_DIR = filepath.Join("../../test", "chart")
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)
}

71
src/cmd/args.go Normal file
View File

@@ -0,0 +1,71 @@
// Package cmd : Parse les arguments
// Arguments : version ==> version d'OpenCloud
// Argument : projet ==> nom du projet
package cmd
import (
"github.com/spf13/cobra"
log "oc-deploy/log_wrapper"
)
var (
context string
version string
)
func Execute() {
log.Log().Debug().Msg("Execute")
var rootCmd = &cobra.Command{Use: "oc-deploy"}
var cmdInstall = &cobra.Command{
Use: "install",
Short: "deploy",
Long: `deploy Charts`,
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
InstallCmd(context, version)
},
Example: "oc-deploy install --version 1.0 --context ex1",
}
var cmdUninstall = &cobra.Command{
Use: "uninstall",
Short: "undeploy",
Long: `Undeploy`,
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
UninstallCmd(context, version)
},
Example: "oc-deploy uninstall --context ex1",
}
var cmdGenerate = &cobra.Command{
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", "p", "opencloud", "Nom du projet")
cmdInstall.Flags().StringVarP(&version, "version", "v", "latest", "Version")
cmdUninstall.Flags().StringVarP(&context, "context", "p", "opencloud", "Nom du projet")
cmdGenerate.Flags().StringVarP(&context, "context", "p", "opencloud", "Nom du projet")
cmdGenerate.Flags().StringVarP(&version, "version", "v", "latest", "Version")
rootCmd.AddCommand(cmdInstall)
rootCmd.AddCommand(cmdUninstall)
rootCmd.AddCommand(cmdGenerate)
cobra.CheckErr(rootCmd.Execute())
}

27
src/cmd/generateCmd.go Normal file
View File

@@ -0,0 +1,27 @@
package cmd
import (
log "oc-deploy/log_wrapper"
"oc-deploy/versionOc"
"oc-deploy/generate"
)
func GenerateCmd(project string, version string) {
log.Log().Info().Msg("Generate >> ")
version, err := versionOc.Get(version)
if err != nil {
log.Log().Fatal().Msg("OpenCloud >> " + err.Error())
}
log.Log().Info().Msg(" >> Version : " + version)
obj := generate.GenerateClass{Workspace: "workspace_" + project, Version: version}
fic, err := obj.New()
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
log.Log().Info().Msg(" >> Value : " + fic)
}

51
src/cmd/installCmd.go Normal file
View File

@@ -0,0 +1,51 @@
package cmd
import (
"fmt"
log "oc-deploy/log_wrapper"
"oc-deploy/versionOc"
"oc-deploy/install"
)
func InstallCmd(context string, version string) {
log.Log().Info().Msg("Install >> ")
log.Log().Info().Msg(" << Contexte : " + context)
version, err := versionOc.Get(version)
log.Log().Info().Msg(" << Version : " + version)
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
workspace := fmt.Sprintf("workspace_%s", context)
obj := install.InstallClass{Workspace: workspace, Version: version}
file, err := obj.New()
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
log.Log().Info().Msg(" >> Config : " + file )
err = obj.Tools()
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
err = obj.ChartRepo()
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
err = obj.K8s(context)
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
err = obj.Charts()
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
}

34
src/cmd/uninstallCmd.go Normal file
View File

@@ -0,0 +1,34 @@
package cmd
import (
// "fmt"
// "strings"
// "github.com/spf13/cobra"
log "oc-deploy/log_wrapper"
"oc-deploy/versionOc"
"oc-deploy/install"
)
func UninstallCmd(context string, version string) {
log.Log().Info().Msg("Install >> ")
log.Log().Info().Msg(" << Contexte : " + context)
version, err := versionOc.Get(version)
log.Log().Info().Msg(" << Version : " + version)
if err != nil {
log.Log().Fatal().Msg(" >> " + err.Error())
}
obj := install.UninstallClass{Workspace: "workspace_" + context, Version: version}
obj.New()
// fic, err := obj.New()
// if err != nil {
// log.Log().Fatal().Msg(" >> " + err.Error())
// }
// log.Log().Info().Msg(" >> Value : " + fic)
}

23
src/generate/generate.go Normal file
View File

@@ -0,0 +1,23 @@
package generate
import (
"fmt"
"oc-deploy/utils"
)
type GenerateClass struct {
Version string
Workspace string
url string
}
func (this GenerateClass) New() (string, error) {
src := fmt.Sprintf("../offline/default_value_%s.yml", this.Version)
dst := fmt.Sprintf("%s/default_value.yml", this.Workspace)
err := utils.CopyFile(src, dst)
if err != nil {
return "", err
}
return src, nil
}

25
src/go.mod Normal file
View File

@@ -0,0 +1,25 @@
module oc-deploy
go 1.22.0
require (
github.com/jarcoal/httpmock v1.3.1
github.com/rs/zerolog v1.33.0
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.22.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

121
src/helm/chart.go Normal file
View File

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

24
src/helm/main_test.go Normal file
View File

@@ -0,0 +1,24 @@
package helm
import (
"os"
"testing"
"path/filepath"
)
var TEST_DEST_DIR = "../wrk_helm"
var TEST_SRC_DIR = filepath.Join("../../test", "helm")
var TEST_BIN_DIR = filepath.Join("../../test", "bin")
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)
}

53
src/helm/repo.go Normal file
View File

@@ -0,0 +1,53 @@
package helm
import (
"fmt"
"strings"
"os/exec"
log "oc-deploy/log_wrapper"
)
type HelmRepo struct {
Bin string // Chemin vers le binaire
Name string
Repository string // Url du dépôt
ForceUpdate bool
Opts string
}
func (this HelmRepo) AddRepository() (string, error) {
helm_bin := this.Bin
force_update := "--force-update=false"
if this.ForceUpdate {
force_update = "--force-update=true"
}
msg := fmt.Sprintf("%s repo add %s %s %s %s", helm_bin, this.Name, this.Repository, force_update, this.Opts)
log.Log().Debug().Msg(msg)
cmd := exec.Command(helm_bin, "repo", "add", this.Name, this.Repository, force_update)
stdout, err := cmd.CombinedOutput()
res := string(stdout)
res = strings.TrimSuffix(res, "\n")
return res, err
}
// helm repo remove [NAME]
func (this HelmRepo) RemoveRepository() (string, error) {
helm_bin := this.Bin
msg := fmt.Sprintf("%s repo remove %s", helm_bin, this.Name)
log.Log().Debug().Msg(msg)
cmd := exec.Command(helm_bin, "repo", "remove", this.Name)
stdout, err := cmd.CombinedOutput()
res := string(stdout)
res = strings.TrimSuffix(res, "\n")
return res, err
}

23
src/helm/repo_test.go Normal file
View File

@@ -0,0 +1,23 @@
package helm
import (
// "os"
// "path/filepath"
"testing"
// "github.com/stretchr/testify/assert"
)
func TestHelmRepoAdd(t *testing.T){
// fmt.Println(" TestVersion ", TEST_BIN_DIR)
// bin := filepath.Join(TEST_BIN_DIR, "helm")
// os.Chmod(bin, 0700)
// assert.FileExists(t, bin, "TestHelmVersion error")
// version, err := Version(bin)
// assert.Nilf(t, err, "error message %s", bin)
// assert.Equal(t, version, "v3.15.4+gfa9efb0", "TestHelmVersion error")
}

20
src/helm/version.go Normal file
View File

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

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

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

200
src/install/install.go Normal file
View File

@@ -0,0 +1,200 @@
package install
import (
"fmt"
"errors"
"sync"
// "time"
log "oc-deploy/log_wrapper"
"oc-deploy/utils"
"oc-deploy/tool"
"oc-deploy/helm"
"oc-deploy/chart"
"oc-deploy/kubectl"
)
type InstallClass struct {
Version string
Workspace string
versionFile string
tools []tool.ToolData
toolsBin map[string]string
charts []chart.ChartRepoData
}
func (this *InstallClass) New() (string, error) {
// Extraction du fichier de version
log.Log().Debug().Msg("Téléchargement du fichier de version")
src := fmt.Sprintf("../offline/oc_%s.yml", this.Version)
dst := fmt.Sprintf("%s/oc.yml", this.Workspace)
err := utils.CopyFile(src, dst)
if err != nil {
return "", err
}
// Lecture du fichier de conf
this.versionFile = dst
this.tools = tool.FromConfigFile(this.versionFile)
this.charts = chart.FromConfigFile(this.versionFile)
return dst, nil
}
func (this *InstallClass) Tools() (error) {
var mem []tool.ToolClass
for _, v := range this.tools {
tool2 := tool.ToolClass{}
v.Bin = this.Workspace
err := tool2.New(v)
if err != nil {
return err
}
mem = append(mem,tool2)
}
this.toolsBin = make(map[string]string)
for _, p := range mem {
data := p.Obj.Get()
log.Log().Info().Msg(fmt.Sprintf(" >> Outils : %s", data.Name))
err := p.Locate()
if err != nil {
log.Log().Info().Msg(fmt.Sprintf(" << %s ", err))
return err
}
log.Log().Info().Msg(fmt.Sprintf(" << %s ", p.Path))
version, err1 := p.Version()
if err1 != nil {
log.Log().Info().Msg(fmt.Sprintf(" << %s ", err1))
return err1
}
log.Log().Info().Msg(fmt.Sprintf(" << %s ", version))
this.toolsBin[data.Name] = p.Path
}
return nil
}
func (this *InstallClass) getToolBin(name string) (string, error) {
for key, value := range this.toolsBin {
if key == name {
return value, nil
}
}
return "", errors.New("Error")
}
func (this *InstallClass) ChartRepo() (error) {
bin_path, _ := this.getToolBin("helm")
for _, v := range this.charts {
log.Log().Info().Msg(fmt.Sprintf(" >> Helm Repo : %s", v.Name))
repo := helm.HelmRepo{Bin: bin_path,
Name: v.Name,
Repository: v.Repository,
ForceUpdate: true}
res, err := repo.AddRepository()
if err != nil {
log.Log().Info().Msg(fmt.Sprintf(" << %s ", err))
return err
}
log.Log().Info().Msg(fmt.Sprintf(" << %s ", res))
}
return nil
}
func (this *InstallClass) K8s(context string) (error) {
bin_path, _ := this.getToolBin("kubectl")
kube := kubectl.KubeContext{Bin: bin_path}
err := kube.UseContext(context)
if err != nil {
log.Log().Info().Msg(fmt.Sprintf(" << Kube : %s ", err))
return err
}
currentcontext, namespace, server, err := kube.GetContext()
if err != nil {
log.Log().Info().Msg(fmt.Sprintf(" << Kube : %s ", err))
return err
}
log.Log().Info().Msg(fmt.Sprintf(" << Kube : %s ", currentcontext))
log.Log().Info().Msg(fmt.Sprintf(" << : %s ", namespace))
log.Log().Info().Msg(fmt.Sprintf(" << : %s ", server))
err = kube.Check()
if err != nil {
log.Log().Info().Msg(fmt.Sprintf(" << : %s ", err))
return err
}
log.Log().Info().Msg(fmt.Sprintf(" << : %s ", "OK"))
return nil
}
func (this *InstallClass) Charts() (error) {
helm_bin, _ := this.getToolBin("helm")
kubectl_bin, _ := this.getToolBin("kubectl")
var wg sync.WaitGroup
for _, v := range this.charts {
for _, v1 := range v.Charts {
wg.Add(1)
go func() {
defer wg.Done()
this.worker(helm_bin, kubectl_bin, v1)
} ()
}
}
wg.Wait()
return nil
}
func (this *InstallClass) worker(helm_bin string, kubectl_bin string, chart chart.ChartData) {
log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name))
helmchart := helm.HelmChart{Bin: helm_bin,
Name: chart.Name,
Chart: chart.Chart,
Version: chart.Version,
Workspace: this.Workspace,
Opts: chart.Opts,
Values: chart.Values,
FileValues: chart.FileValues}
obj := kubectl.KubeObject{Bin: kubectl_bin,
Name: chart.Name}
res, err := helmchart.Install()
if err != nil {
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", helmchart.Name, "KO", err))
return
}
log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", helmchart.Name, res))
err = obj.Wait()
if err != nil {
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", chart.Name, "KO", err))
} else {
log.Log().Info().Msg(fmt.Sprintf(" >> %s %s", chart.Name, "OK"))
}
}

18
src/install/uninstall.go Normal file
View File

@@ -0,0 +1,18 @@
package install
import (
// "fmt"
// "os"
// "io"
// "path/filepath"
// log "oc-deploy/log_wrapper"
)
type UninstallClass struct {
Version string
Workspace string
}
func (this UninstallClass) New() {
}

108
src/kubectl/context.go Normal file
View File

@@ -0,0 +1,108 @@
package kubectl
import (
// "fmt"
"strings"
"errors"
"os/exec"
"encoding/json"
log "oc-deploy/log_wrapper"
)
type KubeContext struct {
Bin string // Chemin vers le binaire
}
type kubeConfig struct {
CurrentContext string `json:"current-context"`
Contexts [] kubeConfigContexts `json:"contexts"`
Clusters [] kubeConfigClusters `json:"clusters"`
}
type kubeConfigContexts struct {
Name string `json:"name"`
Context kubeConfigContext `json:"context"`
}
type kubeConfigContext struct {
Cluster string `json:"cluster"`
User string `json:"user"`
Namespace string `json:"namespace"`
}
type kubeConfigCluster struct {
Server string `json:"server"`
}
type kubeConfigClusters struct {
Name string `json:"name"`
Cluster kubeConfigCluster `json:"cluster"`
}
func (this KubeContext) GetCurrentContext() (string, error) {
cmd := exec.Command(this.Bin, "config", "current-context")
stdout, err := cmd.CombinedOutput()
res := string(stdout)
res = strings.TrimSuffix(res, "\n")
return res, err
}
// Current Context
// namespace, server
func (this KubeContext) GetContext() (string, string, string, error) {
cmd := exec.Command(this.Bin, "config", "view", "-o", "json")
stdout, _ := cmd.CombinedOutput()
var objmap kubeConfig
json.Unmarshal(stdout, &objmap)
currentContext := objmap.CurrentContext
currentCluster := ""
currentNamespace := ""
for _, v := range objmap.Contexts {
if v.Name == currentContext {
currentNamespace = v.Context.Namespace
currentCluster = v.Context.Cluster
}
}
currentServer := ""
for _, v := range objmap.Clusters {
if v.Name == currentCluster {
currentServer = v.Cluster.Server
}
}
return currentContext, currentNamespace, currentServer, nil
}
func (this KubeContext) UseContext(newContext string) (error) {
cmd := exec.Command(this.Bin, "config", "use-context", newContext)
stdout, err := cmd.CombinedOutput()
if err != nil {
log.Log().Debug().Msg(string(stdout))
return errors.New(string(stdout))
}
return nil
}
func (this KubeContext) Check() (error) {
cmd := exec.Command(this.Bin, "cluster-info")
stdout, err := cmd.CombinedOutput()
if err != nil {
log.Log().Debug().Msg(string(stdout))
return errors.New("Kube non disponible")
}
return nil
}

82
src/kubectl/object.go Normal file
View File

@@ -0,0 +1,82 @@
package kubectl
import (
"fmt"
"strings"
"errors"
"time"
"os/exec"
"encoding/json"
log "oc-deploy/log_wrapper"
)
type KubeObject struct {
Bin string // Chemin vers le binaire
Name string
}
type getOutput struct {
Kind string `json:"kind"`
Status getStatusOutput `json:"status"`
}
type getStatusOutput struct {
Replicas int `json:"replicas"`
UnavailableReplicas int `json:"unavailableReplicas"`
}
func (this KubeObject) Get() (map[string]any, error) {
bin := this.Bin
name := this.Name
msg := fmt.Sprintf("%s get deployment %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
}
time.Sleep(sleep)
}
return errors.New("Temps d'attente dépassé")
}

31
src/kubectl/version.go Normal file
View File

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

View File

@@ -0,0 +1,48 @@
package log_wrapper
// https://github.com/rs/zerolog/issues/150
import (
"os"
"github.com/rs/zerolog"
)
var mainLogVar zerolog.Logger
type FilteredWriter struct {
w zerolog.LevelWriter
level zerolog.Level
}
func (w *FilteredWriter) Write(p []byte) (n int, err error) {
return w.w.Write(p)
}
func (w *FilteredWriter) WriteLevel(level zerolog.Level, p []byte) (n int, err error) {
if level == w.level {
return w.w.WriteLevel(level, p)
}
return len(p), nil
}
func Log() *zerolog.Logger {
return &mainLogVar
}
func InitLog(serverName string) bool {
fAll, _ := os.OpenFile("./" + serverName + ".log", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644)
output := zerolog.ConsoleWriter{Out: os.Stdout}
writerInfo := zerolog.MultiLevelWriter(output)
writerError := zerolog.MultiLevelWriter(output)
writerFatal := zerolog.MultiLevelWriter(output)
filteredWriteInfo := &FilteredWriter{writerInfo, zerolog.InfoLevel}
filteredWriterError := &FilteredWriter{writerError, zerolog.ErrorLevel}
filteredWriterFatal := &FilteredWriter{writerFatal, zerolog.FatalLevel}
w := zerolog.MultiLevelWriter(fAll, filteredWriteInfo, filteredWriterError, filteredWriterFatal)
mainLogVar = zerolog.New(w).With().Timestamp().Logger()
return true
}

19
src/main.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import (
"oc-deploy/cmd"
log "oc-deploy/log_wrapper"
)
func main() {
log.InitLog(".oc-deploy")
log.Log().Debug().Msg("Start")
log.Log().Info().Msg("oc-deploy :")
cmd.Execute()
log.Log().Debug().Msg("End")
}

17
src/tool/conf.go Normal file
View File

@@ -0,0 +1,17 @@
package tool
import (
"os"
"gopkg.in/yaml.v2"
)
type toolsData struct {
Tools []ToolData `yaml:"tools"`
}
func FromConfigFile(filename string) ([]ToolData) {
yamlFile, _ := os.ReadFile(filename)
var data toolsData
yaml.Unmarshal(yamlFile, &data)
return data.Tools
}

53
src/tool/helm.go Normal file
View File

@@ -0,0 +1,53 @@
package tool
import (
"fmt"
"os"
// log "oc-deploy/log_wrapper"
"oc-deploy/utils"
"oc-deploy/helm"
)
type HelmInstallData struct {
obj ToolData
tmp string
}
func (this HelmInstallData) Get() (ToolData) {
return this.obj
}
func (this HelmInstallData) Download() (error) {
bin_dir := this.obj.Bin
err2 := os.MkdirAll(bin_dir, os.ModePerm)
if err2 != nil {
fmt.Println(err2)
return err2
}
tmp_file := fmt.Sprintf("%s/oc-deploy-%s", this.tmp, this.obj.Name)
url := fmt.Sprintf(this.obj.Url, this.obj.Version)
err := utils.DownloadFromUrl(tmp_file, url, 0777)
if err != nil {
return err
}
r, _ := os.Open(tmp_file)
err1 := utils.ExtractTarGz(bin_dir, r)
os.Remove(tmp_file)
bin_file := fmt.Sprintf("%s/%s", bin_dir, this.obj.Name)
os.Chmod(bin_file, 0755)
return err1
}
///////////////
func (this HelmInstallData) Version(path string) (string, error) {
return helm.Version(path)
}

Some files were not shown because too many files have changed in this diff Show More