github.com/openshift/installer@v1.4.17/pkg/asset/manifests/ingress.go (about) 1 package manifests 2 3 import ( 4 "context" 5 "fmt" 6 "path/filepath" 7 8 "github.com/pkg/errors" 9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 "sigs.k8s.io/yaml" 11 12 configv1 "github.com/openshift/api/config/v1" 13 operatorv1 "github.com/openshift/api/operator/v1" 14 "github.com/openshift/installer/pkg/asset" 15 "github.com/openshift/installer/pkg/asset/installconfig" 16 "github.com/openshift/installer/pkg/types" 17 "github.com/openshift/installer/pkg/types/aws" 18 ) 19 20 var ( 21 clusterIngressConfigFile = filepath.Join(manifestDir, "cluster-ingress-02-config.yml") 22 defaultIngressControllerFile = filepath.Join(manifestDir, "cluster-ingress-default-ingresscontroller.yaml") 23 ) 24 25 // Ingress generates the cluster-ingress-*.yml files. 26 type Ingress struct { 27 FileList []*asset.File 28 } 29 30 var _ asset.WritableAsset = (*Ingress)(nil) 31 32 // Name returns a human friendly name for the asset. 33 func (*Ingress) Name() string { 34 return "Ingress Config" 35 } 36 37 // Dependencies returns all of the dependencies directly needed to generate 38 // the asset. 39 func (*Ingress) Dependencies() []asset.Asset { 40 return []asset.Asset{ 41 &installconfig.InstallConfig{}, 42 } 43 } 44 45 // Generate generates the ingress cluster config and default ingresscontroller. 46 // 47 // A cluster ingress config is always created. 48 // 49 // A default ingresscontroller is only created if the cluster is using an internal 50 // publishing strategy. In this case, the default ingresscontroller is also set 51 // to use the internal publishing strategy. 52 func (ing *Ingress) Generate(_ context.Context, dependencies asset.Parents) error { 53 installConfig := &installconfig.InstallConfig{} 54 dependencies.Get(installConfig) 55 56 ing.FileList = []*asset.File{} 57 58 clusterConfig, err := ing.generateClusterConfig(installConfig.Config) 59 if err != nil { 60 return errors.Wrap(err, "failed to create cluster config") 61 } 62 ing.FileList = append(ing.FileList, &asset.File{ 63 Filename: clusterIngressConfigFile, 64 Data: clusterConfig, 65 }) 66 67 defaultIngressController, err := ing.generateDefaultIngressController(installConfig.Config) 68 if err != nil { 69 return errors.Wrap(err, "failed to create default ingresscontroller") 70 } 71 if len(defaultIngressController) > 0 { 72 ing.FileList = append(ing.FileList, &asset.File{ 73 Filename: defaultIngressControllerFile, 74 Data: defaultIngressController, 75 }) 76 } 77 78 return nil 79 } 80 81 func (ing *Ingress) generateClusterConfig(config *types.InstallConfig) ([]byte, error) { 82 controlPlaneTopology, _ := determineTopologies(config) 83 84 isSingleControlPlaneNode := controlPlaneTopology == configv1.SingleReplicaTopologyMode 85 86 defaultPlacement := configv1.DefaultPlacementWorkers 87 if config.Platform.None != nil && isSingleControlPlaneNode { 88 // A none-platform single control-plane node cluster doesn't need a 89 // load balancer, the API and ingress traffic for such cluster can be 90 // directed at the single node directly. We want to maintain that even 91 // when worker nodes are added to such cluster. We do that by asking 92 // the Cluster Ingress Operator to place the ingress pod on the single 93 // control plane node. This would ensure that the ingress pod won't 94 // ever be scheduled on the added workers, as that would create a 95 // requirement for a load-balancer. Even when a single control-plane 96 // node cluster is installed with one or more worker nodes since day 1, 97 // we still want control-plane ingress default placement, for the sake 98 // of consistency. Users can override this decision manually if they 99 // wish. 100 defaultPlacement = configv1.DefaultPlacementControlPlane 101 } 102 103 obj := &configv1.Ingress{ 104 TypeMeta: metav1.TypeMeta{ 105 APIVersion: configv1.GroupVersion.String(), 106 Kind: "Ingress", 107 }, 108 ObjectMeta: metav1.ObjectMeta{ 109 Name: "cluster", 110 // not namespaced 111 }, 112 Spec: configv1.IngressSpec{ 113 Domain: fmt.Sprintf("apps.%s", config.ClusterDomain()), 114 }, 115 Status: configv1.IngressStatus{ 116 DefaultPlacement: defaultPlacement, 117 }, 118 } 119 120 switch config.Platform.Name() { 121 case aws.Name: 122 lbType := configv1.Classic 123 if config.AWS.LBType == configv1.NLB { 124 lbType = configv1.NLB 125 } 126 obj.Spec.LoadBalancer = configv1.LoadBalancer{ 127 Platform: configv1.IngressPlatformSpec{ 128 AWS: &configv1.AWSIngressSpec{ 129 Type: lbType, 130 }, 131 Type: configv1.AWSPlatformType, 132 }, 133 } 134 } 135 return yaml.Marshal(obj) 136 } 137 138 func (ing *Ingress) generateDefaultIngressController(config *types.InstallConfig) ([]byte, error) { 139 switch config.Publish { 140 case types.MixedPublishingStrategy: 141 if config.OperatorPublishingStrategy.Ingress != "Internal" { 142 break 143 } 144 fallthrough 145 case types.InternalPublishingStrategy: 146 obj := &operatorv1.IngressController{ 147 TypeMeta: metav1.TypeMeta{ 148 APIVersion: operatorv1.GroupVersion.String(), 149 Kind: "IngressController", 150 }, 151 ObjectMeta: metav1.ObjectMeta{ 152 Namespace: "openshift-ingress-operator", 153 Name: "default", 154 }, 155 Spec: operatorv1.IngressControllerSpec{ 156 EndpointPublishingStrategy: &operatorv1.EndpointPublishingStrategy{ 157 Type: operatorv1.LoadBalancerServiceStrategyType, 158 LoadBalancer: &operatorv1.LoadBalancerStrategy{ 159 Scope: operatorv1.InternalLoadBalancer, 160 }, 161 }, 162 }, 163 } 164 return yaml.Marshal(obj) 165 } 166 return nil, nil 167 } 168 169 // Files returns the files generated by the asset. 170 func (ing *Ingress) Files() []*asset.File { 171 return ing.FileList 172 } 173 174 // Load returns false since this asset is not written to disk by the installer. 175 func (ing *Ingress) Load(asset.FileFetcher) (bool, error) { 176 return false, nil 177 }