diff --git a/src/Components/CloudProviderConfig/CloudProviderConfig.tsx b/src/Components/CloudProviderConfig/CloudProviderConfig.tsx
index 6751f4c8..183685c8 100644
--- a/src/Components/CloudProviderConfig/CloudProviderConfig.tsx
+++ b/src/Components/CloudProviderConfig/CloudProviderConfig.tsx
@@ -1,17 +1,62 @@
-import React from 'react';
+import React, { useCallback, useEffect } from 'react';
import { PageSection, Wizard, WizardStep } from '@patternfly/react-core';
import { useNavigate } from 'react-router-dom';
import { AWSConfig } from './AWSConfig';
+import { isAwsStepValid } from './validators';
+import {
+ changeAWSBucketName,
+ changeAWSCredsPath,
+ reinitializeAWSConfig,
+} from '../../store/cloudProviderConfigSlice';
+import { useGetWorkerConfigQuery } from '../../store/cockpit/cockpitApi';
+import { AWSWorkerConfig } from '../../store/cockpit/types';
+import { useAppDispatch } from '../../store/hooks';
import { resolveRelPath } from '../../Utilities/path';
import { ImageBuilderHeader } from '../sharedComponents/ImageBuilderHeader';
export const CloudProviderConfig = () => {
const navigate = useNavigate();
+ const dispatch = useAppDispatch();
const handleClose = () => navigate(resolveRelPath(''));
+ const { data, error } = useGetWorkerConfigQuery({});
+
+ const initAWSConfig = useCallback(
+ (config: AWSWorkerConfig | undefined) => {
+ if (!config) {
+ dispatch(reinitializeAWSConfig());
+ return;
+ }
+
+ const { bucket, credentials } = config;
+ if (bucket && bucket !== '') {
+ dispatch(changeAWSBucketName(bucket));
+ }
+
+ if (credentials && credentials !== '') {
+ dispatch(changeAWSCredsPath(credentials));
+ }
+ },
+ [dispatch]
+ );
+
+ useEffect(() => {
+ initAWSConfig(data?.aws);
+ }, [data, initAWSConfig]);
+
+ if (error) {
+ // TODO: improve error alert
+ return (
+
+ There was an error reading the `/etc/osbuild-worker/osbuild-worker.toml`
+ config file
+
+ );
+ }
+
return (
<>
@@ -22,6 +67,7 @@ export const CloudProviderConfig = () => {
id="aws-config"
footer={{
nextButtonText: 'Submit',
+ isNextDisabled: !isAwsStepValid(config),
isBackDisabled: true,
}}
>
diff --git a/src/Components/CloudProviderConfig/validators/index.tsx b/src/Components/CloudProviderConfig/validators/index.tsx
index cb5048ea..1503adfe 100644
--- a/src/Components/CloudProviderConfig/validators/index.tsx
+++ b/src/Components/CloudProviderConfig/validators/index.tsx
@@ -1,11 +1,37 @@
import path from 'path';
-export const isAwsBucketValid = (bucket: string): boolean => {
+import { AWSWorkerConfig } from '../../../store/cockpit/types';
+
+export const isAwsBucketValid = (bucket?: string): boolean => {
+ if (!bucket || bucket === '') {
+ return false;
+ }
+
const regex = /^[a-z0-9](?:[a-z0-9]|[-.](?=[a-z0-9])){1,61}[a-z0-9]$/;
return regex.test(bucket);
};
-export const isAwsCredsPathValid = (credsPath: string): boolean => {
+export const isAwsCredsPathValid = (credsPath?: string): boolean => {
+ if (!credsPath || credsPath === '') {
+ return false;
+ }
+
const validPathPattern = /^(\/[^/\0]*)+\/?$/;
return path.isAbsolute(credsPath) && validPathPattern.test(credsPath);
};
+
+export const isAwsStepValid = (
+ config: AWSWorkerConfig | undefined
+): boolean => {
+ if (!config) {
+ return true;
+ }
+
+ if (!config.bucket && !config.credentials) {
+ return false;
+ }
+
+ return (
+ isAwsBucketValid(config.bucket) && isAwsCredsPathValid(config.credentials)
+ );
+};
diff --git a/src/store/cloudProviderConfigSlice.ts b/src/store/cloudProviderConfigSlice.ts
index 55ab5d66..6dc03adc 100644
--- a/src/store/cloudProviderConfigSlice.ts
+++ b/src/store/cloudProviderConfigSlice.ts
@@ -8,6 +8,16 @@ export const initialState: CloudProviderConfigState = {
aws: {},
};
+export const selectAWSConfig = (state: RootState) => {
+ if (Object.keys(state.cloudConfig.aws).length === 0) {
+ // just return undefined since the config is empty
+ // and we don't want to save `[aws]` header to the
+ // worker config file with no body
+ return undefined;
+ }
+ return state.cloudConfig.aws;
+};
+
export const selectAWSBucketName = (state: RootState) => {
return state.cloudConfig.aws.bucket;
};
@@ -20,6 +30,9 @@ export const cloudProviderConfigSlice = createSlice({
name: 'cloudConfig',
initialState,
reducers: {
+ reinitializeAWSConfig: (state) => {
+ state.aws = {};
+ },
changeAWSBucketName: (state, action: PayloadAction) => {
state.aws.bucket = action.payload;
},
@@ -29,5 +42,8 @@ export const cloudProviderConfigSlice = createSlice({
},
});
-export const { changeAWSBucketName, changeAWSCredsPath } =
- cloudProviderConfigSlice.actions;
+export const {
+ reinitializeAWSConfig,
+ changeAWSBucketName,
+ changeAWSCredsPath,
+} = cloudProviderConfigSlice.actions;
diff --git a/src/store/cockpit/cockpitApi.ts b/src/store/cockpit/cockpitApi.ts
index a0c1067d..2220cd59 100644
--- a/src/store/cockpit/cockpitApi.ts
+++ b/src/store/cockpit/cockpitApi.ts
@@ -18,6 +18,7 @@ import { v4 as uuidv4 } from 'uuid';
// the same unix socket. This allows us to split out the code a little
// bit so that the `cockpitApi` doesn't become a monolith.
import { contentSourcesApi } from './contentSourcesApi';
+import type { WorkerConfigResponse } from './types';
import {
mapHostedToOnPrem,
@@ -584,6 +585,24 @@ export const cockpitApi = contentSourcesApi.injectEndpoints({
}
},
}),
+ getWorkerConfig: builder.query({
+ queryFn: async () => {
+ try {
+ const config = await cockpit
+ .file('/etc/osbuild-worker/osbuild-worker.toml')
+ .read();
+
+ return { data: TOML.parse(config) };
+ } catch (error) {
+ // no worker file error message
+ if (error.message === 'input is null') {
+ return { data: {} };
+ }
+
+ return { error };
+ }
+ },
+ }),
};
},
// since we are inheriting some endpoints,
@@ -607,4 +626,5 @@ export const {
useGetComposesQuery,
useGetBlueprintComposesQuery,
useGetComposeStatusQuery,
+ useGetWorkerConfigQuery,
} = cockpitApi;