github.com/openshift/installer@v1.4.17/pkg/asset/agent/manifests/clusterimageset.go (about) 1 package manifests 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 9 "github.com/pkg/errors" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/apimachinery/pkg/util/validation/field" 12 "sigs.k8s.io/yaml" 13 14 hivev1 "github.com/openshift/hive/apis/hive/v1" 15 "github.com/openshift/installer/pkg/asset" 16 "github.com/openshift/installer/pkg/asset/agent" 17 "github.com/openshift/installer/pkg/asset/agent/joiner" 18 "github.com/openshift/installer/pkg/asset/agent/workflow" 19 "github.com/openshift/installer/pkg/asset/releaseimage" 20 "github.com/openshift/installer/pkg/version" 21 ) 22 23 var ( 24 clusterImageSetFilename = filepath.Join(clusterManifestDir, "cluster-image-set.yaml") 25 ) 26 27 // ClusterImageSet generates the cluster-image-set.yaml file. 28 type ClusterImageSet struct { 29 File *asset.File 30 Config *hivev1.ClusterImageSet 31 } 32 33 var _ asset.WritableAsset = (*ClusterImageSet)(nil) 34 35 // Name returns a human friendly name for the asset. 36 func (*ClusterImageSet) Name() string { 37 return "ClusterImageSet Config" 38 } 39 40 // Dependencies returns all of the dependencies directly needed to generate 41 // the asset. 42 func (*ClusterImageSet) Dependencies() []asset.Asset { 43 return []asset.Asset{ 44 &workflow.AgentWorkflow{}, 45 &joiner.ClusterInfo{}, 46 &releaseimage.Image{}, 47 &agent.OptionalInstallConfig{}, 48 } 49 } 50 51 // Generate generates the ClusterImageSet manifest. 52 func (a *ClusterImageSet) Generate(ctx context.Context, dependencies asset.Parents) error { 53 agentWorkflow := &workflow.AgentWorkflow{} 54 clusterInfo := &joiner.ClusterInfo{} 55 releaseImage := &releaseimage.Image{} 56 installConfig := &agent.OptionalInstallConfig{} 57 dependencies.Get(releaseImage, installConfig, agentWorkflow, clusterInfo) 58 59 switch agentWorkflow.Workflow { 60 case workflow.AgentWorkflowTypeInstall: 61 currentVersion, err := version.Version() 62 if err != nil { 63 return err 64 } 65 66 clusterNamespace := "" 67 if installConfig.Config != nil { 68 clusterNamespace = installConfig.ClusterNamespace() 69 } 70 err = a.generateManifest(currentVersion, releaseImage.PullSpec, clusterNamespace) 71 if err != nil { 72 return err 73 } 74 case workflow.AgentWorkflowTypeAddNodes: 75 return a.generateManifest(clusterInfo.Version, clusterInfo.ReleaseImage, clusterInfo.Namespace) 76 77 default: 78 return fmt.Errorf("AgentWorkflowType value not supported: %s", agentWorkflow.Workflow) 79 } 80 81 return a.finish(ctx, agentWorkflow.Workflow) 82 } 83 84 func (a *ClusterImageSet) generateManifest(version, releaseImage, clusterNamespace string) error { 85 clusterImageSet := &hivev1.ClusterImageSet{ 86 TypeMeta: metav1.TypeMeta{ 87 Kind: "ClusterImageSet", 88 APIVersion: hivev1.SchemeGroupVersion.String(), 89 }, 90 ObjectMeta: metav1.ObjectMeta{ 91 Name: fmt.Sprintf("openshift-%s", version), 92 Namespace: clusterNamespace, 93 }, 94 Spec: hivev1.ClusterImageSetSpec{ 95 ReleaseImage: releaseImage, 96 }, 97 } 98 99 configData, err := yaml.Marshal(clusterImageSet) 100 if err != nil { 101 return errors.Wrap(err, "failed to marshal agent cluster image set") 102 } 103 104 a.Config = clusterImageSet 105 a.File = &asset.File{ 106 Filename: clusterImageSetFilename, 107 Data: configData, 108 } 109 110 return nil 111 } 112 113 // Files returns the files generated by the asset. 114 func (a *ClusterImageSet) Files() []*asset.File { 115 if a.File != nil { 116 return []*asset.File{a.File} 117 } 118 return []*asset.File{} 119 } 120 121 // Load returns ClusterImageSet asset from the disk. 122 func (a *ClusterImageSet) Load(f asset.FileFetcher) (bool, error) { 123 ctx := context.TODO() 124 125 agentWorkflow := &workflow.AgentWorkflow{} 126 _, err := agentWorkflow.Load(f) 127 if err != nil { 128 return false, err 129 } 130 131 clusterImageSetFile, err := f.FetchByName(clusterImageSetFilename) 132 if err != nil { 133 if os.IsNotExist(err) { 134 return false, nil 135 } 136 return false, errors.Wrap(err, fmt.Sprintf("failed to load %s file", clusterImageSetFilename)) 137 } 138 139 a.File = clusterImageSetFile 140 141 clusterImageSet := &hivev1.ClusterImageSet{} 142 if err := yaml.UnmarshalStrict(clusterImageSetFile.Data, clusterImageSet); err != nil { 143 err = errors.Wrapf(err, "failed to unmarshal %s", clusterImageSetFilename) 144 return false, err 145 } 146 a.Config = clusterImageSet 147 148 if err = a.finish(ctx, agentWorkflow.Workflow); err != nil { 149 return false, err 150 } 151 return true, nil 152 } 153 154 func (a *ClusterImageSet) finish(ctx context.Context, workflowType workflow.AgentWorkflowType) error { 155 if a.Config == nil { 156 return errors.New("missing configuration or manifest file") 157 } 158 159 if err := a.validateClusterImageSet(ctx, workflowType).ToAggregate(); err != nil { 160 return errors.Wrapf(err, "invalid ClusterImageSet configuration") 161 } 162 163 return nil 164 } 165 166 func (a *ClusterImageSet) validateClusterImageSet(ctx context.Context, workflowType workflow.AgentWorkflowType) field.ErrorList { 167 allErrs := field.ErrorList{} 168 169 if err := a.validateReleaseVersion(ctx, workflowType); err != nil { 170 allErrs = append(allErrs, err...) 171 } 172 173 return allErrs 174 } 175 176 func (a *ClusterImageSet) validateReleaseVersion(ctx context.Context, workflowType workflow.AgentWorkflowType) field.ErrorList { 177 // skip release version check in case of add nodes workflow 178 if workflowType == workflow.AgentWorkflowTypeAddNodes { 179 return nil 180 } 181 182 var allErrs field.ErrorList 183 184 fieldPath := field.NewPath("Spec", "ReleaseImage") 185 186 releaseImage := &releaseimage.Image{} 187 if err := releaseImage.Generate(ctx, asset.Parents{}); err != nil { 188 return append(allErrs, field.InternalError(fieldPath, fmt.Errorf("failed to generate the release image asset: %w", err))) 189 } 190 191 if a.Config.Spec.ReleaseImage != releaseImage.PullSpec { 192 allErrs = append(allErrs, field.Forbidden(fieldPath, fmt.Sprintf("value must be equal to %s", releaseImage.PullSpec))) 193 } 194 195 return allErrs 196 }