diff --git a/config/cluster-api/kustomization.yaml b/config/cluster-api/kustomization.yaml index d56dcc782f82..4c2acf0e8158 100644 --- a/config/cluster-api/kustomization.yaml +++ b/config/cluster-api/kustomization.yaml @@ -13,7 +13,3 @@ resources: - infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml - infrastructure.cluster.x-k8s.io_awsmanagedclusters.yaml - infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml -- manager-serviceaccount.yaml -- manager-clusterrole.yaml -- manager-clusterrolebinding.yaml -- manager-deployment.yaml diff --git a/config/install/development/kustomization.yaml b/config/install/development/kustomization.yaml index 46b09b0bc94d..f410f9d3e3ef 100644 --- a/config/install/development/kustomization.yaml +++ b/config/install/development/kustomization.yaml @@ -6,9 +6,6 @@ resources: - ../../hypershift-operator images: -- name: cluster-api - newName: quay.io/hypershift/cluster-api - newTag: hypershift - name: hypershift newName: quay.io/hypershift/hypershift newTag: latest diff --git a/config/install/production/kustomization.yaml b/config/install/production/kustomization.yaml index 9bc5105349fc..b1f52af0f431 100644 --- a/config/install/production/kustomization.yaml +++ b/config/install/production/kustomization.yaml @@ -6,9 +6,6 @@ resources: - ../../hypershift-operator images: -- name: cluster-api - newName: quay.io/hypershift/cluster-api - newTag: hypershift - name: hypershift newName: quay.io/hypershift/hypershift newTag: latest diff --git a/hypershift-operator/assets/controlplane/hypershift/bindata.go b/hypershift-operator/assets/controlplane/hypershift/bindata.go index fc80ae0bf22e..3875b5cadeb8 100644 --- a/hypershift-operator/assets/controlplane/hypershift/bindata.go +++ b/hypershift-operator/assets/controlplane/hypershift/bindata.go @@ -7,8 +7,12 @@ // hypershift-operator/assets/controlplane/hypershift/apiserver-haproxy/teardown-apiserver-ip.sh (168B) // hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-clusterrole.yaml (2.963kB) // hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-clusterrolebinding.yaml (303B) -// hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml (1.335kB) +// hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml (1.378kB) // hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-serviceaccount.yaml (77B) +// hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrole.yaml (1.113kB) +// hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrolebinding.yaml (266B) +// hypershift-operator/assets/controlplane/hypershift/capi/manager-deployment.yaml (516B) +// hypershift-operator/assets/controlplane/hypershift/capi/manager-serviceaccount.yaml (66B) // hypershift-operator/assets/controlplane/hypershift/cluster-bootstrap/00000_namespaces-needed-for-monitoring.yaml (770B) // hypershift-operator/assets/controlplane/hypershift/cluster-bootstrap/cluster-config-v1-configmap.yaml (338B) // hypershift-operator/assets/controlplane/hypershift/cluster-bootstrap/cluster-dns-02-config.yaml (146B) @@ -359,7 +363,7 @@ func capiCapaManagerClusterrolebindingYaml() (*asset, error) { return a, nil } -var _capiCapaManagerDeploymentYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x4d\x6f\xdb\x30\x0c\xbd\xfb\x57\xe8\x0f\xb8\x59\x81\x5e\x26\x60\x87\xa0\xcd\xba\x02\x5d\x61\x34\xc5\x76\x2c\x58\x99\x8d\x85\x52\xa2\x46\xd1\x2e\xbc\x5f\x3f\xa8\x49\x0a\xc7\x59\xbb\x0f\x9d\x6c\x8a\xef\x3d\x3e\x8a\xac\xeb\xba\x82\xe4\xbf\xa1\x64\xcf\xd1\x1a\x48\x29\x2f\x86\xd3\xea\xc9\xc7\xd6\x9a\x0b\x4c\xc4\x63\xc0\xa8\x55\x40\x85\x16\x14\x6c\x65\x4c\x84\x80\xd6\x38\x48\x50\x3b\x8e\x2a\x4c\x84\x52\x07\x88\xb0\x41\xa9\x8c\x21\x78\x40\xca\x25\xd3\x98\x5d\x42\x9d\x08\xe2\x3b\xa0\x9c\xd0\x15\x40\x46\x42\xa7\x2c\x5b\x70\x00\x75\xdd\xf5\x84\xed\xaf\xf9\x8c\x11\x4c\xe4\x1d\x64\x6b\x4e\x2b\x63\x14\x43\x22\x50\xdc\xf1\x4e\xcc\x94\x43\x07\x12\xff\x20\x62\xcc\xbe\xf0\x97\x6f\x94\xc1\x3b\x5c\x3a\xc7\x7d\xd4\x9b\x3f\x74\x69\x2f\x04\x3e\xa2\x4c\xc4\x6b\x03\xb2\x99\xfc\x6f\x63\x75\x0d\x94\x99\x78\xa3\x9c\xb5\x45\x91\xa3\xfb\xe1\xd3\xd9\x24\xe6\x03\x6c\xd0\x9a\x1f\x3d\x8c\x27\x9e\x17\xdd\x98\x50\x72\xe7\x1f\x75\xe1\xa8\xcf\x8a\x52\x43\xf2\x75\x12\x1e\x7c\x5b\x7e\x9e\xb3\x0d\x50\xe2\x73\x8e\xa6\x27\x6a\x98\xbc\x1b\xad\x59\xd2\x33\x8c\x79\x92\xb1\x9d\x84\x43\x4f\xe5\x24\x16\x3d\xb2\xf0\x6a\xb6\x61\x51\x6b\x3e\x9e\x9d\x7d\x38\xc8\xd8\xd3\x75\x08\xa4\xdd\xcf\xd9\x5d\x12\x56\x76\x4c\xd6\xdc\x9d\x37\x93\x3b\x41\x68\x7d\xc4\x9c\x1b\xe1\x07\x3c\xd4\xec\x54\xd3\x25\xaa\x9d\x53\x81\x76\xd6\x2c\x0a\x72\x3c\x92\x79\xa9\xed\xb8\x04\xf2\x03\xfe\x97\xca\x1b\x6e\xde\x90\xc1\x38\xcc\xdb\xb6\x6d\xca\xf2\xfb\xfa\x7e\xfd\x65\x79\xbb\xba\xb8\x3f\xbf\x5d\x5d\xac\x6e\xee\xae\x96\xd7\xeb\xfb\xcf\x57\xd7\xab\x19\xf5\x00\xd4\x63\x11\xe6\x80\x8b\x13\x78\xce\x0b\x27\xd8\x62\x54\x0f\x34\x7d\xbb\x81\xa9\x0f\xf8\xb5\x8c\xea\xd1\x53\xed\x36\xfc\xb7\xb8\x72\x42\x41\x35\x3b\x83\x7b\x9d\x6a\xca\x7b\x30\xd0\xef\xd1\x65\x74\x32\x6f\xde\x36\xb6\x5d\xa0\xd7\x11\x2d\xf0\x3d\x50\x51\x82\x8f\xa0\x9e\xe3\xa5\x80\xc3\x06\xc5\x73\xbb\x46\xc7\xb1\x2d\x1b\xbf\x1f\x2c\x65\x42\x79\x49\x3b\xa8\x07\x1f\x1f\xd1\xa9\x35\x37\xbc\x76\x1d\xb6\x3d\xe1\x44\xfe\x09\x47\x6b\x22\xb7\x58\x0b\x13\x9e\x3c\xf5\x0f\x28\x11\x15\x73\xd9\xa3\xdd\x8e\xfc\x0a\x00\x00\xff\xff\xd3\xe4\x2f\x44\x37\x05\x00\x00") +var _capiCapaManagerDeploymentYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x54\xdd\x4e\xe3\x3c\x10\xbd\xcf\x53\xf8\x05\xd2\x7e\x48\xdc\x7c\x96\xb8\xa8\xa0\xcb\x22\xb1\x55\x44\xd1\xee\x25\x1a\x9c\xa1\xb1\x98\x78\xbc\xe3\x49\x50\x16\xf1\xee\x2b\xd3\x06\xa5\xed\xc2\xfe\xf8\x2a\x1e\xcf\x39\x67\xe6\x64\xec\xb2\x2c\x0b\x88\xfe\x2b\x4a\xf2\x1c\xac\x81\x18\xd3\xbc\x3f\x29\x1e\x7d\xa8\xad\xb9\xc0\x48\x3c\xb4\x18\xb4\x68\x51\xa1\x06\x05\x5b\x18\x13\xa0\x45\x6b\x1c\x44\x28\x1d\x07\x15\x26\x42\x29\x5b\x08\xb0\x41\x29\x8c\x21\xb8\x47\x4a\x39\xd3\x98\x5d\x42\x19\x09\xc2\x07\xa0\x14\xd1\x65\x40\x42\x42\xa7\x2c\x5b\x70\x0b\xea\x9a\xeb\x09\xdb\x1f\xf3\x19\x23\x18\xc9\x3b\x48\xd6\x9c\x14\xc6\x28\xb6\x91\x40\x71\xc7\x3b\x69\x26\x2f\xda\x93\xf8\x0b\x11\x63\xc6\xc2\x5f\xbf\x51\x7a\xef\x70\xe1\x1c\x77\x41\x57\xbf\x71\x69\x14\x02\x1f\x50\x26\xe2\xa5\x01\xd9\x4c\xf6\xdb\x58\x59\x66\xd7\x53\x04\x87\x67\xcf\xcf\x66\xb6\x1a\x77\xe6\xe5\xe5\x28\x15\x28\x31\xf1\x46\x39\x69\x8d\x22\x47\xe7\xfd\xd9\xe9\x24\xe6\x5b\xd8\xa0\x35\xdf\x3b\x18\x66\x9e\xe7\xcd\x10\x51\x52\xe3\x1f\x74\xee\xa8\x4b\x8a\x52\x42\xf4\x65\x14\xee\x7d\x9d\x37\x4f\xc9\xb6\x90\xe3\x87\x1c\x55\x47\x54\x31\x79\x37\x58\xb3\xa0\x27\x18\xd2\x24\x63\x3b\x34\xfb\xed\xe7\x15\x59\xf4\xa8\xdb\x37\x5f\x2a\x16\xb5\xe6\xff\xd3\xd3\xff\xf6\x32\x46\xba\x06\x81\xb4\xf9\x71\x70\x16\x85\x95\x1d\x93\x35\xb7\xe7\xd5\xe4\x4c\x10\x6a\x1f\x30\xa5\x4a\xf8\x1e\xf7\x35\x1b\xd5\x78\x89\x6a\x0f\xa9\x40\x1b\x6b\xe6\x19\x39\x1c\xc9\xbc\xd6\x76\x5c\x02\xf9\x1e\xff\x49\xe5\x9d\x6e\xde\x91\xc1\xd0\x1f\xda\xb6\x35\x65\xf1\x6d\x7d\xb7\xfe\xbc\xb8\x59\x5e\xdc\x9d\xdf\x2c\x2f\x96\xab\xdb\xab\xc5\xf5\xfa\xee\xd3\xd5\xf5\xf2\x80\xba\x07\xea\x30\x0b\x73\x8b\xf3\x19\x3c\xa5\xb9\x13\xac\x31\xa8\x07\x9a\xfe\xbb\x9e\xa9\x6b\xf1\x4b\x9e\xea\xa3\x5f\xb5\x7b\x0c\x7e\x89\xcb\xab\xcd\xa8\x6a\xd7\xe0\xa8\x53\x4c\x79\xf7\x66\xff\x23\xba\x84\x4e\x0e\xcd\xdb\xc6\xb6\x77\xed\x6d\x44\x33\x7c\x04\x2a\x4a\xeb\x03\xa8\xe7\x70\x29\xe0\xb0\x42\xf1\x5c\xaf\xd1\x71\xa8\xf3\xe3\x30\x0e\x96\x32\xa1\xbc\xa6\xed\xd5\x83\x0f\x0f\xe8\xd4\x9a\x15\xaf\x5d\x83\x75\x47\x38\x91\x7f\xc4\xc1\x9a\xc0\x35\x96\xc2\x84\xb3\xc7\xee\x1e\x25\xa0\x62\xca\xf7\x68\x77\x47\x7e\x06\x00\x00\xff\xff\xf3\x15\x82\xb3\x62\x05\x00\x00") func capiCapaManagerDeploymentYamlBytes() ([]byte, error) { return bindataRead( @@ -374,8 +378,8 @@ func capiCapaManagerDeploymentYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "capi/capa-manager-deployment.yaml", size: 1335, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x1c, 0x2d, 0xff, 0x4d, 0x81, 0xc9, 0xa, 0x62, 0xd4, 0x45, 0xfd, 0x3a, 0x28, 0x94, 0x51, 0x99, 0xbd, 0xcf, 0x70, 0xa8, 0x4c, 0xfe, 0x1b, 0xa2, 0xa, 0x19, 0x9, 0xe1, 0x5c, 0x74, 0x88, 0x1e}} + info := bindataFileInfo{name: "capi/capa-manager-deployment.yaml", size: 1378, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xff, 0x23, 0xd4, 0xb0, 0x50, 0x30, 0xe5, 0x5a, 0x57, 0xcd, 0x18, 0xba, 0x5c, 0x42, 0xce, 0x8b, 0x6, 0xcc, 0x79, 0xcb, 0xf9, 0x8e, 0xb1, 0x5e, 0xb8, 0xf2, 0x8a, 0x96, 0xd8, 0x90, 0xf0, 0x57}} return a, nil } @@ -399,6 +403,86 @@ func capiCapaManagerServiceaccountYaml() (*asset, error) { return a, nil } +var _capiManagerClusterroleYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x52\xb1\x8e\xdb\x30\x0c\xdd\xfd\x15\x42\x96\x00\x05\xec\xa0\x5b\xe1\xb5\x43\xf7\x0e\xdd\x19\x89\x8e\x85\xc8\xa4\x40\x52\x69\xda\xaf\x2f\xec\x38\x6d\x2f\xb1\x93\x3b\xdc\x4d\x96\xc9\xc7\xf7\xc8\x87\x07\x39\xfe\x40\xd1\xc8\xd4\x3a\xd9\x83\x6f\xa0\x58\xcf\x12\x7f\x83\x45\xa6\xe6\xf8\x45\x9b\xc8\xbb\xd3\xe7\xea\x18\x29\xb4\xee\x6b\x2a\x6a\x28\xdf\x39\x61\x35\xa0\x41\x00\x83\xb6\x72\x8e\x60\xc0\xd6\xf9\x4b\xb7\x86\x1c\x2b\x29\x09\xb5\xad\x6a\x07\x39\x7e\x13\x2e\x59\x47\xdc\xf4\x8b\x67\x43\x1a\x25\x75\xe6\xaf\x9c\x13\x54\x2e\xe2\x71\x46\xf9\xa2\xc6\xc3\xb5\x18\xb0\x8b\x14\xc7\x85\xb4\x72\xee\x84\xb2\x9f\x61\x07\xb4\xe9\x9b\xa2\x5e\x1e\x3f\xc1\x7c\x7f\x2f\xba\x67\x36\x35\x81\xdc\xcc\x2b\x36\xe7\xfa\xaf\x74\xed\x3c\x93\x09\xa7\x9c\x80\x70\x19\x11\xa9\x13\x50\x93\xe2\xad\xc8\x0a\x66\x00\xdf\x47\x42\x5d\xee\xe2\x39\x37\xaf\x61\x81\x10\x46\x63\x56\x39\x96\x0f\xb8\x2f\xde\x18\xba\xfd\xb4\x7d\x69\xdd\x58\xb8\xf3\xa9\xff\x95\x51\xb4\x8f\x9d\x35\x9c\x91\x2e\xaf\x25\xba\x9e\xd5\x30\xfc\xef\x9b\xae\xd5\x77\x6a\x60\x45\xe7\x03\x0c\x85\x20\x4d\x46\xcc\x4b\x3f\xe8\xfc\x1b\x7d\xb6\xf8\x66\xb3\x90\x21\xa6\x2e\x1e\x06\xc8\xcf\x42\x93\xa7\xd0\x3c\x88\xcf\x12\x3b\x9e\x90\xec\x86\xd9\x0b\x82\xe1\x07\x8a\x10\x07\x5c\xd7\x08\x98\xf0\xb9\x5c\xc9\xe1\x3a\xf0\x06\x65\x45\x2f\xf8\x9e\xfb\xfe\x04\x00\x00\xff\xff\x8a\x12\xad\x14\x59\x04\x00\x00") + +func capiManagerClusterroleYamlBytes() ([]byte, error) { + return bindataRead( + _capiManagerClusterroleYaml, + "capi/manager-clusterrole.yaml", + ) +} + +func capiManagerClusterroleYaml() (*asset, error) { + bytes, err := capiManagerClusterroleYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "capi/manager-clusterrole.yaml", size: 1113, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7d, 0xe4, 0xc3, 0x70, 0xab, 0xae, 0x6f, 0xee, 0xa9, 0x21, 0xd2, 0x46, 0x1d, 0xc4, 0x90, 0xf6, 0xdd, 0x12, 0xfe, 0xe3, 0x3f, 0x1b, 0x43, 0x3f, 0xc5, 0x25, 0xb1, 0xd0, 0xf6, 0x33, 0x81, 0xba}} + return a, nil +} + +var _capiManagerClusterrolebindingYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x8d\xb1\xae\xc2\x30\x0c\x45\xf7\x7c\x85\x7f\xa0\x79\x7a\x1b\xca\x06\x0c\x6c\x0c\x45\x62\x77\x53\x03\xa6\x6d\x1c\x25\x4e\x07\xaa\xfe\x3b\x42\x85\x89\x8a\xd1\xbe\xf7\xdc\x83\x91\xcf\x94\x32\x4b\x70\x90\x1a\xf4\x16\x8b\xde\x24\xf1\x03\x95\x25\xd8\x6e\x93\x2d\xcb\xdf\xf8\x6f\x3a\x0e\xad\x83\x7d\x5f\xb2\x52\xaa\xa5\xa7\x1d\x87\x96\xc3\xd5\x0c\xa4\xd8\xa2\xa2\x33\x00\x01\x07\x72\xe0\x97\x52\x85\x91\x4d\x92\x9e\x6a\xba\xbc\x42\x8c\x7c\x48\x52\xe2\x0f\x91\x01\xf8\xf2\xac\xce\xe6\xd2\xdc\xc9\x6b\x76\xa6\x7a\x13\x27\x4a\x23\x7b\xda\x7a\x2f\x25\xe8\x2a\xb4\xfc\x72\x44\x4f\x0e\xa6\x09\xec\xf1\x73\xc2\x3c\x9b\x67\x00\x00\x00\xff\xff\x1a\x7b\x6c\x93\x0a\x01\x00\x00") + +func capiManagerClusterrolebindingYamlBytes() ([]byte, error) { + return bindataRead( + _capiManagerClusterrolebindingYaml, + "capi/manager-clusterrolebinding.yaml", + ) +} + +func capiManagerClusterrolebindingYaml() (*asset, error) { + bytes, err := capiManagerClusterrolebindingYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "capi/manager-clusterrolebinding.yaml", size: 266, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xb8, 0x27, 0x2, 0x83, 0x2c, 0x93, 0x57, 0x2, 0x8b, 0xb2, 0x1, 0x17, 0x59, 0xf5, 0x89, 0x5a, 0x53, 0x9d, 0x7b, 0xd6, 0xb2, 0xf6, 0x98, 0x5c, 0xd1, 0x5d, 0xff, 0x3c, 0xa4, 0x59, 0x40, 0x7d}} + return a, nil +} + +var _capiManagerDeploymentYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x8f\xbb\x6e\xf3\x30\x0c\x85\x77\x3d\x05\x5f\xc0\x31\x02\xfc\x93\x80\x0c\x01\xfe\xb1\x08\x32\x75\x67\x69\xd6\x11\x4a\x5d\x2a\xd2\x29\x8c\x20\xef\x5e\xb8\xcd\xc5\x2e\xac\x49\xe2\x39\xe7\x3b\x14\x96\xf0\xca\x55\x43\x4e\x1e\xb0\x14\x6d\xcf\x5b\xf7\x11\x52\xe7\xe1\x3f\x17\xc9\x63\xe4\x64\x2e\xb2\x61\x87\x86\xde\x01\x24\x8c\xec\x81\x64\x50\xe3\xda\x60\x09\x4e\x0b\xd3\xa4\x54\x2e\x12\x08\xd5\xc3\xd6\x01\x28\x0b\x93\xe5\x3a\x29\x00\x11\x8d\x4e\x2f\xf8\xc6\xa2\xbf\x83\x35\x10\x80\x71\x2c\x82\xc6\xb7\xd0\xac\x76\x3a\xb2\xc8\xaf\x13\x00\xee\xeb\xfc\xdc\xb9\x9e\x03\xf1\x9e\x28\x0f\xc9\x0e\xab\x7e\x00\xca\xc9\x30\x24\xae\x0f\x76\x73\x63\x47\x4c\xd8\x73\x7d\x34\x86\x88\x3d\x7b\xf8\x1c\x70\xdc\x84\xdc\x9e\xc6\xc2\x55\x4f\xe1\xdd\xda\x19\xd5\x3f\xc7\xcb\xe0\x71\x10\x39\x66\x09\x34\x7a\xd8\xcb\x17\x8e\xfa\xd0\x29\xc7\x88\xa9\x7b\xfe\xad\x81\xf6\x6f\x39\xd6\x5e\xe7\x86\xa6\x99\x96\xd4\x82\xc4\xbb\xcb\x05\x36\x87\xfb\x0b\xae\xd7\x85\x0d\x45\xb3\xe4\xde\xb2\x5a\xc7\xb5\x2e\xb4\xf3\xee\x9f\xfb\x0e\x00\x00\xff\xff\x02\x65\x5c\xe9\x04\x02\x00\x00") + +func capiManagerDeploymentYamlBytes() ([]byte, error) { + return bindataRead( + _capiManagerDeploymentYaml, + "capi/manager-deployment.yaml", + ) +} + +func capiManagerDeploymentYaml() (*asset, error) { + bytes, err := capiManagerDeploymentYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "capi/manager-deployment.yaml", size: 516, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xd5, 0xe2, 0xdb, 0xed, 0xe7, 0x68, 0x5f, 0xa5, 0x61, 0x62, 0x6b, 0x41, 0x89, 0xb1, 0xaa, 0xf0, 0x2, 0x28, 0xc2, 0x45, 0x6d, 0xba, 0xef, 0x3c, 0xb8, 0xf3, 0x36, 0x5e, 0x51, 0xbf, 0xd7, 0x89}} + return a, nil +} + +var _capiManagerServiceaccountYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x04\xc0\x31\x0e\x80\x20\x0c\x05\xd0\xbd\xa7\xe8\x05\x1c\x5c\xbb\x79\x06\x13\xf7\xa6\xfc\xa1\x51\x0a\x81\xc2\xf9\x7d\xda\xfd\xc1\x98\xde\x42\x78\x9f\xf4\x7a\x14\xe1\x1b\x63\xbb\xe1\x32\x6b\x2b\x92\x2a\x52\x8b\xa6\x0a\x31\x87\x56\x08\xdb\xb7\x66\x62\x1c\xda\x9d\xfe\x00\x00\x00\xff\xff\x14\xfb\x48\x04\x42\x00\x00\x00") + +func capiManagerServiceaccountYamlBytes() ([]byte, error) { + return bindataRead( + _capiManagerServiceaccountYaml, + "capi/manager-serviceaccount.yaml", + ) +} + +func capiManagerServiceaccountYaml() (*asset, error) { + bytes, err := capiManagerServiceaccountYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "capi/manager-serviceaccount.yaml", size: 66, mode: os.FileMode(0644), modTime: time.Unix(1, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x48, 0xd3, 0x3c, 0x7d, 0xa3, 0x26, 0x1e, 0x82, 0x92, 0x74, 0x79, 0x40, 0xca, 0x91, 0x9e, 0x73, 0x8d, 0x2a, 0xe9, 0x1a, 0xf7, 0xcb, 0xa3, 0x30, 0x3c, 0xdd, 0xaf, 0x7a, 0xca, 0xbb, 0x42, 0x55}} + return a, nil +} + var _clusterBootstrap00000_namespacesNeededForMonitoringYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x92\x31\x6e\xc3\x30\x0c\x45\x77\x9d\x82\xc8\xae\x14\x5d\x75\x88\x8e\xdd\x19\x99\xb5\x09\xcb\xa4\x40\x52\x29\x7a\xfb\x22\x43\xd1\x14\x9d\x0c\x7b\xff\x78\x7a\x7a\x60\xce\x39\x61\xe7\x77\x32\x67\x95\x02\xf7\xd7\xb4\xb2\x4c\x05\xde\x70\x23\xef\x58\x29\x6d\x14\x38\x61\x60\x49\x00\x82\x1b\x15\xd0\x4e\xe2\x0b\x7f\x44\xc6\xce\x4e\x76\x27\x4b\x07\x41\x55\x25\x4c\x5b\x23\xcb\x1b\x0a\xce\xc7\x89\xeb\xb8\xd1\x93\x1f\x40\xc3\x1b\x35\x7f\x4c\xe1\x77\x76\x65\x7d\xa9\x6d\x78\x3c\x1e\x56\xe1\x50\x63\x99\x0b\x5c\xc2\x06\x5d\x4e\x71\xf0\xba\xd0\x34\xda\x49\x3f\x3a\x3f\x14\x45\x9d\xf6\x32\x9e\x5b\x0a\xc5\xa7\xda\x7a\xfd\xd3\xb4\x6b\xe3\xfa\x95\x67\xd3\xd1\x0b\xb0\xcc\x46\xee\xbb\xd2\xff\x17\xfd\xa1\x1c\xbd\xd9\x11\x0b\x49\x70\xc5\x60\x95\xf4\x1d\x00\x00\xff\xff\x97\xb6\x41\xc5\x02\x03\x00\x00") func clusterBootstrap00000_namespacesNeededForMonitoringYamlBytes() ([]byte, error) { @@ -3339,6 +3423,10 @@ var _bindata = map[string]func() (*asset, error){ "capi/capa-manager-clusterrolebinding.yaml": capiCapaManagerClusterrolebindingYaml, "capi/capa-manager-deployment.yaml": capiCapaManagerDeploymentYaml, "capi/capa-manager-serviceaccount.yaml": capiCapaManagerServiceaccountYaml, + "capi/manager-clusterrole.yaml": capiManagerClusterroleYaml, + "capi/manager-clusterrolebinding.yaml": capiManagerClusterrolebindingYaml, + "capi/manager-deployment.yaml": capiManagerDeploymentYaml, + "capi/manager-serviceaccount.yaml": capiManagerServiceaccountYaml, "cluster-bootstrap/00000_namespaces-needed-for-monitoring.yaml": clusterBootstrap00000_namespacesNeededForMonitoringYaml, "cluster-bootstrap/cluster-config-v1-configmap.yaml": clusterBootstrapClusterConfigV1ConfigmapYaml, "cluster-bootstrap/cluster-dns-02-config.yaml": clusterBootstrapClusterDns02ConfigYaml, @@ -3539,6 +3627,10 @@ var _bintree = &bintree{nil, map[string]*bintree{ "capa-manager-clusterrolebinding.yaml": {capiCapaManagerClusterrolebindingYaml, map[string]*bintree{}}, "capa-manager-deployment.yaml": {capiCapaManagerDeploymentYaml, map[string]*bintree{}}, "capa-manager-serviceaccount.yaml": {capiCapaManagerServiceaccountYaml, map[string]*bintree{}}, + "manager-clusterrole.yaml": {capiManagerClusterroleYaml, map[string]*bintree{}}, + "manager-clusterrolebinding.yaml": {capiManagerClusterrolebindingYaml, map[string]*bintree{}}, + "manager-deployment.yaml": {capiManagerDeploymentYaml, map[string]*bintree{}}, + "manager-serviceaccount.yaml": {capiManagerServiceaccountYaml, map[string]*bintree{}}, }}, "cluster-bootstrap": {nil, map[string]*bintree{ "00000_namespaces-needed-for-monitoring.yaml": {clusterBootstrap00000_namespacesNeededForMonitoringYaml, map[string]*bintree{}}, diff --git a/hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml b/hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml index cdc01c262273..038c4afc22c9 100644 --- a/hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml +++ b/hypershift-operator/assets/controlplane/hypershift/capi/capa-manager-deployment.yaml @@ -18,6 +18,7 @@ spec: serviceAccountName: capa-controller-manager containers: - args: + - --namespace={{ .Namespace }} - --alsologtostderr - --v=4 image: quay.io/hypershift/cluster-api-provider-aws:master diff --git a/config/cluster-api/manager-clusterrole.yaml b/hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrole.yaml similarity index 97% rename from config/cluster-api/manager-clusterrole.yaml rename to hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrole.yaml index cc1d028be232..38ed50150a8f 100644 --- a/config/cluster-api/manager-clusterrole.yaml +++ b/hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrole.yaml @@ -1,7 +1,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: cluster-api rules: - apiGroups: diff --git a/config/cluster-api/manager-clusterrolebinding.yaml b/hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrolebinding.yaml similarity index 88% rename from config/cluster-api/manager-clusterrolebinding.yaml rename to hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrolebinding.yaml index dd557a4cafcd..621d4d627331 100644 --- a/config/cluster-api/manager-clusterrolebinding.yaml +++ b/hypershift-operator/assets/controlplane/hypershift/capi/manager-clusterrolebinding.yaml @@ -9,4 +9,4 @@ roleRef: subjects: - kind: ServiceAccount name: cluster-api - namespace: hypershift + namespace: {{ .Namespace }} diff --git a/config/cluster-api/manager-deployment.yaml b/hypershift-operator/assets/controlplane/hypershift/capi/manager-deployment.yaml similarity index 81% rename from config/cluster-api/manager-deployment.yaml rename to hypershift-operator/assets/controlplane/hypershift/capi/manager-deployment.yaml index 641648dbb668..4618b1eb29d0 100644 --- a/config/cluster-api/manager-deployment.yaml +++ b/hypershift-operator/assets/controlplane/hypershift/capi/manager-deployment.yaml @@ -1,7 +1,6 @@ apiVersion: apps/v1 kind: Deployment metadata: - namespace: hypershift name: cluster-api spec: replicas: 1 @@ -16,11 +15,11 @@ spec: serviceAccountName: cluster-api containers: - name: manager - image: cluster-api:latest + image: quay.io/hypershift/cluster-api:hypershift imagePullPolicy: Always command: - /manager args: - - --namespace=hypershift + - --namespace={{ .Namespace }} - --alsologtostderr - --v=4 diff --git a/config/cluster-api/manager-serviceaccount.yaml b/hypershift-operator/assets/controlplane/hypershift/capi/manager-serviceaccount.yaml similarity index 73% rename from config/cluster-api/manager-serviceaccount.yaml rename to hypershift-operator/assets/controlplane/hypershift/capi/manager-serviceaccount.yaml index 24488264be27..cf27c742d002 100644 --- a/config/cluster-api/manager-serviceaccount.yaml +++ b/hypershift-operator/assets/controlplane/hypershift/capi/manager-serviceaccount.yaml @@ -1,5 +1,4 @@ apiVersion: v1 kind: ServiceAccount metadata: - namespace: hypershift name: cluster-api diff --git a/hypershift-operator/controllers/controlplane.go b/hypershift-operator/controllers/controlplane.go index af4ca9b3bb18..e84e5bf1eddd 100644 --- a/hypershift-operator/controllers/controlplane.go +++ b/hypershift-operator/controllers/controlplane.go @@ -14,6 +14,8 @@ import ( "os" "strings" + "github.com/go-logr/logr" + "sigs.k8s.io/cluster-api/util" "github.com/blang/semver" @@ -55,55 +57,29 @@ var ( version46 = semver.MustParse("4.6.0") ) -func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, hcp *hyperv1.HostedControlPlane, infraStatus InfrastructureStatus, releaseImage *releaseinfo.ReleaseImage) error { - r.Log.Info("ensuring control plane for cluster", "cluster", hcp.Name) +func (r *HostedControlPlaneReconciler) generateControlPlaneManifests(ctx context.Context, hcp *hyperv1.HostedControlPlane, infraStatus InfrastructureStatus, releaseImage *releaseinfo.ReleaseImage) (map[string][]byte, error) { + targetNamespace := hcp.GetName() - name := hcp.Name - - var pullSecret corev1.Secret - err := r.Client.Get(ctx, client.ObjectKey{Namespace: hcp.Namespace, Name: hcp.Spec.PullSecret.Name}, &pullSecret) - if err != nil { - return fmt.Errorf("failed to get pull secret %s: %w", hcp.Spec.PullSecret.Name, err) - } - pullSecretData, hasPullSecretData := pullSecret.Data[".dockerconfigjson"] - if !hasPullSecretData { - return fmt.Errorf("pull secret %s is missing the .dockerconfigjson key", hcp.Spec.PullSecret.Name) - } - - var providerCredsSecret corev1.Secret - err = r.Client.Get(ctx, client.ObjectKey{Namespace: hcp.Namespace, Name: hcp.Spec.ProviderCreds.Name}, &providerCredsSecret) - if err != nil { - return fmt.Errorf("failed to get provider creds %s: %w", hcp.Spec.ProviderCreds.Name, err) - } - providerCredsData, hasProviderCredsData := providerCredsSecret.Data["credentials"] - if !hasProviderCredsData { - return fmt.Errorf("provider credentials %s is missing the credentials key", hcp.Spec.PullSecret.Name) - } - - version, err := semver.Parse(releaseImage.Version()) - if err != nil { - return fmt.Errorf("cannot parse release version (%s): %v", releaseImage.Version(), err) - } controlPlaneOperatorImage, err := r.LookupControlPlaneOperatorImage(r.Client) if err != nil { - return fmt.Errorf("failed to lookup control plane operator image: %w", err) + return nil, fmt.Errorf("failed to lookup control plane operator image: %w", err) } var sshKeySecret corev1.Secret err = r.Client.Get(ctx, client.ObjectKey{Namespace: hcp.Namespace, Name: hcp.Spec.SSHKey.Name}, &sshKeySecret) if err != nil { - return fmt.Errorf("failed to get SSH key secret %s: %w", hcp.Spec.SSHKey.Name, err) + return nil, fmt.Errorf("failed to get SSH key secret %s: %w", hcp.Spec.SSHKey.Name, err) } sshKeyData, hasSSHKeyData := sshKeySecret.Data["id_rsa.pub"] if !hasSSHKeyData { - return fmt.Errorf("SSH key secret secret %s is missing the id_rsa.pub key", hcp.Spec.SSHKey.Name) + return nil, fmt.Errorf("SSH key secret secret %s is missing the id_rsa.pub key", hcp.Spec.SSHKey.Name) } baseDomain, err := ClusterBaseDomain(r.Client, ctx, hcp.Name) if err != nil { - return fmt.Errorf("couldn't determine cluster base domain name: %w", err) + return nil, fmt.Errorf("couldn't determine cluster base domain name: %w", err) } params := hypershiftcp.NewClusterParams() - params.Namespace = name + params.Namespace = targetNamespace params.ExternalAPIDNSName = infraStatus.APIAddress params.ExternalAPIPort = APIServerPort params.ExternalAPIAddress = DefaultAPIServerIPAddress @@ -135,7 +111,7 @@ func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, h // we're effectively doing an uncontrolled cert rotation each generation. pkiSecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Namespace: name, + Namespace: targetNamespace, Name: "pki", }, Data: map[string][]byte{}, @@ -145,7 +121,7 @@ func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, h if apierrors.IsNotFound(err) { needsPkiSecret = true } else { - return fmt.Errorf("failed to get pki secret: %w", err) + return nil, fmt.Errorf("failed to get pki secret: %w", err) } } else { r.Log.Info("using existing pki secret") @@ -161,30 +137,71 @@ func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, h IngressSubdomain: "apps." + baseDomain, MachineConfigServerAddress: infraStatus.IgnitionProviderAddress, ExternalOpenVPNAddress: infraStatus.VPNAddress, - Namespace: name, + Namespace: targetNamespace, } log.Info("generating PKI secret data") data, err := pki.GeneratePKI(pkiParams) if err != nil { - return fmt.Errorf("failed to generate PKI data: %w", err) + return nil, fmt.Errorf("failed to generate PKI data: %w", err) } pkiSecret.Data = data if err := r.Create(ctx, pkiSecret); err != nil { - return fmt.Errorf("failed to create pki secret: %w", err) + return nil, fmt.Errorf("failed to create pki secret: %w", err) } r.Log.Info("created pki secret") } caBytes := pkiSecret.Data["combined-ca.crt"] if err != nil { - return fmt.Errorf("failed to read combined CA: %w", err) + return nil, fmt.Errorf("failed to read combined CA: %w", err) } params.OpenshiftAPIServerCABundle = base64.StdEncoding.EncodeToString(caBytes) params.OauthAPIServerCABundle = params.OpenshiftAPIServerCABundle + var pullSecret corev1.Secret + if err := r.Client.Get(ctx, client.ObjectKey{Namespace: hcp.GetNamespace(), Name: hcp.Spec.PullSecret.Name}, &pullSecret); err != nil { + return nil, fmt.Errorf("failed to get pull secret %s: %w", hcp.Spec.PullSecret.Name, err) + } + pullSecretData, hasPullSecretData := pullSecret.Data[".dockerconfigjson"] + if !hasPullSecretData { + return nil, fmt.Errorf("pull secret %s is missing the .dockerconfigjson key", hcp.Spec.PullSecret.Name) + } manifests, err := hypershiftcp.RenderClusterManifests(params, releaseImage, pullSecretData, pkiSecret.Data) if err != nil { - return fmt.Errorf("failed to render hypershift manifests for cluster: %w", err) + return nil, fmt.Errorf("failed to render hypershift manifests for cluster: %w", err) + } + return manifests, nil +} + +func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, hcp *hyperv1.HostedControlPlane, infraStatus InfrastructureStatus, releaseImage *releaseinfo.ReleaseImage) error { + r.Log.Info("ensuring control plane for cluster", "cluster", hcp.Name) + + targetNamespace := hcp.GetName() + version, err := semver.Parse(releaseImage.Version()) + if err != nil { + return fmt.Errorf("cannot parse release version (%s): %v", releaseImage.Version(), err) + } + + // Create the configmap with the pull secret for the guest cluster + var pullSecret corev1.Secret + if err := r.Client.Get(ctx, client.ObjectKey{Namespace: targetNamespace, Name: pullSecretName}, &pullSecret); err != nil { + return fmt.Errorf("failed to get pull secret %s: %w", pullSecretName, err) + } + pullSecretData, hasPullSecretData := pullSecret.Data[".dockerconfigjson"] + if !hasPullSecretData { + return fmt.Errorf("pull secret %s is missing the .dockerconfigjson key", pullSecretName) + } + targetPullSecret, err := generateTargetPullSecret(r.Scheme(), pullSecretData, targetNamespace) + if err != nil { + return fmt.Errorf("failed to create pull secret manifest for target cluster: %w", err) + } + if err := r.Create(ctx, targetPullSecret); err != nil && !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("failed to generate targetPullSecret: %v", err) + } + + manifests, err := r.generateControlPlaneManifests(ctx, hcp, infraStatus, releaseImage) + if err != nil { + return err } // Create oauth branding manifest because it cannot be applied @@ -193,33 +210,15 @@ func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, h if err := yaml.NewYAMLOrJSONDecoder(strings.NewReader(string(manifestBytes)), 100).Decode(manifestObj); err != nil { return fmt.Errorf("failed to decode manifest %s: %w", oauthBrandingManifest, err) } - manifestObj.SetNamespace(name) + manifestObj.SetNamespace(targetNamespace) if err = r.Create(context.TODO(), manifestObj); err != nil { if !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to apply manifest %s: %w", oauthBrandingManifest, err) } } - // Use server side apply for manifestss - applyErrors := []error{} - for manifestName, manifestBytes := range manifests { - if excludeManifests.Has(manifestName) { - continue - } - obj := &unstructured.Unstructured{} - if err := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifestBytes), 100).Decode(obj); err != nil { - applyErrors = append(applyErrors, fmt.Errorf("failed to decode manifest %s: %w", manifestName, err)) - } - obj.SetNamespace(name) - err = r.Patch(ctx, obj, client.RawPatch(types.ApplyPatchType, manifestBytes), client.ForceOwnership, client.FieldOwner("hypershift-operator")) - if err != nil { - applyErrors = append(applyErrors, fmt.Errorf("failed to apply manifest %s: %w", manifestName, err)) - } else { - r.Log.Info("applied manifest", "manifest", manifestName) - } - } - if errs := errors.NewAggregate(applyErrors); errs != nil { - return fmt.Errorf("failed to apply some manifests: %w", errs) + if err := applyManifests(ctx, r, r.Log, targetNamespace, manifests); err != nil { + return err } r.Log.Info("successfully applied all manifests") @@ -227,71 +226,130 @@ func (r *HostedControlPlaneReconciler) ensureControlPlane(ctx context.Context, h if err := r.Create(ctx, userDataSecret); err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to generate user data secret: %w", err) } - userDataSecret.OwnerReferences = util.EnsureOwnerRef(userDataSecret.OwnerReferences, metav1.OwnerReference{ - APIVersion: hyperv1.GroupVersion.String(), - Kind: "HostedControlPlane", - Name: hcp.GetName(), - UID: hcp.UID, - }) + userDataSecret.OwnerReferences = ensureHCPOwnerRef(hcp, userDataSecret.OwnerReferences) kubeadminPassword, err := generateKubeadminPassword() if err != nil { return fmt.Errorf("failed to generate kubeadmin password: %w", err) } - kubeadminPasswordTargetSecret, err := generateKubeadminPasswordTargetSecret(r.Scheme(), kubeadminPassword, name) + kubeadminPasswordTargetSecret, err := generateKubeadminPasswordTargetSecret(r.Scheme(), kubeadminPassword, targetNamespace) if err != nil { return fmt.Errorf("failed to create kubeadmin secret manifest for target cluster: %w", err) } + kubeadminPasswordTargetSecret.OwnerReferences = ensureHCPOwnerRef(hcp, kubeadminPasswordTargetSecret.OwnerReferences) if err := r.Create(ctx, kubeadminPasswordTargetSecret); err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to generate kubeadminPasswordTargetSecret: %w", err) } - kubeadminPasswordSecret := generateKubeadminPasswordSecret(name, kubeadminPassword) + kubeadminPasswordSecret := generateKubeadminPasswordSecret(targetNamespace, kubeadminPassword) + kubeadminPasswordSecret.OwnerReferences = ensureHCPOwnerRef(hcp, kubeadminPasswordSecret.OwnerReferences) if err := r.Create(ctx, kubeadminPasswordSecret); err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to generate kubeadminPasswordSecret: %w", err) } + pkiSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: targetNamespace, + Name: "pki", + }, + Data: map[string][]byte{}, + } + if err := r.Get(ctx, client.ObjectKeyFromObject(pkiSecret), pkiSecret); err != nil { + return fmt.Errorf("failed to get pki secret: %w", err) + } + kubeconfigSecret, err := generateKubeconfigSecret(hcp.GetName(), hcp.GetNamespace(), pkiSecret.Data["admin.kubeconfig"]) if err != nil { return fmt.Errorf("failed to create kubeconfig secret manifest for management cluster: %w", err) } - kubeconfigSecret.OwnerReferences = util.EnsureOwnerRef(kubeconfigSecret.OwnerReferences, metav1.OwnerReference{ - APIVersion: hyperv1.GroupVersion.String(), - Kind: "HostedControlPlane", - Name: hcp.GetName(), - UID: hcp.UID, - }) + kubeconfigSecret.OwnerReferences = ensureHCPOwnerRef(hcp, kubeconfigSecret.OwnerReferences) if err := r.Create(ctx, kubeconfigSecret); err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to generate kubeconfigSecret: %w", err) } - targetPullSecret, err := generateTargetPullSecret(r.Scheme(), pullSecretData, name) + baseDomain, err := ClusterBaseDomain(r.Client, ctx, hcp.Name) if err != nil { - return fmt.Errorf("failed to create pull secret manifest for target cluster: %w", err) - } - if err := r.Create(ctx, targetPullSecret); err != nil && !apierrors.IsAlreadyExists(err) { - return fmt.Errorf("failed to generate targetPullSecret: %v", err) + return fmt.Errorf("couldn't determine cluster base domain name: %w", err) } + log.Infof("Cluster API URL: %s", fmt.Sprintf("https://%s:%d", infraStatus.APIAddress, APIServerPort)) + log.Infof("Kubeconfig is available in secret %q in the %s namespace", fmt.Sprintf("%s-kubeconfig", targetNamespace), hcp.GetNamespace()) + log.Infof("Console URL: %s", fmt.Sprintf("https://console-openshift-console.%s", fmt.Sprintf("apps.%s", baseDomain))) + log.Infof("kubeadmin password is available in secret %q in the %s namespace", "kubeadmin-password", targetNamespace) - targetProviderCredsSecret, err := generateTargetProviderCredsSecret(providerCredsData, name) - if err != nil { - return fmt.Errorf("failed to create providerCreds secret manifest for target cluster: %w", err) + return nil +} + +func ensureHCPOwnerRef(hcp *hyperv1.HostedControlPlane, ownerReferences []metav1.OwnerReference) []metav1.OwnerReference { + return util.EnsureOwnerRef(ownerReferences, metav1.OwnerReference{ + APIVersion: hyperv1.GroupVersion.String(), + Kind: "HostedControlPlane", + Name: hcp.GetName(), + UID: hcp.UID, + }) +} +func applyManifests(ctx context.Context, c client.Client, log logr.Logger, namespace string, manifests map[string][]byte) error { + // Use server side apply for manifestss + applyErrors := []error{} + for manifestName, manifestBytes := range manifests { + if excludeManifests.Has(manifestName) { + continue + } + obj := &unstructured.Unstructured{} + if err := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifestBytes), 100).Decode(obj); err != nil { + applyErrors = append(applyErrors, fmt.Errorf("failed to decode manifest %s: %w", manifestName, err)) + } + obj.SetNamespace(namespace) + err := c.Patch(ctx, obj, client.RawPatch(types.ApplyPatchType, manifestBytes), client.ForceOwnership, client.FieldOwner("hypershift-operator")) + if err != nil { + applyErrors = append(applyErrors, fmt.Errorf("failed to apply manifest %s: %w", manifestName, err)) + } else { + log.Info("applied manifest", "manifest", manifestName) + } } - if err := r.Create(ctx, targetProviderCredsSecret); err != nil && !apierrors.IsAlreadyExists(err) { - return fmt.Errorf("failed to generate providerCreds secret: %v", err) + if errs := errors.NewAggregate(applyErrors); errs != nil { + return fmt.Errorf("failed to apply some manifests: %w", errs) } - log.Infof("Cluster API URL: %s", fmt.Sprintf("https://%s:%d", infraStatus.APIAddress, APIServerPort)) - log.Infof("Kubeconfig is available in secret %q in the %s namespace", fmt.Sprintf("%s-kubeconfig", name), hcp.GetNamespace()) - log.Infof("Console URL: %s", fmt.Sprintf("https://console-openshift-console.%s", params.IngressSubdomain)) - log.Infof("kubeadmin password is available in secret %q in the %s namespace", "kubeadmin-password", name) + return nil +} +func deleteManifests(ctx context.Context, c client.Client, log logr.Logger, namespace string, manifests map[string][]byte) error { + // Use server side apply for manifestss + applyErrors := []error{} + for manifestName, manifestBytes := range manifests { + if excludeManifests.Has(manifestName) { + continue + } + obj := &unstructured.Unstructured{} + if err := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifestBytes), 100).Decode(obj); err != nil { + applyErrors = append(applyErrors, fmt.Errorf("failed to decode manifest %s: %w", manifestName, err)) + } + obj.SetNamespace(namespace) + err := c.Delete(ctx, obj) + if err != nil { + applyErrors = append(applyErrors, fmt.Errorf("failed to delete manifest %s: %w", manifestName, err)) + } else { + log.Info("deleted manifest", "manifest", manifestName) + } + } + if errs := errors.NewAggregate(applyErrors); errs != nil { + return fmt.Errorf("failed to delete some manifests: %w", errs) + } return nil } -func generateTargetProviderCredsSecret(data []byte, namespace string) (*corev1.Secret, error) { +func generateSSHSecret(data []byte, namespace string) (*corev1.Secret, error) { + secret := &corev1.Secret{} + secret.Name = sshKeySecretName + secret.Namespace = namespace + secret.Data = map[string][]byte{"id_rsa.pub": data} + secret.Type = corev1.SecretTypeOpaque + return secret, nil +} + +func generateProviderCredsSecret(data []byte, namespace string) (*corev1.Secret, error) { secret := &corev1.Secret{} - secret.Name = "provider-creds" + secret.Name = providerCredsSecretName secret.Namespace = namespace secret.Data = map[string][]byte{"credentials": data} secret.Type = corev1.SecretTypeOpaque diff --git a/hypershift-operator/controllers/hosted_controlplane_controller.go b/hypershift-operator/controllers/hosted_controlplane_controller.go index 246e13a1957b..55affe30f70d 100644 --- a/hypershift-operator/controllers/hosted_controlplane_controller.go +++ b/hypershift-operator/controllers/hosted_controlplane_controller.go @@ -8,9 +8,7 @@ import ( "github.com/go-logr/logr" configv1 "github.com/openshift/api/config/v1" "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" "sigs.k8s.io/cluster-api/util" @@ -87,7 +85,7 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R // Return early if deleted if !hostedControlPlane.DeletionTimestamp.IsZero() { - if err := r.delete(ctx, req); err != nil { + if err := r.delete(ctx, hostedControlPlane); err != nil { r.Log.Error(err, "failed to delete cluster") return ctrl.Result{}, err } @@ -125,7 +123,7 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R return result, nil } - // First, set up infrastructure + r.Log.Info("Creating API services") infraStatus, err := r.ensureInfrastructure(ctx, hostedControlPlane) if err != nil { r.Log.Error(err, "failed to ensure infrastructure") @@ -152,7 +150,9 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, fmt.Errorf("invalid component versions found in release info: %w", err) } r.Log.Info("found release info for image", "releaseImage", hostedControlPlane.Spec.ReleaseImage, "info", releaseImage, "componentImages", releaseImage.ComponentImages(), "componentVersions", componentVersions) + // Install the control plane into the infrastructure + r.Log.Info("Creating hosted control plane") err = r.ensureControlPlane(ctx, hostedControlPlane, infraStatus, releaseImage) if err != nil { r.Log.Error(err, "failed to ensure control plane") @@ -168,13 +168,17 @@ func (r *HostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R return ctrl.Result{}, nil } -func (r *HostedControlPlaneReconciler) delete(ctx context.Context, req ctrl.Request) error { - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{Name: req.Name}, +func (r *HostedControlPlaneReconciler) delete(ctx context.Context, hcp *hyperv1.HostedControlPlane) error { + releaseImage, err := r.ReleaseProvider.Lookup(ctx, hcp.Spec.ReleaseImage) + if err != nil { + return fmt.Errorf("failed to look up release info: %w", err) + } + manifests, err := r.generateControlPlaneManifests(ctx, hcp, InfrastructureStatus{}, releaseImage) + if err != nil { + return nil } - if err := waitForDeletion(ctx, r.Log, r.Client, ns); err != nil && !apierrors.IsNotFound(err) { - return fmt.Errorf("failed to delete namespace: %w", err) + if err := deleteManifests(ctx, r, r.Log, hcp.GetName(), manifests); err != nil { + return err } - r.Log.Info("deleted namespace", "name", req.Name) return nil } diff --git a/hypershift-operator/controllers/infra.go b/hypershift-operator/controllers/infra.go index b7c68e7e3b6e..1bf2ca2011ed 100644 --- a/hypershift-operator/controllers/infra.go +++ b/hypershift-operator/controllers/infra.go @@ -45,36 +45,12 @@ func (s InfrastructureStatus) IsReady() bool { func (r *HostedControlPlaneReconciler) ensureInfrastructure(ctx context.Context, hcp *hyperv1.HostedControlPlane) (InfrastructureStatus, error) { status := InfrastructureStatus{} - name := hcp.Name - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - } - // Start creating resources on management cluster - err := r.Create(ctx, ns) - if err != nil && !apierrors.IsAlreadyExists(err) { - return status, fmt.Errorf("failed to create target namespace %q: %w", ns.Name, err) - } - + targetNamespace := hcp.GetName() // Ensure that we can run privileged pods - if err := ensureVPNSCC(r, name); err != nil { + if err := ensureVPNSCC(r, hcp, targetNamespace); err != nil { return status, fmt.Errorf("failed to ensure privileged SCC for the new namespace: %w", err) } - // Create pull secret - r.Log.Info("Creating pull secret") - var pullSecret corev1.Secret - err = r.Client.Get(ctx, ctrl.ObjectKey{Namespace: hcp.Namespace, Name: hcp.Spec.PullSecret.Name}, &pullSecret) - if err != nil { - return status, fmt.Errorf("failed to get pull secret %s: %w", hcp.Spec.PullSecret.Name, err) - } - pullSecretData, hasPullSecretData := pullSecret.Data[".dockerconfigjson"] - if !hasPullSecretData { - return status, fmt.Errorf("pull secret %s is missing the .dockerconfigjson key", hcp.Spec.PullSecret.Name) - } - if _, err := createPullSecret(r, name, pullSecretData); err != nil { - return status, fmt.Errorf("failed to create pull secret: %w", err) - } - baseDomain, err := ClusterBaseDomain(r.Client, ctx, hcp.Name) if err != nil { return status, fmt.Errorf("couldn't determine cluster base domain name: %w", err) @@ -82,46 +58,47 @@ func (r *HostedControlPlaneReconciler) ensureInfrastructure(ctx context.Context, // Create Kube APIServer service r.Log.Info("Creating Kube API service") - apiService, err := createKubeAPIServerService(r, name) + apiService, err := createKubeAPIServerService(r, hcp, targetNamespace) if err != nil { return status, fmt.Errorf("failed to create Kube API service: %w", err) } r.Log.Info("Created Kube API service") r.Log.Info("Creating VPN service") - vpnService, err := createVPNServerService(r, name) + vpnService, err := createVPNServerService(r, hcp, targetNamespace) if err != nil { return status, fmt.Errorf("failed to create vpn server service: %w", err) } r.Log.Info("Created VPN service") r.Log.Info("Creating Openshift API service") - openshiftAPIService, err := createOpenshiftService(r, name) + openshiftAPIService, err := createOpenshiftService(r, hcp, targetNamespace) if err != nil { return status, fmt.Errorf("failed to create openshift server service: %w", err) } r.Log.Info("Created Openshift API service") r.Log.Info("Creating Openshift OAuth API service") - oauthAPIService, err := createOauthAPIService(r, name) + oauthAPIService, err := createOauthAPIService(r, hcp, targetNamespace) if err != nil { return status, fmt.Errorf("failed to create openshift oauth api service: %w", err) } r.Log.Info("Created Openshift Oauth API service") r.Log.Info("Creating OAuth service") - oauthService, err := createOauthService(r, name) + oauthService, err := createOauthService(r, hcp, targetNamespace) if err != nil { return status, fmt.Errorf("error creating service for oauth: %w", err) } r.Log.Info("Creating router shard") - if err := createIngressController(r, name, baseDomain); err != nil { + if err := createIngressController(r, hcp, targetNamespace, baseDomain); err != nil { return status, fmt.Errorf("cannot create router shard: %w", err) } r.Log.Info("Creating ignition provider route") - ignitionRoute := createIgnitionServerRoute(r, ctx, name) + ignitionRoute := createIgnitionServerRoute(r, ctx, targetNamespace) + ignitionRoute.OwnerReferences = ensureHCPOwnerRef(hcp, ignitionRoute.OwnerReferences) if err := r.Create(ctx, ignitionRoute); err != nil && !apierrors.IsAlreadyExists(err) { return status, fmt.Errorf("failed to create ignition route: %w", err) } @@ -156,7 +133,7 @@ func (r *HostedControlPlaneReconciler) ensureInfrastructure(ctx context.Context, return status, nil } -func createKubeAPIServerService(client ctrl.Client, namespace string) (*corev1.Service, error) { +func createKubeAPIServerService(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) (*corev1.Service, error) { svc := &corev1.Service{} svc.Namespace = namespace svc.Name = kubeAPIServerServiceName @@ -169,6 +146,7 @@ func createKubeAPIServerService(client ctrl.Client, namespace string) (*corev1.S TargetPort: intstr.FromInt(6443), }, } + svc.OwnerReferences = ensureHCPOwnerRef(hcp, svc.OwnerReferences) if err := client.Create(context.TODO(), svc); err != nil { if !apierrors.IsAlreadyExists(err) { return nil, fmt.Errorf("failed to create api server service: %w", err) @@ -177,7 +155,7 @@ func createKubeAPIServerService(client ctrl.Client, namespace string) (*corev1.S return svc, nil } -func createVPNServerService(client ctrl.Client, namespace string) (*corev1.Service, error) { +func createVPNServerService(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) (*corev1.Service, error) { svc := &corev1.Service{} svc.Namespace = namespace svc.Name = vpnServiceName @@ -190,6 +168,7 @@ func createVPNServerService(client ctrl.Client, namespace string) (*corev1.Servi TargetPort: intstr.FromInt(1194), }, } + svc.OwnerReferences = ensureHCPOwnerRef(hcp, svc.OwnerReferences) if err := client.Create(context.TODO(), svc); err != nil { if !apierrors.IsAlreadyExists(err) { return nil, fmt.Errorf("failed to create vpn server service: %w", err) @@ -198,7 +177,7 @@ func createVPNServerService(client ctrl.Client, namespace string) (*corev1.Servi return svc, nil } -func createOpenshiftService(client ctrl.Client, namespace string) (*corev1.Service, error) { +func createOpenshiftService(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) (*corev1.Service, error) { svc := &corev1.Service{} svc.Namespace = namespace svc.Name = "openshift-apiserver" @@ -212,6 +191,7 @@ func createOpenshiftService(client ctrl.Client, namespace string) (*corev1.Servi TargetPort: intstr.FromInt(8443), }, } + svc.OwnerReferences = ensureHCPOwnerRef(hcp, svc.OwnerReferences) if err := client.Create(context.TODO(), svc); err != nil { if apierrors.IsAlreadyExists(err) { return svc, client.Get(context.TODO(), ctrl.ObjectKeyFromObject(svc), svc) @@ -222,7 +202,7 @@ func createOpenshiftService(client ctrl.Client, namespace string) (*corev1.Servi return svc, nil } -func createOauthAPIService(client ctrl.Client, namespace string) (*corev1.Service, error) { +func createOauthAPIService(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) (*corev1.Service, error) { svc := &corev1.Service{} svc.Namespace = namespace svc.Name = "openshift-oauth-apiserver" @@ -236,6 +216,7 @@ func createOauthAPIService(client ctrl.Client, namespace string) (*corev1.Servic TargetPort: intstr.FromInt(8443), }, } + svc.OwnerReferences = ensureHCPOwnerRef(hcp, svc.OwnerReferences) if err := client.Create(context.TODO(), svc); err != nil { if apierrors.IsAlreadyExists(err) { return svc, client.Get(context.TODO(), ctrl.ObjectKeyFromObject(svc), svc) @@ -246,7 +227,7 @@ func createOauthAPIService(client ctrl.Client, namespace string) (*corev1.Servic return svc, nil } -func createOauthService(client ctrl.Client, namespace string) (*corev1.Service, error) { +func createOauthService(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) (*corev1.Service, error) { svc := &corev1.Service{} svc.Namespace = namespace svc.Name = oauthServiceName @@ -260,6 +241,7 @@ func createOauthService(client ctrl.Client, namespace string) (*corev1.Service, TargetPort: intstr.FromInt(6443), }, } + svc.OwnerReferences = ensureHCPOwnerRef(hcp, svc.OwnerReferences) err := client.Create(context.TODO(), svc) if err != nil && !apierrors.IsAlreadyExists(err) { return nil, fmt.Errorf("failed to create oauth service: %w", err) @@ -270,7 +252,7 @@ func createOauthService(client ctrl.Client, namespace string) (*corev1.Service, func createPullSecret(client ctrl.Client, namespace string, data []byte) (*corev1.Secret, error) { secret := &corev1.Secret{} secret.Namespace = namespace - secret.Name = "pull-secret" + secret.Name = pullSecretName secret.Data = map[string][]byte{".dockerconfigjson": []byte(data)} secret.Type = corev1.SecretTypeDockerConfigJson if err := client.Create(context.TODO(), secret); err != nil { @@ -291,7 +273,7 @@ func createPullSecret(client ctrl.Client, namespace string, data []byte) (*corev }) } -func ensureVPNSCC(client ctrl.Client, namespace string) error { +func ensureVPNSCC(client ctrl.Client, hcp *hyperv1.HostedControlPlane, namespace string) error { scc := &securityv1.SecurityContextConstraints{} if err := client.Get(context.TODO(), ctrl.ObjectKey{Name: "privileged"}, scc); err != nil { return fmt.Errorf("failed to get privileged scc: %w", err) @@ -303,13 +285,14 @@ func ensureVPNSCC(client ctrl.Client, namespace string) error { } userSet.Insert(svcAccount) scc.Users = userSet.List() + scc.OwnerReferences = ensureHCPOwnerRef(hcp, scc.OwnerReferences) if err := client.Update(context.TODO(), scc); err != nil { return fmt.Errorf("failed to update privileged scc: %w", err) } return nil } -func createIngressController(client ctrl.Client, name string, parentDomain string) error { +func createIngressController(client ctrl.Client, hcp *hyperv1.HostedControlPlane, name string, parentDomain string) error { // First ensure that the default ingress controller doesn't use routes generated for hypershift clusters err := ensureDefaultIngressControllerSelector(client) if err != nil { @@ -329,6 +312,7 @@ func createIngressController(client ctrl.Client, name string, parentDomain strin }, }, } + ic.OwnerReferences = ensureHCPOwnerRef(hcp, ic.OwnerReferences) if err := client.Create(context.TODO(), ic); err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("failed to create ingress controller for %s: %w", name, err) } diff --git a/hypershift-operator/controllers/nodepool_controller.go b/hypershift-operator/controllers/nodepool_controller.go index bb6eb7ca3fb8..4a9c9fab2042 100644 --- a/hypershift-operator/controllers/nodepool_controller.go +++ b/hypershift-operator/controllers/nodepool_controller.go @@ -75,10 +75,15 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, err } + ocluster, err := GetOClusterByName(ctx, r.Client, nodePool.GetNamespace(), nodePool.Spec.ClusterName) + if err != nil { + return ctrl.Result{}, err + } + // Ignore deleted nodePools, this can happen when foregroundDeletion // is enabled if !nodePool.DeletionTimestamp.IsZero() { - machineSet, _, err := generateScalableResources(r, ctx, r.Infra.Status.InfrastructureName, r.Infra.Status.PlatformStatus.AWS.Region, nodePool) + machineSet, _, err := generateScalableResources(r, ctx, r.Infra.Status.InfrastructureName, r.Infra.Status.PlatformStatus.AWS.Region, nodePool, ocluster.GetName()) if err != nil { return reconcile.Result{}, fmt.Errorf("failed to generate worker machineset: %w", err) } @@ -104,11 +109,6 @@ func (r *NodePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c } } - ocluster, err := GetOClusterByName(ctx, r.Client, nodePool.GetNamespace(), nodePool.Spec.ClusterName) - if err != nil { - return ctrl.Result{}, err - } - // Initialize the patch helper patchHelper, err := patch.NewHelper(nodePool, r.Client) if err != nil { @@ -143,7 +143,7 @@ func (r *NodePoolReconciler) reconcile(ctx context.Context, ocluster *hyperv1.Op }) // Create a machine scalable resources for the new cluster's worker nodes - machineSet, AWSMachineTemplate, err := generateScalableResources(r, ctx, r.Infra.Status.InfrastructureName, r.Infra.Status.PlatformStatus.AWS.Region, nodePool) + machineSet, AWSMachineTemplate, err := generateScalableResources(r, ctx, r.Infra.Status.InfrastructureName, r.Infra.Status.PlatformStatus.AWS.Region, nodePool, ocluster.GetName()) if err != nil { return reconcile.Result{}, fmt.Errorf("failed to generate worker machineset: %w", err) } @@ -182,7 +182,8 @@ func GetOClusterByName(ctx context.Context, c client.Client, namespace, name str return ocluster, nil } -func generateScalableResources(client ctrlclient.Client, ctx context.Context, infraName, region string, nodePool *hyperv1.NodePool) (*capiv1.MachineSet, *capiaws.AWSMachineTemplate, error) { +func generateScalableResources(client ctrlclient.Client, ctx context.Context, + infraName, region string, nodePool *hyperv1.NodePool, targetNamespace string) (*capiv1.MachineSet, *capiaws.AWSMachineTemplate, error) { // find AMI machineSets := &unstructured.UnstructuredList{} machineSets.SetGroupVersionKind(schema.GroupVersionKind{ @@ -242,7 +243,7 @@ func generateScalableResources(client ctrlclient.Client, ctx context.Context, in TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ Name: resourcesName, - Namespace: nodePool.GetNamespace(), + Namespace: targetNamespace, }, Spec: capiaws.AWSMachineTemplateSpec{ Template: capiaws.AWSMachineTemplateResource{ @@ -266,7 +267,7 @@ func generateScalableResources(client ctrlclient.Client, ctx context.Context, in machineSet := &capiv1.MachineSet{ ObjectMeta: metav1.ObjectMeta{ Name: resourcesName, - Namespace: nodePool.GetNamespace(), + Namespace: targetNamespace, // TODO (alberto): drop/expose this annotation at the nodePool API Annotations: map[string]string{ "machine.cluster.x-k8s.io/exclude-node-draining": "true", @@ -307,8 +308,6 @@ func generateScalableResources(client ctrlclient.Client, ctx context.Context, in }, }, } - if err := ctrl.SetControllerReference(nodePool, machineSet, client.Scheme()); err != nil { - return nil, nil, err - } + return machineSet, AWSMachineTemplate, nil } diff --git a/hypershift-operator/controllers/openshiftcluster_controller.go b/hypershift-operator/controllers/openshiftcluster_controller.go index a14a6a3c682b..e653639255e4 100644 --- a/hypershift-operator/controllers/openshiftcluster_controller.go +++ b/hypershift-operator/controllers/openshiftcluster_controller.go @@ -21,35 +21,40 @@ import ( "fmt" "time" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - configv1 "github.com/openshift/api/config/v1" - "github.com/go-logr/logr" + configv1 "github.com/openshift/api/config/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/workqueue" hyperv1 "openshift.io/hypershift/api/v1alpha1" + "openshift.io/hypershift/hypershift-operator/releaseinfo" + hypershiftcp "openshift.io/hypershift/hypershift-operator/render/controlplane/hypershift" capiv1 "sigs.k8s.io/cluster-api/api/v1alpha4" "sigs.k8s.io/cluster-api/util/patch" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" ) const ( - finalizer = "hypershift.openshift.io/finalizer" + finalizer = "hypershift.openshift.io/finalizer" + pullSecretName = "pull-secret" + sshKeySecretName = "ssh-key" + providerCredsSecretName = "provider-creds" ) // OpenShiftClusterReconciler reconciles a OpenShiftCluster object type OpenShiftClusterReconciler struct { client.Client - Log logr.Logger - Infra *configv1.Infrastructure + Log logr.Logger + ReleaseProvider releaseinfo.Provider + Infra *configv1.Infrastructure } // +kubebuilder:rbac:groups=hypershift.openshift.io,resources=openshiftclusters,verbs=get;list;watch;create;update;patch;delete @@ -72,7 +77,7 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req // Return early if deleted if isMissing || !ocluster.DeletionTimestamp.IsZero() { - if err := r.delete(ctx, req.Name, req.Namespace); err != nil { + if err := r.delete(ctx, req); err != nil { r.Log.Error(err, "failed to delete cluster") return ctrl.Result{}, err } @@ -99,9 +104,79 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req return ctrl.Result{}, nil } + targetNamespace := ocluster.GetName() + r.Log.Info("Creating the target namespace", "namespace", targetNamespace) + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: targetNamespace}, + } + if err := r.Create(ctx, ns); err != nil && !apierrors.IsAlreadyExists(err) { + return ctrl.Result{}, fmt.Errorf("failed to create target namespace %q: %w", ns.Name, err) + } + + r.Log.Info("Creating provider creds secret in the target namespace", "namespace", targetNamespace) + var providerCredsSecret corev1.Secret + err = r.Client.Get(ctx, client.ObjectKey{Namespace: ocluster.GetNamespace(), Name: ocluster.Spec.ProviderCreds.Name}, &providerCredsSecret) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get provider creds %s: %w", ocluster.Spec.ProviderCreds.Name, err) + } + providerCredsData, hasProviderCredsData := providerCredsSecret.Data["credentials"] + if !hasProviderCredsData { + return ctrl.Result{}, fmt.Errorf("provider credentials %s is missing the credentials key", ocluster.Spec.PullSecret.Name) + } + targetProviderCredsSecret, err := generateProviderCredsSecret(providerCredsData, targetNamespace) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create providerCreds secret manifest for target cluster: %w", err) + } + if err := r.Create(ctx, targetProviderCredsSecret); err != nil && !apierrors.IsAlreadyExists(err) { + return ctrl.Result{}, fmt.Errorf("failed to generate providerCreds secret: %v", err) + } + + r.Log.Info("Creating pull secret in the target namespace", "namespace", targetNamespace) + var pullSecret corev1.Secret + if err := r.Client.Get(ctx, ctrlclient.ObjectKey{Namespace: ocluster.GetNamespace(), Name: ocluster.Spec.PullSecret.Name}, &pullSecret); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get pull secret %s: %w", ocluster.Spec.PullSecret.Name, err) + } + pullSecretData, hasPullSecretData := pullSecret.Data[".dockerconfigjson"] + if !hasPullSecretData { + return ctrl.Result{}, fmt.Errorf("pull secret %s is missing the .dockerconfigjson key", ocluster.Spec.PullSecret.Name) + } + if _, err := createPullSecret(r, targetNamespace, pullSecretData); err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create pull secret: %w", err) + } + + r.Log.Info("Creating ssh key secret in the target namespace", "namespace", targetNamespace) + var sshKeySecret corev1.Secret + err = r.Client.Get(ctx, client.ObjectKey{Namespace: ocluster.Namespace, Name: ocluster.Spec.SSHKey.Name}, &sshKeySecret) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to get SSH key secret %s: %w", ocluster.Spec.SSHKey.Name, err) + } + sshKeyData, hasSSHKeyData := sshKeySecret.Data["id_rsa.pub"] + if !hasSSHKeyData { + return ctrl.Result{}, fmt.Errorf("SSH key secret secret %s is missing the id_rsa.pub key", ocluster.Spec.SSHKey.Name) + } + targetSSHSecret, err := generateSSHSecret(sshKeyData, targetNamespace) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to generate ssh secret manifest for target cluster: %w", err) + } + if err := r.Create(ctx, targetSSHSecret); err != nil && !apierrors.IsAlreadyExists(err) { + return ctrl.Result{}, fmt.Errorf("failed to create target ssh secret : %v", err) + } + + // run CAPI controllers + params := hypershiftcp.NewClusterParams() + params.Namespace = targetNamespace + releaseImage, err := r.ReleaseProvider.Lookup(ctx, ocluster.Spec.Release.Image) + manifests, err := hypershiftcp.RenderCAPIManifests(params, releaseImage, nil, nil) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to render hypershift manifests for cluster: %w", err) + } + if err := applyManifests(ctx, r, r.Log, targetNamespace, manifests); err != nil { + return ctrl.Result{}, err + } + cluster := &capiv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ocluster.GetNamespace(), + Namespace: targetNamespace, Name: ocluster.GetName(), }, Spec: capiv1.ClusterSpec{ @@ -109,13 +184,13 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req ControlPlaneRef: &corev1.ObjectReference{ APIVersion: "hypershift.openshift.io/v1alpha1", Kind: "HostedControlPlane", - Namespace: ocluster.GetNamespace(), + Namespace: targetNamespace, Name: ocluster.GetName(), }, InfrastructureRef: &corev1.ObjectReference{ APIVersion: "hypershift.openshift.io/v1alpha1", Kind: "ExternalInfraCluster", - Namespace: ocluster.GetNamespace(), + Namespace: targetNamespace, Name: ocluster.GetName(), }, }, @@ -124,27 +199,30 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req if err != nil { return ctrl.Result{}, fmt.Errorf("failed to init patch helper: %w", err) } - if err := ctrl.SetControllerReference(ocluster, cluster, r.Client.Scheme()); err != nil { - return ctrl.Result{}, err - } hcp := &hyperv1.HostedControlPlane{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ocluster.GetNamespace(), + Namespace: targetNamespace, Name: ocluster.GetName(), }, Spec: hyperv1.HostedControlPlaneSpec{ - ProviderCreds: ocluster.Spec.ProviderCreds, - PullSecret: ocluster.Spec.PullSecret, - ServiceCIDR: ocluster.Spec.ServiceCIDR, - PodCIDR: ocluster.Spec.PodCIDR, - SSHKey: ocluster.Spec.SSHKey, - ReleaseImage: ocluster.Spec.Release.Image, + ProviderCreds: corev1.LocalObjectReference{ + Name: providerCredsSecretName, + }, + PullSecret: corev1.LocalObjectReference{ + Name: pullSecretName, + }, + SSHKey: corev1.LocalObjectReference{ + Name: sshKeySecretName, + }, + ServiceCIDR: ocluster.Spec.ServiceCIDR, + PodCIDR: ocluster.Spec.PodCIDR, + ReleaseImage: ocluster.Spec.Release.Image, }, } ExternalInfraCluster := &hyperv1.ExternalInfraCluster{ ObjectMeta: metav1.ObjectMeta{ - Namespace: ocluster.GetNamespace(), + Namespace: targetNamespace, Name: ocluster.GetName(), }, Spec: hyperv1.ExternalInfraClusterSpec{ @@ -185,7 +263,7 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req nodePool := &hyperv1.NodePool{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%v-default", ocluster.GetName()), + Name: ocluster.GetName(), Namespace: ocluster.GetNamespace(), }, Spec: hyperv1.NodePoolSpec{ @@ -208,29 +286,40 @@ func (r *OpenShiftClusterReconciler) Reconcile(ctx context.Context, req ctrl.Req return ctrl.Result{}, nil } -func (r *OpenShiftClusterReconciler) delete(ctx context.Context, name, namespace string) error { - cluster := &capiv1.Cluster{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } +func (r *OpenShiftClusterReconciler) delete(ctx context.Context, req ctrl.Request) error { + targetNamespace := req.Name + + r.Log.Info("Deleting default nodePool", "name", req.Name) defaultNodePool := &hyperv1.NodePool{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-default", name), - Namespace: namespace, + Name: req.Name, + Namespace: req.Namespace, }, } if err := r.Delete(ctx, defaultNodePool); err != nil && !apierrors.IsNotFound(err) { - return fmt.Errorf("failed to delete cluster: %w", err) + return fmt.Errorf("failed to delete defaultNodePool: %w", err) + } + + r.Log.Info("Deleting cluster", "name", req.Name, "namespace", targetNamespace) + cluster := &capiv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: req.Name, + Namespace: targetNamespace, + }, } - if err := r.Delete(ctx, cluster); err != nil && !apierrors.IsNotFound(err) { + if err := waitForDeletion(ctx, r.Log, r, cluster); err != nil && !apierrors.IsNotFound(err) { return fmt.Errorf("failed to delete cluster: %w", err) } - r.Log.Info("Deleted cluster", "name", name) + r.Log.Info("Deleting target namespace", "namespace", targetNamespace) + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: targetNamespace}, + } + if err := r.Delete(ctx, ns); err != nil && !apierrors.IsNotFound(err) { + return fmt.Errorf("failed to delete namespace: %w", err) + } return nil } diff --git a/hypershift-operator/main.go b/hypershift-operator/main.go index 63d1023e742a..b26165ee6c3b 100644 --- a/hypershift-operator/main.go +++ b/hypershift-operator/main.go @@ -142,6 +142,9 @@ func NewStartCommand() *cobra.Command { if err = (&controllers.OpenShiftClusterReconciler{ Client: mgr.GetClient(), + ReleaseProvider: &releaseinfo.PodProvider{ + Pods: kubeClient.CoreV1().Pods("hypershift"), + }, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "OpenShiftCluster") os.Exit(1) diff --git a/hypershift-operator/render/controlplane/hypershift/manifests.go b/hypershift-operator/render/controlplane/hypershift/manifests.go index cf05fabcf330..8f2ab1f6038c 100644 --- a/hypershift-operator/render/controlplane/hypershift/manifests.go +++ b/hypershift-operator/render/controlplane/hypershift/manifests.go @@ -12,6 +12,16 @@ import ( ) // RenderClusterManifests renders manifests for a hosted control plane cluster +func RenderCAPIManifests(params *ClusterParams, image *releaseinfo.ReleaseImage, pullSecret []byte, pki map[string][]byte) (map[string][]byte, error) { + componentVersions, err := image.ComponentVersions() + if err != nil { + return nil, err + } + ctx := newClusterManifestContext(image.ComponentImages(), componentVersions, params, pullSecret, pki) + ctx.capi() + return ctx.renderManifests() +} + func RenderClusterManifests(params *ClusterParams, image *releaseinfo.ReleaseImage, pullSecret []byte, pki map[string][]byte) (map[string][]byte, error) { componentVersions, err := image.ComponentVersions() if err != nil { @@ -75,7 +85,6 @@ func (c *clusterManifestContext) setupManifests() { c.routerProxy() c.machineConfigServer() c.ignitionConfigs() - c.capi() } func (c *clusterManifestContext) serviceAdminKubeconfig() { @@ -159,6 +168,10 @@ func (c *clusterManifestContext) capi() { "capi/capa-manager-clusterrole.yaml", "capi/capa-manager-clusterrolebinding.yaml", "capi/capa-manager-deployment.yaml", + "capi/manager-serviceaccount.yaml", + "capi/manager-clusterrole.yaml", + "capi/manager-clusterrolebinding.yaml", + "capi/manager-deployment.yaml", ) }