add uninstall cmd and restructure compose pkg

Signed-off-by: aiordache <anca.iordache@docker.com>
This commit is contained in:
aiordache 2020-04-06 12:22:52 +02:00
parent 898b7d4666
commit 896b9fd47e
12 changed files with 259 additions and 122 deletions

View File

@ -1,28 +1,9 @@
package compose
import (
"log"
"os"
chartloader "helm.sh/helm/v3/pkg/chart/loader"
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/docker/helm-prototype/pkg/compose/internal/convert"
"github.com/docker/helm-prototype/pkg/compose/internal/helm"
utils "github.com/docker/helm-prototype/pkg/compose/internal/utils"
"helm.sh/helm/v3/pkg/action"
env "helm.sh/helm/v3/pkg/cli"
k "helm.sh/helm/v3/pkg/kube"
)
// Orchestrator is "kubernetes" or "swarm"
type Orchestrator string
const (
// Kubernetes specifies to use kubernetes.
Kubernetes Orchestrator = "kubernetes"
// Swarm specifies to use Docker swarm.
Swarm Orchestrator = "swarm"
internal "github.com/docker/helm-prototype/pkg/compose/internal"
)
type ProjectOptions struct {
@ -30,107 +11,48 @@ type ProjectOptions struct {
Name string
}
type Project struct {
Config *types.Config
ProjectDir string
Name string `yaml:"-" json:"-"`
Orchestrator Orchestrator
}
var Settings = internal.GetDefault()
func NewProject(config types.ConfigDetails, name string) (*Project, error) {
model, err := loader.Load(config)
if err != nil {
return nil, err
}
p := Project{
Config: model,
ProjectDir: config.WorkingDir,
Name: name,
}
return &p, nil
type ComposeAPI struct {
project *internal.Project
}
// projectFromOptions load a compose project based on command line options
func ProjectFromOptions(options *ProjectOptions) (*Project, error) {
func ProjectFromOptions(options *ProjectOptions) (*ComposeAPI, error) {
if options == nil {
options = &ProjectOptions{
ConfigPaths: []string{},
Name: "docker-compose",
}
}
if options.Name == "" {
options.Name = "docker-compose"
}
workingDir, configs, err := utils.GetConfigs(
options.Name,
options.ConfigPaths,
)
project, err := internal.GetProject(options.Name, options.ConfigPaths)
if err != nil {
return nil, err
}
return NewProject(types.ConfigDetails{
WorkingDir: workingDir,
ConfigFiles: configs,
Environment: utils.Environment(),
}, options.Name)
return &ComposeAPI{project: project}, nil
}
func (p *Project) GenerateChart(path string) error {
objects, err := convert.MapToKubernetesObjects(p.Config, p.Name)
if err != nil {
return err
}
err = helm.Write(p.Name, objects, path)
if err != nil {
return err
}
return nil
func (c *ComposeAPI) GenerateChart(dirname string) error {
return c.project.ExportToCharts(dirname)
}
func (p *Project) InstallChart(n, path string) error {
func (c *ComposeAPI) Install(name, path string) error {
if path == "" {
err := p.GenerateChart(path)
cwd, err := os.Getwd()
if err != nil {
return err
}
path = cwd
}
settings := env.New()
actionConfig := new(action.Configuration)
println(".......... here ............")
if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), "memory", nil); err != nil {
log.Fatal(err)
}
println(settings.EnvVars())
client := action.NewInstall(actionConfig)
println("Original chart version:", client.Version)
client.Version = ">0.0.0-0"
name, chart, err := client.NameAndChart([]string{n, path})
if err != nil {
return nil
}
client.ReleaseName = name
client.Namespace = settings.Namespace()
cp, err := client.ChartPathOptions.LocateChart(chart, settings)
if err != nil {
return err
}
println("CHART PATH: ", cp)
chartRequested, err := chartloader.Load(cp)
if err != nil {
return err
}
kclient := k.New(settings.RESTClientGetter())
println(kclient.Namespace)
if err = actionConfig.KubeClient.IsReachable(); err != nil {
println("Kube API is not reachable")
return err
}
println("....Running.....")
println("Chart description: ", chartRequested.Metadata.Description)
release, err := client.Run(chartRequested, map[string]interface{}{})
println(release.Name)
return err
return c.project.Install(name, path)
}
func (c *ComposeAPI) Uninstall(name string) error {
return c.project.Uninstall(name)
}

View File

@ -0,0 +1,70 @@
package helm
import (
"gopkg.in/yaml.v2"
action "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
loader "helm.sh/helm/v3/pkg/chart/loader"
)
type HelmChart struct {
chart *chart.Chart
actionConfig *HelmConfig
Path string
Name string
}
func NewChart(name, chartpath string) *HelmChart {
chart, err := loader.Load(chartpath)
if err != nil {
return nil
}
return &HelmChart{
chart: chart,
Path: chartpath,
Name: name,
}
}
func (chart *HelmChart) SetActionConfig(config *HelmConfig) error {
chart.actionConfig = config
return nil
}
func (chart *HelmChart) Validate() error {
_, err := yaml.Marshal(chart.chart.Metadata)
if err != nil {
return nil
}
return nil
}
func (chart *HelmChart) Install() error {
err := chart.actionConfig.InitKubeClient()
if err != nil {
return err
}
actInstall := action.NewInstall(chart.actionConfig.Config)
actInstall.ReleaseName = chart.Name
actInstall.Namespace = chart.actionConfig.Settings.Namespace()
release, err := actInstall.Run(chart.chart, map[string]interface{}{})
if err != nil {
return err
}
println("Release status: ", release.Info.Status)
println("Release description: ", release.Info.Description)
return chart.actionConfig.Config.Releases.Update(release)
}
func (chart *HelmChart) Uninstall() error {
err := chart.actionConfig.InitKubeClient()
if err != nil {
return err
}
actUninstall := action.NewUninstall(chart.actionConfig.Config)
_, err = actUninstall.Run(chart.Name)
return err
}

View File

@ -0,0 +1,39 @@
package helm
import (
"log"
action "helm.sh/helm/v3/pkg/action"
env "helm.sh/helm/v3/pkg/cli"
)
type HelmConfig struct {
Config *action.Configuration
Settings *env.EnvSettings
kube_conn_init bool
}
func NewHelmConfig(settings *env.EnvSettings) *HelmConfig {
if settings == nil {
settings = env.New()
}
return &HelmConfig{
Config: new(action.Configuration),
Settings: settings,
kube_conn_init: false,
}
}
func (hc *HelmConfig) InitKubeClient() error {
if hc.kube_conn_init {
return nil
}
if err := hc.Config.Init(hc.Settings.RESTClientGetter(), hc.Settings.Namespace(), "memory", log.Printf); err != nil {
log.Fatal(err)
}
if err := hc.Config.KubeClient.IsReachable(); err != nil {
return err
}
hc.kube_conn_init = true
return nil
}

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"fmt"

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"regexp"

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"reflect"

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"fmt"

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"fmt"

View File

@ -1,4 +1,4 @@
package convert
package kube
import (
"fmt"

112
compose/internal/project.go Normal file
View File

@ -0,0 +1,112 @@
package project
import (
"github.com/compose-spec/compose-go/loader"
"github.com/compose-spec/compose-go/types"
"github.com/docker/helm-prototype/pkg/compose/internal/helm"
"github.com/docker/helm-prototype/pkg/compose/internal/utils"
"github.com/docker/helm-prototype/pkg/compose/internal/kube"
)
// Kind is "kubernetes" or "docker"
type Kind string
const (
// Kubernetes specifies to use a kubernetes cluster.
Kubernetes Kind = "kubernetes"
// Docker specifies to use Docker engine.
DockerEngine Kind = "docker"
)
type Engine struct {
Namespace string
Kind Kind
Config string
// Context is the name of the kubeconfig/docker context.
Context string
// Token used for authentication (kubernetes)
Token string
// Kubernetes API Server Endpoint for authentication
APIServer string
}
func GetDefault() *Engine {
return &Engine{Kind: Kubernetes}
}
type Project struct {
Config *types.Config
HelmConfig *helm.HelmConfig
HelmChart *helm.HelmChart
ProjectDir string
Name string `yaml:"-" json:"-"`
}
func NewProject(config types.ConfigDetails, name string) (*Project, error) {
model, err := loader.Load(config)
if err != nil {
return nil, err
}
p := Project{
Config: model,
HelmConfig: helm.NewHelmConfig(nil),
HelmChart: nil,
ProjectDir: config.WorkingDir,
Name: name,
}
return &p, nil
}
func GetProject(name string, configPaths []string) (*Project, error) {
if name == "" {
name = "docker-compose"
}
workingDir, configs, err := utils.GetConfigs(
name,
configPaths,
)
if err != nil {
return nil, err
}
return NewProject(types.ConfigDetails{
WorkingDir: workingDir,
ConfigFiles: configs,
Environment: utils.Environment(),
}, name)
}
func (p *Project) ExportToCharts(path string) error {
objects, err := kube.MapToKubernetesObjects(p.Config, p.Name)
if err != nil {
return err
}
err = helm.Write(p.Name, objects, path)
if err != nil {
return err
}
return nil
}
func (p *Project) Install(name, path string) error {
if p.HelmChart == nil {
chart := helm.NewChart(name, path)
chart.SetActionConfig(p.HelmConfig)
p.HelmChart = chart
}
return p.HelmChart.Install()
}
func (p *Project) Uninstall(name string) error {
if p.HelmChart == nil {
p.HelmChart = helm.NewChart(name, "")
p.HelmChart.SetActionConfig(p.HelmConfig)
}
return p.HelmChart.Uninstall()
}

View File

@ -20,13 +20,11 @@ func GetConfigs(name string, configPaths []string) (string, []types.ConfigFile,
if err != nil {
return "", nil, err
}
workingDir := filepath.Dir(configPath[0])
if name == "" {
name = os.Getenv("COMPOSE_PROJECT_NAME")
}
workingDir := filepath.Dir(configPath[0])
if name == "" {
r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
name = r.ReplaceAllString(strings.ToLower(filepath.Base(workingDir)), "")

View File

@ -6,15 +6,11 @@ import (
)
func Environment() map[string]string {
return getAsEqualsMap(os.Environ())
}
// getAsEqualsMap split key=value formatted strings into a key : value map
func getAsEqualsMap(em []string) map[string]string {
m := make(map[string]string)
for _, v := range em {
kv := strings.SplitN(v, "=", 2)
m[kv[0]] = kv[1]
vars := make(map[string]string)
env := os.Environ()
for _, v := range env {
k := strings.SplitN(v, "=", 2)
vars[k[0]] = k[1]
}
return m
return vars
}