mirror of
https://github.com/docker/compose.git
synced 2025-04-08 17:05:13 +02:00
Merge pull request #1221 from aiordache/kube_progress_writer
Kube backend: Add progress writer to `compose up/down`
This commit is contained in:
commit
7d0be7ad5a
@ -1,120 +0,0 @@
|
|||||||
// +build kube
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright 2020 Docker Compose CLI authors
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package charts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"github.com/docker/compose-cli/api/compose"
|
|
||||||
apicontext "github.com/docker/compose-cli/api/context"
|
|
||||||
"github.com/docker/compose-cli/api/context/store"
|
|
||||||
"github.com/docker/compose-cli/kube/charts/helm"
|
|
||||||
"github.com/docker/compose-cli/kube/charts/kubernetes"
|
|
||||||
chart "helm.sh/helm/v3/pkg/chart"
|
|
||||||
util "helm.sh/helm/v3/pkg/chartutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
//SDK chart SDK
|
|
||||||
type SDK struct {
|
|
||||||
action *helm.Actions
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSDK new chart SDK
|
|
||||||
func NewSDK(ctx context.Context) (SDK, error) {
|
|
||||||
contextStore := store.ContextStore(ctx)
|
|
||||||
currentContext := apicontext.CurrentContext(ctx)
|
|
||||||
var kubeContext store.KubeContext
|
|
||||||
|
|
||||||
if err := contextStore.GetEndpoint(currentContext, &kubeContext); err != nil {
|
|
||||||
return SDK{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
config, err := kubernetes.LoadConfig(kubeContext)
|
|
||||||
if err != nil {
|
|
||||||
return SDK{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
actions, err := helm.NewHelmActions(ctx, config)
|
|
||||||
if err != nil {
|
|
||||||
return SDK{}, err
|
|
||||||
}
|
|
||||||
return SDK{
|
|
||||||
action: actions,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install deploys a Compose stack
|
|
||||||
func (s SDK) Install(project *types.Project) error {
|
|
||||||
chart, err := s.GetChartInMemory(project)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.action.InstallChart(project.Name, chart)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uninstall removes a runnign compose stack
|
|
||||||
func (s SDK) Uninstall(projectName string) error {
|
|
||||||
return s.action.Uninstall(projectName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List returns a list of compose stacks
|
|
||||||
func (s SDK) List() ([]compose.Stack, error) {
|
|
||||||
return s.action.ListReleases()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChartInMemory get memory representation of helm chart
|
|
||||||
func (s SDK) GetChartInMemory(project *types.Project) (*chart.Chart, error) {
|
|
||||||
// replace _ with - in volume names
|
|
||||||
for k, v := range project.Volumes {
|
|
||||||
volumeName := strings.ReplaceAll(k, "_", "-")
|
|
||||||
if volumeName != k {
|
|
||||||
project.Volumes[volumeName] = v
|
|
||||||
delete(project.Volumes, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
objects, err := kubernetes.MapToKubernetesObjects(project)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
//in memory files
|
|
||||||
return helm.ConvertToChart(project.Name, objects)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveChart converts compose project to helm and saves the chart
|
|
||||||
func (s SDK) SaveChart(project *types.Project, dest string) error {
|
|
||||||
chart, err := s.GetChartInMemory(project)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return util.SaveDir(chart, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateChart generates helm chart from Compose project
|
|
||||||
func (s SDK) GenerateChart(project *types.Project, dirname string) error {
|
|
||||||
if strings.Contains(dirname, ".") {
|
|
||||||
splits := strings.SplitN(dirname, ".", 2)
|
|
||||||
dirname = splits[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
dirname = filepath.Dir(dirname)
|
|
||||||
return s.SaveChart(project, dirname)
|
|
||||||
}
|
|
@ -20,42 +20,98 @@ package kube
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/api/compose"
|
"github.com/docker/compose-cli/api/compose"
|
||||||
|
apicontext "github.com/docker/compose-cli/api/context"
|
||||||
|
"github.com/docker/compose-cli/api/context/store"
|
||||||
"github.com/docker/compose-cli/api/errdefs"
|
"github.com/docker/compose-cli/api/errdefs"
|
||||||
"github.com/docker/compose-cli/kube/charts"
|
"github.com/docker/compose-cli/api/progress"
|
||||||
|
"github.com/docker/compose-cli/kube/helm"
|
||||||
|
"github.com/docker/compose-cli/kube/resources"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type composeService struct {
|
||||||
|
sdk *helm.Actions
|
||||||
|
}
|
||||||
|
|
||||||
// NewComposeService create a kubernetes implementation of the compose.Service API
|
// NewComposeService create a kubernetes implementation of the compose.Service API
|
||||||
func NewComposeService(ctx context.Context) (compose.Service, error) {
|
func NewComposeService(ctx context.Context) (compose.Service, error) {
|
||||||
chartsAPI, err := charts.NewSDK(ctx)
|
contextStore := store.ContextStore(ctx)
|
||||||
|
currentContext := apicontext.CurrentContext(ctx)
|
||||||
|
var kubeContext store.KubeContext
|
||||||
|
|
||||||
|
if err := contextStore.GetEndpoint(currentContext, &kubeContext); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config, err := resources.LoadConfig(kubeContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
actions, err := helm.NewActions(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &composeService{
|
return &composeService{
|
||||||
sdk: chartsAPI,
|
sdk: actions,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type composeService struct {
|
|
||||||
sdk charts.SDK
|
|
||||||
}
|
|
||||||
|
|
||||||
// Up executes the equivalent to a `compose up`
|
// Up executes the equivalent to a `compose up`
|
||||||
func (s *composeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
|
func (s *composeService) Up(ctx context.Context, project *types.Project, options compose.UpOptions) error {
|
||||||
return s.sdk.Install(project)
|
w := progress.ContextWriter(ctx)
|
||||||
|
|
||||||
|
eventName := "Convert to Helm charts"
|
||||||
|
w.Event(progress.CreatingEvent(eventName))
|
||||||
|
|
||||||
|
chart, err := helm.GetChartInMemory(project)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.Event(progress.NewEvent(eventName, progress.Done, ""))
|
||||||
|
|
||||||
|
eventName = "Install Helm charts"
|
||||||
|
w.Event(progress.CreatingEvent(eventName))
|
||||||
|
|
||||||
|
err = s.sdk.InstallChart(project.Name, chart, func(format string, v ...interface{}) {
|
||||||
|
message := fmt.Sprintf(format, v...)
|
||||||
|
w.Event(progress.NewEvent(eventName, progress.Done, message))
|
||||||
|
})
|
||||||
|
|
||||||
|
w.Event(progress.NewEvent(eventName, progress.Done, ""))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Down executes the equivalent to a `compose down`
|
// Down executes the equivalent to a `compose down`
|
||||||
func (s *composeService) Down(ctx context.Context, projectName string, options compose.DownOptions) error {
|
func (s *composeService) Down(ctx context.Context, projectName string, options compose.DownOptions) error {
|
||||||
return s.sdk.Uninstall(projectName)
|
w := progress.ContextWriter(ctx)
|
||||||
|
|
||||||
|
eventName := fmt.Sprintf("Remove %s", projectName)
|
||||||
|
w.Event(progress.CreatingEvent(eventName))
|
||||||
|
|
||||||
|
logger := func(format string, v ...interface{}) {
|
||||||
|
message := fmt.Sprintf(format, v...)
|
||||||
|
if strings.Contains(message, "Starting delete") {
|
||||||
|
action := strings.Replace(message, "Starting delete for", "Delete", 1)
|
||||||
|
|
||||||
|
w.Event(progress.CreatingEvent(action))
|
||||||
|
w.Event(progress.NewEvent(action, progress.Done, ""))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Event(progress.NewEvent(eventName, progress.Working, message))
|
||||||
|
}
|
||||||
|
err := s.sdk.Uninstall(projectName, logger)
|
||||||
|
w.Event(progress.NewEvent(eventName, progress.Done, ""))
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// List executes the equivalent to a `docker stack ls`
|
// List executes the equivalent to a `docker stack ls`
|
||||||
func (s *composeService) List(ctx context.Context) ([]compose.Stack, error) {
|
func (s *composeService) List(ctx context.Context) ([]compose.Stack, error) {
|
||||||
return s.sdk.List()
|
return s.sdk.ListReleases()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build executes the equivalent to a `compose build`
|
// Build executes the equivalent to a `compose build`
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"github.com/docker/compose-cli/api/errdefs"
|
"github.com/docker/compose-cli/api/errdefs"
|
||||||
"github.com/docker/compose-cli/utils/prompt"
|
"github.com/docker/compose-cli/utils/prompt"
|
||||||
|
|
||||||
"github.com/docker/compose-cli/kube/charts/kubernetes"
|
"github.com/docker/compose-cli/kube/resources"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContextParams options for creating a Kubernetes context
|
// ContextParams options for creating a Kubernetes context
|
||||||
@ -47,7 +47,7 @@ func (cp ContextParams) CreateContextData() (interface{}, string, error) {
|
|||||||
}
|
}
|
||||||
user := prompt.User{}
|
user := prompt.User{}
|
||||||
selectContext := func() error {
|
selectContext := func() error {
|
||||||
contexts, err := kubernetes.ListAvailableKubeConfigContexts(cp.KubeConfigPath)
|
contexts, err := resources.ListAvailableKubeConfigContexts(cp.KubeConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,15 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"html/template"
|
"html/template"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/compose-spec/compose-go/types"
|
||||||
|
"github.com/docker/compose-cli/kube/resources"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
chart "helm.sh/helm/v3/pkg/chart"
|
chart "helm.sh/helm/v3/pkg/chart"
|
||||||
loader "helm.sh/helm/v3/pkg/chart/loader"
|
loader "helm.sh/helm/v3/pkg/chart/loader"
|
||||||
|
util "helm.sh/helm/v3/pkg/chartutil"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -107,3 +111,41 @@ func jsonToYaml(j []byte, spaces int) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChartInMemory get memory representation of helm chart
|
||||||
|
func GetChartInMemory(project *types.Project) (*chart.Chart, error) {
|
||||||
|
// replace _ with - in volume names
|
||||||
|
for k, v := range project.Volumes {
|
||||||
|
volumeName := strings.ReplaceAll(k, "_", "-")
|
||||||
|
if volumeName != k {
|
||||||
|
project.Volumes[volumeName] = v
|
||||||
|
delete(project.Volumes, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects, err := resources.MapToKubernetesObjects(project)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//in memory files
|
||||||
|
return ConvertToChart(project.Name, objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveChart converts compose project to helm and saves the chart
|
||||||
|
func SaveChart(project *types.Project, dest string) error {
|
||||||
|
chart, err := GetChartInMemory(project)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return util.SaveDir(chart, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateChart generates helm chart from Compose project
|
||||||
|
func GenerateChart(project *types.Project, dirname string) error {
|
||||||
|
if strings.Contains(dirname, ".") {
|
||||||
|
splits := strings.SplitN(dirname, ".", 2)
|
||||||
|
dirname = splits[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
dirname = filepath.Dir(dirname)
|
||||||
|
return SaveChart(project, dirname)
|
||||||
|
}
|
@ -19,27 +19,25 @@
|
|||||||
package helm
|
package helm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/docker/compose-cli/api/compose"
|
"github.com/docker/compose-cli/api/compose"
|
||||||
action "helm.sh/helm/v3/pkg/action"
|
"helm.sh/helm/v3/pkg/action"
|
||||||
chart "helm.sh/helm/v3/pkg/chart"
|
"helm.sh/helm/v3/pkg/chart"
|
||||||
loader "helm.sh/helm/v3/pkg/chart/loader"
|
|
||||||
env "helm.sh/helm/v3/pkg/cli"
|
env "helm.sh/helm/v3/pkg/cli"
|
||||||
"helm.sh/helm/v3/pkg/release"
|
"helm.sh/helm/v3/pkg/release"
|
||||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Actions helm actions
|
// Actions implements charts installation management
|
||||||
type Actions struct {
|
type Actions struct {
|
||||||
Config *action.Configuration
|
Config *action.Configuration
|
||||||
Namespace string
|
Namespace string
|
||||||
|
initialize func(f func(format string, v ...interface{})) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHelmActions new helm action
|
// NewActions new helm action
|
||||||
func NewHelmActions(ctx context.Context, getter genericclioptions.RESTClientGetter) (*Actions, error) {
|
func NewActions(getter genericclioptions.RESTClientGetter) (*Actions, error) {
|
||||||
if getter == nil {
|
if getter == nil {
|
||||||
settings := env.New()
|
settings := env.New()
|
||||||
getter = settings.RESTClientGetter()
|
getter = settings.RESTClientGetter()
|
||||||
@ -55,40 +53,38 @@ func NewHelmActions(ctx context.Context, getter genericclioptions.RESTClientGett
|
|||||||
},
|
},
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
}
|
}
|
||||||
err := actions.Config.Init(getter, namespace, "configmap", log.Printf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return actions, actions.Config.KubeClient.IsReachable()
|
actions.initialize = func(f func(format string, v ...interface{})) error {
|
||||||
|
err := actions.Config.Init(getter, namespace, "configmap", f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return actions.Config.KubeClient.IsReachable()
|
||||||
|
}
|
||||||
|
return actions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//InstallChartFromDir install from dir
|
// InstallChart installs chart
|
||||||
func (hc *Actions) InstallChartFromDir(name string, chartpath string) error {
|
func (hc *Actions) InstallChart(name string, chart *chart.Chart, logger func(format string, v ...interface{})) error {
|
||||||
chart, err := loader.Load(chartpath)
|
err := hc.initialize(logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return hc.InstallChart(name, chart)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstallChart instal chart
|
|
||||||
func (hc *Actions) InstallChart(name string, chart *chart.Chart) error {
|
|
||||||
actInstall := action.NewInstall(hc.Config)
|
actInstall := action.NewInstall(hc.Config)
|
||||||
actInstall.ReleaseName = name
|
actInstall.ReleaseName = name
|
||||||
actInstall.Namespace = hc.Namespace
|
actInstall.Namespace = hc.Namespace
|
||||||
|
_, err = actInstall.Run(chart, map[string]interface{}{})
|
||||||
release, err := actInstall.Run(chart, map[string]interface{}{})
|
return err
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Println("Release status: ", release.Info.Status)
|
|
||||||
log.Println(release.Info.Description)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uninstall uninstall chart
|
// Uninstall uninstall chart
|
||||||
func (hc *Actions) Uninstall(name string) error {
|
func (hc *Actions) Uninstall(name string, logger func(format string, v ...interface{})) error {
|
||||||
|
err := hc.initialize(logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
release, err := hc.Get(name)
|
release, err := hc.Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -97,12 +93,8 @@ func (hc *Actions) Uninstall(name string) error {
|
|||||||
return errors.New("no release found with the name provided")
|
return errors.New("no release found with the name provided")
|
||||||
}
|
}
|
||||||
actUninstall := action.NewUninstall(hc.Config)
|
actUninstall := action.NewUninstall(hc.Config)
|
||||||
response, err := actUninstall.Run(name)
|
_, err = actUninstall.Run(name)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Println(response.Release.Info.Description)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get get released object for a named chart
|
// Get get released object for a named chart
|
||||||
@ -113,6 +105,10 @@ func (hc *Actions) Get(name string) (*release.Release, error) {
|
|||||||
|
|
||||||
// ListReleases lists chart releases
|
// ListReleases lists chart releases
|
||||||
func (hc *Actions) ListReleases() ([]compose.Stack, error) {
|
func (hc *Actions) ListReleases() ([]compose.Stack, error) {
|
||||||
|
err := hc.initialize(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
actList := action.NewList(hc.Config)
|
actList := action.NewList(hc.Config)
|
||||||
releases, err := actList.Run()
|
releases, err := actList.Run()
|
||||||
if err != nil {
|
if err != nil {
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -16,7 +16,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubernetes
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
Loading…
x
Reference in New Issue
Block a user