github.com/caos/orbos@v1.5.14-0.20221103111702-e6cd0cea7ad4/internal/operator/boom/application/applications/reconciling/customimage/customimage.go (about)

     1  package customimage
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/caos/orbos/internal/operator/boom/api/latest/reconciling"
    10  	"github.com/caos/orbos/internal/operator/boom/application/applications/reconciling/info"
    11  	"github.com/caos/orbos/internal/operator/boom/application/resources"
    12  	"github.com/caos/orbos/internal/operator/boom/labels"
    13  	"github.com/caos/orbos/internal/utils/helper"
    14  	"github.com/caos/orbos/pkg/secret"
    15  	"github.com/caos/orbos/pkg/secret/read"
    16  )
    17  
    18  const (
    19  	tab           string = "  "
    20  	nl            string = "\n"
    21  	sshFolderName string = "/home/argocd/ssh-keys"
    22  	gpgFolderName string = "/home/argocd/gpg-import"
    23  )
    24  
    25  type SecretVolume struct {
    26  	Name        string  `yaml:"name"`
    27  	Secret      *Secret `yaml:"secret,omitempty"`
    28  	DefaultMode int     `yaml:"defaultMode"`
    29  }
    30  
    31  type Secret struct {
    32  	SecretName string  `yaml:"secretName,omitempty"`
    33  	Items      []*Item `yaml:"items,omitempty"`
    34  }
    35  
    36  type Item struct {
    37  	Key  string `yaml:"key"`
    38  	Path string `yaml:"path"`
    39  }
    40  
    41  type VolumeMount struct {
    42  	Name      string `yaml:"name"`
    43  	MountPath string `yaml:"mountPath,omitempty"`
    44  	SubPath   string `yaml:"subPath,omitempty"`
    45  	ReadOnly  bool   `yaml:"readOnly,omitempty"`
    46  }
    47  
    48  type CustomImage struct {
    49  	ImageRepository  string
    50  	ImageTag         string
    51  	AddSecretVolumes []*SecretVolume
    52  	AddVolumeMounts  []*VolumeMount
    53  }
    54  
    55  func getSecretName(store string, ty string) string {
    56  	return strings.Join([]string{"argocd", getInternalName(store, ty)}, "-")
    57  }
    58  func getSecretKey(store string, ty string) string {
    59  	return strings.Join([]string{store, ty}, "-")
    60  }
    61  func getInternalName(store string, ty string) string {
    62  	return strings.Join([]string{"store", store, ty}, "-")
    63  }
    64  
    65  func GetSecrets(spec *reconciling.Reconciling) []interface{} {
    66  	namespace := "caos-system"
    67  	secrets := make([]interface{}, 0)
    68  
    69  	if spec.CustomImage == nil || spec.CustomImage.GopassStores == nil {
    70  		return secrets
    71  	}
    72  
    73  	for _, store := range spec.CustomImage.GopassStores {
    74  		if read.IsCrdSecret(store.GPGKey, store.ExistingGPGKeySecret) {
    75  			ty := "gpg"
    76  			data := map[string]string{
    77  				getSecretKey(store.StoreName, ty): store.GPGKey.Value,
    78  			}
    79  
    80  			conf := &resources.SecretConfig{
    81  				Name:      getSecretName(store.StoreName, ty),
    82  				Namespace: namespace,
    83  				Labels:    labels.GetAllApplicationLabels(info.GetName()),
    84  				Data:      data,
    85  			}
    86  			secretRes := resources.NewSecret(conf)
    87  			secrets = append(secrets, secretRes)
    88  		}
    89  
    90  		if read.IsCrdSecret(store.SSHKey, store.ExistingSSHKeySecret) {
    91  			ty := "ssh"
    92  			data := map[string]string{
    93  				getSecretKey(store.StoreName, ty): store.SSHKey.Value,
    94  			}
    95  
    96  			conf := &resources.SecretConfig{
    97  				Name:      getSecretName(store.StoreName, ty),
    98  				Namespace: namespace,
    99  				Labels:    labels.GetAllApplicationLabels(info.GetName()),
   100  				Data:      data,
   101  			}
   102  			secretRes := resources.NewSecret(conf)
   103  			secrets = append(secrets, secretRes)
   104  		}
   105  	}
   106  
   107  	return secrets
   108  }
   109  
   110  func FromSpec(spec *reconciling.Reconciling, imageTags map[string]string) *CustomImage {
   111  	imageRepository := "ghcr.io/caos/argocd-secrets"
   112  
   113  	vols := make([]*SecretVolume, 0)
   114  	volMounts := make([]*VolumeMount, 0)
   115  	for _, store := range spec.CustomImage.GopassStores {
   116  
   117  		volGPG, volMountGPG := getVolAndVolMount(store.StoreName, "gpg", store.GPGKey, store.ExistingGPGKeySecret, gpgFolderName)
   118  		if volGPG != nil && volMountGPG != nil {
   119  			vols = append(vols, volGPG)
   120  			volMounts = append(volMounts, volMountGPG)
   121  		}
   122  
   123  		volSSH, volMountSSH := getVolAndVolMount(store.StoreName, "ssh", store.SSHKey, store.ExistingSSHKeySecret, sshFolderName)
   124  		if volSSH != nil && volMountSSH != nil {
   125  			vols = append(vols, volSSH)
   126  			volMounts = append(volMounts, volMountSSH)
   127  		}
   128  	}
   129  
   130  	return &CustomImage{
   131  		ImageRepository:  imageRepository,
   132  		ImageTag:         imageTags[imageRepository],
   133  		AddSecretVolumes: vols,
   134  		AddVolumeMounts:  volMounts,
   135  	}
   136  }
   137  
   138  func getVolAndVolMount(storeName string, ty string, secret *secret.Secret, existent *secret.Existing, foldername string) (*SecretVolume, *VolumeMount) {
   139  	internalName := ""
   140  	name := ""
   141  	key := ""
   142  
   143  	if read.IsCrdSecret(secret, existent) {
   144  		internalName = getInternalName(storeName, ty)
   145  		name = getSecretName(storeName, ty)
   146  		key = getSecretKey(storeName, ty)
   147  	} else if read.IsExistentSecret(secret, existent) {
   148  		internalName = existent.InternalName
   149  		name = existent.Name
   150  		key = existent.Key
   151  	} else {
   152  		return nil, nil
   153  	}
   154  
   155  	return getVol(internalName, name, key), getVolMount(internalName, foldername)
   156  }
   157  
   158  func getVol(internal string, name string, key string) *SecretVolume {
   159  	return &SecretVolume{
   160  		Name: internal,
   161  		Secret: &Secret{
   162  			SecretName: name,
   163  			Items: []*Item{{
   164  				Key:  key,
   165  				Path: internal,
   166  			},
   167  			},
   168  		},
   169  		DefaultMode: 0544,
   170  	}
   171  }
   172  
   173  func getVolMount(internal, foldername string) *VolumeMount {
   174  	mountPath := filepath.Join(foldername, internal)
   175  	return &VolumeMount{
   176  		Name:      internal,
   177  		MountPath: mountPath,
   178  		SubPath:   internal,
   179  		ReadOnly:  false,
   180  	}
   181  }
   182  
   183  type stores struct {
   184  	Stores []*store `json:"stores"`
   185  }
   186  
   187  type store struct {
   188  	Directory string `json:"directory"`
   189  	StoreName string `json:"storename"`
   190  }
   191  
   192  func AddPostStartFromSpec(spec *reconciling.Reconciling, resultFilePath string) error {
   193  	stores := &stores{}
   194  	for _, v := range spec.CustomImage.GopassStores {
   195  		stores.Stores = append(stores.Stores, &store{Directory: v.Directory, StoreName: v.StoreName})
   196  	}
   197  	jsonStores, err := json.Marshal(stores)
   198  	if err != nil {
   199  		return fmt.Errorf("marshaling gopass stores in json failed: %w", err)
   200  	}
   201  	jsonStoresStr := strings.ReplaceAll(string(jsonStores), "\"", "\\\"")
   202  
   203  	addCommand := strings.Join([]string{"/home/argocd/initialize_gopass.sh '", jsonStoresStr, "' ", gpgFolderName, " ", sshFolderName}, "")
   204  	addLifecycle := strings.Join([]string{
   205  		tab, tab, tab, tab, "lifecycle:", nl,
   206  		tab, tab, tab, tab, tab, "postStart:", nl,
   207  		tab, tab, tab, tab, tab, tab, "exec:", nl,
   208  		tab, tab, tab, tab, tab, tab, tab, "command: [\"/bin/bash\", \"-c\", \"", addCommand, "\"]", nl,
   209  	}, "")
   210  
   211  	return helper.AddStringBeforePointForKindAndName(resultFilePath, "Deployment", "argocd-repo-server", "imagePullPolicy:", addLifecycle)
   212  }