Skip to content

Commit adc56ce

Browse files
committed
agent-day2: retrieve ignition endpoint to add a new node
This patch allows using the secure port, if configured, in the target cluster when adding a new node
1 parent fcaa07d commit adc56ce

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

data/data/agent/systemd/units/agent-import-cluster.service.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ EnvironmentFile=/usr/local/share/assisted-service/assisted-service.env
1616
EnvironmentFile=/etc/assisted/add-nodes.env
1717
ExecStartPre=/bin/rm -f %t/%n.ctr-id
1818
ExecStartPre=/usr/local/bin/wait-for-assisted-service.sh
19-
ExecStart=podman run --net host --cidfile=%t/%n.ctr-id --cgroups=no-conmon --log-driver=journald --rm --pod-id-file=%t/assisted-service-pod.pod-id --replace --name=agent-import-cluster -v /etc/assisted/manifests:/manifests -v /etc/assisted/extra-manifests:/extra-manifests {{ if .HaveMirrorConfig }}-v /etc/containers:/etc/containers{{ end }} {{.CaBundleMount}} --env SERVICE_BASE_URL --env OPENSHIFT_INSTALL_RELEASE_IMAGE_MIRROR --env CLUSTER_ID --env CLUSTER_NAME --env CLUSTER_API_VIP_DNS_NAME $SERVICE_IMAGE /usr/local/bin/agent-installer-client importCluster
19+
ExecStart=podman run --net host --cidfile=%t/%n.ctr-id --cgroups=no-conmon --log-driver=journald --rm --pod-id-file=%t/assisted-service-pod.pod-id --replace --name=agent-import-cluster -v /etc/assisted/clusterconfig:/clusterconfig -v /etc/assisted/manifests:/manifests -v /etc/assisted/extra-manifests:/extra-manifests {{ if .HaveMirrorConfig }}-v /etc/containers:/etc/containers{{ end }} {{.CaBundleMount}} --env SERVICE_BASE_URL --env OPENSHIFT_INSTALL_RELEASE_IMAGE_MIRROR --env CLUSTER_ID --env CLUSTER_NAME --env CLUSTER_API_VIP_DNS_NAME $SERVICE_IMAGE /usr/local/bin/agent-installer-client importCluster
2020
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
2121
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
2222

pkg/asset/agent/image/ignition.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package image
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"net"
78
"net/url"
@@ -46,6 +47,7 @@ const nmConnectionsPath = "/etc/assisted/network"
4647
const extraManifestPath = "/etc/assisted/extra-manifests"
4748
const registriesConfPath = "/etc/containers/registries.conf"
4849
const registryCABundlePath = "/etc/pki/ca-trust/source/anchors/domain.crt"
50+
const clusterConfigPath = "/etc/assisted/clusterconfig"
4951

5052
// Ignition is an asset that generates the agent installer ignition file.
5153
type Ignition struct {
@@ -195,6 +197,10 @@ func (a *Ignition) Generate(dependencies asset.Parents) error {
195197
streamGetter = func(ctx context.Context) (*stream.Stream, error) {
196198
return clusterInfo.OSImage, nil
197199
}
200+
// If defined, add the ignition endpoints
201+
if err := addDay2IgnitionEndpoints(&config, *clusterInfo); err != nil {
202+
return err
203+
}
198204

199205
default:
200206
return fmt.Errorf("AgentWorkflowType value not supported: %s", agentWorkflow.Workflow)
@@ -531,6 +537,35 @@ func addHostConfig(config *igntypes.Config, agentHosts *agentconfig.AgentHosts)
531537
return nil
532538
}
533539

540+
func addDay2IgnitionEndpoints(config *igntypes.Config, clusterInfo joiner.ClusterInfo) error {
541+
if clusterInfo.IgnitionEndpointWorker == nil {
542+
return nil
543+
}
544+
545+
user := "root"
546+
mode := 0644
547+
config.Storage.Directories = append(config.Storage.Directories, igntypes.Directory{
548+
Node: igntypes.Node{
549+
Path: clusterConfigPath,
550+
User: igntypes.NodeUser{
551+
Name: &user,
552+
},
553+
Overwrite: util.BoolToPtr(true),
554+
},
555+
DirectoryEmbedded1: igntypes.DirectoryEmbedded1{
556+
Mode: &mode,
557+
},
558+
})
559+
560+
workerIgnitionBytes, err := json.Marshal(clusterInfo.IgnitionEndpointWorker)
561+
if err != nil {
562+
return err
563+
}
564+
workerIgnitionFile := ignition.FileFromBytes(path.Join(clusterConfigPath, "worker-ignition-endpoint.json"), user, mode, workerIgnitionBytes)
565+
config.Storage.Files = append(config.Storage.Files, workerIgnitionFile)
566+
return nil
567+
}
568+
534569
func addExtraManifests(config *igntypes.Config, extraManifests *manifests.ExtraManifests) error {
535570

536571
user := "root"

pkg/asset/agent/joiner/clusterinfo.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"strings"
78

9+
igntypes "github.com/coreos/ignition/v2/config/v3_2/types"
810
"github.com/coreos/stream-metadata-go/arch"
911
"github.com/coreos/stream-metadata-go/stream"
1012
"k8s.io/apimachinery/pkg/api/errors"
@@ -15,6 +17,7 @@ import (
1517
"sigs.k8s.io/yaml"
1618

1719
hiveext "github.com/openshift/assisted-service/api/hiveextension/v1beta1"
20+
"github.com/openshift/assisted-service/models"
1821
configclient "github.com/openshift/client-go/config/clientset/versioned"
1922
"github.com/openshift/installer/pkg/asset"
2023
"github.com/openshift/installer/pkg/asset/agent"
@@ -45,6 +48,7 @@ type ClusterInfo struct {
4548
SSHKey string
4649
OSImage *stream.Stream
4750
OSImageLocation string
51+
IgnitionEndpointWorker *models.IgnitionEndpoint
4852
}
4953

5054
var _ asset.WritableAsset = (*ClusterInfo)(nil)
@@ -106,6 +110,10 @@ func (ci *ClusterInfo) Generate(dependencies asset.Parents) error {
106110
if err != nil {
107111
return err
108112
}
113+
err = ci.retrieveIgnitionEndpointWorker()
114+
if err != nil {
115+
return err
116+
}
109117

110118
ci.Namespace = "cluster0"
111119

@@ -269,6 +277,48 @@ func (ci *ClusterInfo) retrieveOsImage() error {
269277
return nil
270278
}
271279

280+
// This method retrieves, if present, the secured ignition endpoint - along with its ca certificate.
281+
// These information will be used to configure subsequently the imported Assisted Service cluster,
282+
// so that the secure port (22623) could be used by the nodes to fetch the worker ignition.
283+
func (ci *ClusterInfo) retrieveIgnitionEndpointWorker() error {
284+
workerUserDataManaged, err := ci.Client.CoreV1().Secrets("openshift-machine-api").Get(context.Background(), "worker-user-data-managed", metav1.GetOptions{})
285+
if err != nil {
286+
if errors.IsNotFound(err) {
287+
return nil
288+
}
289+
return err
290+
}
291+
userData := workerUserDataManaged.Data["userData"]
292+
293+
config := &igntypes.Config{}
294+
err = json.Unmarshal(userData, config)
295+
if err != nil {
296+
return err
297+
}
298+
299+
// Check if there is at least a CA certificate in the ignition
300+
if len(config.Ignition.Security.TLS.CertificateAuthorities) == 0 {
301+
return nil
302+
}
303+
304+
// Get the first source and ca certificate (and strip the base64 data header)
305+
ignEndpointURL := config.Ignition.Config.Merge[0].Source
306+
caCertSource := *config.Ignition.Security.TLS.CertificateAuthorities[0].Source
307+
308+
hdrIndex := strings.Index(caCertSource, ",")
309+
if hdrIndex == -1 {
310+
return fmt.Errorf("error while parsing ignition endpoints ca certificate, invalid data url format")
311+
}
312+
caCert := caCertSource[hdrIndex+1:]
313+
314+
ci.IgnitionEndpointWorker = &models.IgnitionEndpoint{
315+
URL: ignEndpointURL,
316+
CaCertificate: &caCert,
317+
}
318+
319+
return nil
320+
}
321+
272322
// Files returns the files generated by the asset.
273323
func (*ClusterInfo) Files() []*asset.File {
274324
return []*asset.File{}

pkg/asset/agent/joiner/clusterinfo_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import (
1010
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1111
"k8s.io/apimachinery/pkg/runtime"
1212
"k8s.io/client-go/kubernetes/fake"
13+
"k8s.io/utils/ptr"
1314
"sigs.k8s.io/yaml"
1415

1516
configv1 "github.com/openshift/api/config/v1"
1617
"github.com/openshift/assisted-service/api/hiveextension/v1beta1"
18+
"github.com/openshift/assisted-service/models"
1719
fakeclientconfig "github.com/openshift/client-go/config/clientset/versioned/fake"
1820
"github.com/openshift/installer/pkg/asset"
1921
"github.com/openshift/installer/pkg/asset/agent/workflow"
@@ -114,6 +116,17 @@ func TestClusterInfo_Generate(t *testing.T) {
114116
"stream": makeCoreOsBootImages(t, buildStreamData()),
115117
},
116118
},
119+
&corev1.Secret{
120+
ObjectMeta: v1.ObjectMeta{
121+
Name: "worker-user-data-managed",
122+
Namespace: "openshift-machine-api",
123+
},
124+
Data: map[string][]byte{
125+
"userData": []byte(`{"ignition":{"config":{"merge":[{"source":"https://192.168.111.5:22623/config/worker","verification":{}}],
126+
"replace":{"verification":{}}},"proxy":{},"security":{"tls":{"certificateAuthorities":[{"source":"data:text/plain;charset=utf-8;base64,LS0tL_FakeCertificate_LS0tCg==",
127+
"verification":{}}]}},"timeouts":{},"version":"3.4.0"},"kernelArguments":{},"passwd":{},"storage":{},"systemd":{}}`),
128+
},
129+
},
117130
},
118131
expectedClusterInfo: ClusterInfo{
119132
ClusterID: "1b5ba46b-7e56-47b1-a326-a9eebddfb38c",
@@ -142,6 +155,10 @@ func TestClusterInfo_Generate(t *testing.T) {
142155
SSHKey: "my-ssh-key",
143156
OSImage: buildStreamData(),
144157
OSImageLocation: "http://my-coreosimage-url/416.94.202402130130-0",
158+
IgnitionEndpointWorker: &models.IgnitionEndpoint{
159+
URL: ptr.To("https://192.168.111.5:22623/config/worker"),
160+
CaCertificate: ptr.To("LS0tL_FakeCertificate_LS0tCg=="),
161+
},
145162
},
146163
},
147164
}
@@ -179,6 +196,7 @@ func TestClusterInfo_Generate(t *testing.T) {
179196
assert.Equal(t, tc.expectedClusterInfo.SSHKey, clusterInfo.SSHKey)
180197
assert.Equal(t, tc.expectedClusterInfo.OSImageLocation, clusterInfo.OSImageLocation)
181198
assert.Equal(t, tc.expectedClusterInfo.OSImage, clusterInfo.OSImage)
199+
assert.Equal(t, tc.expectedClusterInfo.IgnitionEndpointWorker, clusterInfo.IgnitionEndpointWorker)
182200
})
183201
}
184202
}

0 commit comments

Comments
 (0)