github.com/openshift/installer@v1.4.17/pkg/asset/agent/joiner/addnodesconfig.go (about)

     1  package joiner
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/util/validation/field"
    12  	"sigs.k8s.io/yaml"
    13  
    14  	"github.com/openshift/installer/pkg/asset"
    15  	"github.com/openshift/installer/pkg/types/agent"
    16  	"github.com/openshift/installer/pkg/validate"
    17  )
    18  
    19  const (
    20  	addNodesParamsFile  = ".addnodesparams"
    21  	nodesConfigFilename = "nodes-config.yaml"
    22  )
    23  
    24  // AddNodesConfig is used to store the current configuration
    25  // for the command.
    26  type AddNodesConfig struct {
    27  	Params Params
    28  	Config Config
    29  }
    30  
    31  var _ asset.WritableAsset = (*AddNodesConfig)(nil)
    32  
    33  // Config defines the configuration for the nodes-config.yaml file
    34  // used by the add-nodes command.
    35  type Config struct {
    36  	metav1.TypeMeta   `json:",inline"`
    37  	metav1.ObjectMeta `json:"metadata,omitempty"`
    38  
    39  	CPUArchitecture string       `json:"cpuArchitecture,omitempty"`
    40  	SSHKey          string       `json:"sshKey,omitempty"`
    41  	Hosts           []agent.Host `json:"hosts,omitempty"`
    42  }
    43  
    44  // Params is used to store the command line parameters.
    45  type Params struct {
    46  	Kubeconfig string `json:"kubeconfig,omitempty"`
    47  }
    48  
    49  // Save stores the current parameters on disk.
    50  func (p *Params) Save(assetsDir string) error {
    51  	data, err := json.Marshal(p)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	fileName := filepath.Join(assetsDir, addNodesParamsFile)
    57  	return os.WriteFile(fileName, data, 0o600)
    58  }
    59  
    60  // Name returns the human-friendly name of the asset.
    61  func (*AddNodesConfig) Name() string {
    62  	return "AddNodes Config"
    63  }
    64  
    65  // Dependencies returns all of the dependencies directly needed to generate
    66  // the asset.
    67  func (*AddNodesConfig) Dependencies() []asset.Asset {
    68  	return []asset.Asset{}
    69  }
    70  
    71  // Generate it's empty for this asset, always loaded from disk.
    72  func (*AddNodesConfig) Generate(_ context.Context, dependencies asset.Parents) error {
    73  	return nil
    74  }
    75  
    76  // Files returns the files generated by the asset.
    77  func (*AddNodesConfig) Files() []*asset.File {
    78  	return []*asset.File{}
    79  }
    80  
    81  // Load returns agent config asset from the disk.
    82  func (a *AddNodesConfig) Load(f asset.FileFetcher) (bool, error) {
    83  	// Load params file.
    84  	file, err := f.FetchByName(addNodesParamsFile)
    85  	if err != nil {
    86  		if os.IsNotExist(err) {
    87  			return false, nil
    88  		}
    89  		return false, fmt.Errorf("failed to load %s file: %w", addNodesParamsFile, err)
    90  	}
    91  
    92  	params := &Params{}
    93  	if err = json.Unmarshal(file.Data, params); err != nil {
    94  		return false, fmt.Errorf("failed to unmarshal %s: %w", addNodesParamsFile, err)
    95  	}
    96  	a.Params = *params
    97  
    98  	// Load nodes-config.yaml file.
    99  	file, err = f.FetchByName(nodesConfigFilename)
   100  	if err != nil {
   101  		return false, fmt.Errorf("failed to load %s file: %w", nodesConfigFilename, err)
   102  	}
   103  
   104  	config := Config{}
   105  	if err = yaml.Unmarshal(file.Data, &config); err != nil {
   106  		return false, fmt.Errorf("failed to unmarshal %s: %w", nodesConfigFilename, err)
   107  	}
   108  	a.Config = config
   109  
   110  	err = a.finish()
   111  	if err != nil {
   112  		return false, err
   113  	}
   114  	return true, nil
   115  }
   116  
   117  func (a *AddNodesConfig) finish() error {
   118  	allErrs := field.ErrorList{}
   119  
   120  	if err := a.validateHosts(); err != nil {
   121  		allErrs = append(allErrs, err...)
   122  	}
   123  	if err := a.validateSSHKey(); err != nil {
   124  		allErrs = append(allErrs, err...)
   125  	}
   126  
   127  	return allErrs.ToAggregate()
   128  }
   129  
   130  func (a *AddNodesConfig) validateHosts() field.ErrorList {
   131  	var allErrs field.ErrorList
   132  
   133  	if len(a.Config.Hosts) == 0 {
   134  		fieldPath := field.NewPath("hosts")
   135  		allErrs = append(allErrs, field.Required(fieldPath, "at least one host must be defined"))
   136  	}
   137  
   138  	return allErrs
   139  }
   140  
   141  func (a *AddNodesConfig) validateSSHKey() field.ErrorList {
   142  	var allErrs field.ErrorList
   143  
   144  	if a.Config.SSHKey == "" {
   145  		return nil
   146  	}
   147  
   148  	if err := validate.SSHPublicKey(a.Config.SSHKey); err != nil {
   149  		allErrs = append(allErrs, field.Invalid(field.NewPath("sshKey"), a.Config.SSHKey, err.Error()))
   150  	}
   151  	return allErrs
   152  }