Skip to content

Commit

Permalink
AGENT-227: Add host configuration support to ephemeral installer clie…
Browse files Browse the repository at this point in the history
…nt (#4051)

* AGENT-227: Add host configuration support to ephemeral installer client (#4014)

* Ephemeral installer: refactor client command

In future we'll want to do different things with this, not just register
the Cluster and InfraEnv.

* Ephemeral installer: Split environment options for subcommands

* Add subcommands to ephemeral installer client

Change the command to register the Cluster and InfraEnv from:

    /agent-based-installer-register-cluster-and-infraenv

to:

    /usr/local/bin/agent-installer-client register

This allows us to add further subcommands to the same binary in future.

A symlink is provided for backward compatibility with the existing
agent-based installer ISOs. When invoked using the old name, the command
will retain the existing behaviour. This backward compatibility can be
removed once the agent-based installer is using the subcommand syntax.

* Implement host configuration framework for ephemeral installer

* Create library func to evaluate root device hints

* Set root device in ephemeral installer client

Read root device hints from (by default)
/etc/assisted/hostconfig/*/root-device-hints.yaml and use them to select
an install disk for each host and configure it through the assisted API.

* Add role configuration to ephemeral installer client

Read role files from (by default) /etc/assisted/hostconfig/*/role and
use them to set the role for each host through the assisted API.

* Record failures and log more useful information on the cause

(cherry picked from commit eba9079)

* AGENT-227: Don't exit when inventory not available (#4030)

Before an agent's inventory has been discovered, we cannot match it to
any host configuration (which would require knowing the MAC addresses).
Therefore, treat it as equivalent to the host not having shown up yet.

Previously we exited with an error caused by trying to Unmarshal from
zero-length data, which results in the install failing when the
configuration command runs before inventory is available.

(cherry picked from commit eb6c54e)
  • Loading branch information
zaneb committed Jul 1, 2022
1 parent b102c21 commit 4160cc4
Show file tree
Hide file tree
Showing 7 changed files with 572 additions and 87 deletions.
5 changes: 3 additions & 2 deletions Dockerfile.assisted-service
Expand Up @@ -28,7 +28,7 @@ COPY . .
RUN CGO_ENABLED=1 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service cmd/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service-operator cmd/operator/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service-admission cmd/webadmission/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/agent-based-installer-register-cluster-and-infraenv cmd/agentbasedinstaller/client/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/agent-installer-client cmd/agentbasedinstaller/client/main.go

FROM quay.io/ocpmetal/oc-image:bug-1823143-multi-arch-ai-bug-2069976 as oc-image

Expand All @@ -49,7 +49,8 @@ COPY --from=oc-image /oc /usr/local/bin/
COPY --from=builder /build/assisted-service /assisted-service
COPY --from=builder /build/assisted-service-operator /assisted-service-operator
COPY --from=builder /build/assisted-service-admission /assisted-service-admission
COPY --from=builder /build/agent-based-installer-register-cluster-and-infraenv /agent-based-installer-register-cluster-and-infraenv
COPY --from=builder /build/agent-installer-client /usr/local/bin/agent-installer-client
RUN ln -s /usr/local/bin/agent-installer-client /agent-based-installer-register-cluster-and-infraenv
COPY --from=pybuilder /assisted-service/build/dist/* /clients/
ENV GODEBUG=madvdontneed=1
ENV GOGC=50
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile.assisted-service.ocp
Expand Up @@ -5,7 +5,7 @@ COPY . .
RUN CGO_ENABLED=1 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service cmd/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service-operator cmd/operator/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service-admission cmd/webadmission/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/agent-based-installer-register-cluster-and-infraenv cmd/agentbasedinstaller/client/main.go
RUN CGO_ENABLED=0 GOFLAGS="" GO111MODULE=on go build -o /build/agent-installer-client cmd/agentbasedinstaller/client/main.go


FROM registry.ci.openshift.org/ocp/4.11:cli AS oc-image
Expand All @@ -32,7 +32,8 @@ COPY --from=oc-image /usr/bin/oc /usr/local/bin/
COPY --from=builder /build/assisted-service /assisted-service
COPY --from=builder /build/assisted-service-operator /assisted-service-operator
COPY --from=builder /build/assisted-service-admission /assisted-service-admission
COPY --from=builder /build/agent-based-installer-register-cluster-and-infraenv /agent-based-installer-register-cluster-and-infraenv
COPY --from=builder /build/agent-installer-client /usr/local/bin/agent-installer-client
RUN ln -s /usr/local/bin/agent-installer-client /agent-based-installer-register-cluster-and-infraenv
ENV GODEBUG=madvdontneed=1
ENV GOGC=50
CMD ["/assisted-service"]
129 changes: 118 additions & 11 deletions cmd/agentbasedinstaller/client/main.go
Expand Up @@ -23,9 +23,15 @@ package main

import (
"context"
"fmt"
"io/ioutil"
"net/url"
"os"
"path"
"strings"
"time"

"github.com/go-openapi/strfmt"
"github.com/openshift/assisted-service/cmd/agentbasedinstaller"

"github.com/kelseyhightower/envconfig"
Expand All @@ -34,31 +40,35 @@ import (
corev1 "k8s.io/api/core/v1"
)

const failureOutputPath = "/var/run/agent-installer/host-config-failures"

var Options struct {
ServiceBaseUrl string `envconfig:"SERVICE_BASE_URL" default:""`
}

var RegisterOptions struct {
ClusterDeploymentFile string `envconfig:"CLUSTER_DEPLOYMENT_FILE" default:"/manifests/cluster-deployment.yaml"`
AgentClusterInstallFile string `envconfig:"AGENT_CLUSTER_INSTALL_FILE" default:"/manifests/agent-cluster-install.yaml"`
InfraEnvFile string `envconfig:"INFRA_ENV_FILE" default:"/manifests/infraenv.yaml"`
PullSecretFile string `envconfig:"PULL_SECRET_FILE" default:"/manifests/pull-secret.yaml"`
ClusterImageSetFile string `envconfig:"CLUSTER_IMAGE_SET_FILE" default:"/manifests/cluster-image-set.yaml"`
NMStateConfigFile string `envconfig:"NMSTATE_CONFIG_FILE" default:"/manifests/nmstateconfig.yaml"`
ServiceBaseUrl string `envconfig:"SERVICE_BASE_URL" default:""`
ImageTypeISO string `envconfig:"IMAGE_TYPE_ISO" default:"full-iso"`
ReleaseImageMirror string `envconfig:"OPENSHIFT_INSTALL_RELEASE_IMAGE_MIRROR" default:""`
}

var ConfigureOptions struct {
InfraEnvID string `envconfig:"INFRA_ENV_ID" default:""`
HostConfigDir string `envconfig:"HOST_CONFIG_DIR" default:"/etc/assisted/hostconfig"`
}

func main() {
err := envconfig.Process("", &Options)
log := log.New()
if err != nil {
log.Fatal(err.Error())
}

var secret corev1.Secret
if secretErr := agentbasedinstaller.GetFileData(Options.PullSecretFile, &secret); secretErr != nil {
log.Fatal(secretErr.Error())
}
pullSecret := secret.StringData[".dockerconfigjson"]

clientConfig := client.Config{}
u, parseErr := url.Parse(Options.ServiceBaseUrl)
if parseErr != nil {
Expand All @@ -68,12 +78,45 @@ func main() {
clientConfig.URL = u
bmInventory := client.New(clientConfig)
ctx := context.Background()

log.Info("SERVICE_BASE_URL: " + Options.ServiceBaseUrl)

// TODO: This is for backward compatibility and should be removed once the
// ephemeral ISO services are using the subcommands.
if path.Base(os.Args[0]) == "agent-based-installer-register-cluster-and-infraenv" {
register(ctx, log, bmInventory)
return
}

if len(os.Args) < 2 {
log.Fatal("No subcommand specified")
}
switch os.Args[1] {
case "register":
infraEnvID := register(ctx, log, bmInventory)
os.WriteFile("/etc/assisted/client_config", []byte("INFRA_ENV_ID="+infraEnvID), 0644)
case "configure":
configure(ctx, log, bmInventory)
default:
log.Fatalf("Unknown subcommand %s", os.Args[1])
}
}

func register(ctx context.Context, log *log.Logger, bmInventory *client.AssistedInstall) string {
err := envconfig.Process("", &RegisterOptions)
if err != nil {
log.Fatal(err.Error())
}

var secret corev1.Secret
if secretErr := agentbasedinstaller.GetFileData(RegisterOptions.PullSecretFile, &secret); secretErr != nil {
log.Fatal(secretErr.Error())
}
pullSecret := secret.StringData[".dockerconfigjson"]

log.Info("Registering cluster")

modelsCluster, registerClusterErr := agentbasedinstaller.RegisterCluster(ctx, log, bmInventory, pullSecret,
Options.ClusterDeploymentFile, Options.AgentClusterInstallFile, Options.ClusterImageSetFile, Options.ReleaseImageMirror)
RegisterOptions.ClusterDeploymentFile, RegisterOptions.AgentClusterInstallFile, RegisterOptions.ClusterImageSetFile, RegisterOptions.ReleaseImageMirror)
if registerClusterErr != nil {
log.Fatal(registerClusterErr, "Failed to register cluster with assisted-service")
}
Expand All @@ -83,10 +126,74 @@ func main() {
log.Info("Registering infraenv")

modelsInfraEnv, registerInfraEnvErr := agentbasedinstaller.RegisterInfraEnv(ctx, log, bmInventory, pullSecret,
modelsCluster, Options.InfraEnvFile, Options.NMStateConfigFile, Options.ImageTypeISO)
modelsCluster, RegisterOptions.InfraEnvFile, RegisterOptions.NMStateConfigFile, RegisterOptions.ImageTypeISO)
if registerInfraEnvErr != nil {
log.Fatal(registerInfraEnvErr, "Failed to register infraenv with assisted-service")
}

log.Info("Registered infraenv with id: " + modelsInfraEnv.ID.String())
infraEnvID := modelsInfraEnv.ID.String()
log.Info("Registered infraenv with id: " + infraEnvID)

return infraEnvID
}

func configure(ctx context.Context, log *log.Logger, bmInventory *client.AssistedInstall) {
err := envconfig.Process("", &ConfigureOptions)
if err != nil {
log.Fatal(err.Error())
}

if ConfigureOptions.InfraEnvID == "" {
log.Fatal("No INFRA_ENV_ID specified")
}

hostConfigs, err := agentbasedinstaller.LoadHostConfigs(ConfigureOptions.HostConfigDir)
if err != nil {
log.Fatal("Failed to load host configuration: ", err)
}

done := false
sleepTime := 1 * time.Second
for !done {
failures, err := agentbasedinstaller.ApplyHostConfigs(ctx, log, bmInventory, hostConfigs, strfmt.UUID(ConfigureOptions.InfraEnvID))
if err != nil {
log.Fatal("Failed to apply host configuration: ", err)
}
if len(failures) > 0 {
log.Infof("Sleeping for %v", sleepTime)
time.Sleep(sleepTime)
if sleepTime < (30 * time.Second) {
sleepTime = sleepTime * 2
}
} else {
done = true
}
if err := recordFailures(failures); err != nil {
log.Fatal("Unable to record failures to disk: ", err)
}
}
log.Info("Configured all hosts")
}

func recordFailures(failures []agentbasedinstaller.Failure) error {
if len(failures) == 0 {
err := os.Remove(failureOutputPath)
if os.IsNotExist(err) {
return nil
}
return err
}
if err := os.MkdirAll(path.Dir(failureOutputPath), 0644); err != nil {
return err
}

messages := make([]string, len(failures))
for i, f := range failures {
messages[i] = fmt.Sprintf("%s: %s\n", f.Hostname(), f.DescribeFailure())
}

return ioutil.WriteFile(
failureOutputPath,
[]byte(strings.Join(messages, "")),
0644)
}

0 comments on commit 4160cc4

Please sign in to comment.