github.com/argoproj/argo-cd@v1.8.7/util/ksonnet/ksonnet.go (about)

     1  package ksonnet
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/argoproj/gitops-engine/pkg/utils/kube"
    13  	"github.com/ghodss/yaml"
    14  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    15  
    16  	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
    17  	executil "github.com/argoproj/argo-cd/util/exec"
    18  )
    19  
    20  // Destination returns the deployment destination for an environment in app spec data
    21  func Destination(data []byte, environment string) (*v1alpha1.ApplicationDestination, error) {
    22  	var appSpec struct {
    23  		Environments map[string]struct {
    24  			Destination v1alpha1.ApplicationDestination
    25  		}
    26  	}
    27  	err := yaml.Unmarshal(data, &appSpec)
    28  	if err != nil {
    29  		return nil, fmt.Errorf("could not unmarshal ksonnet spec app.yaml: %v", err)
    30  	}
    31  
    32  	envSpec, ok := appSpec.Environments[environment]
    33  	if !ok {
    34  		return nil, fmt.Errorf("environment '%s' does not exist in ksonnet app", environment)
    35  	}
    36  
    37  	return &envSpec.Destination, nil
    38  }
    39  
    40  // KsonnetApp represents a ksonnet application directory and provides wrapper functionality around
    41  // the `ks` command.
    42  type KsonnetApp interface {
    43  	// Root is the root path ksonnet application directory
    44  	Root() string
    45  
    46  	// Show returns a list of unstructured objects that would be applied to an environment
    47  	Show(environment string) ([]*unstructured.Unstructured, error)
    48  
    49  	// Destination returns the deployment destination for an environment
    50  	Destination(environment string) (*v1alpha1.ApplicationDestination, error)
    51  
    52  	// ListParams returns list of ksonnet parameters
    53  	ListParams(environment string) ([]*v1alpha1.KsonnetParameter, error)
    54  
    55  	// SetComponentParams updates component parameter in specified environment.
    56  	SetComponentParams(environment string, component string, param string, value string) error
    57  }
    58  
    59  // Version returns the version of ksonnet used when running ksonnet commands
    60  func Version() (string, error) {
    61  	ksApp := ksonnetApp{}
    62  	out, err := ksApp.ksCmd("", "version")
    63  	if err != nil {
    64  		return "", fmt.Errorf("unable to determine ksonnet version: %v", err)
    65  	}
    66  	ksonnetVersionStr := strings.Split(out, "\n")[0]
    67  	parts := strings.SplitN(ksonnetVersionStr, ":", 2)
    68  	if len(parts) != 2 {
    69  		return "", fmt.Errorf("unexpected version string format: %s", ksonnetVersionStr)
    70  	}
    71  	version := strings.TrimSpace(parts[1])
    72  	if version[0] != 'v' {
    73  		version = "v" + version
    74  	}
    75  	return version, nil
    76  }
    77  
    78  type ksonnetApp struct {
    79  	rootDir string
    80  }
    81  
    82  // NewKsonnetApp tries to create a new wrapper to run commands on the `ks` command-line tool.
    83  func NewKsonnetApp(path string) (KsonnetApp, error) {
    84  	ksApp := ksonnetApp{rootDir: path}
    85  	// ensure that the file exists
    86  	if _, err := ksApp.appYamlPath(); err != nil {
    87  		return nil, err
    88  	}
    89  	return &ksApp, nil
    90  }
    91  
    92  func (k *ksonnetApp) appYamlPath() (string, error) {
    93  	const appYamlName = "app.yaml"
    94  	p := filepath.Join(k.Root(), appYamlName)
    95  	if _, err := os.Stat(p); err != nil {
    96  		return "", err
    97  	}
    98  	return p, nil
    99  }
   100  
   101  func (k *ksonnetApp) ksCmd(args ...string) (string, error) {
   102  	cmd := exec.Command("ks", args...)
   103  	cmd.Dir = k.Root()
   104  
   105  	return executil.Run(cmd)
   106  }
   107  
   108  func (k *ksonnetApp) Root() string {
   109  	return k.rootDir
   110  }
   111  
   112  // Show generates a concatenated list of Kubernetes manifests in the given environment.
   113  func (k *ksonnetApp) Show(environment string) ([]*unstructured.Unstructured, error) {
   114  	out, err := k.ksCmd("show", environment)
   115  	if err != nil {
   116  		return nil, fmt.Errorf("`ks show` failed: %v", err)
   117  	}
   118  	return kube.SplitYAML([]byte(out))
   119  }
   120  
   121  // Destination returns the deployment destination for an environment
   122  func (k *ksonnetApp) Destination(environment string) (*v1alpha1.ApplicationDestination, error) {
   123  	p, err := k.appYamlPath()
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	data, err := ioutil.ReadFile(p)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	return Destination(data, environment)
   132  }
   133  
   134  // ListParams returns list of ksonnet parameters
   135  func (k *ksonnetApp) ListParams(environment string) ([]*v1alpha1.KsonnetParameter, error) {
   136  	args := []string{"param", "list", "--output", "json"}
   137  	if environment != "" {
   138  		args = append(args, "--env", environment)
   139  	}
   140  	out, err := k.ksCmd(args...)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	// Auxiliary data to hold unmarshaled JSON output, which may use different field names
   145  	var ksParams struct {
   146  		Data []struct {
   147  			Component string `json:"component"`
   148  			Key       string `json:"param"`
   149  			Value     string `json:"value"`
   150  		} `json:"data"`
   151  	}
   152  	if err := json.Unmarshal([]byte(out), &ksParams); err != nil {
   153  		return nil, err
   154  	}
   155  	var params []*v1alpha1.KsonnetParameter
   156  	for _, ksParam := range ksParams.Data {
   157  		value := strings.Trim(ksParam.Value, `'"`)
   158  		params = append(params, &v1alpha1.KsonnetParameter{
   159  			Component: ksParam.Component,
   160  			Name:      ksParam.Key,
   161  			Value:     value,
   162  		})
   163  	}
   164  	return params, nil
   165  }
   166  
   167  // SetComponentParams updates component parameter in specified environment.
   168  func (k *ksonnetApp) SetComponentParams(environment string, component string, param string, value string) error {
   169  	_, err := k.ksCmd("param", "set", component, param, value, "--env", environment)
   170  	return err
   171  }