Skip to content

Commit

Permalink
MGMT-12329: Implements assisted boot reporter and add to ignition
Browse files Browse the repository at this point in the history
Implements: openshift#4444
  • Loading branch information
Nir Magnezi committed Jan 17, 2023
1 parent cb3b1c1 commit d796cf0
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 58 deletions.
3 changes: 3 additions & 0 deletions Dockerfile.assisted-service
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ RUN cd ./cmd/operator && CGO_ENABLED=1 GOFLAGS="" GO111MODULE=on go build -o /bu
RUN cd ./cmd/webadmission && CGO_ENABLED=1 GOFLAGS="" GO111MODULE=on go build -o /build/assisted-service-admission
RUN cd ./cmd/agentbasedinstaller/client && CGO_ENABLED=1 GOFLAGS="" GO111MODULE=on go build -o /build/agent-installer-client

COPY internal/ignition/boot-reporter/assisted-boot-reporter.sh /build

# Create final image
FROM quay.io/centos/centos:stream8

Expand All @@ -58,6 +60,7 @@ 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-installer-client /usr/local/bin/agent-installer-client
COPY --from=builder /build/assisted-boot-reporter.sh /assisted-boot-reporter.sh
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
Expand Down
2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func main() {
failOnError(err, "failed to create valid bm config S3 endpoint URL from %s", Options.BMConfig.S3EndpointURL)
Options.BMConfig.S3EndpointURL = newUrl

generator := generator.New(log, objectHandler, Options.GeneratorConfig, Options.WorkDir, operatorsManager, providerRegistry, Options.ClusterTLSCertOverrideDir)
generator := generator.New(log, db, objectHandler, Options.GeneratorConfig, Options.WorkDir, operatorsManager, providerRegistry, Options.ClusterTLSCertOverrideDir)
var crdUtils bminventory.CRDUtils
if ctrlMgr != nil {
crdUtils = controllers.NewCRDUtils(ctrlMgr.GetClient(), hostApi)
Expand Down
7 changes: 4 additions & 3 deletions internal/bminventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ func (b *bareMetalInventory) InstallClusterInternal(ctx context.Context, params
}
}()

if err = b.generateClusterInstallConfig(asyncCtx, *cluster, clusterInfraenvs); err != nil {
if err = b.generateClusterInstallConfig(asyncCtx, *cluster, clusterInfraenvs, b.ServiceBaseURL); err != nil {
return
}
log.Infof("generated ignition for cluster %s", cluster.ID.String())
Expand Down Expand Up @@ -1659,7 +1659,7 @@ func (b *bareMetalInventory) setInstallConfigOverridesUsage(featureUsages string
return nil
}

func (b *bareMetalInventory) generateClusterInstallConfig(ctx context.Context, cluster common.Cluster, clusterInfraenvs []*common.InfraEnv) error {
func (b *bareMetalInventory) generateClusterInstallConfig(ctx context.Context, cluster common.Cluster, clusterInfraenvs []*common.InfraEnv, serviceBaseURL string) error {
log := logutil.FromContext(ctx, b.log)

rhRootCa := ignition.RedhatRootCA
Expand Down Expand Up @@ -1694,7 +1694,7 @@ func (b *bareMetalInventory) generateClusterInstallConfig(ctx context.Context, c
installerReleaseImageOverride = *defaultArchImage.URL
}

if err := b.generator.GenerateInstallConfig(ctx, cluster, cfg, *releaseImage.URL, installerReleaseImageOverride); err != nil {
if err := b.generator.GenerateInstallConfig(ctx, cluster, cfg, *releaseImage.URL, installerReleaseImageOverride, serviceBaseURL, b.authHandler.AuthType()); err != nil {
msg := fmt.Sprintf("failed generating install config for cluster %s", cluster.ID)
log.WithError(err).Error(msg)
return errors.Wrap(err, msg)
Expand Down Expand Up @@ -3566,6 +3566,7 @@ func (b *bareMetalInventory) getLogFileForDownload(ctx context.Context, clusterI
if err != nil {
return "", "", err
}
b.log.Debugf("log type to download: %s", logsType)
switch logsType {
case string(models.LogsTypeHost), string(models.LogsTypeNodeBoot):
if hostId == nil {
Expand Down
6 changes: 4 additions & 2 deletions internal/bminventory/inventory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ var (
imageServiceHost = "image-service.example.com:8080"
imageServiceBaseURL = fmt.Sprintf("https://%s%s", imageServiceHost, imageServicePath)
fakePullSecret = `{\"auths\":{\"cloud.openshift.com\":{\"auth\":\"dG9rZW46dGVzdAo=\",\"email\":\"coyote@acme.com\"}}}"` // #nosec
serviceBaseURL = "https://assisted.example.com:6008"
)

func toMac(macStr string) *strfmt.MAC {
Expand Down Expand Up @@ -297,7 +298,7 @@ func getDefaultClusterCreateParams() *models.ClusterCreateParams {
func mockGenerateInstallConfigSuccess(mockGenerator *generator.MockISOInstallConfigGenerator, mockVersions *versions.MockHandler) {
if mockGenerator != nil {
mockVersions.EXPECT().GetReleaseImage(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(common.TestDefaultConfig.ReleaseImage, nil).Times(1)
mockGenerator.EXPECT().GenerateInstallConfig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1)
mockGenerator.EXPECT().GenerateInstallConfig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), "https://assisted.example.com:6008", getTestAuthHandler().AuthType()).Return(nil).Times(1)
}
}

Expand Down Expand Up @@ -5235,7 +5236,7 @@ var _ = Describe("cluster", func() {
mockGetInstallConfigSuccess(mockInstallConfigBuilder)
mockVersions.EXPECT().GetReleaseImage(gomock.Any(), gomock.Any(), common.ARM64CPUArchitecture, gomock.Any()).Return(armRelease, nil).Times(1)
mockVersions.EXPECT().GetReleaseImage(gomock.Any(), gomock.Any(), common.DefaultCPUArchitecture, gomock.Any()).Return(common.TestDefaultConfig.ReleaseImage, nil).Times(1)
mockGenerator.EXPECT().GenerateInstallConfig(gomock.Any(), gomock.Any(), gomock.Any(), *armRelease.URL, *common.TestDefaultConfig.ReleaseImage.URL).Return(nil).Times(1)
mockGenerator.EXPECT().GenerateInstallConfig(gomock.Any(), gomock.Any(), gomock.Any(), *armRelease.URL, *common.TestDefaultConfig.ReleaseImage.URL, "https://assisted.example.com:6008", getTestAuthHandler().AuthType()).Return(nil).Times(1)

mockClusterPrepareForInstallationSuccess(mockClusterApi)
mockHostPrepareForRefresh(mockHostApi)
Expand Down Expand Up @@ -15122,6 +15123,7 @@ func createInventory(db *gorm.DB, cfg Config) *bareMetalInventory {
mockStaticNetworkConfig, gcConfig, mockProviderRegistry, true)

bm.ImageServiceBaseURL = imageServiceBaseURL
bm.ServiceBaseURL = serviceBaseURL
return bm
}

Expand Down
1 change: 1 addition & 0 deletions internal/bminventory/inventory_v2_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ func (b *bareMetalInventory) V2DownloadClusterLogs(ctx context.Context, params i
log := logutil.FromContext(ctx, b.log)
log.Infof("Downloading logs from cluster %s", params.ClusterID)
fileName, downloadFileName, err := b.getLogFileForDownload(ctx, &params.ClusterID, params.HostID, swag.StringValue(params.LogsType))
log.Debugf("file details: logs type=%s, filename=%s, downloadFileName=%s", fileName, downloadFileName, swag.StringValue(params.LogsType))
if err != nil {
return common.GenerateErrorResponder(err)
}
Expand Down
7 changes: 6 additions & 1 deletion internal/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,12 @@ func (m *Manager) PrepareClusterLogFile(ctx context.Context, c *common.Cluster,
if hostObject.Bootstrap {
role = string(models.HostRoleBootstrap)
}
tarredFilename = fmt.Sprintf("%s_%s_%s.tar.gz", sanitize.Name(c.Name), role, sanitize.Name(hostutil.GetHostnameForMsg(hostObject)))
name := sanitize.Name(hostutil.GetHostnameForMsg(hostObject))
if strings.Contains(file, "boot_") {
name = fmt.Sprintf("boot_%s", name)

}
tarredFilename = fmt.Sprintf("%s_%s_%s.tar.gz", sanitize.Name(c.Name), role, name)
}
} else {
tarredFilename = fmt.Sprintf("%s_%s", fileNameSplit[len(fileNameSplit)-2], fileNameSplit[len(fileNameSplit)-1])
Expand Down
104 changes: 104 additions & 0 deletions internal/ignition/boot-reporter/assisted-boot-reporter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env bash

export LOG_SEND_FREQUENCY_IN_MINUTES=5
export SERVICE_TIMEOUT_MINUTES=60

function log() {
echo "$(date '+%F %T') ${HOSTNAME} $2[$$]: level=$1 msg=\"$3\""
}

function log_info() {
log "info" "$1" "$2"
}

function log_error() {
log "error" "$1" "$2"
}

function init_variables() {
func_name=${FUNCNAME[0]}
init_failed="false"

if [ "$ASSISTED_SERVICE_URL" == "" ]; then
init_failed="true"
log_error "${func_name}" "ASSISTED_SERVICE_URL is empty."
elif [ "${ASSISTED_SERVICE_URL: -1}" == "/" ]; then
export ASSISTED_SERVICE_URL="${ASSISTED_SERVICE_URL::-1}"
fi

if [ "$CLUSTER_ID" == "" ]; then
init_failed="true"
log_error "${func_name}" "CLUSTER_ID is empty."
fi

if [ "$INFRA_ENV_ID" == "" ]; then
init_failed="true"
log_error "${func_name}" "INFRA_ENV_ID is empty."
fi

if [ "$HOST_ID" == "" ]; then
init_failed="true"
log_error "${func_name}" "HOST_ID is empty."
fi

if [ "$init_failed" == "true" ]; then
log_error "${func_name}" "Failed to initialize variables. Exiting."
exit 1
fi
}

function collect_and_upload_logs() {
func_name=${FUNCNAME[0]}

log_info "${func_name}" "Collecting logs."
logs_dir_name=boot_logs_$HOST_ID
logs_path=/tmp/$logs_dir_name

rm -rf $logs_path
mkdir -p $logs_path

journalctl > "$logs_path"/journalctl.log
log_info "${func_name}" "Copying journalctl to $logs_path/"
ip a > $logs_path/ip_a.log
log_info "${func_name}" "Capturing the output of 'ip a' to $logs_path/"
cp /etc/resolv.conf $logs_path
log_info "${func_name}" "Copying /etc/resolv.conf to $logs_path/"

pushd /tmp
log_info "${func_name}" "Compressing logs to $logs_dir_name.tar.gz"
tar -czvf "$logs_dir_name".tar.gz "$logs_dir_name"
popd

log_info "${func_name}" "Uploading logs."

curl -X POST -H "X-Secret-Key: ${PULL_SECRET_TOKEN}" \
-F upfile=@$logs_path.tar.gz \
"$ASSISTED_SERVICE_URL/api/assisted-install/v2/clusters/$CLUSTER_ID/logs?logs_type=node-boot&infra_env_id=$INFRA_ENV_ID&host_id=$HOST_ID"

if [ $? -eq 0 ]; then
log_info "${func_name}" "Successfully uploaded logs."
else
log_error "${func_name}" "Failed to upload logs."
fi
}

function main() {
func_name=${FUNCNAME[0]}
count=$((SERVICE_TIMEOUT_MINUTES/LOG_SEND_FREQUENCY_IN_MINUTES))

for i in $(seq $count)
do
log_info "${func_name}" "Upload logs attempt ${i}/${count}"
collect_and_upload_logs
if [ "$i" != "$count" ]; then # don't sleep at the last iteration.
log_info "${func_name}" "Sleeping for ${LOG_SEND_ITERATION_MINUTES} minutes until the next attempt."
sleep $((LOG_SEND_FREQUENCY_IN_MINUTES*60))
fi
done
}

log_info assisted-boot-reporter "assisted-boot-reporter start"
init_variables
main
log_info assisted-boot-reporter "assisted-boot-reporter end"
exit 0
26 changes: 16 additions & 10 deletions internal/ignition/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,35 @@ import (
"github.com/openshift/assisted-service/internal/common"
"github.com/openshift/assisted-service/internal/host/hostutil"
"github.com/openshift/assisted-service/models"
"github.com/openshift/assisted-service/pkg/auth"
"github.com/openshift/assisted-service/pkg/s3wrapper"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)

type dummyGenerator struct {
log logrus.FieldLogger
workDir string
cluster *common.Cluster
s3Client s3wrapper.API
log logrus.FieldLogger
db *gorm.DB
serviceBaseURL string
workDir string
cluster *common.Cluster
s3Client s3wrapper.API
}

// NewDummyGenerator returns a Generator that creates the expected files but with nonsense content
func NewDummyGenerator(workDir string, cluster *common.Cluster, s3Client s3wrapper.API, log logrus.FieldLogger) Generator {
func NewDummyGenerator(db *gorm.DB, serviceBaseURL string, workDir string, cluster *common.Cluster, s3Client s3wrapper.API, log logrus.FieldLogger) Generator {
return &dummyGenerator{
workDir: workDir,
log: log,
cluster: cluster,
s3Client: s3Client,
workDir: workDir,
log: log,
db: db,
serviceBaseURL: serviceBaseURL,
cluster: cluster,
s3Client: s3Client,
}
}

// Generate creates the expected ignition and related files but with nonsense content
func (g *dummyGenerator) Generate(_ context.Context, installConfig []byte, platformType models.PlatformType) error {
func (g *dummyGenerator) Generate(_ context.Context, installConfig []byte, platformType models.PlatformType, serviceBaseURL string, authType auth.AuthType) error {
toUpload := fileNames[:]
for _, host := range g.cluster.Hosts {
toUpload = append(toUpload, hostutil.IgnitionFileName(host))
Expand Down

0 comments on commit d796cf0

Please sign in to comment.