diff --git a/src/components/Wizard/CreateImageWizard.js b/src/components/Wizard/CreateImageWizard.js
index 6d9776179..66a09e683 100644
--- a/src/components/Wizard/CreateImageWizard.js
+++ b/src/components/Wizard/CreateImageWizard.js
@@ -14,6 +14,7 @@ import {
vmwareDest,
ociAuth,
ociDest,
+ gcp,
ostreeSettings,
review,
} from "../../forms/steps";
@@ -33,6 +34,7 @@ import Packages from "../../forms/components/Packages";
import Review from "../../forms/components/Review";
import TextFieldCustom from "../../forms/components/TextFieldCustom";
import UploadOCIFile from "../../forms/components/UploadOCIFile";
+import UploadFile from "../../forms/components/UploadFile";
import BlueprintSelect from "../../forms/components/BlueprintSelect";
import { FormSpy, useFormApi } from "@data-driven-forms/react-form-renderer";
@@ -142,6 +144,19 @@ const CreateImageWizard = (props) => {
tenancy: formValues.image.upload.settings.tenancy,
},
};
+ } else if (formValues?.image?.type === "gce") {
+ const credentialsEncoded = window.btoa(
+ formValues.image.upload.settings.credentials
+ );
+ uploadSettings = {
+ image_name: formValues.image.upload.image_name,
+ provider: "gcp",
+ settings: {
+ region: formValues.image.upload.settings.region,
+ bucket: formValues.image.upload.settings.bucket,
+ credentials: credentialsEncoded,
+ },
+ };
}
}
@@ -208,6 +223,7 @@ const CreateImageWizard = (props) => {
awsDest(intl),
azureAuth(intl),
azureDest(intl),
+ gcp(intl),
ociAuth(intl),
ociDest(intl),
vmwareAuth(intl),
@@ -244,6 +260,7 @@ const CreateImageWizard = (props) => {
blueprintNames: blueprintNames,
},
"blueprint-listener": BlueprintListenerWrapper,
+ "upload-file": UploadFile,
}}
onCancel={handleClose}
/>
diff --git a/src/constants.js b/src/constants.js
index 6d414d96f..214215423 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -21,6 +21,7 @@ export const ImageTypeLabels = {
"edge-simplified-installer": "RHEL for Edge Simplified Installer (.iso)",
vhd: "Microsoft Azure (.vhd)",
vmdk: "VMWare VSphere (.vmdk)",
+ gce: "Google Cloud Platform (.tar.gz)",
};
export const UNIT_KIB = 1024 ** 1;
diff --git a/src/forms/steps/gcp.js b/src/forms/steps/gcp.js
new file mode 100644
index 000000000..3f0f57172
--- /dev/null
+++ b/src/forms/steps/gcp.js
@@ -0,0 +1,144 @@
+import React from "react";
+import { defineMessages, FormattedMessage } from "react-intl";
+import validatorTypes from "@data-driven-forms/react-form-renderer/validator-types";
+import { Popover, Button } from "@patternfly/react-core";
+import { HelpIcon } from "@patternfly/react-icons";
+
+const messages = defineMessages({
+ imageNamePopoverBody: {
+ defaultMessage:
+ "Provide a file name to be used for the image file that will be uploaded.",
+ },
+ imageNamePopoverAria: {
+ defaultMessage: "Image name help",
+ },
+ bucketPopoverBody: {
+ defaultMessage:
+ "Provide the name of the bucket where the image will be uploaded. This bucket must already exist.",
+ },
+ bucketPopoverAria: {
+ defaultMessage: "Bucket help",
+ },
+ regionPopoverBody: {
+ defaultMessage:
+ "Provide the region where the bucket is located. This region can be a regular Google storage region, but also a dual or multi region.",
+ },
+ regionPopoverAria: {
+ defaultMessage: "Region help",
+ },
+ credentialsPopoverBody: {
+ defaultMessage:
+ "The credentials file is a JSON file downloaded from GCP. The credentials are used to determine the GCP project to upload the image to.",
+ },
+ credentialsPopoverAria: {
+ defaultMessage: "Credentials help",
+ },
+});
+
+const gcp = (intl) => {
+ return {
+ title: ,
+ name: "gcp",
+ nextStep: "review",
+ fields: [
+ {
+ component: "text-field-custom",
+ name: "image.upload.image_name",
+ className: "pf-u-w-50",
+ type: "text",
+ label: ,
+ labelIcon: (
+
+
+
+ ),
+ isRequired: true,
+ autoFocus: true,
+ validate: [
+ {
+ type: validatorTypes.REQUIRED,
+ },
+ ],
+ },
+ {
+ component: "text-field-custom",
+ name: "image.upload.settings.region",
+ className: "pf-u-w-50",
+ type: "text",
+ label: ,
+ labelIcon: (
+
+
+
+ ),
+ isRequired: true,
+ validate: [
+ {
+ type: validatorTypes.REQUIRED,
+ },
+ ],
+ },
+ {
+ component: "text-field-custom",
+ name: "image.upload.settings.bucket",
+ className: "pf-u-w-50",
+ type: "text",
+ label: ,
+ labelIcon: (
+
+
+
+ ),
+ isRequired: true,
+ validate: [
+ {
+ type: validatorTypes.REQUIRED,
+ },
+ ],
+ },
+ {
+ component: "upload-file",
+ name: "image.upload.settings.credentials",
+ className: "pf-u-w-50",
+ type: "text",
+ label: ,
+ labelIcon: (
+
+
+
+ ),
+ isRequired: true,
+ validate: [
+ {
+ type: validatorTypes.REQUIRED,
+ },
+ ],
+ },
+ ],
+ };
+};
+
+export default gcp;
diff --git a/src/forms/steps/imageOutput.js b/src/forms/steps/imageOutput.js
index b9e3e43c5..8607ef1fb 100644
--- a/src/forms/steps/imageOutput.js
+++ b/src/forms/steps/imageOutput.js
@@ -222,6 +222,15 @@ const imageOutput = (intl) => {
is: "vhd",
},
},
+ {
+ name: "image.isUpload",
+ component: componentTypes.CHECKBOX,
+ label: ,
+ condition: {
+ when: "image.type",
+ is: "gce",
+ },
+ },
{
name: "image.isUpload",
component: componentTypes.CHECKBOX,
diff --git a/src/forms/steps/imageOutputStepMapper.js b/src/forms/steps/imageOutputStepMapper.js
index aa742415a..a8213ada9 100644
--- a/src/forms/steps/imageOutputStepMapper.js
+++ b/src/forms/steps/imageOutputStepMapper.js
@@ -9,6 +9,8 @@ export default (props) => {
return "azure-auth";
case "vmdk":
return "vmware-auth";
+ case "gce":
+ return "gcp";
default:
return "review";
}
diff --git a/src/forms/steps/index.js b/src/forms/steps/index.js
index b09997807..46a30bfa0 100644
--- a/src/forms/steps/index.js
+++ b/src/forms/steps/index.js
@@ -24,3 +24,4 @@ export { default as locale } from "./locale";
export { default as other } from "./other";
export { default as openscap } from "./openscap";
export { default as ignition } from "./ignition";
+export { default as gcp } from "./gcp";
diff --git a/test/verify/check-imageWizard b/test/verify/check-imageWizard
index 965e51b3c..e31ffa3d8 100755
--- a/test/verify/check-imageWizard
+++ b/test/verify/check-imageWizard
@@ -3,6 +3,8 @@
import time
import composerlib
import testlib
+import unittest
+import os
@testlib.nondestructive
@@ -33,6 +35,30 @@ class TestImageWizard(composerlib.ComposerCase):
# Create image
b.click("footer button:contains('Create')")
+ @unittest.skipIf(os.environ.get("TEST_OS").split('-')[0] != "rhel", "Skipping test for non RHEL")
+ def testUploadGCPFields(self):
+ b = self.browser
+
+ self.login_and_go("/composer", superuser=True)
+ b.wait_visible("#main")
+
+ # Create blueprint
+ b.click("tr[data-testid=httpd-server] button[aria-label='Create image']")
+ b.wait_in_text(".pf-c-wizard__main", "httpd-server")
+ time.sleep(1)
+ # select qcow2 image type and keep default size
+ b.select_PF4("#image-output-select-toggle", "Google Cloud Platform (.gce)")
+ b.click("input[id='image.isUpload']")
+ b.click("button:contains('Next')")
+
+ b.set_input_text("input[id='image.upload.image_name']", "testImageName")
+ b.set_input_text("input[id='image.upload.settings.region']", "testStorageName")
+ b.set_input_text("input[id='image.upload.settings.bucket']", "testBucket")
+ b.wait_in_text(".pf-c-wizard__main-body", "Credentials")
+
+ # Cancel upload
+ b.click("footer button:contains('Cancel')")
+
if __name__ == '__main__':
testlib.test_main()
diff --git a/translations/en.json b/translations/en.json
index cf1d2c6bc..bb0b7847f 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -3,6 +3,7 @@
"+YJ/Sw": "Append",
"+ubJEs": "Manufacturing server URL",
"/9I/o9": "Add partition",
+ "/Ktg9J": "GCP",
"/VnDMl": "Other",
"/f2U0m": "{blueprint} Image creation is {queue}.",
"/nwCxv": "File system configurations",
@@ -34,6 +35,7 @@
"9+Ddtu": "Next",
"96NKhh": "Add zone",
"9OVLWd": "Filesystem info",
+ "9RX5kq": "Provide a file name to be used for the image file that will be uploaded.",
"9XUYQt": "Import",
"9fE5XX": "No root partition configured.",
"9llaed": "Download logs",
@@ -58,6 +60,7 @@
"GsBRWL": "Languages",
"HAlOn1": "Name",
"HIQslE": "Image output",
+ "HLZ9CC": "Credentials",
"I3b4hn": "Version",
"IHusTg": "Firstboot URL",
"IMpl6/": "Secret access key",
@@ -78,6 +81,7 @@
"M8FAMU": "Manually configure partitions",
"MKV/jm": "Image Builder may extend this size based on requirements, selected packages, and configurations.",
"N26JOi": "{blueprint} Image creation has been added to the {queue}.",
+ "N9tOr0": "Bucket help",
"NNkgEU": "Source names cannot contain spaces.",
"NOOrvy": "Zone sources",
"ORGv1Q": "Created",
@@ -96,6 +100,7 @@
"RcxFT1": "Locale",
"Ry6SwO": "Disabled Services",
"SNzHd8": "Remove key",
+ "Sb1B69": "Storage region",
"TADV5r": "Are you sure you want to stop the image build?",
"TLiG9d": "NTP Servers",
"TP/O/b": "Remove user",
@@ -109,20 +114,24 @@
"Ucrl50": "Disabled services",
"V52jNn": "Enabled",
"VC1pOq": "Add locale",
+ "VH3Xt/": "Bucket",
"VcpIj8": "No blueprints",
"Vp6WM3": "Mount point",
"VzWTJu": "Blueprints",
"VzzYJk": "Create",
"WWUaVx": "Enter kernel name.",
"WyriYH": "Storage container",
+ "Wz9Z1Z": "Credentials help",
"XZCsHB": "Upload to VMWare",
"Xe56d/": "Bucket region",
+ "XsPqPW": "Provide the region where the bucket is located. This region can be a regular Google storage region, but also a dual or multi region.",
"XyfAvU": "Mirrorlist",
"YDMrKK": "Users",
"YIf1rr": "Image ID",
"YMk8tG": "Enter valid device node such as /dev/sda1. Only used for the simplified-installer image type.",
"YeKWbP": "Authentication",
"ZuzLh4": "Blueprints table",
+ "ZvnTwM": "Provide the name of the bucket where the image will be uploaded. This bucket must already exist.",
"aQ7PKk": "Manufacturing Server URL",
"agOXPD": "Size",
"ax75cZ": "Minimum size",
@@ -139,10 +148,12 @@
"eALudX": "Add services",
"eKEL/g": "Pending",
"f3funQ": "Installation device",
+ "f7FU1f": "Image name help",
"fE1QI4": "User OCID",
"fhwTpA": "Sources",
"gL86bv": "Group name",
"gP2Vek": "Enter values",
+ "gQL2CA": "Region help",
"guBlw5": "NTP servers",
"hpiPhh": "Enter kernel commandline arguments.",
"hzmswI": "Groups",
@@ -156,6 +167,7 @@
"kPQ+0U": "A source with this name already exists.",
"kkxJBT": "Create image",
"l8uwaa": "Configure partitions",
+ "lX0x2F": "The credentials file is a JSON file downloaded from GCP. The credentials are used to determine the GCP project to upload the image to.",
"leet9B": "Yum repository",
"m+E44N": "No packages selected",
"mA1RDm": "Edit source",
@@ -187,6 +199,7 @@
"tthToS": "Disabled",
"tzMNF3": "Status",
"uPDgth": "Hostname",
+ "uRdfZs": "Upload to GCP",
"vAPLDS": "Toggle which package list to show",
"vXCeIi": "Failed",
"vr2saa": "{blueprint} Image creation failed.",