pkg/provider/kind/kind.go (153 lines of code) (raw):
// Copyright 2020 The Prometheus 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 kind
import (
"context"
"fmt"
"strings"
"github.com/pkg/errors"
"gopkg.in/alecthomas/kingpin.v2"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"sigs.k8s.io/kind/pkg/cluster"
"sigs.k8s.io/kind/pkg/cmd"
"github.com/prometheus/test-infra/pkg/provider"
k8sProvider "github.com/prometheus/test-infra/pkg/provider/k8s"
)
type Resource = provider.Resource
// KIND holds the fields used to generate an API request.
type KIND struct {
// The k8s provider used when we work with the manifest files.
k8sProvider *k8sProvider.K8s
// The kind provider used to instantiate a new provider.
kindProvider *cluster.Provider
// Final DeploymentFiles files.
DeploymentFiles []string
// Final DeploymentVars.
DeploymentVars map[string]string
// DeployResource to construct DeploymentVars and DeploymentFiles
DeploymentResource *provider.DeploymentResource
// Content bytes after parsing the template variables, grouped by filename.
kindResources []Resource
// K8s resource.runtime objects after parsing the template variables, grouped by filename.
k8sResources []k8sProvider.Resource
ctx context.Context
// KIND kuberconfig file
kubeconfig string
}
// New is the KIND constructor.
func New(dr *provider.DeploymentResource) *KIND {
return &KIND{
DeploymentResource: dr,
kindProvider: cluster.NewProvider(
cluster.ProviderWithLogger(cmd.NewLogger()),
),
ctx: context.Background(),
kubeconfig: homedir.HomeDir() + "/.kube/config",
}
}
// SetupDeploymentResources Sets up DeploymentVars and DeploymentFiles
func (c *KIND) SetupDeploymentResources(*kingpin.ParseContext) error {
customDeploymentVars := map[string]string{
"NGINX_SERVICE_TYPE": "NodePort",
"LOADGEN_SCALE_UP_REPLICAS": "2",
}
c.DeploymentFiles = c.DeploymentResource.DeploymentFiles
c.DeploymentVars = provider.MergeDeploymentVars(
c.DeploymentResource.DefaultDeploymentVars,
customDeploymentVars,
c.DeploymentResource.FlagDeploymentVars,
)
return nil
}
// KINDDeploymentsParse parses the environment/kind deployment files and saves the result as bytes grouped by the filename.
// Any DeploymentVar will be replaced in the resources files following the golang text template format.
func (c *KIND) KINDDeploymentsParse(*kingpin.ParseContext) error {
if err := c.checkDeploymentVarsAndFiles(); err != nil {
return err
}
deploymentResource, err := provider.DeploymentsParse(c.DeploymentFiles, c.DeploymentVars)
if err != nil {
return err
}
c.kindResources = deploymentResource
return nil
}
func (c *KIND) K8SDeploymentsParse(*kingpin.ParseContext) error {
if err := c.checkDeploymentVarsAndFiles(); err != nil {
return err
}
deploymentResource, err := provider.DeploymentsParse(c.DeploymentFiles, c.DeploymentVars)
if err != nil {
return err
}
for _, deployment := range deploymentResource {
decode := scheme.Codecs.UniversalDeserializer().Decode
k8sObjects := make([]runtime.Object, 0)
for _, text := range strings.Split(string(deployment.Content), provider.Separator) {
text = strings.TrimSpace(text)
if len(text) == 0 {
continue
}
resource, _, err := decode([]byte(text), nil, nil)
if err != nil {
return errors.Wrapf(err, "decoding the resource file:%v, section:%v...", deployment.FileName, text[:100])
}
if resource == nil {
continue
}
k8sObjects = append(k8sObjects, resource)
}
if len(k8sObjects) > 0 {
c.k8sResources = append(c.k8sResources, k8sProvider.Resource{FileName: deployment.FileName, Objects: k8sObjects})
}
}
return nil
}
// checkDeploymentVarsAndFiles checks whether the requied deployment vars are passed.
func (c *KIND) checkDeploymentVarsAndFiles() error {
reqDepVars := []string{"CLUSTER_NAME"}
for _, k := range reqDepVars {
if v, ok := c.DeploymentVars[k]; !ok || v == "" {
return fmt.Errorf("missing required %v variable", k)
}
}
if len(c.DeploymentFiles) == 0 {
return fmt.Errorf("missing deployment file(s)")
}
return nil
}
// ClusterCreate create a new cluster or applies changes to an existing cluster.
func (c *KIND) ClusterCreate(*kingpin.ParseContext) error {
for _, deployment := range c.kindResources {
CreateWithConfigFile := cluster.CreateWithRawConfig(deployment.Content)
err := c.kindProvider.Create(c.DeploymentVars["CLUSTER_NAME"], CreateWithConfigFile)
if err != nil {
return err
}
}
return nil
}
// ClusterDelete deletes a k8s cluster.
func (c *KIND) ClusterDelete(*kingpin.ParseContext) error {
err := c.kindProvider.Delete(c.DeploymentVars["CLUSTER_NAME"], c.kubeconfig)
if err != nil {
return err
}
return nil
}
// NewK8sProvider sets the k8s provider used for deploying k8s manifests.
func (c *KIND) NewK8sProvider(*kingpin.ParseContext) error {
var err error
apiConfig, err := clientcmd.LoadFromFile(c.kubeconfig)
if err != nil {
return err
}
c.k8sProvider, err = k8sProvider.New(c.ctx, apiConfig)
if err != nil {
return err
}
return nil
}
// ResourceApply calls k8s.ResourceApply to apply the k8s objects in the manifest files.
func (c *KIND) ResourceApply(*kingpin.ParseContext) error {
if err := c.k8sProvider.ResourceApply(c.k8sResources); err != nil {
return err
}
return nil
}
// ResourceDelete calls k8s.ResourceDelete to apply the k8s objects in the manifest files.
func (c *KIND) ResourceDelete(*kingpin.ParseContext) error {
if err := c.k8sProvider.ResourceDelete(c.k8sResources); err != nil {
return err
}
return nil
}
// GetDeploymentVars shows deployment variables.
func (c *KIND) GetDeploymentVars(parseContext *kingpin.ParseContext) error {
fmt.Print("-------------------\n DeploymentVars \n------------------- \n")
for key, value := range c.DeploymentVars {
fmt.Println(key, ": ", value)
}
return nil
}