Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
009062c51a | |||
|
1b9b79c67f | ||
|
981ee7dce4 | ||
|
0c35993122 | ||
|
3abf53ec6c | ||
|
19790f61e2 | ||
|
ebf9d3fc6d | ||
|
741d1a0ffe | ||
|
8632b02f0e | ||
|
95884e14d6 | ||
|
bd58ac1e02 | ||
|
9f0218a4da | ||
|
dfa9fe3f1e | ||
|
5d4de618dd | ||
|
3481bccc22 | ||
|
199209d9f1 | ||
|
330e4e9d4a | ||
|
6fef803ae9 | ||
|
3271246e74 | ||
|
80ef56bbc4 | ||
|
c1134f7403 | ||
|
9561dc5493 | ||
|
279f93224f | ||
|
c7f8503fb6 | ||
|
4bce096e1f | ||
|
75b7b94a50 | ||
|
13025746e6 | ||
|
550675a4aa | ||
|
a1af83689d | ||
|
53a614bd7e | ||
|
da9aab90eb | ||
|
052e6f1368 | ||
|
dddd5d1831 | ||
|
a7a5465a22 | ||
|
48301bf82e | ||
|
d12d3e31bf | ||
|
9e267becca | ||
|
756638fe21 | ||
|
11a4d5cc90 | ||
|
26404e5892 | ||
|
9cf954776f | ||
|
11f56722f7 | ||
|
4ae5926b01 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
k8s/deployed_config
|
bin
|
||||||
|
*.base64
|
||||||
|
env
|
||||||
|
34
Makefile
Normal file
34
Makefile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!make
|
||||||
|
|
||||||
|
include env
|
||||||
|
export
|
||||||
|
|
||||||
|
ifndef OC_VERSION
|
||||||
|
$(error OC_VERSION is not set)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef PUBLISH_TOKEN
|
||||||
|
$(error PUBLISH_TOKEN is not set)
|
||||||
|
endif
|
||||||
|
|
||||||
|
PUBLISH_REPO := "core/oc-deploy"
|
||||||
|
PUBLISH_BRANCH := main
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo 'Usage:'
|
||||||
|
@echo ' make publish'
|
||||||
|
@echo ' make clean'
|
||||||
|
|
||||||
|
.PHONY: publish
|
||||||
|
publish:
|
||||||
|
@echo Publication de : ${OC_VERSION}
|
||||||
|
@(cd src && make --quiet build VERSION=$(OC_VERSION))
|
||||||
|
@(cd publish && \
|
||||||
|
PUBLISH_REPO=${PUBLISH_REPO} \
|
||||||
|
PUBLISH_TOKEN=${PUBLISH_TOKEN} \
|
||||||
|
PUBLISH_BRANCH=${PUBLISH_BRANCH} \
|
||||||
|
go run main.go ${OC_VERSION})
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm *.base64
|
172
README.md
172
README.md
@ -4,100 +4,114 @@ The purpose of oc-deploy, is to deploy all the OC components over a Kubernetes c
|
|||||||
|
|
||||||
An OpenCloud deployment is composed of the following layers:
|
An OpenCloud deployment is composed of the following layers:
|
||||||
|
|
||||||
OpenCloud components | <-- TODO
|
|
||||||
--------------------------
|
| Layer | Tool |
|
||||||
KubernetesCluster | <-- TODO
|
| ------------------------ | --------------------- |
|
||||||
--------------------------
|
| OpenCloud components | oc-deploy binary |
|
||||||
IaaS (VMs, LAN) | <-- pre-requisite
|
| KubernetesCluster | TODO or pre-requisite |
|
||||||
--------------------------
|
| IaaS (VMs, LAN) | pre-requisite |
|
||||||
HW (network and servers) | <-- pre-requisite
|
| HW (network and servers) | <-- pre-requisite |
|
||||||
--------------------------
|
|
||||||
|
|
||||||
|
|
||||||
It thus contains a first optional installation layer which deploys the Kubernetes nodes (control plane(s) and workers) above an existing infrastructure (Iaas).
|
It thus contains a first optional installation layer which deploys the Kubernetes nodes (control plane(s) and workers) above an existing infrastructure (Iaas).
|
||||||
|
|
||||||
Then the second installation layer uses Helm charts to deploy and configure all the OC components.
|
|
||||||
|
|
||||||
This documentation will be updated with the needed command and/or requirements to properly execute the installation.
|
This documentation will be updated with the needed command and/or requirements to properly execute the installation.
|
||||||
|
|
||||||
# Deploy cluster
|
|
||||||
## For dev in Docker
|
# oc-deploy tools
|
||||||
Install brew
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
| ----------------------------------------------------------------------------- | --------------------------- |
|
||||||
|
| ```oc-deploy``` | Display help |
|
||||||
|
| ```oc-deploy version``` | Display the version of tool |
|
||||||
|
| ```oc-deploy install [-c\|--context <context>] [-v\|--version <OcVersion>]``` | Deploy an OpenCloud |
|
||||||
|
| ```oc-deploy uninstall [-c\|--context <context>]``` | Undeploy an OpenCloud |
|
||||||
|
|
||||||
|
| Arguments | Description | Default |
|
||||||
|
| ---------------- | --------------------------- | ------------ |
|
||||||
|
| ```context``` | Context Kubernetes | _opencloud_ |
|
||||||
|
| ```OcVersion``` | Specific version or latest | _latest_ |
|
||||||
|
|
||||||
|
## Principe
|
||||||
|
|
||||||
|
* Download an "OpenCloud file version" : oc_<version>.yml from relase on GitEa (core/oc-version).
|
||||||
|
* Initialise an workspace direcotry : ./workspace_<contextK8S>
|
||||||
|
* Install tools as describe, if not found on the path :
|
||||||
|
* Helm
|
||||||
|
* Kubectl
|
||||||
|
* Check if the Cluster (context) is available
|
||||||
|
* Install all charts as describe :
|
||||||
|
* Charts : from Harbor or local
|
||||||
|
* Images : from Harbor or local
|
||||||
|
* Check if componants are available
|
||||||
|
|
||||||
|
## Pre-requis
|
||||||
|
|
||||||
|
**oc-deploy** need to access to an Kubernetes Cluster, c'est-à-dire : kubeconfig.
|
||||||
|
|
||||||
|
**oc-deploy** need to access to Internet :
|
||||||
|
|
||||||
|
* to download the _oc.json_ file (contient _oc.yml_) :
|
||||||
|
* Url : https://cloud.o-forge.io/core/oc-deploy/releases
|
||||||
|
* to download _kubectl_ and _helm_ tools if
|
||||||
|
* Url : Urls are specified into _oc.yml_
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
Cf. src/README.md
|
||||||
|
|
||||||
|
## Publish
|
||||||
|
|
||||||
|
Publish in the relase GitEa the binary (the binary is base64 coding).
|
||||||
|
|
||||||
|
Set **env** file to overwrite varibable as :
|
||||||
|
|
||||||
|
#!make
|
||||||
|
PUBLISH_TOKEN = <gitea_token>
|
||||||
|
|
||||||
|
To publish :
|
||||||
|
|
||||||
|
OC_VERSION = <x.y.z> make publish
|
||||||
|
|
||||||
|
# Installation on Kubernetes
|
||||||
|
|
||||||
|
## Minikube
|
||||||
|
|
||||||
|
TO DO
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
TO DO
|
||||||
|
|
||||||
|
## RKE2
|
||||||
|
|
||||||
|
TO DO
|
||||||
|
|
||||||
|
## OpenShift
|
||||||
|
|
||||||
|
TO DO
|
||||||
|
|
||||||
|
# Installation on Docker
|
||||||
|
|
||||||
|
Without Kubernetes, for dev in Docker
|
||||||
|
|
||||||
|
## Install brew
|
||||||
|
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
|
||||||
Install Talos
|
## Install Talos
|
||||||
|
|
||||||
brew install siderolabs/tap/talosctl
|
brew install siderolabs/tap/talosctl
|
||||||
talosctl cluster create
|
talosctl cluster create
|
||||||
# Install helm
|
## Install helm
|
||||||
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
|
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
|
||||||
chmod 700 get_helm.sh
|
chmod 700 get_helm.sh
|
||||||
./get_helm.sh
|
./get_helm.sh
|
||||||
|
|
||||||
--------------------------
|
## Create OpenCloud Chart
|
||||||
# Create OpenCloud Chart
|
|
||||||
|
|
||||||
# `oc-deploy` Component
|
Obsolete : use oc-deploy tool
|
||||||
|
|
||||||
The `oc-deploy` component aims to simplify and automate the deployment of OpenCloud components on a Kubernetes cluster through the creation of Helm Charts.
|
helm create occhart
|
||||||
|
|
||||||
## 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
|
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
|
|
||||||
REPOS=(
|
|
||||||
"oc-auth"
|
|
||||||
"oc-catalog"
|
|
||||||
"oc-datacenter"
|
|
||||||
"oc-front"
|
|
||||||
"oc-monitord"
|
|
||||||
"oc-peer"
|
|
||||||
"oc-shared"
|
|
||||||
"oc-scheduler"
|
|
||||||
"oc-schedulerd"
|
|
||||||
"oc-workflow"
|
|
||||||
"oc-workspace"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Function to clone repositories
|
|
||||||
clone_repo() {
|
|
||||||
local repo_url="https://cloud.o-forge.io/core/$1.git"
|
|
||||||
local repo_name=$(basename "$repo_url" .git)
|
|
||||||
local branch=$2
|
|
||||||
echo "Processing repository: $repo_name"
|
|
||||||
|
|
||||||
if [ ! -d "$repo_name" ]; then
|
|
||||||
echo "Cloning repository: $repo_name"
|
|
||||||
git clone "$repo_url"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Error cloning $repo_url"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Repository '$repo_name' already exists. Pulling latest changes..."
|
|
||||||
cd "$repo_name" && git pull origin $branch && cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
# Iterate through each repository in the list
|
|
||||||
branch = "main"
|
|
||||||
if [ -n "$1" ]; then
|
|
||||||
branch = $1
|
|
||||||
fi
|
|
||||||
for repo in "${REPOS[@]}"; do
|
|
||||||
clone_repo $repo $branch
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "All repositories processed successfully."
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
docker cp ./datas mongo:.
|
|
||||||
|
|
||||||
for i in $(ls ./datas); do
|
|
||||||
firstString=$i
|
|
||||||
echo "ADD file $i in collection ${i/.json/}"
|
|
||||||
docker exec -it mongo sh -c "mongoimport --jsonArray --db DC_myDC --collection ${i/.json/} --file ./datas/$i"
|
|
||||||
done
|
|
@ -1 +0,0 @@
|
|||||||
[{"_id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","abstractobject":{"id":"0b6a375f-be3e-49a9-9827-3c2d5eddb057","name":"test","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":{"$date":"2025-01-27T10:41:47.741Z"},"update_date":{"$date":"2025-01-27T10:41:47.741Z"},"updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":0},"description":"Proto Collaborative area example","collaborative_area":{},"workflows":["58314c99-c595-4ca2-8b5e-822a6774efed"],"allowed_peers_group":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"workspaces":[]}]
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
|||||||
[{"_id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"04bc70b5-8d7b-44e6-9015-fadfa0fb102d","name":"IRT risk database","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT risk database.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"env":[{"attr":"source","readonly":true}],"resourceinstance":{"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":false,"security_level":"public","size":50,"size_type":3,"redundancy":"RAID5","throughput":"r:200,w:150"}]},"storage_type":5,"acronym":"DC_myDC"},{"_id":"e726020a-b68e-4abc-ab36-c3640ea3f557","abstractinstanciatedresource":{"abstractresource":{"type":"storage","abstractobject":{"id":"e726020a-b68e-4abc-ab36-c3640ea3f557","name":"IRT local file storage","is_draft":false,"creator_id":"c0cece97-7730-4c2a-8c20-a30944564106","creation_date":"2021-09-30T14:00:00.000Z","update_date":"2021-09-30T14:00:00.000Z","updater_id":"c0cece97-7730-4c2a-8c20-a30944564106","access_mode":1},"logo":"https://cloud.o-forge.io/core/deperecated-oc-catalog/raw/branch/main/scripts/local_imgs/IRT local file storage.png","description":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.","short_description":"S3 compliant IRT file storage","owners":[{"name":"IRT"}]},"instances":[{"resourceinstance":{"env":[{"attr":"source","readonly":true}],"abstractobject":{"id":"7fdccb9c-7090-40a5-bacd-7435bc56c90d","name":"IRT local file storage Marseille"},"location":{"latitude":50.62925,"longitude":3.057256},"country":250,"partnerships":[{"resourcepartnership":{"namespace":"default","peer_groups":{"c0cece97-7730-4c2a-8c20-a30944564106":["*"]},"pricing_profiles":[{"pricing":{"price":50,"currency":"EUR","buying_strategy":0,"time_pricing_strategy":0}}]}}]},"source":"/mnt/vol","local":true,"security_level":"public","size":500,"size_type":0,"encryption":true,"redundancy":"RAID5S","throughput":"r:300,w:350"}]},"storage_type":5,"acronym":"DC_myDC"}]
|
|
File diff suppressed because one or more lines are too long
@ -1,31 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
docker network create oc | true
|
|
||||||
|
|
||||||
docker compose down
|
|
||||||
cd ./tools && docker compose -f ./docker-compose.dev.yml up --force-recreate -d && cd ..
|
|
||||||
cd ./tools && docker compose -f ./docker-compose.traefik.yml up --force-recreate -d && cd ..
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
REPOS=(
|
|
||||||
"oc-auth"
|
|
||||||
"oc-catalog"
|
|
||||||
"oc-datacenter"
|
|
||||||
"oc-monitord"
|
|
||||||
"oc-peer"
|
|
||||||
"oc-shared"
|
|
||||||
"oc-scheduler"
|
|
||||||
"oc-schedulerd"
|
|
||||||
"oc-workflow"
|
|
||||||
"oc-workspace"
|
|
||||||
"oc-front"
|
|
||||||
)
|
|
||||||
for i in "${REPOS[@]}"
|
|
||||||
do
|
|
||||||
echo "Building $i"
|
|
||||||
docker kill $i | true
|
|
||||||
docker rm $i | true
|
|
||||||
cd ./$i
|
|
||||||
docker build . -t $i && docker compose up -d
|
|
||||||
cd ..
|
|
||||||
done
|
|
@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
docker network delete oc | true
|
|
||||||
|
|
||||||
docker compose -f ./tools/docker-compose.traefik.yml down
|
|
||||||
|
|
||||||
TOOLS=(
|
|
||||||
"mongo"
|
|
||||||
"mongo-express"
|
|
||||||
"nats"
|
|
||||||
"loki"
|
|
||||||
"grafana"
|
|
||||||
"hydra-client"
|
|
||||||
"hydra"
|
|
||||||
"keto"
|
|
||||||
"ldap"
|
|
||||||
)
|
|
||||||
|
|
||||||
for i in "${TOOLS[@]}"
|
|
||||||
do
|
|
||||||
echo "kill $i"
|
|
||||||
docker kill $i | true
|
|
||||||
docker rm $i | true
|
|
||||||
done
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
REPOS=(
|
|
||||||
"oc-auth"
|
|
||||||
"oc-catalog"
|
|
||||||
"oc-datacenter"
|
|
||||||
"oc-monitord"
|
|
||||||
"oc-peer"
|
|
||||||
"oc-shared"
|
|
||||||
"oc-scheduler"
|
|
||||||
"oc-schedulerd"
|
|
||||||
"oc-workflow"
|
|
||||||
"oc-workspace"
|
|
||||||
"oc-front"
|
|
||||||
)
|
|
||||||
for i in "${REPOS[@]}"
|
|
||||||
do
|
|
||||||
echo "Kill $i"
|
|
||||||
cd ./$i
|
|
||||||
docker kill $i | true
|
|
||||||
docker rm $i | true
|
|
||||||
make purge | true
|
|
||||||
cd ..
|
|
||||||
done
|
|
@ -1,8 +0,0 @@
|
|||||||
datasources:
|
|
||||||
- name: Loki
|
|
||||||
type: loki
|
|
||||||
access: proxy
|
|
||||||
url: http://loki:3100
|
|
||||||
isDefault: true
|
|
||||||
jsonData:
|
|
||||||
httpMethod: POST
|
|
@ -1,162 +0,0 @@
|
|||||||
version: '3.4'
|
|
||||||
|
|
||||||
services:
|
|
||||||
mongo:
|
|
||||||
image: 'mongo:latest'
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
ports:
|
|
||||||
- 27017:27017
|
|
||||||
container_name: mongo
|
|
||||||
volumes:
|
|
||||||
- oc-data:/data/db
|
|
||||||
- oc-data:/data/configdb
|
|
||||||
|
|
||||||
mongo-express:
|
|
||||||
image: "mongo-express:latest"
|
|
||||||
restart: always
|
|
||||||
depends_on:
|
|
||||||
- mongo
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
ports:
|
|
||||||
- 8081:8081
|
|
||||||
environment:
|
|
||||||
- ME_CONFIG_BASICAUTH_USERNAME=test
|
|
||||||
- ME_CONFIG_BASICAUTH_PASSWORD=test
|
|
||||||
nats:
|
|
||||||
image: 'nats:latest'
|
|
||||||
container_name: nats
|
|
||||||
ports:
|
|
||||||
- 4222:4222
|
|
||||||
command:
|
|
||||||
- "--debug"
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
loki:
|
|
||||||
image: 'grafana/loki'
|
|
||||||
container_name: loki
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.loki.entrypoints=web"
|
|
||||||
- "traefik.http.routers.loki.rule=PathPrefix(`/tools/loki`)"
|
|
||||||
- "traefik.http.services.loki.loadbalancer.server.port=3100"
|
|
||||||
- "traefik.http.middlewares.loki-stripprefix.stripprefix.prefixes=/tools/loki"
|
|
||||||
- "traefik.http.routers.loki.middlewares=loki-stripprefix"
|
|
||||||
- "traefik.http.middlewares.loki.forwardauth.address=http://oc-auth:8080/oc/forward"
|
|
||||||
ports :
|
|
||||||
- "3100:3100"
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
grafana:
|
|
||||||
image: 'grafana/grafana'
|
|
||||||
container_name: grafana
|
|
||||||
ports:
|
|
||||||
- '3000:3000'
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.grafana.entrypoints=web"
|
|
||||||
- "traefik.http.routers.grafana.rule=PathPrefix(`/tools/grafana`)"
|
|
||||||
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
|
||||||
- "traefik.http.middlewares.grafana-stripprefix.stripprefix.prefixes=/tools/grafana"
|
|
||||||
- "traefik.http.routers.grafana.middlewares=grafana-stripprefix"
|
|
||||||
- "traefik.http.middlewares.grafana.forwardauth.address=http://oc-auth:8080/oc/forward"
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
volumes:
|
|
||||||
- ./conf/grafana_data_source.yml:/etc/grafana/provisioning/datasources/datasource.yml
|
|
||||||
environment:
|
|
||||||
- GF_SECURITY_ADMIN_PASSWORD=pfnirt # Change this to anything but admin to not have a password change page at startup
|
|
||||||
- GF_SECURITY_ADMIN_USER=admin
|
|
||||||
- GF_SECURITY_DISABLE_INITIAL_ADMIN_PASSWORD_CHANGE=true
|
|
||||||
hydra-client:
|
|
||||||
image: oryd/hydra:v2.2.0
|
|
||||||
container_name: hydra-client
|
|
||||||
environment:
|
|
||||||
HYDRA_ADMIN_URL: http://hydra:4445
|
|
||||||
ORY_SDK_URL: http://hydra:4445
|
|
||||||
command:
|
|
||||||
- create
|
|
||||||
- oauth2-client
|
|
||||||
- --skip-tls-verify
|
|
||||||
- --name
|
|
||||||
- test-client
|
|
||||||
- --secret
|
|
||||||
- oc-auth-got-secret
|
|
||||||
- --response-type
|
|
||||||
- id_token,token,code
|
|
||||||
- --grant-type
|
|
||||||
- implicit,refresh_token,authorization_code,client_credentials
|
|
||||||
- --scope
|
|
||||||
- openid,profile,email,roles
|
|
||||||
- --token-endpoint-auth-method
|
|
||||||
- client_secret_post
|
|
||||||
- --redirect-uri
|
|
||||||
- http://localhost:3000
|
|
||||||
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
deploy:
|
|
||||||
restart_policy:
|
|
||||||
condition: none
|
|
||||||
depends_on:
|
|
||||||
- hydra
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://hydra:4445"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 10
|
|
||||||
hydra:
|
|
||||||
container_name: hydra
|
|
||||||
image: oryd/hydra:v2.2.0
|
|
||||||
environment:
|
|
||||||
SECRETS_SYSTEM: oc-auth-got-secret
|
|
||||||
LOG_LEAK_SENSITIVE_VALUES: true
|
|
||||||
# OAUTH2_TOKEN_HOOK_URL: http://oc-auth:8080/oc/claims
|
|
||||||
URLS_SELF_ISSUER: http://hydra:4444
|
|
||||||
URLS_SELF_PUBLIC: http://hydra:4444
|
|
||||||
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_SCOPES: profile,email,phone,roles
|
|
||||||
WEBFINGER_OIDC_DISCOVERY_SUPPORTED_CLAIMS: name,family_name,given_name,nickname,email,phone_number
|
|
||||||
DSN: memory
|
|
||||||
command: serve all --dev
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
ports:
|
|
||||||
- "4444:4444"
|
|
||||||
- "4445:4445"
|
|
||||||
deploy:
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
ldap:
|
|
||||||
image: pgarrett/ldap-alpine
|
|
||||||
container_name: ldap
|
|
||||||
volumes:
|
|
||||||
- "./ldap.ldif:/ldif/ldap.ldif"
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
ports:
|
|
||||||
- "390:389"
|
|
||||||
deploy:
|
|
||||||
restart_policy:
|
|
||||||
condition: on-failure
|
|
||||||
keto:
|
|
||||||
image: oryd/keto:v0.7.0-alpha.1-sqlite
|
|
||||||
ports:
|
|
||||||
- "4466:4466"
|
|
||||||
- "4467:4467"
|
|
||||||
command: serve -c /home/ory/keto.yml
|
|
||||||
restart: on-failure
|
|
||||||
volumes:
|
|
||||||
- type: bind
|
|
||||||
source: .
|
|
||||||
target: /home/ory
|
|
||||||
container_name: keto
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
oc-data:
|
|
||||||
|
|
||||||
networks:
|
|
||||||
oc:
|
|
||||||
external: true
|
|
@ -1,24 +0,0 @@
|
|||||||
version: '3.4'
|
|
||||||
|
|
||||||
services:
|
|
||||||
traefik:
|
|
||||||
image: traefik:v2.10.4
|
|
||||||
container_name: traefik
|
|
||||||
restart: unless-stopped
|
|
||||||
networks:
|
|
||||||
- oc
|
|
||||||
command:
|
|
||||||
- "--api.insecure=true"
|
|
||||||
- "--providers.docker=true"
|
|
||||||
- "--entrypoints.web.address=:80"
|
|
||||||
ports:
|
|
||||||
- "80:80" # Expose Traefik on port 80
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
oc-data:
|
|
||||||
|
|
||||||
networks:
|
|
||||||
oc:
|
|
||||||
external: true
|
|
@ -1,18 +0,0 @@
|
|||||||
version: v0.6.0-alpha.1
|
|
||||||
|
|
||||||
log:
|
|
||||||
level: debug
|
|
||||||
|
|
||||||
namespaces:
|
|
||||||
- id: 0
|
|
||||||
name: open-cloud
|
|
||||||
|
|
||||||
dsn: memory
|
|
||||||
|
|
||||||
serve:
|
|
||||||
read:
|
|
||||||
host: 0.0.0.0
|
|
||||||
port: 4466
|
|
||||||
write:
|
|
||||||
host: 0.0.0.0
|
|
||||||
port: 4467
|
|
@ -1,24 +0,0 @@
|
|||||||
dn: uid=admin,ou=Users,dc=example,dc=com
|
|
||||||
objectClass: inetOrgPerson
|
|
||||||
cn: Admin
|
|
||||||
sn: Istrator
|
|
||||||
uid: admin
|
|
||||||
userPassword: admin
|
|
||||||
mail: admin@example.com
|
|
||||||
ou: Users
|
|
||||||
|
|
||||||
dn: ou=AppRoles,dc=example,dc=com
|
|
||||||
objectClass: organizationalunit
|
|
||||||
ou: AppRoles
|
|
||||||
description: AppRoles
|
|
||||||
|
|
||||||
dn: ou=App1,ou=AppRoles,dc=example,dc=com
|
|
||||||
objectClass: organizationalunit
|
|
||||||
ou: App1
|
|
||||||
description: App1
|
|
||||||
|
|
||||||
dn: cn=traveler,ou=App1,ou=AppRoles,dc=example,dc=com
|
|
||||||
objectClass: groupofnames
|
|
||||||
cn: traveler
|
|
||||||
description: traveler
|
|
||||||
member: uid=admin,ou=Users,dc=example,dc=com
|
|
@ -1,53 +0,0 @@
|
|||||||
@startuml Arch Diagram
|
|
||||||
|
|
||||||
top to bottom direction
|
|
||||||
|
|
||||||
component front as "oc-front" #MistyRose
|
|
||||||
|
|
||||||
component api as "oc-api" #BlueViolet
|
|
||||||
component auth as "oc-auth" #BlueViolet
|
|
||||||
|
|
||||||
component catalog as "oc-catalog" #MistyRose
|
|
||||||
component workspace as "oc-workspace" #MistyRose
|
|
||||||
component workflow as "oc-workflow" #MistyRose
|
|
||||||
component calendarIn as "oc-calendar-in" #MistyRose
|
|
||||||
component calendarOut as "oc-calendar-out" #MistyRose
|
|
||||||
component stat as "oc-status" #MistyRose
|
|
||||||
|
|
||||||
component disco as "oc-discovery" #MistyRose
|
|
||||||
component agg as "oc-aggregator" #MistyRose
|
|
||||||
|
|
||||||
component scheduler as "oc-scheduler" #LightYellow
|
|
||||||
component monitor as "oc-monitor" #LightYellow
|
|
||||||
|
|
||||||
database rd as "Nats" #Green
|
|
||||||
database zn as "Zinc" #Green
|
|
||||||
database loki as "Loki" #Green
|
|
||||||
database mongo as "MongoDB" #Green
|
|
||||||
database nats as "Nats" #Green
|
|
||||||
|
|
||||||
front -- api
|
|
||||||
|
|
||||||
api -- auth : auth user
|
|
||||||
api -- catalog : local search
|
|
||||||
api -- workspace : store user data
|
|
||||||
api -- workflow
|
|
||||||
api -- calendarIn
|
|
||||||
api -- calendarOut
|
|
||||||
api -- stat
|
|
||||||
|
|
||||||
catalog -- disco
|
|
||||||
catalog -- agg
|
|
||||||
|
|
||||||
scheduler -- monitor
|
|
||||||
scheduler -- catalog
|
|
||||||
|
|
||||||
rd -- scheduler
|
|
||||||
loki -- monitor
|
|
||||||
|
|
||||||
catalog -- mongo : store resources available for users
|
|
||||||
workspace -- mongo : store resources allocated to a workspace
|
|
||||||
workflow -- mongo : store workflow
|
|
||||||
calendarOut -- mongo : store booking informations for this dc
|
|
||||||
|
|
||||||
@enduml
|
|
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
## Deploy the opencloud chart
|
|
||||||
|
|
||||||
```
|
|
||||||
./start.sh <mode: dev|prod default:dev> <branche | default:main>
|
|
||||||
```
|
|
||||||
|
|
||||||
Feel free to modify/create a new opencloud/dev-values.yaml. Provided setup should work out of the box, but is not suitable for production usage.
|
|
||||||
|
|
||||||
## Hostname settings
|
|
||||||
|
|
||||||
Edit your /etc/hosts file, and add following line:
|
|
||||||
|
|
||||||
```
|
|
||||||
127.0.0.1 beta.opencloud.com
|
|
||||||
```
|
|
||||||
|
|
||||||
## Done
|
|
||||||
|
|
||||||
Everything should be operational now, go to http://beta.opencloud.com and enjoy the ride
|
|
||||||
|
|
||||||
# Prebuilt microservices deployment procedure
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
# First steps
|
|
||||||
|
|
||||||
Go to http://beta.opencloud.com/users
|
|
||||||
|
|
||||||
Log in using default user/password combo ldapadmin/ldapadmin
|
|
||||||
|
|
||||||
Create a new user, or change the default one
|
|
||||||
|
|
||||||
Go to http://beta.opencloud.com
|
|
||||||
|
|
||||||
Log in using your fresh credentials
|
|
||||||
|
|
||||||
Do stuff
|
|
||||||
|
|
||||||
You can go to http://beta.opencloud.com/mongoexpress
|
|
||||||
|
|
||||||
... for mongo express web client access (default login/password is test/testme)
|
|
||||||
|
|
||||||
You can go to http://localhost/dashboard/
|
|
||||||
|
|
||||||
... for access to Traefik reverse proxy front-end
|
|
21
k8s/start.sh
21
k8s/start.sh
@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
mode=${1:-dev}
|
|
||||||
branch=${2:-main}
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
if [ ! -d "oc-k8s" ]; then
|
|
||||||
echo "Cloning repository: $repo_name"
|
|
||||||
git clone "https://cloud.o-forge.io/core/oc-k8s.git"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Error cloning oc-k8s"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Repository 'oc-k8s' already exists. Pulling latest changes..."
|
|
||||||
cd "oc-k8s" && git checkout $branch && git pull
|
|
||||||
|
|
||||||
./create_kind_cluster.sh
|
|
||||||
./clone_opencloud_microservices.sh $branch
|
|
||||||
./build_opencloud_microservices.sh
|
|
||||||
./install.sh $mode
|
|
20
k8s/stop.sh
20
k8s/stop.sh
@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
mode=${1:-dev}
|
|
||||||
branch=${2:-main}
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
if [ ! -d "oc-k8s" ];
|
|
||||||
echo "Cloning repository: $repo_name"
|
|
||||||
git clone "https://cloud.o-forge.io/core/oc-k8s.git"
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Error cloning oc-k8s"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Repository 'oc-k8s' already exists. Pulling latest changes..."
|
|
||||||
cd "oc-k8s" && git checkout $branch && git pull
|
|
||||||
|
|
||||||
./uninstall.sh $mode
|
|
||||||
./delete_kind_cluster.sh
|
|
||||||
|
|
3
offline/latest.yml
Normal file
3
offline/latest.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
version: 0.1.0
|
41
offline/oc_1.0.yml
Normal file
41
offline/oc_1.0.yml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
# Définition d'une version
|
||||||
|
|
||||||
|
version: 1.0
|
||||||
|
|
||||||
|
tools:
|
||||||
|
- name: kubectl
|
||||||
|
url: https://dl.k8s.io/release/%s/bin/linux/amd64/kubectl
|
||||||
|
version: v1.31.0
|
||||||
|
- name: helm
|
||||||
|
url: https://get.helm.sh/helm-%s-linux-amd64.tar.gz
|
||||||
|
version: v3.16.0
|
||||||
|
|
||||||
|
# helm install my-release <repo>/<chart>
|
||||||
|
opencloud:
|
||||||
|
- repository:
|
||||||
|
name: bitnami
|
||||||
|
url: https://charts.bitnami.com/bitnami # Repository des Charts
|
||||||
|
charts:
|
||||||
|
- name: wordpress
|
||||||
|
chart: bitnami/wordpress
|
||||||
|
version: 23.1.0
|
||||||
|
values: {}
|
||||||
|
helm_opts: --wait-for-jobs
|
||||||
|
helm_filevalues: values-init.yml
|
||||||
|
|
||||||
|
- name: phpmyadmin
|
||||||
|
chart: bitnami/phpmyadmin
|
||||||
|
version: 17.0.4
|
||||||
|
values: {}
|
||||||
|
|
||||||
|
- charts:
|
||||||
|
- name: mongo
|
||||||
|
chart: ../oc-mongo/mongo
|
||||||
|
|
||||||
|
- charts:
|
||||||
|
- name: myfirstrelease
|
||||||
|
chart: myfirstchart-0.1.0.tgz
|
||||||
|
url: https://zzzz/myfirstchart-0.1.0.tgz
|
||||||
|
|
||||||
|
# helm install myfirstrelease myfirstchart-0.1.0.tgz
|
3
publish/.gitignore
vendored
Normal file
3
publish/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
go.sum
|
||||||
|
*_
|
||||||
|
.coverage.*
|
3
publish/go.mod
Normal file
3
publish/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module oc-publish
|
||||||
|
|
||||||
|
go 1.22.2
|
83
publish/main.go
Normal file
83
publish/main.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"io/ioutil"
|
||||||
|
"encoding/base64"
|
||||||
|
"oc-publish/releases"
|
||||||
|
"oc-publish/occonst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
version := os.Args[1]
|
||||||
|
|
||||||
|
fmt.Printf(" >> oc-publish :\n")
|
||||||
|
|
||||||
|
fmt.Printf(" << Url : %s/%s\n", occonst.PUBLISH_URL, occonst.PUBLISH_REPO)
|
||||||
|
|
||||||
|
fmt.Printf(" << version : %s %s\n", version, occonst.PUBLISH_BRANCH)
|
||||||
|
|
||||||
|
vversion := fmt.Sprintf("v%s", version)
|
||||||
|
existe, _ := releases.CheckRelease(vversion)
|
||||||
|
|
||||||
|
if existe == false {
|
||||||
|
err := releases.CreateRelease(vversion, occonst.PUBLISH_BRANCH)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idRelease, _ := releases.GetReleaseId(vversion)
|
||||||
|
if existe == true {
|
||||||
|
fmt.Println(fmt.Sprintf(" << Release existante : %d ", idRelease))
|
||||||
|
} else {
|
||||||
|
fmt.Println(fmt.Sprintf(" << Release crée : %d ", idRelease))
|
||||||
|
}
|
||||||
|
|
||||||
|
assetname := "oc-deploy.base64"
|
||||||
|
binary := fmt.Sprintf("../bin/oc-deploy")
|
||||||
|
binary64 := fmt.Sprintf("../%s", assetname)
|
||||||
|
err := createBinaryFile(binary, binary64)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
idAsset, _ := releases.GetAssetId(idRelease, assetname)
|
||||||
|
if idAsset == 0 {
|
||||||
|
fmt.Println(fmt.Sprintf(" << Ajout Asset : %s", assetname))
|
||||||
|
err := releases.CreateAsset(idRelease, binary64, assetname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(fmt.Sprintf(" << Mise à jour : %s (idAsset=%d) ", assetname, idAsset))
|
||||||
|
err := releases.UpdateAsset(idRelease, idAsset, binary64, assetname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func createBinaryFile(source string, dest string) error {
|
||||||
|
fout, _ := os.Create(dest)
|
||||||
|
defer fout.Close()
|
||||||
|
|
||||||
|
byteValue, err := ioutil.ReadFile(source)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("64e", err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data64 := base64.StdEncoding.EncodeToString(byteValue)
|
||||||
|
fout.Write([]byte(data64))
|
||||||
|
return nil
|
||||||
|
}
|
18
publish/occonst/variables.go
Normal file
18
publish/occonst/variables.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package occonst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var PUBLISH_URL = getenv("PUBLISH_URL", "https://cloud.o-forge.io")
|
||||||
|
var PUBLISH_REPO = getenv("PUBLISH_REPO", "core/oc-deploy")
|
||||||
|
var PUBLISH_TOKEN = getenv("PUBLISH_TOKEN", "")
|
||||||
|
var PUBLISH_BRANCH = getenv("PUBLISH_BRANCH", "main")
|
||||||
|
|
||||||
|
func getenv(key string, defaut string) string {
|
||||||
|
value := os.Getenv(key)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return defaut
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
6
publish/release.txt
Normal file
6
publish/release.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Version %s d'OpenCloud
|
||||||
|
|
||||||
|
```
|
||||||
|
wget %s/%s/releases/download/%s/oc-deploy.base64 -O - | base64 -d > oc-deploy
|
||||||
|
chmod u+x ./oc-deploy
|
||||||
|
```
|
145
publish/releases/assets.go
Normal file
145
publish/releases/assets.go
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package releases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"mime/multipart"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"oc-publish/occonst"
|
||||||
|
)
|
||||||
|
|
||||||
|
type assetStruct struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAssetId(idRelease int, name string) (int, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/%d/assets",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO,
|
||||||
|
idRelease)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return -2, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []assetStruct
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return -3, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ele := range data {
|
||||||
|
if ele.Name == name {
|
||||||
|
return ele.Id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// curl -X 'POST' \
|
||||||
|
// 'https://cloud.o-forge.io/api/v1/repos/core/oc-deploy/releases/2/assets?name=zzzz' \
|
||||||
|
// -H 'accept: application/json' \
|
||||||
|
// -H 'Content-Type: multipart/form-data' \
|
||||||
|
// -F 'attachment=oc-deploy'
|
||||||
|
func CreateAsset(idRelease int, filename string, name string) (error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/%d/assets?name=%s&token=%s",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO,
|
||||||
|
idRelease,
|
||||||
|
name,
|
||||||
|
occonst.PUBLISH_TOKEN)
|
||||||
|
|
||||||
|
err := uploadFile(url, "attachment", filename)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateAsset(idRelease int, idAsset int, filename string, name string) (error) {
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/%d/assets/%d?token=%s",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO,
|
||||||
|
idRelease,
|
||||||
|
idAsset,
|
||||||
|
occonst.PUBLISH_TOKEN)
|
||||||
|
|
||||||
|
// Create client
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
// Create request
|
||||||
|
req, err := http.NewRequest("DELETE", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch Request
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Read Response Body
|
||||||
|
respBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
|
||||||
|
return CreateAsset(idRelease, filename, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadFile(url string, paramName string, filePath string) error {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
part, err := writer.CreateFormFile(paramName, filepath.Base(filePath))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(part, file)
|
||||||
|
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest("POST", url, body)
|
||||||
|
request.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
request.Header.Add("accept", "application/json")
|
||||||
|
client := &http.Client{}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(109, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
if response.StatusCode > 400 {
|
||||||
|
return fmt.Errorf(response.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err1 := io.ReadAll(response.Body)
|
||||||
|
|
||||||
|
// Handle the server response...
|
||||||
|
return err1
|
||||||
|
}
|
126
publish/releases/release.go
Normal file
126
publish/releases/release.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package releases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"oc-publish/occonst"
|
||||||
|
)
|
||||||
|
|
||||||
|
type checkStruct struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Id int `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckRelease(version string) (bool, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data []checkStruct
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ele := range data {
|
||||||
|
if ele.Name == version {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return data.Name != "", nil
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetReleaseId(version string) (int, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/tags/%s",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO,
|
||||||
|
version)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data checkStruct
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// curl -X 'POST' \
|
||||||
|
// 'https://cloud.o-forge.io/api/v1/repos/na/oc-version/releases?token=sss' \
|
||||||
|
// -H 'accept: application/json' \
|
||||||
|
// -H 'Content-Type: application/json' \
|
||||||
|
// -d '{
|
||||||
|
// "body": "string",
|
||||||
|
// "draft": true,
|
||||||
|
// "name": "string",
|
||||||
|
// "prerelease": true,
|
||||||
|
// "tag_name": "string",
|
||||||
|
// "target_commitish": "string"
|
||||||
|
// }'
|
||||||
|
func CreateRelease(version string, branch string) (error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases?token=%s",
|
||||||
|
occonst.PUBLISH_URL,
|
||||||
|
occonst.PUBLISH_REPO,
|
||||||
|
occonst.PUBLISH_TOKEN)
|
||||||
|
|
||||||
|
releasebytes, err := ioutil.ReadFile("release.txt")
|
||||||
|
releasetxt := string(releasebytes)
|
||||||
|
releasetxt = strings.Replace(releasetxt, "\n", "\\n", -1)
|
||||||
|
releasetxt = fmt.Sprintf(releasetxt, version, occonst.PUBLISH_URL, occonst.PUBLISH_REPO, version)
|
||||||
|
|
||||||
|
body := fmt.Sprintf(`{
|
||||||
|
"body": "%s",
|
||||||
|
"draft": false,
|
||||||
|
"name": "%s",
|
||||||
|
"prerelease": false,
|
||||||
|
"tag_name": "%s",
|
||||||
|
"target_commitish": "%s"
|
||||||
|
}`, releasetxt, version, version, branch)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("POST", url, strings.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request.Header.Add("accept", "application/json")
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
_, err1 := io.ReadAll(response.Body)
|
||||||
|
// cnt, err1 := io.ReadAll(response.Body)
|
||||||
|
// fmt.Println(string(cnt))
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
5
src/.gitignore
vendored
Normal file
5
src/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
go.sum
|
||||||
|
*_
|
||||||
|
.coverage.*
|
||||||
|
.*.log
|
||||||
|
workspace_*
|
101
src/Makefile
Normal file
101
src/Makefile
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
BIN_NAME := oc-deploy
|
||||||
|
|
||||||
|
BIN_OPTS :=
|
||||||
|
|
||||||
|
##################
|
||||||
|
|
||||||
|
SOURCES := $(wildcard *.go) $(wildcard */*.go)
|
||||||
|
BIN_DIR = ../bin/
|
||||||
|
|
||||||
|
PLUGINS := $(wildcard ../plugins/*/*.go)
|
||||||
|
OBJS := ${PLUGINS:.go=.so}
|
||||||
|
|
||||||
|
##################
|
||||||
|
DATE := $(shell date --iso-8601)
|
||||||
|
GOVERSION := $(shell go version)
|
||||||
|
VERSION := $(shell git describe --tags --abbrev=8 --dirty --always --long)
|
||||||
|
PREFIX := oc-deploy/occonst
|
||||||
|
|
||||||
|
LDFLAGS := "-X '${PREFIX}.Version=${VERSION}' -X '${PREFIX}.Date=${DATE}' -X '${PREFIX}.GoVersion=${GOVERSION}'"
|
||||||
|
|
||||||
|
##################
|
||||||
|
|
||||||
|
%.so: %.go
|
||||||
|
go build -buildmode=plugin -o $@ $<
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo
|
||||||
|
@echo 'Usage:'
|
||||||
|
@echo ' make build Génère les exécutables.'
|
||||||
|
@echo ' make get-deps Dependency download'
|
||||||
|
|
||||||
|
@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 run_version 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 exec_version exécutable'
|
||||||
|
|
||||||
|
@echo ' make test Test'
|
||||||
|
@echo ' make clean Clean the directory tree.'
|
||||||
|
@echo
|
||||||
|
|
||||||
|
@echo ' DATE ${DATE}'
|
||||||
|
@echo ' GOVERSION ${GOVERSION}'
|
||||||
|
@echo ' VERSION ${VERSION}'
|
||||||
|
@echo
|
||||||
|
|
||||||
|
${BIN_DIR}/${BIN_NAME}: ${SOURCES} $(OBJS)
|
||||||
|
go build -o ${BIN_DIR}/${BIN_NAME} -ldflags ${LDFLAGS}
|
||||||
|
|
||||||
|
get-deps:
|
||||||
|
@go mod tidy
|
||||||
|
|
||||||
|
build: ${BIN_DIR}/${BIN_NAME}
|
||||||
|
|
||||||
|
run:
|
||||||
|
@go run main.go ${BIN_OPTS}
|
||||||
|
|
||||||
|
run_generate:
|
||||||
|
@go run main.go generate ${BIN_OPTS}
|
||||||
|
|
||||||
|
run_install:
|
||||||
|
@go run main.go install ${BIN_OPTS}
|
||||||
|
|
||||||
|
run_uninstall:
|
||||||
|
@go run main.go uninstall ${BIN_OPTS}
|
||||||
|
|
||||||
|
run_version:
|
||||||
|
@go run main.go version
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
exec_version: ${BIN_DIR}/${BIN_NAME} $(OBJS)
|
||||||
|
@${BIN_DIR}/${BIN_NAME} version
|
||||||
|
|
||||||
|
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_*
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test_%:
|
||||||
|
go test oc-deploy/$(subst test_,,$@) -coverprofile=.coverage.out -v
|
||||||
|
@go tool cover -html=.coverage.out -o .coverage.html
|
||||||
|
|
||||||
|
test:
|
||||||
|
@go test ./... -coverprofile=.coverage.out -v
|
||||||
|
go tool cover -html=.coverage.out -o .coverage.html
|
58
src/README.md
Normal file
58
src/README.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Purpose
|
||||||
|
|
||||||
|
**oc-deploy** is a tool to deploy (with **helm**) all component of **OpenCloud**.
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
To init:
|
||||||
|
|
||||||
|
```
|
||||||
|
make get-deps
|
||||||
|
```
|
||||||
|
|
||||||
|
## To build
|
||||||
|
|
||||||
|
```
|
||||||
|
make build
|
||||||
|
```
|
||||||
|
|
||||||
|
## To run
|
||||||
|
|
||||||
|
```
|
||||||
|
make run_install [BIN_OPTS="<args>"]
|
||||||
|
make run_uninstall [BIN_OPTS="<args>"]
|
||||||
|
make run_generate [BIN_OPTS="<args>"]
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
make exec_install [BIN_OPTS="<args>"]
|
||||||
|
make exec_uninstall [BIN_OPTS="<args>"]
|
||||||
|
make exec_generate [BIN_OPTS="<args>"]
|
||||||
|
```
|
||||||
|
|
||||||
|
# To Test
|
||||||
|
|
||||||
|
All packages:
|
||||||
|
|
||||||
|
```
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
or to test an specific package:
|
||||||
|
|
||||||
|
```
|
||||||
|
make test_<package>
|
||||||
|
```
|
||||||
|
|
||||||
|
Test generate _.coverage.html_ file to view the coverage of test.
|
||||||
|
|
||||||
|
## To Publish
|
||||||
|
|
||||||
|
Cf : ../publish
|
||||||
|
|
||||||
|
## Divers
|
||||||
|
|
||||||
|
* Latest version for _kubectl_: https://dl.k8s.io/release/stable.txt
|
||||||
|
* Release for _helm_: https://github.com/helm/helm/releases
|
51
src/chart/conf.go
Normal file
51
src/chart/conf.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package chart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChartData struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Chart string `yaml:"chart"`
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
|
||||||
|
Opts string `yaml:"helm_opts"`
|
||||||
|
Values map[string]string `yaml:"helm_values"`
|
||||||
|
FileValues []string `yaml:"helm_filevalues"`
|
||||||
|
|
||||||
|
Overwrite string `yaml:"helm_overwrite"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type repoData struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
ForceUpdate bool `yaml:"forceupdate"`
|
||||||
|
Opts string `yaml:"opts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ociData struct {
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChartRepoData struct {
|
||||||
|
Repository repoData `yaml:"repository"`
|
||||||
|
Oci ociData `yaml:"oci"`
|
||||||
|
Charts []ChartData `yaml:"charts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type chartsRepoParse struct {
|
||||||
|
Charts []ChartRepoData `yaml:"opencloud"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromConfigFile(filename string) ([]ChartRepoData, error) {
|
||||||
|
yamlFile, _ := os.ReadFile(filename)
|
||||||
|
|
||||||
|
var data chartsRepoParse
|
||||||
|
err := yaml.Unmarshal(yamlFile, &data)
|
||||||
|
if err != nil {
|
||||||
|
return data.Charts, err
|
||||||
|
}
|
||||||
|
return data.Charts, nil
|
||||||
|
}
|
63
src/chart/conf_test.go
Normal file
63
src/chart/conf_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package chart
|
||||||
|
|
||||||
|
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, "bitnami", data[0].Repository.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "https://charts.bitnami.com/bitnami", data[0].Repository.Url, "FromConfigFile error")
|
||||||
|
|
||||||
|
wordpress := data[0].Charts[0]
|
||||||
|
assert.Equal(t, "wordpress", wordpress.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "bitnami/wordpress", wordpress.Chart, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "23.1.0", wordpress.Version, "FromConfigFile error")
|
||||||
|
assert.Equal(t, 0, len(wordpress.FileValues), "FromConfigFile error")
|
||||||
|
assert.Equal(t, 0, len(wordpress.Values), "FromConfigFile error")
|
||||||
|
|
||||||
|
phpmyadmin := data[0].Charts[1]
|
||||||
|
assert.Equal(t, "phpmyadmin", phpmyadmin.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "bitnami/phpmyadmin", phpmyadmin.Chart,"FromConfigFile error")
|
||||||
|
assert.Equal(t, "17.0.4", phpmyadmin.Version, "FromConfigFile error")
|
||||||
|
assert.Equal(t, 2, len(phpmyadmin.FileValues), "FromConfigFile error")
|
||||||
|
assert.Equal(t, 1, len(phpmyadmin.Values), "FromConfigFile error")
|
||||||
|
|
||||||
|
data1 := data[1]
|
||||||
|
assert.Equal(t, "", data1.Repository.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "", data1.Repository.Url, "FromConfigFile error")
|
||||||
|
|
||||||
|
myfirstrelease := data1.Charts[0]
|
||||||
|
assert.Equal(t, "myfirstrelease", myfirstrelease.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "https://zzzz/myfirstchart-0.1.0.tgz", myfirstrelease.Url, "FromConfigFile error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TestReadConfChartOverwrite(t *testing.T){
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "oc_overwrite.yml")
|
||||||
|
|
||||||
|
assert.FileExists(t, src, "FromConfigFile error")
|
||||||
|
|
||||||
|
data, _ := FromConfigFile(src)
|
||||||
|
// Nombre de lettres
|
||||||
|
assert.Equal(t, 70, len(data[0].Charts[0].Overwrite), "TestReadConfChartOverwrite error")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestReadConfChartOci(t *testing.T) {
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "oc_oci.yml")
|
||||||
|
|
||||||
|
assert.FileExists(t, src, "FromConfigFile error")
|
||||||
|
|
||||||
|
data, _ := FromConfigFile(src)
|
||||||
|
assert.Equal(t, "", data[0].Repository.Name, "FromConfigFile error")
|
||||||
|
assert.Equal(t, "oci://harbor.dtf/dev", data[0].Oci.Url, "FromConfigFile error")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
23
src/chart/main_test.go
Normal file
23
src/chart/main_test.go
Normal 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)
|
||||||
|
}
|
104
src/cmd/args.go
Normal file
104
src/cmd/args.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// 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
|
||||||
|
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 {
|
||||||
|
log.Log().Info().Msg("oc-deploy :")
|
||||||
|
return InstallCmd(context, version, modules)
|
||||||
|
},
|
||||||
|
Example: "oc-deploy install --version 0.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 {
|
||||||
|
log.Log().Info().Msg("oc-deploy :")
|
||||||
|
return UninstallCmd(context, modules)
|
||||||
|
},
|
||||||
|
Example: "oc-deploy uninstall --context ex1",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func cobraGenerateCmd() *cobra.Command{
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "generate",
|
||||||
|
Short: "generate",
|
||||||
|
Long: "generate",
|
||||||
|
Args: cobra.MaximumNArgs(0),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
log.Log().Info().Msg("oc-deploy :")
|
||||||
|
return GenerateCmd(context, version)
|
||||||
|
},
|
||||||
|
Example: "oc-deploy generate --version 0.1.0 --context ex1",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cobraVersionCmd() *cobra.Command{
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "version",
|
||||||
|
Long: "Get Version",
|
||||||
|
Args: cobra.MaximumNArgs(0),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return VersionCmd()
|
||||||
|
},
|
||||||
|
Example: "oc-deploy version",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
|
||||||
|
log.Log().Debug().Msg("Execute")
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{Use: "oc-deploy"}
|
||||||
|
|
||||||
|
var cmdInstall = cobraInstallCmd()
|
||||||
|
var cmdUninstall = cobraUninstallCmd()
|
||||||
|
var cmdGenerate = cobraGenerateCmd()
|
||||||
|
var cmdVersion = cobraVersionCmd()
|
||||||
|
|
||||||
|
cmdInstall.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context")
|
||||||
|
cmdInstall.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")
|
||||||
|
cmdUninstall.Flags().StringArrayVarP(&modules, "modules", "m", []string{}, "modules, ...")
|
||||||
|
|
||||||
|
cmdGenerate.Flags().StringVarP(&context, "context", "c", "opencloud", "Nom du context")
|
||||||
|
cmdGenerate.Flags().StringVarP(&version, "version", "v", "latest", "Version")
|
||||||
|
|
||||||
|
rootCmd.AddCommand(cmdInstall)
|
||||||
|
rootCmd.AddCommand(cmdUninstall)
|
||||||
|
rootCmd.AddCommand(cmdGenerate)
|
||||||
|
rootCmd.AddCommand(cmdVersion)
|
||||||
|
|
||||||
|
cobra.CheckErr(rootCmd.Execute())
|
||||||
|
|
||||||
|
}
|
9
src/cmd/args_test.go
Normal file
9
src/cmd/args_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecute(t *testing.T) {
|
||||||
|
Execute()
|
||||||
|
}
|
23
src/cmd/generateCmd.go
Normal file
23
src/cmd/generateCmd.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
|
||||||
|
// "oc-deploy/versionOc"
|
||||||
|
"oc-deploy/install"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateCmd(prcontextoject string, version string) error {
|
||||||
|
log.Log().Info().Msg("Generate >> ")
|
||||||
|
|
||||||
|
workspace := fmt.Sprintf("workspace_%s", context)
|
||||||
|
|
||||||
|
obj := install.InstallClass{Workspace: workspace, Version: version}
|
||||||
|
_, err := obj.NewGenerate()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
51
src/cmd/installCmd.go
Normal file
51
src/cmd/installCmd.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
|
||||||
|
"oc-deploy/install"
|
||||||
|
)
|
||||||
|
|
||||||
|
func InstallCmd(context string, version string, modules []string) error {
|
||||||
|
log.Log().Info().Msg("Install >> ")
|
||||||
|
|
||||||
|
log.Log().Info().Msg(" << Contexte : " + context)
|
||||||
|
if len(modules) > 0 {
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Modules : %s", modules))
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace := fmt.Sprintf("workspace_%s", context)
|
||||||
|
obj := install.InstallClass{Workspace: workspace, Version: version}
|
||||||
|
|
||||||
|
file, err := obj.NewInstall()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Version : %s", obj.Version))
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> Config : %s", file))
|
||||||
|
|
||||||
|
err = obj.Tools()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.SetCommands()
|
||||||
|
|
||||||
|
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.InstallCharts(modules)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
41
src/cmd/installCmd_test.go
Normal file
41
src/cmd/installCmd_test.go
Normal 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")
|
||||||
|
}
|
47
src/cmd/uninstallCmd.go
Normal file
47
src/cmd/uninstallCmd.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
|
||||||
|
"oc-deploy/install"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UninstallCmd(context string, modules []string) error {
|
||||||
|
log.Log().Info().Msg("Uninstall >> ")
|
||||||
|
|
||||||
|
log.Log().Info().Msg(" << Contexte : " + context)
|
||||||
|
if len(modules) > 0 {
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Modules : %s", modules))
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace := fmt.Sprintf("workspace_%s", context)
|
||||||
|
obj := install.InstallClass{Workspace: workspace}
|
||||||
|
|
||||||
|
file, err := obj.NewUninstall()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Version : %s", obj.Version))
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> Config : %s", file))
|
||||||
|
|
||||||
|
err = obj.Tools()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.SetCommands()
|
||||||
|
|
||||||
|
err = obj.K8s(context)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = obj.UninstallCharts(modules)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Fatal().Msg(" >> " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
41
src/cmd/uninstallCmd_test.go
Normal file
41
src/cmd/uninstallCmd_test.go
Normal 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")
|
||||||
|
}
|
19
src/cmd/versionCmd.go
Normal file
19
src/cmd/versionCmd.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"oc-deploy/occonst"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VersionCmd() error {
|
||||||
|
|
||||||
|
version := occonst.Version
|
||||||
|
date := occonst.Date
|
||||||
|
goversion := occonst.GoVersion
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(fmt.Sprintf("Version : %s (%s) ; GoVersion : %s", version, date, goversion))
|
||||||
|
fmt.Println(version)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
25
src/go.mod
Normal file
25
src/go.mod
Normal 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
|
||||||
|
)
|
169
src/helm/chart.go
Normal file
169
src/helm/chart.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
"encoding/json"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HelmChart struct {
|
||||||
|
Bin string
|
||||||
|
Name string
|
||||||
|
Chart string
|
||||||
|
Version string
|
||||||
|
Url string
|
||||||
|
|
||||||
|
Workspace string
|
||||||
|
Opts string
|
||||||
|
Values map[string]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 HelmCommand) ChartInstall(data HelmChart) (string, error) {
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
existe, err := this.chartExists(data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if existe {
|
||||||
|
return "Existe déjà", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ficChart := data.Chart
|
||||||
|
// Recherche locale
|
||||||
|
if _, err := os.Stat(ficChart); err != nil {
|
||||||
|
} else {
|
||||||
|
// Recherche voa le Workspace
|
||||||
|
ficChart := filepath.Join(data.Workspace, data.Chart)
|
||||||
|
if _, err := os.Stat(ficChart); err == nil {
|
||||||
|
} else {
|
||||||
|
if data.Url != "" {
|
||||||
|
fmt.Println("============ 52 Télechargement", data.Url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s install %s %s %s --output json", bin, data.Name, ficChart, data.Opts)
|
||||||
|
|
||||||
|
if data.Version != "" {
|
||||||
|
msg = fmt.Sprintf("%s --version %s", msg, data.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range data.Values {
|
||||||
|
msg = fmt.Sprintf("%s --set %s=%s", msg, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
ficoverwrite := filepath.Join(data.Workspace, fmt.Sprintf("value-%s.yml", data.Name))
|
||||||
|
if _, err := os.Stat(ficoverwrite); err != nil {
|
||||||
|
log.Log().Warn().Msg(ficoverwrite)
|
||||||
|
} else {
|
||||||
|
msg = fmt.Sprintf("%s --values %s", msg, ficoverwrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, valuefilename := range data.FileValues {
|
||||||
|
fic := filepath.Join(data.Workspace, valuefilename)
|
||||||
|
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 := this.Exec(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
|
||||||
|
|
||||||
|
i := strings.Index(string(stdout), "{")
|
||||||
|
stdout2 := string(stdout)[i:]
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(stdout2), &objmap)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := objmap.Info.Status
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmCommand) ChartUninstall(data HelmChart) (string, error) {
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
log.Log().Info().Msg(" >> Chart : " + data.Name)
|
||||||
|
|
||||||
|
existe, err := this.chartExists(data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if ! existe {
|
||||||
|
return "Non présent", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s uninstall %s", bin, data.Name)
|
||||||
|
log.Log().Debug().Msg(msg)
|
||||||
|
|
||||||
|
cmd_args := strings.Split(msg, " ")
|
||||||
|
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(res)
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ../bin/helm list --filter phpmyadminm --short
|
||||||
|
func (this HelmCommand) chartExists(data HelmChart) (bool, error) {
|
||||||
|
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s list --filter %s --no-headers", bin, data.Name)
|
||||||
|
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 {
|
||||||
|
log.Log().Debug().Msg(string(stdout))
|
||||||
|
return false, errors.New(string(stdout))
|
||||||
|
}
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(string(stdout))
|
||||||
|
log.Log().Debug().Msg(strconv.FormatBool(res != ""))
|
||||||
|
|
||||||
|
return res != "", nil
|
||||||
|
}
|
30
src/helm/chart_test.go
Normal file
30
src/helm/chart_test.go
Normal 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")
|
||||||
|
}
|
22
src/helm/helm.go
Normal file
22
src/helm/helm.go
Normal 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
17
src/helm/helm_test.go
Normal 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")
|
||||||
|
}
|
84
src/helm/main_test.go
Normal file
84
src/helm/main_test.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
102
src/helm/repo.go
Normal file
102
src/helm/repo.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HelmRepo struct {
|
||||||
|
Name string
|
||||||
|
Repository string // Url du dépôt
|
||||||
|
ForceUpdate bool
|
||||||
|
Opts string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmCommand) AddRepository(repo HelmRepo) (string, error) {
|
||||||
|
|
||||||
|
helm_bin := this.Bin
|
||||||
|
|
||||||
|
force_update := "--force-update=false"
|
||||||
|
if repo.ForceUpdate {
|
||||||
|
force_update = "--force-update=true"
|
||||||
|
} else {
|
||||||
|
list, _ := this.ListRepository()
|
||||||
|
if utils.StringInSlice(repo.Name, list) {
|
||||||
|
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 = strings.TrimSuffix(msg, " ")
|
||||||
|
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 "", fmt.Errorf(string(stdout))
|
||||||
|
}
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
log.Log().Debug().Msg(res)
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseList struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmCommand) ListRepository() ([]string, error) {
|
||||||
|
|
||||||
|
helm_bin := this.Bin
|
||||||
|
res := make([]string, 0, 0)
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s repo list -o json", helm_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 res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var objmap []parseList
|
||||||
|
|
||||||
|
err = json.Unmarshal(stdout, &objmap)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ele := range objmap {
|
||||||
|
res = append(res, ele.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// helm repo remove [NAME]
|
||||||
|
func (this HelmCommand) RemoveRepository(repo HelmRepo) (string, error) {
|
||||||
|
helm_bin := this.Bin
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s repo remove %s", helm_bin, repo.Name)
|
||||||
|
log.Log().Debug().Msg(msg)
|
||||||
|
|
||||||
|
cmd_args := strings.Split(msg, " ")
|
||||||
|
|
||||||
|
cmd := this.Exec(cmd_args[0], cmd_args[1:]...)
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
72
src/helm/repo_test.go
Normal file
72
src/helm/repo_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHelmListRepository(t *testing.T){
|
||||||
|
|
||||||
|
cmd := getCmdHelm(true, `[{"name":"bitnami","url":"https://charts.bitnami.com/bitnami"}]`)
|
||||||
|
|
||||||
|
res, err := cmd.ListRepository()
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, "bitnami", res[0], "TestHelmVersion error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHelmRemoveRepository(t *testing.T){
|
||||||
|
|
||||||
|
cmd := getCmdHelm(true, `"bitnami" has been removed from your repositories`)
|
||||||
|
|
||||||
|
repo := HelmRepo{Name: "bitnami"}
|
||||||
|
res, err := cmd.RemoveRepository(repo)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, `"bitnami" has been removed from your repositories`, res, "TestHelmRemoveRepository error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHelmRemoveRepository2(t *testing.T){
|
||||||
|
|
||||||
|
cmd := getCmdHelm(true, `Error: no repositories configured`)
|
||||||
|
|
||||||
|
repo := HelmRepo{Name: "bitnami"}
|
||||||
|
res, err := cmd.RemoveRepository(repo)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
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")
|
||||||
|
}
|
70
src/helm/ressources.go
Normal file
70
src/helm/ressources.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "fmt"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
////
|
||||||
|
|
||||||
|
type parseStatusInfoResourcesMetadata struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// type parseStatusInfoResourcesPod struct {
|
||||||
|
// Api string `json:"apiVersion"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
type parseStatusInfoResourcesStatefulSet struct {
|
||||||
|
Api string `json:"apiVersion"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Metadata parseStatusInfoResourcesMetadata `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseStatusInfoResourcesDeployment struct {
|
||||||
|
Api string `json:"apiVersion"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Metadata parseStatusInfoResourcesMetadata `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseStatusInfoResources struct {
|
||||||
|
// Pod []parseStatusInfoResourcesPod `json:"v1/Pod(related)"`
|
||||||
|
StatefulSet []parseStatusInfoResourcesStatefulSet `json:"v1/StatefulSet"`
|
||||||
|
Deployment []parseStatusInfoResourcesDeployment `json:"v1/Deployment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseStatusInfo struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Resources parseStatusInfoResources `json:"Resources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type parseStatus struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Info parseStatusInfo `json:"info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmCommand) GetRessources(data HelmChart) (map[string]string, error) {
|
||||||
|
|
||||||
|
res := make(map[string]string)
|
||||||
|
|
||||||
|
status, err := this.Status(data)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var objmap parseStatus
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(status), &objmap)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ele := range objmap.Info.Resources.StatefulSet {
|
||||||
|
res[ele.Metadata.Name] = ele.Kind
|
||||||
|
}
|
||||||
|
for _, ele := range objmap.Info.Resources.Deployment {
|
||||||
|
res[ele.Metadata.Name] = ele.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
24
src/helm/ressources_test.go
Normal file
24
src/helm/ressources_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHelmRessources(t *testing.T){
|
||||||
|
|
||||||
|
fileName := filepath.Join(TEST_SRC_DIR, "helm_status.json")
|
||||||
|
res_json, _ := os.ReadFile(fileName)
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
28
src/helm/status.go
Normal file
28
src/helm/status.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this HelmCommand) Status(data HelmChart) (string, error) {
|
||||||
|
|
||||||
|
helm_bin := this.Bin
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s status %s --show-resources -o json", helm_bin, data.Name)
|
||||||
|
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 {
|
||||||
|
log.Log().Debug().Msg(string(stdout))
|
||||||
|
return "", errors.New(string(stdout))
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(stdout), nil
|
||||||
|
}
|
20
src/helm/version.go
Normal file
20
src/helm/version.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func (this HelmCommand) GetVersion() (string, error) {
|
||||||
|
|
||||||
|
cmd := this.Exec(this.Bin, "version", "--short")
|
||||||
|
stdout, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
return res, nil
|
||||||
|
}
|
18
src/helm/version_test.go
Normal file
18
src/helm/version_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package helm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHelmVersion(t *testing.T){
|
||||||
|
|
||||||
|
cmd := getCmdHelm(true, "v3.15.4+gfa9efb0\n")
|
||||||
|
|
||||||
|
version, err := cmd.GetVersion()
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, "v3.15.4+gfa9efb0", version, "TestHelmVersion error")
|
||||||
|
}
|
||||||
|
|
145
src/install/common.go
Normal file
145
src/install/common.go
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/tool"
|
||||||
|
"oc-deploy/chart"
|
||||||
|
"oc-deploy/kubectl"
|
||||||
|
"oc-deploy/helm"
|
||||||
|
"oc-deploy/versionOc"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstallClass struct {
|
||||||
|
Version string
|
||||||
|
Workspace string
|
||||||
|
|
||||||
|
tools []tool.ToolData
|
||||||
|
toolsBin map[string]string
|
||||||
|
charts []chart.ChartRepoData
|
||||||
|
|
||||||
|
commandHelm helm.HelmCommand
|
||||||
|
commandKubectl kubectl.KubectlCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
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) SetCommands() {
|
||||||
|
helm_bin, _ := this.getToolBin("helm")
|
||||||
|
this.commandHelm = helm.HelmCommand{Bin: helm_bin}
|
||||||
|
this.commandHelm.New()
|
||||||
|
|
||||||
|
kubectl_bin, _ := this.getToolBin("kubectl")
|
||||||
|
this.commandKubectl = kubectl.KubectlCommand{Bin: kubectl_bin}
|
||||||
|
this.commandKubectl.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) K8s(context string) (error) {
|
||||||
|
|
||||||
|
kube := this.commandKubectl
|
||||||
|
|
||||||
|
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) extractVersion() (string, error) {
|
||||||
|
|
||||||
|
// Extraction du fichier de version
|
||||||
|
dst := fmt.Sprintf("%s/oc.yml", this.Workspace)
|
||||||
|
log.Log().Debug().Msg(fmt.Sprintf("Check du fichier de version : %s", dst))
|
||||||
|
if _, err := os.Stat(dst); err == nil {
|
||||||
|
log.Log().Debug().Msg("Existe déjà")
|
||||||
|
version, err := versionOc.GetFromFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
this.Version = version
|
||||||
|
} else {
|
||||||
|
log.Log().Debug().Msg("Téléchargement du fichier de version "+ this.Version)
|
||||||
|
version, fileversion, err := versionOc.GetFromOnline(this.Version)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
this.Version = version
|
||||||
|
|
||||||
|
err = utils.CopyContentFile(fileversion, dst)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, nil
|
||||||
|
}
|
36
src/install/generate.go
Normal file
36
src/install/generate.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
"oc-deploy/chart"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *InstallClass) NewGenerate() (string, error) {
|
||||||
|
|
||||||
|
// Extraction du fichier de la version
|
||||||
|
dst, err := this.extractVersion()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
this.charts, _ = chart.FromConfigFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ele1 := range this.charts {
|
||||||
|
for _, ele2 := range ele1.Charts {
|
||||||
|
|
||||||
|
filename := filepath.Join(this.Workspace, fmt.Sprintf("values-%s.yml", ele2.Name) )
|
||||||
|
utils.CopyContentFile(ele2.Overwrite, filename)
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(">> %s : %s", ele2.Name, filename))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, nil
|
||||||
|
}
|
127
src/install/install.go
Normal file
127
src/install/install.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
"oc-deploy/tool"
|
||||||
|
"oc-deploy/chart"
|
||||||
|
"oc-deploy/helm"
|
||||||
|
"oc-deploy/kubectl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *InstallClass) NewInstall() (string, error) {
|
||||||
|
|
||||||
|
// Extraction du fichier de la version
|
||||||
|
dst, err := this.extractVersion()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lecture du fichier de conf
|
||||||
|
this.tools, err = tool.FromConfigFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
this.charts, _ = chart.FromConfigFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (this *InstallClass) ChartRepo() (error) {
|
||||||
|
|
||||||
|
for _, v := range this.charts {
|
||||||
|
if v.Repository.Name != "" {
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> Helm Repo : %s", v.Repository.Name))
|
||||||
|
repo := helm.HelmRepo{Name: v.Repository.Name,
|
||||||
|
Repository: v.Repository.Url,
|
||||||
|
ForceUpdate: v.Repository.ForceUpdate,
|
||||||
|
Opts: v.Repository.Opts}
|
||||||
|
res, err := this.commandHelm.AddRepository(repo)
|
||||||
|
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) InstallCharts(modules []string) (error) {
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
for _, v := range this.charts {
|
||||||
|
repoName := ""
|
||||||
|
if v.Repository.Name != "" {
|
||||||
|
repoName = v.Repository.Name
|
||||||
|
} else {
|
||||||
|
if v.Oci.Url != "" {
|
||||||
|
repoName = v.Oci.Url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v1 := range v.Charts {
|
||||||
|
if len(modules) == 0 || utils.StringInSlice(v1.Name, modules) {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
this.installChart(repoName, v1)
|
||||||
|
} ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *InstallClass) installChart(repoName string, chart chart.ChartData) {
|
||||||
|
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name))
|
||||||
|
|
||||||
|
chartName := chart.Chart
|
||||||
|
if chartName == "" {
|
||||||
|
chartName = chart.Name
|
||||||
|
}
|
||||||
|
if repoName != "" {
|
||||||
|
chartName = fmt.Sprintf("%s/%s", repoName, chartName)
|
||||||
|
}
|
||||||
|
data := helm.HelmChart{Name: chart.Name,
|
||||||
|
Chart: chartName,
|
||||||
|
Url: chart.Url,
|
||||||
|
Version: chart.Version,
|
||||||
|
Workspace: this.Workspace,
|
||||||
|
Opts: chart.Opts,
|
||||||
|
Values: chart.Values,
|
||||||
|
FileValues: chart.FileValues}
|
||||||
|
|
||||||
|
res, err := this.commandHelm.ChartInstall(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", data.Name, "KO", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", data.Name, res))
|
||||||
|
|
||||||
|
ressources, _ := this.commandHelm.GetRessources(data)
|
||||||
|
|
||||||
|
for key, value := range ressources {
|
||||||
|
obj := kubectl.KubectlObject{Name: key, Kind: value}
|
||||||
|
err := this.commandKubectl.Wait(obj)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Error().Msg(fmt.Sprintf(" >> %s/%s KO (%s)", chart.Name, key, err))
|
||||||
|
} else {
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> %s/%s OK", chart.Name, key))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
src/install/uninstall.go
Normal file
82
src/install/uninstall.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package install
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
"oc-deploy/versionOc"
|
||||||
|
"oc-deploy/tool"
|
||||||
|
"oc-deploy/chart"
|
||||||
|
"oc-deploy/helm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (this *InstallClass) NewUninstall() (string, error) {
|
||||||
|
dst := fmt.Sprintf("%s/oc.yml", this.Workspace)
|
||||||
|
|
||||||
|
if _, err := os.Stat(dst); err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := versionOc.GetFromFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Version = version
|
||||||
|
|
||||||
|
// Lecture du fichier de conf
|
||||||
|
this.tools, err = tool.FromConfigFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
this.charts, _ = chart.FromConfigFile(dst)
|
||||||
|
if err != nil {
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *InstallClass) UninstallCharts(modules []string) (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 {
|
||||||
|
if len(modules) == 0 || utils.StringInSlice(v1.Name, modules) {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
this.uninstallChart(helm_bin, kubectl_bin, v1)
|
||||||
|
} ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *InstallClass) uninstallChart(helm_bin string, kubectl_bin string, chart chart.ChartData) {
|
||||||
|
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" << Chart : %s ", chart.Name))
|
||||||
|
|
||||||
|
|
||||||
|
helm_cmd := helm.HelmCommand{Bin: helm_bin}
|
||||||
|
helm_cmd.New()
|
||||||
|
|
||||||
|
data := helm.HelmChart{Name: chart.Name}
|
||||||
|
|
||||||
|
res, err := helm_cmd.ChartUninstall(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Error().Msg(fmt.Sprintf(" >> %s %s (%s)", data.Name, "KO", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> %s (%s)", data.Name, res))
|
||||||
|
}
|
130
src/kubectl/context.go
Normal file
130
src/kubectl/context.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"errors"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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 KubectlCommand) GetCurrentContext() (string, error) {
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
res := string(stdout)
|
||||||
|
res = strings.TrimSuffix(res, "\n")
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// currentContext, currentNamespace, currentServer
|
||||||
|
func (this KubectlCommand) GetContext() (string, string, string, error) {
|
||||||
|
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
err = json.Unmarshal(stdout, &objmap)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
|
}
|
||||||
|
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 KubectlCommand) UseContext(newContext string) (error) {
|
||||||
|
|
||||||
|
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()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Debug().Msg(string(stdout))
|
||||||
|
return errors.New(string(stdout))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlCommand) Check() (error) {
|
||||||
|
bin := this.Bin
|
||||||
|
|
||||||
|
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()
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Debug().Msg(string(stdout))
|
||||||
|
return errors.New("Kube non disponible")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
86
src/kubectl/context_test.go
Normal file
86
src/kubectl/context_test.go
Normal 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
40
src/kubectl/deployment.go
Normal 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
|
||||||
|
}
|
29
src/kubectl/deployment_test.go
Normal file
29
src/kubectl/deployment_test.go
Normal 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
22
src/kubectl/kubectl.go
Normal 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...)
|
||||||
|
}
|
||||||
|
}
|
17
src/kubectl/kubectl_test.go
Normal file
17
src/kubectl/kubectl_test.go
Normal 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")
|
||||||
|
}
|
104
src/kubectl/main_test.go
Normal file
104
src/kubectl/main_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TEST_DEST_DIR = "../wrk_kubectl"
|
||||||
|
var TEST_SRC_DIR = filepath.Join("../../test", "kubectl")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
57
src/kubectl/object.go
Normal file
57
src/kubectl/object.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type KubectlObject struct {
|
||||||
|
Name string
|
||||||
|
Kind string
|
||||||
|
}
|
||||||
|
|
||||||
|
type getOutput struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Status getStatusOutput `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type getStatusOutput struct {
|
||||||
|
Replicas int `json:"replicas"`
|
||||||
|
UnavailableReplicas int `json:"unavailableReplicas"`
|
||||||
|
AvailableReplicas int `json:"availableReplicas"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlCommand) Get(data KubectlObject) (map[string]any, error) {
|
||||||
|
if data.Kind == "Deployment" {return this.getDeployment(data)}
|
||||||
|
if data.Kind == "StatefulSet" {return this.getStatefulSet(data)}
|
||||||
|
return make(map[string]any), fmt.Errorf("Kind %s inconnu", data.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlCommand) Wait(data KubectlObject) (error) {
|
||||||
|
|
||||||
|
boucle := 10
|
||||||
|
sleep := 10000 * time.Millisecond
|
||||||
|
|
||||||
|
for _ = range boucle {
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(fmt.Sprintf("Check Deployement %s", data.Name))
|
||||||
|
|
||||||
|
m, err := this.Get(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ko := m["unavailableReplicas"].(int)
|
||||||
|
if ko == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Log().Info().Msg(fmt.Sprintf(" >> %s (Unavailable : %d)...", data.Name, ko))
|
||||||
|
time.Sleep(sleep)
|
||||||
|
|
||||||
|
}
|
||||||
|
return errors.New("Temps d'attente dépassé")
|
||||||
|
}
|
44
src/kubectl/stateful_test.go
Normal file
44
src/kubectl/stateful_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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.getStatefulSet(data)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, "StatefulSet", res["kind"], "TestKubectStatefulset error")
|
||||||
|
assert.Equal(t, 1, res["replicas"], "TestKubectStatefulset error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKubectStatefulsetPending(t *testing.T) {
|
||||||
|
|
||||||
|
fileName := filepath.Join(TEST_SRC_DIR, "mongo_pending.json")
|
||||||
|
cmd_json, _ := os.ReadFile(fileName)
|
||||||
|
|
||||||
|
cmd := getCmdKubectl(true, string(cmd_json))
|
||||||
|
|
||||||
|
data := KubectlObject{Name: "dep1", Kind: "Statefulset"}
|
||||||
|
|
||||||
|
res, err := cmd.getStatefulSet(data)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, 1, res["unavailableReplicas"], "TestKubectStatefulsetPending error")
|
||||||
|
assert.Equal(t, "StatefulSet", res["kind"], "TestKubectStatefulsetPending error")
|
||||||
|
assert.Equal(t, 1, res["replicas"], "TestKubectStatefulsetPending error")
|
||||||
|
}
|
43
src/kubectl/statefulset.go
Normal file
43
src/kubectl/statefulset.go
Normal 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.Replicas - status.AvailableReplicas
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
29
src/kubectl/version.go
Normal file
29
src/kubectl/version.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type toolClientVersion struct {
|
||||||
|
GitVersion string `json:"gitVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type toolVersion struct {
|
||||||
|
ClientVersion toolClientVersion `json:"clientVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlCommand) GetVersion() (string, error) {
|
||||||
|
|
||||||
|
cmd := this.Exec(this.Bin, "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
|
||||||
|
}
|
33
src/kubectl/version_test.go
Normal file
33
src/kubectl/version_test.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package kubectl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKubectlVersion(t *testing.T) {
|
||||||
|
|
||||||
|
cmd_json := `
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}`
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
50
src/log_wrapper/log_wrapper.go
Normal file
50
src/log_wrapper/log_wrapper.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package log_wrapper
|
||||||
|
|
||||||
|
// https://github.com/rs/zerolog/issues/150
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"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(filename string) bool {
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
21
src/log_wrapper/log_wrapper_test.go
Normal file
21
src/log_wrapper/log_wrapper_test.go
Normal 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")
|
||||||
|
}
|
21
src/log_wrapper/main_test.go
Normal file
21
src/log_wrapper/main_test.go
Normal 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)
|
||||||
|
}
|
18
src/main.go
Normal file
18
src/main.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"oc-deploy/cmd"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
log.InitLog(".oc-deploy")
|
||||||
|
|
||||||
|
log.Log().Debug().Msg("Start")
|
||||||
|
|
||||||
|
cmd.Execute()
|
||||||
|
|
||||||
|
log.Log().Debug().Msg("End")
|
||||||
|
|
||||||
|
}
|
9
src/occonst/main_test.go
Normal file
9
src/occonst/main_test.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package occonst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
}
|
22
src/occonst/variables.go
Normal file
22
src/occonst/variables.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package occonst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var OCDEPLOY_ONLINE_URL = getenv("OCDEPLOY_ONLINE_URL", "https://cloud.o-forge.io")
|
||||||
|
var OCDEPLOY_ONLINE_REPO = getenv("OCDEPLOY_ONLINE_REPO", "core/oc-version")
|
||||||
|
|
||||||
|
var OCDEPLOY_OFFLINE_DIR = getenv("OCDEPLOY_OFFLINE_DIR", "../../offline")
|
||||||
|
|
||||||
|
var Version = "dev"
|
||||||
|
var Date = "now"
|
||||||
|
var GoVersion = ""
|
||||||
|
|
||||||
|
func getenv(key string, defaut string) string {
|
||||||
|
value := os.Getenv(key)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return defaut
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
21
src/tool/conf.go
Normal file
21
src/tool/conf.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type toolsData struct {
|
||||||
|
Tools []ToolData `yaml:"tools"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lecture de la liste des outils
|
||||||
|
func FromConfigFile(filename string) ([]ToolData, error) {
|
||||||
|
yamlFile, _ := os.ReadFile(filename)
|
||||||
|
var data toolsData
|
||||||
|
err := yaml.Unmarshal(yamlFile, &data)
|
||||||
|
if err != nil {
|
||||||
|
return data.Tools, nil
|
||||||
|
}
|
||||||
|
return data.Tools, nil
|
||||||
|
}
|
18
src/tool/conf_test.go
Normal file
18
src/tool/conf_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestToolConf(t *testing.T) {
|
||||||
|
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "oc.yml")
|
||||||
|
|
||||||
|
data, err := FromConfigFile(src)
|
||||||
|
assert.Equal(t, "kubectl", data[0].Name, "TestToolConf error")
|
||||||
|
assert.Nilf(t, err, "error message %s", src)
|
||||||
|
}
|
57
src/tool/helm.go
Normal file
57
src/tool/helm.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"oc-deploy/utils"
|
||||||
|
"oc-deploy/helm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HelmInstall struct {
|
||||||
|
obj ToolData
|
||||||
|
tmp string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmInstall) Get() (ToolData) {
|
||||||
|
return this.obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this HelmInstall) Download() (error) {
|
||||||
|
|
||||||
|
bin_dir := this.obj.Bin
|
||||||
|
err2 := os.MkdirAll(bin_dir, os.ModePerm)
|
||||||
|
if err2 != nil {
|
||||||
|
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)
|
||||||
|
if err1 != nil {
|
||||||
|
return err1
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(tmp_file)
|
||||||
|
|
||||||
|
bin_file := fmt.Sprintf("%s/%s", bin_dir, this.obj.Name)
|
||||||
|
|
||||||
|
errChmod := os.Chmod(bin_file, 0755)
|
||||||
|
if errChmod != nil {return errChmod}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
func (this HelmInstall) Version(path string) (string, error) {
|
||||||
|
cmd := helm.HelmCommand{Bin: path}
|
||||||
|
cmd.New()
|
||||||
|
return cmd.GetVersion()
|
||||||
|
}
|
62
src/tool/helm_test.go
Normal file
62
src/tool/helm_test.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
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")
|
||||||
|
}
|
43
src/tool/kubectl.go
Normal file
43
src/tool/kubectl.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/utils"
|
||||||
|
"oc-deploy/kubectl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubectlInstall struct {
|
||||||
|
obj ToolData
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlInstall) Get() (ToolData) {
|
||||||
|
return this.obj
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this KubectlInstall) Download() (error) {
|
||||||
|
|
||||||
|
bin_dir := this.obj.Bin
|
||||||
|
bin := filepath.Join(bin_dir, this.obj.Name)
|
||||||
|
url := fmt.Sprintf(this.obj.Url, this.obj.Version)
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(fmt.Sprintf("Téléchargement : %s, %s", bin, url))
|
||||||
|
os.MkdirAll(bin_dir, os.ModePerm)
|
||||||
|
|
||||||
|
err := utils.DownloadFromUrl(bin, url, 0777)
|
||||||
|
if err != nil {return err}
|
||||||
|
|
||||||
|
os.Chmod(bin, 0755)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
func (this KubectlInstall) Version(path string) (string, error) {
|
||||||
|
cmd := kubectl.KubectlCommand{Bin: path}
|
||||||
|
cmd.New()
|
||||||
|
return cmd.GetVersion()
|
||||||
|
}
|
82
src/tool/kubectl_test.go
Normal file
82
src/tool/kubectl_test.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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")
|
||||||
|
assert.Nilf(t, err1, "TestToolKubectl error")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestToolKubectlErr(t *testing.T) {
|
||||||
|
|
||||||
|
httpmock.Activate()
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
httpmock.RegisterResponder("GET", "http://test/1.0",
|
||||||
|
httpmock.NewStringResponder(404, ""))
|
||||||
|
|
||||||
|
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", err)
|
||||||
|
}
|
23
src/tool/main_test.go
Normal file
23
src/tool/main_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TEST_DEST_DIR = "../wrk_tool"
|
||||||
|
var TEST_SRC_DIR = filepath.Join("../../test", "tool")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
79
src/tool/tool.go
Normal file
79
src/tool/tool.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ToolData struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Url string `yaml:"url"`
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
Bin string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolClass struct {
|
||||||
|
Obj Forme
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Forme interface {
|
||||||
|
Download() error
|
||||||
|
Version(string) (string, error)
|
||||||
|
Get() ToolData
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////
|
||||||
|
func (this *ToolClass) New(data ToolData) (error) {
|
||||||
|
f, err := factory(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
this.Obj = f
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ToolClass) Locate() (error) {
|
||||||
|
|
||||||
|
obj := this.Obj
|
||||||
|
data := obj.Get()
|
||||||
|
path := filepath.Join(data.Bin, data.Name)
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); err != nil {
|
||||||
|
path2, _ := exec.LookPath(data.Name)
|
||||||
|
if path2 != "" {
|
||||||
|
path = path2
|
||||||
|
} else {
|
||||||
|
err = obj.Download()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Path = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ToolClass) Version() (string, error) {
|
||||||
|
obj := (this.Obj)
|
||||||
|
return obj.Version(this.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////
|
||||||
|
func factory(data ToolData) (Forme, error) {
|
||||||
|
var f Forme
|
||||||
|
|
||||||
|
switch data.Name {
|
||||||
|
case "kubectl":
|
||||||
|
f = KubectlInstall{obj: data}
|
||||||
|
case "helm":
|
||||||
|
f = HelmInstall{obj: data, tmp: "/tmp"}
|
||||||
|
default:
|
||||||
|
return f, fmt.Errorf("Outil Inconnu : %s", data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
53
src/utils/copyFile.go
Normal file
53
src/utils/copyFile.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CopyFile(src string, dst string) (error) {
|
||||||
|
|
||||||
|
if _, err := os.Stat(src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fin, errOpen := os.Open(src)
|
||||||
|
if errOpen != nil {
|
||||||
|
return errOpen
|
||||||
|
}
|
||||||
|
defer fin.Close()
|
||||||
|
|
||||||
|
folderPath := filepath.Dir(dst)
|
||||||
|
os.MkdirAll(folderPath, os.ModePerm)
|
||||||
|
|
||||||
|
fout, errCreate := os.Create(dst)
|
||||||
|
if errCreate != nil {
|
||||||
|
return errCreate
|
||||||
|
}
|
||||||
|
defer fout.Close()
|
||||||
|
|
||||||
|
_, errCopy := io.Copy(fout, fin)
|
||||||
|
if errCopy != nil {
|
||||||
|
return errCopy
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyContentFile(content string, dst string) (error) {
|
||||||
|
|
||||||
|
folderPath := filepath.Dir(dst)
|
||||||
|
os.MkdirAll(folderPath, os.ModePerm)
|
||||||
|
|
||||||
|
fout, errCreate := os.Create(dst)
|
||||||
|
if errCreate != nil {
|
||||||
|
return errCreate
|
||||||
|
}
|
||||||
|
defer fout.Close()
|
||||||
|
|
||||||
|
_, errCopy := fout.WriteString(content)
|
||||||
|
if errCopy != nil {
|
||||||
|
return errCopy
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
57
src/utils/copyFile_test.go
Normal file
57
src/utils/copyFile_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
// https://pkg.go.dev/github.com/stretchr/testify/assert#Nilf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"path/filepath"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCopyFileExist(t *testing.T) {
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "fichier1")
|
||||||
|
dest := filepath.Join(TEST_DEST_DIR, "fichier1")
|
||||||
|
|
||||||
|
err := CopyFile(src, dest)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message %s", src)
|
||||||
|
assert.FileExists(t, dest, "CopyFile error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyErrSrcFileNotExist(t *testing.T) {
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "inconnu")
|
||||||
|
dest := filepath.Join(TEST_DEST_DIR, "inconnu")
|
||||||
|
|
||||||
|
err := CopyFile(src, dest)
|
||||||
|
|
||||||
|
assert.NotNilf(t, err, "CopyFile error %s", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyFileErrCreate(t *testing.T){
|
||||||
|
src := filepath.Join(TEST_SRC_DIR, "fichier1")
|
||||||
|
dest := filepath.Join("/INCONNU", "fichier1")
|
||||||
|
|
||||||
|
err := CopyFile(src, dest)
|
||||||
|
|
||||||
|
assert.NotNilf(t, err, "error message %s", src)
|
||||||
|
assert.NoFileExists(t, dest, "CopyFile error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyErrSrcWrite(t *testing.T) {
|
||||||
|
src := "/"
|
||||||
|
dest := filepath.Join(TEST_DEST_DIR, "inconnu")
|
||||||
|
|
||||||
|
err := CopyFile(src, dest)
|
||||||
|
|
||||||
|
assert.NotNilf(t, err, "CopyFile error %s", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyContentFile(t *testing.T) {
|
||||||
|
content := "TestCopyContentFileExist"
|
||||||
|
dest := filepath.Join(TEST_DEST_DIR, "fichier1")
|
||||||
|
|
||||||
|
err := CopyContentFile(content, dest)
|
||||||
|
|
||||||
|
assert.Nilf(t, err, "error message")
|
||||||
|
assert.FileExists(t, dest, "CopyFile error")
|
||||||
|
}
|
76
src/utils/download.go
Normal file
76
src/utils/download.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"net/http"
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DownloadFromUrl(dest string, url string, chmod os.FileMode) error {
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode > 400 {
|
||||||
|
txt, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf(string(txt))
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := os.Create(dest)
|
||||||
|
defer out.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(out, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Chmod(dest, chmod)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func ExtractTarGz(dest string, gzipStream io.Reader) error {
|
||||||
|
uncompressedStream, err := gzip.NewReader(gzipStream)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tarReader := tar.NewReader(uncompressedStream)
|
||||||
|
|
||||||
|
for {
|
||||||
|
header, err := tarReader.Next()
|
||||||
|
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeDir:
|
||||||
|
// if err := os.Mkdir(dest + "/" + header.Name, 0755); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
case tar.TypeReg:
|
||||||
|
outName := dest + "/" + path.Base(header.Name)
|
||||||
|
outFile, _ := os.Create(outName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
51
src/utils/download_test.go
Normal file
51
src/utils/download_test.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/jarcoal/httpmock"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDownload(t *testing.T) {
|
||||||
|
httpmock.Activate()
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
url := "http://test.download.com"
|
||||||
|
|
||||||
|
httpmock.RegisterResponder("GET", url,
|
||||||
|
httpmock.NewStringResponder(200, `CONTENU_URL`))
|
||||||
|
|
||||||
|
dest := filepath.Join(TEST_DEST_DIR, "url")
|
||||||
|
|
||||||
|
err := DownloadFromUrl(dest, url, 777)
|
||||||
|
assert.Nilf(t, err, "error message %s", url)
|
||||||
|
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)
|
||||||
|
}
|
25
src/utils/main_test.go
Normal file
25
src/utils/main_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
// https://pkg.go.dev/github.com/stretchr/testify/assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TEST_DEST_DIR = "../wrk_utils"
|
||||||
|
var TEST_SRC_DIR = filepath.Join("../../test", "utils")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
10
src/utils/slice.go
Normal file
10
src/utils/slice.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
func StringInSlice(a string, list []string) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
22
src/utils/slice_test.go
Normal file
22
src/utils/slice_test.go
Normal 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")
|
||||||
|
}
|
23
src/versionOc/main_test.go
Normal file
23
src/versionOc/main_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package versionOc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TEST_DEST_DIR = "../wrk_versionOc"
|
||||||
|
var TEST_SRC_DIR = filepath.Join("../../test", "versionOc")
|
||||||
|
|
||||||
|
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/versionOc/offline.go
Normal file
71
src/versionOc/offline.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Package :
|
||||||
|
package versionOc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
"oc-deploy/occonst"
|
||||||
|
)
|
||||||
|
|
||||||
|
type versionInput struct {
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get : Retourne la version
|
||||||
|
func GetFromOffline(version string) (string, string, error) {
|
||||||
|
|
||||||
|
version2 := version
|
||||||
|
if version == "latest" {
|
||||||
|
versionLatest, err := readLatestFromOffline()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
version2 = versionLatest
|
||||||
|
}
|
||||||
|
|
||||||
|
ficversion := fmt.Sprintf("oc_%s.yml", version2)
|
||||||
|
src := filepath.Join(occonst.OCDEPLOY_OFFLINE_DIR, ficversion)
|
||||||
|
if _, err := os.Stat(src); err != nil {
|
||||||
|
log.Log().Debug().Msg(err.Error())
|
||||||
|
return "", "", errors.New("Version non disponible")
|
||||||
|
}
|
||||||
|
|
||||||
|
fin, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
defer fin.Close()
|
||||||
|
byteValue, err := io.ReadAll(fin)
|
||||||
|
|
||||||
|
return version2, string(byteValue), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readLatestFile : Lit le numéro de la version dans le fichier lastest.yml
|
||||||
|
func readLatestFromOffline() (string, error) {
|
||||||
|
src := filepath.Join(occonst.OCDEPLOY_OFFLINE_DIR, "latest.yml")
|
||||||
|
|
||||||
|
fin, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer fin.Close()
|
||||||
|
|
||||||
|
byteValue, err := io.ReadAll(fin)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var objmap versionInput
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(byteValue, &objmap)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return objmap.Version, nil
|
||||||
|
}
|
27
src/versionOc/offline_test.go
Normal file
27
src/versionOc/offline_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package versionOc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"oc-deploy/occonst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetOffline(t *testing.T) {
|
||||||
|
|
||||||
|
_, _, err := GetFromOffline("99.1")
|
||||||
|
assert.NotNilf(t, err, "error message %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLatest(t *testing.T) {
|
||||||
|
|
||||||
|
occonst.OCDEPLOY_OFFLINE_DIR = filepath.Join(TEST_SRC_DIR, "offline")
|
||||||
|
|
||||||
|
version, _, err := GetFromOffline("latest")
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, "99.1", version, "TestGetFromFile error")
|
||||||
|
|
||||||
|
}
|
110
src/versionOc/online.go
Normal file
110
src/versionOc/online.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package versionOc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/base64"
|
||||||
|
|
||||||
|
"oc-deploy/occonst"
|
||||||
|
log "oc-deploy/log_wrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func GetFromOnline(version string) (string, string, error) {
|
||||||
|
|
||||||
|
version2 := version
|
||||||
|
if version == "latest" {
|
||||||
|
versionLatest, err := readLatestFromOnline()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
version2 = versionLatest
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := getFileVersion(version2)
|
||||||
|
if err != nil {
|
||||||
|
log.Log().Debug().Msg(err.Error())
|
||||||
|
return "", "", errors.New("Version non disponible")
|
||||||
|
}
|
||||||
|
|
||||||
|
return version2, content, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type releaseStruct struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ocJsonStruct struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cherche dans Online la dernière version (non draft, non pre-releases)
|
||||||
|
func readLatestFromOnline() (string, error) {
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/latest",
|
||||||
|
occonst.OCDEPLOY_ONLINE_URL,
|
||||||
|
occonst.OCDEPLOY_ONLINE_REPO)
|
||||||
|
|
||||||
|
log.Log().Debug().Msg(url)
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data releaseStruct
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(data.Message) > 0 {
|
||||||
|
log.Log().Debug().Msg(data.Message)
|
||||||
|
return "", fmt.Errorf("Dernière version introuvable")
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Name, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupère le fichier version de la version
|
||||||
|
func getFileVersion(version string) (string, error) {
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s/%s/releases/download/%s/oc.json",
|
||||||
|
occonst.OCDEPLOY_ONLINE_URL,
|
||||||
|
occonst.OCDEPLOY_ONLINE_REPO,
|
||||||
|
version)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(body) == "Not Found\n" {
|
||||||
|
return "", fmt.Errorf("Not found %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
var data ocJsonStruct
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
data64, err64 := base64.StdEncoding.DecodeString(data.Value)
|
||||||
|
if err64 != nil {
|
||||||
|
return "", err64
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(data64), nil
|
||||||
|
}
|
60
src/versionOc/online_test.go
Normal file
60
src/versionOc/online_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package versionOc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"oc-deploy/occonst"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/jarcoal/httpmock"
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
func TestGetOnline(t *testing.T) {
|
||||||
|
|
||||||
|
httpmock.Activate()
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
version := "99.1"
|
||||||
|
url := fmt.Sprintf("%s/%s/releases/download/%s/oc.json",
|
||||||
|
occonst.OCDEPLOY_ONLINE_URL,
|
||||||
|
occonst.OCDEPLOY_ONLINE_REPO,
|
||||||
|
version)
|
||||||
|
|
||||||
|
httpmock.RegisterResponder("GET", url,
|
||||||
|
httpmock.NewStringResponder(200, `{"value": "e30K"}`))
|
||||||
|
|
||||||
|
res, _, err := GetFromOnline(version)
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, version, res, "TestGetOnline error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetOnlineLatest(t *testing.T) {
|
||||||
|
|
||||||
|
httpmock.Activate()
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
// version := "99.1"
|
||||||
|
url := fmt.Sprintf("%s/api/v1/repos/%s/releases/latest",
|
||||||
|
occonst.OCDEPLOY_ONLINE_URL,
|
||||||
|
occonst.OCDEPLOY_ONLINE_REPO)
|
||||||
|
|
||||||
|
httpmock.RegisterResponder("GET", url,
|
||||||
|
httpmock.NewStringResponder(200, `{"name": "99.0", "id": 2}`))
|
||||||
|
|
||||||
|
version := "99.0"
|
||||||
|
url2 := fmt.Sprintf("%s/%s/releases/download/%s/oc.json",
|
||||||
|
occonst.OCDEPLOY_ONLINE_URL,
|
||||||
|
occonst.OCDEPLOY_ONLINE_REPO,
|
||||||
|
version)
|
||||||
|
|
||||||
|
httpmock.RegisterResponder("GET", url2,
|
||||||
|
httpmock.NewStringResponder(200, `{"value": "e30K"}`))
|
||||||
|
|
||||||
|
|
||||||
|
version, _, err := GetFromOnline("latest")
|
||||||
|
assert.Nilf(t, err, "error message %s", err)
|
||||||
|
assert.Equal(t, "99.0", version, "TestGetFromFile error")
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user