Repository: osbuild/osbuild-composer
Pull request #3597 (2023-08-03 23:17:51)

Main cloud size
This pull request includes:

- [X] adequate testing for the new functionality or fixed issue
- [X] adequate documentation informing people about the change such as
  - [ ] submit a PR for the [guides](https://github.com/osbuild/guides) repository if this PR changed any behavior described there: https://www.osbuild.org/guides/


bcl: Unit tests on this will fail until https://github.com/osbuild/images/pull/77 is merged and included in the PR.

Patch:
diff --git a/go.mod b/go.mod
index 9b9ffc09a..71b4743b5 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
 	github.com/Azure/go-autorest/autorest v0.11.29
 	github.com/Azure/go-autorest/autorest/azure/auth v0.5.12
 	github.com/BurntSushi/toml v1.3.2
-	github.com/aws/aws-sdk-go v1.44.313
+	github.com/aws/aws-sdk-go v1.44.316
 	github.com/coreos/go-semver v0.3.1
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
 	github.com/deepmap/oapi-codegen v1.8.2
@@ -31,14 +31,14 @@ require (
 	github.com/labstack/gommon v0.4.0
 	github.com/openshift-online/ocm-sdk-go v0.1.315
 	github.com/oracle/oci-go-sdk/v54 v54.0.0
-	github.com/osbuild/images v0.0.0-20230801094908-157e798fdf8d
+	github.com/osbuild/images v0.0.0-20230804084728-03212162ff49
 	github.com/prometheus/client_golang v1.16.0
 	github.com/segmentio/ksuid v1.0.4
 	github.com/sirupsen/logrus v1.9.3
 	github.com/spf13/cobra v1.7.0
 	github.com/stretchr/testify v1.8.4
 	github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453
-	github.com/vmware/govmomi v0.30.6
+	github.com/vmware/govmomi v0.30.7
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
 	golang.org/x/oauth2 v0.10.0
 	golang.org/x/sync v0.3.0
diff --git a/go.sum b/go.sum
index e0043cfdc..f239741a0 100644
--- a/go.sum
+++ b/go.sum
@@ -100,8 +100,8 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
 github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/aws/aws-sdk-go v1.44.313 h1:u6EuNQqgAmi09GEZ5g/XGHLF0XV31WcdU5rnHyIBHBc=
-github.com/aws/aws-sdk-go v1.44.313/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.316 h1:UC3alCEyzj2XU13ZFGIOHW3yjCNLGTIGVauyetl9fwE=
+github.com/aws/aws-sdk-go v1.44.316/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -580,8 +580,8 @@ github.com/openshift-online/ocm-sdk-go v0.1.315 h1:e4kDMkrWGyl90zF1dTD+GzcQlO5E8
 github.com/openshift-online/ocm-sdk-go v0.1.315/go.mod h1:KYOw8kAKAHyPrJcQoVR82CneQ4ofC02Na4cXXaTq4Nw=
 github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4=
 github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc=
-github.com/osbuild/images v0.0.0-20230801094908-157e798fdf8d h1:tRM7/UW2AK1u2mRL0anFtBZ0m+2U3h9J1FK7Y08yCsQ=
-github.com/osbuild/images v0.0.0-20230801094908-157e798fdf8d/go.mod h1:l0EGnNOVGwW4HdwZ/LwuT1yot0ITyz3cjezc01w7Rmo=
+github.com/osbuild/images v0.0.0-20230804084728-03212162ff49 h1:euwgCymcfkTkAew7NjNqvvYiODuph3F/dl24RqHiytQ=
+github.com/osbuild/images v0.0.0-20230804084728-03212162ff49/go.mod h1:KvRGkMnSQPmVxPeC4NQV0YYCvsiuGTBm76rgfMYKRIg=
 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -703,8 +703,8 @@ github.com/vbauerster/mpb/v8 v8.4.0 h1:Jq2iNA7T6SydpMVOwaT+2OBWlXS9Th8KEvBqeu5ee
 github.com/vbauerster/mpb/v8 v8.4.0/go.mod h1:vjp3hSTuCtR+x98/+2vW3eZ8XzxvGoP8CPseHMhiPyc=
 github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
 github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
-github.com/vmware/govmomi v0.30.6 h1:O3tjSwQBy0XwI5uK1/yVIfQ1LP9bAECEDUfifnyGs9U=
-github.com/vmware/govmomi v0.30.6/go.mod h1:epgoslm97rLECMV4D+08ORzUBEU7boFSepKjt7AYVGg=
+github.com/vmware/govmomi v0.30.7 h1:YO8CcDpLJzmq6PK5/CBQbXyV21iCMh8SbdXt+xNkXp8=
+github.com/vmware/govmomi v0.30.7/go.mod h1:epgoslm97rLECMV4D+08ORzUBEU7boFSepKjt7AYVGg=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
diff --git a/internal/cloudapi/v2/compose.go b/internal/cloudapi/v2/compose.go
new file mode 100644
index 000000000..98ac94624
--- /dev/null
+++ b/internal/cloudapi/v2/compose.go
@@ -0,0 +1,318 @@
+package v2
+
+// ComposeRequest methods to make it easier to use and test
+import (
+	"fmt"
+
+	"github.com/osbuild/images/pkg/subscription"
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+)
+
+// GetBlueprintWithCustomizations returns a new Blueprint with all of the
+// customizations set from the ComposeRequest
+func (request *ComposeRequest) GetBlueprintWithCustomizations() (blueprint.Blueprint, error) {
+	var bp = blueprint.Blueprint{Name: "empty blueprint"}
+	err := bp.Initialize()
+	if err != nil {
+		return bp, HTTPErrorWithInternal(ErrorFailedToInitializeBlueprint, err)
+	}
+
+	if request.Customizations == nil {
+		return bp, nil
+	}
+
+	// Set the blueprint customisation to take care of the user
+	if request.Customizations.Users != nil {
+		var userCustomizations []blueprint.UserCustomization
+		for _, user := range *request.Customizations.Users {
+			var groups []string
+			if user.Groups != nil {
+				groups = *user.Groups
+			} else {
+				groups = nil
+			}
+			userCustomizations = append(userCustomizations,
+				blueprint.UserCustomization{
+					Name:   user.Name,
+					Key:    user.Key,
+					Groups: groups,
+				},
+			)
+		}
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				User: userCustomizations,
+			}
+		} else {
+			bp.Customizations.User = userCustomizations
+		}
+	}
+
+	if request.Customizations.Packages != nil {
+		for _, p := range *request.Customizations.Packages {
+			bp.Packages = append(bp.Packages, blueprint.Package{
+				Name: p,
+			})
+		}
+	}
+
+	if request.Customizations.Containers != nil {
+		for _, c := range *request.Customizations.Containers {
+			bc := blueprint.Container{
+				Source:    c.Source,
+				TLSVerify: c.TlsVerify,
+			}
+			if c.Name != nil {
+				bc.Name = *c.Name
+			}
+			bp.Containers = append(bp.Containers, bc)
+		}
+	}
+
+	if request.Customizations.Directories != nil {
+		var dirCustomizations []blueprint.DirectoryCustomization
+		for _, d := range *request.Customizations.Directories {
+			dirCustomization := blueprint.DirectoryCustomization{
+				Path: d.Path,
+			}
+			if d.Mode != nil {
+				dirCustomization.Mode = *d.Mode
+			}
+			if d.User != nil {
+				dirCustomization.User = *d.User
+				if uid, ok := dirCustomization.User.(float64); ok {
+					// check if uid can be converted to int64
+					if uid != float64(int64(uid)) {
+						return bp, fmt.Errorf("invalid user %f: must be an integer", uid)
+					}
+					dirCustomization.User = int64(uid)
+				}
+			}
+			if d.Group != nil {
+				dirCustomization.Group = *d.Group
+				if gid, ok := dirCustomization.Group.(float64); ok {
+					// check if gid can be converted to int64
+					if gid != float64(int64(gid)) {
+						return bp, fmt.Errorf("invalid group %f: must be an integer", gid)
+					}
+					dirCustomization.Group = int64(gid)
+				}
+			}
+			if d.EnsureParents != nil {
+				dirCustomization.EnsureParents = *d.EnsureParents
+			}
+			dirCustomizations = append(dirCustomizations, dirCustomization)
+		}
+
+		// Validate the directory customizations, because the Cloud API does not use the custom unmarshaller
+		_, err := blueprint.DirectoryCustomizationsToFsNodeDirectories(dirCustomizations)
+		if err != nil {
+			return bp, HTTPErrorWithInternal(ErrorInvalidCustomization, err)
+		}
+
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				Directories: dirCustomizations,
+			}
+		} else {
+			bp.Customizations.Directories = dirCustomizations
+		}
+	}
+
+	if request.Customizations.Files != nil {
+		var fileCustomizations []blueprint.FileCustomization
+		for _, f := range *request.Customizations.Files {
+			fileCustomization := blueprint.FileCustomization{
+				Path: f.Path,
+			}
+			if f.Data != nil {
+				fileCustomization.Data = *f.Data
+			}
+			if f.Mode != nil {
+				fileCustomization.Mode = *f.Mode
+			}
+			if f.User != nil {
+				fileCustomization.User = *f.User
+				if uid, ok := fileCustomization.User.(float64); ok {
+					// check if uid can be converted to int64
+					if uid != float64(int64(uid)) {
+						return bp, fmt.Errorf("invalid user %f: must be an integer", uid)
+					}
+					fileCustomization.User = int64(uid)
+				}
+			}
+			if f.Group != nil {
+				fileCustomization.Group = *f.Group
+				if gid, ok := fileCustomization.Group.(float64); ok {
+					// check if gid can be converted to int64
+					if gid != float64(int64(gid)) {
+						return bp, fmt.Errorf("invalid group %f: must be an integer", gid)
+					}
+					fileCustomization.Group = int64(gid)
+				}
+			}
+			fileCustomizations = append(fileCustomizations, fileCustomization)
+		}
+
+		// Validate the file customizations, because the Cloud API does not use the custom unmarshaller
+		_, err := blueprint.FileCustomizationsToFsNodeFiles(fileCustomizations)
+		if err != nil {
+			return bp, HTTPErrorWithInternal(ErrorInvalidCustomization, err)
+		}
+
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				Files: fileCustomizations,
+			}
+		} else {
+			bp.Customizations.Files = fileCustomizations
+		}
+	}
+
+	if request.Customizations.Filesystem != nil {
+		var fsCustomizations []blueprint.FilesystemCustomization
+		for _, f := range *request.Customizations.Filesystem {
+
+			fsCustomizations = append(fsCustomizations,
+				blueprint.FilesystemCustomization{
+					Mountpoint: f.Mountpoint,
+					MinSize:    f.MinSize,
+				},
+			)
+		}
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				Filesystem: fsCustomizations,
+			}
+		} else {
+			bp.Customizations.Filesystem = fsCustomizations
+		}
+	}
+
+	if request.Customizations.Services != nil {
+		servicesCustomization := &blueprint.ServicesCustomization{}
+		if request.Customizations.Services.Enabled != nil {
+			servicesCustomization.Enabled = make([]string, len(*request.Customizations.Services.Enabled))
+			copy(servicesCustomization.Enabled, *request.Customizations.Services.Enabled)
+		}
+		if request.Customizations.Services.Disabled != nil {
+			servicesCustomization.Disabled = make([]string, len(*request.Customizations.Services.Disabled))
+			copy(servicesCustomization.Disabled, *request.Customizations.Services.Disabled)
+		}
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				Services: servicesCustomization,
+			}
+		} else {
+			bp.Customizations.Services = servicesCustomization
+		}
+	}
+
+	if request.Customizations.Openscap != nil {
+		openSCAPCustomization := &blueprint.OpenSCAPCustomization{
+			ProfileID: request.Customizations.Openscap.ProfileId,
+		}
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				OpenSCAP: openSCAPCustomization,
+			}
+		} else {
+			bp.Customizations.OpenSCAP = openSCAPCustomization
+		}
+	}
+
+	if request.Customizations.CustomRepositories != nil {
+		repoCustomizations := []blueprint.RepositoryCustomization{}
+		for _, repo := range *request.Customizations.CustomRepositories {
+			repoCustomization := blueprint.RepositoryCustomization{
+				Id: repo.Id,
+			}
+
+			if repo.Name != nil {
+				repoCustomization.Name = *repo.Name
+			}
+
+			if repo.Filename != nil {
+				repoCustomization.Filename = *repo.Filename
+			}
+
+			if repo.Baseurl != nil && len(*repo.Baseurl) > 0 {
+				repoCustomization.BaseURLs = *repo.Baseurl
+			}
+
+			if repo.Gpgkey != nil && len(*repo.Gpgkey) > 0 {
+				repoCustomization.GPGKeys = *repo.Gpgkey
+			}
+
+			if repo.CheckGpg != nil {
+				repoCustomization.GPGCheck = repo.CheckGpg
+			}
+
+			if repo.CheckRepoGpg != nil {
+				repoCustomization.RepoGPGCheck = repo.CheckRepoGpg
+			}
+
+			if repo.Enabled != nil {
+				repoCustomization.Enabled = repo.Enabled
+			}
+
+			if repo.Metalink != nil {
+				repoCustomization.Metalink = *repo.Metalink
+			}
+
+			if repo.Mirrorlist != nil {
+				repoCustomization.Mirrorlist = *repo.Mirrorlist
+			}
+
+			if repo.SslVerify != nil {
+				repoCustomization.SSLVerify = repo.SslVerify
+			}
+
+			if repo.Priority != nil {
+				repoCustomization.Priority = repo.Priority
+			}
+
+			repoCustomizations = append(repoCustomizations, repoCustomization)
+		}
+		if bp.Customizations == nil {
+			bp.Customizations = &blueprint.Customizations{
+				Repositories: repoCustomizations,
+			}
+		} else {
+			bp.Customizations.Repositories = repoCustomizations
+		}
+	}
+	return bp, nil
+}
+
+// GetPayloadRepositories returns the custom repos
+// If there are none it returns a nil slice
+func (request *ComposeRequest) GetPayloadRepositories() (repos []Repository) {
+	if request.Customizations != nil && request.Customizations.PayloadRepositories != nil {
+		repos = *request.Customizations.PayloadRepositories
+	}
+
+	return
+}
+
+// GetSubscription returns an ImageOptions struct populated by the subscription information
+// included in the request, or nil if it has not been included.
+func (request *ComposeRequest) GetSubscription() (sub *subscription.ImageOptions) {
+	if request.Customizations != nil && request.Customizations.Subscription != nil {
+		// Rhc is optional, default to false if not included
+		var rhc bool
+		if request.Customizations.Subscription.Rhc != nil {
+			rhc = *request.Customizations.Subscription.Rhc
+		}
+		sub = &subscription.ImageOptions{
+			Organization:  request.Customizations.Subscription.Organization,
+			ActivationKey: request.Customizations.Subscription.ActivationKey,
+			ServerUrl:     request.Customizations.Subscription.ServerUrl,
+			BaseUrl:       request.Customizations.Subscription.BaseUrl,
+			Insights:      request.Customizations.Subscription.Insights,
+			Rhc:           rhc,
+		}
+	}
+
+	return
+}
diff --git a/internal/cloudapi/v2/handler.go b/internal/cloudapi/v2/handler.go
index a6e7632b0..9fa40267f 100644
--- a/internal/cloudapi/v2/handler.go
+++ b/internal/cloudapi/v2/handler.go
@@ -11,18 +11,14 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/aws/aws-sdk-go/service/ec2"
 	"github.com/google/uuid"
 	"github.com/labstack/echo/v4"
 
 	"github.com/osbuild/images/pkg/distro"
 	"github.com/osbuild/images/pkg/manifest"
 	"github.com/osbuild/images/pkg/osbuild"
-	"github.com/osbuild/images/pkg/ostree"
 	"github.com/osbuild/images/pkg/rhsm/facts"
 	"github.com/osbuild/images/pkg/rpmmd"
-	"github.com/osbuild/images/pkg/subscription"
-	"github.com/osbuild/osbuild-composer/internal/blueprint"
 	"github.com/osbuild/osbuild-composer/internal/common"
 	"github.com/osbuild/osbuild-composer/internal/target"
 	"github.com/osbuild/osbuild-composer/internal/worker"
@@ -136,280 +132,15 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 		return HTTPError(ErrorUnsupportedDistribution)
 	}
 
-	var bp = blueprint.Blueprint{Name: "empty blueprint"}
-	err = bp.Initialize()
+	// Create a blueprint from the customizations included in the request
+	bp, err := request.GetBlueprintWithCustomizations()
 	if err != nil {
-		return HTTPErrorWithInternal(ErrorFailedToInitializeBlueprint, err)
-	}
-
-	// Set the blueprint customisation to take care of the user
-	if request.Customizations != nil && request.Customizations.Users != nil {
-		var userCustomizations []blueprint.UserCustomization
-		for _, user := range *request.Customizations.Users {
-			var groups []string
-			if user.Groups != nil {
-				groups = *user.Groups
-			} else {
-				groups = nil
-			}
-			userCustomizations = append(userCustomizations,
-				blueprint.UserCustomization{
-					Name:   user.Name,
-					Key:    user.Key,
-					Groups: groups,
-				},
-			)
-		}
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				User: userCustomizations,
-			}
-		} else {
-			bp.Customizations.User = userCustomizations
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Packages != nil {
-		for _, p := range *request.Customizations.Packages {
-			bp.Packages = append(bp.Packages, blueprint.Package{
-				Name: p,
-			})
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Containers != nil {
-		for _, c := range *request.Customizations.Containers {
-			bc := blueprint.Container{
-				Source:    c.Source,
-				TLSVerify: c.TlsVerify,
-			}
-			if c.Name != nil {
-				bc.Name = *c.Name
-			}
-			bp.Containers = append(bp.Containers, bc)
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Directories != nil {
-		var dirCustomizations []blueprint.DirectoryCustomization
-		for _, d := range *request.Customizations.Directories {
-			dirCustomization := blueprint.DirectoryCustomization{
-				Path: d.Path,
-			}
-			if d.Mode != nil {
-				dirCustomization.Mode = *d.Mode
-			}
-			if d.User != nil {
-				dirCustomization.User = *d.User
-				if uid, ok := dirCustomization.User.(float64); ok {
-					// check if uid can be converted to int64
-					if uid != float64(int64(uid)) {
-						return fmt.Errorf("invalid user %f: must be an integer", uid)
-					}
-					dirCustomization.User = int64(uid)
-				}
-			}
-			if d.Group != nil {
-				dirCustomization.Group = *d.Group
-				if gid, ok := dirCustomization.Group.(float64); ok {
-					// check if gid can be converted to int64
-					if gid != float64(int64(gid)) {
-						return fmt.Errorf("invalid group %f: must be an integer", gid)
-					}
-					dirCustomization.Group = int64(gid)
-				}
-			}
-			if d.EnsureParents != nil {
-				dirCustomization.EnsureParents = *d.EnsureParents
-			}
-			dirCustomizations = append(dirCustomizations, dirCustomization)
-		}
-
-		// Validate the directory customizations, because the Cloud API does not use the custom unmarshaller
-		_, err := blueprint.DirectoryCustomizationsToFsNodeDirectories(dirCustomizations)
-		if err != nil {
-			return HTTPErrorWithInternal(ErrorInvalidCustomization, err)
-		}
-
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				Directories: dirCustomizations,
-			}
-		} else {
-			bp.Customizations.Directories = dirCustomizations
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Files != nil {
-		var fileCustomizations []blueprint.FileCustomization
-		for _, f := range *request.Customizations.Files {
-			fileCustomization := blueprint.FileCustomization{
-				Path: f.Path,
-			}
-			if f.Data != nil {
-				fileCustomization.Data = *f.Data
-			}
-			if f.Mode != nil {
-				fileCustomization.Mode = *f.Mode
-			}
-			if f.User != nil {
-				fileCustomization.User = *f.User
-				if uid, ok := fileCustomization.User.(float64); ok {
-					// check if uid can be converted to int64
-					if uid != float64(int64(uid)) {
-						return fmt.Errorf("invalid user %f: must be an integer", uid)
-					}
-					fileCustomization.User = int64(uid)
-				}
-			}
-			if f.Group != nil {
-				fileCustomization.Group = *f.Group
-				if gid, ok := fileCustomization.Group.(float64); ok {
-					// check if gid can be converted to int64
-					if gid != float64(int64(gid)) {
-						return fmt.Errorf("invalid group %f: must be an integer", gid)
-					}
-					fileCustomization.Group = int64(gid)
-				}
-			}
-			fileCustomizations = append(fileCustomizations, fileCustomization)
-		}
-
-		// Validate the file customizations, because the Cloud API does not use the custom unmarshaller
-		_, err := blueprint.FileCustomizationsToFsNodeFiles(fileCustomizations)
-		if err != nil {
-			return HTTPErrorWithInternal(ErrorInvalidCustomization, err)
-		}
-
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				Files: fileCustomizations,
-			}
-		} else {
-			bp.Customizations.Files = fileCustomizations
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Filesystem != nil {
-		var fsCustomizations []blueprint.FilesystemCustomization
-		for _, f := range *request.Customizations.Filesystem {
-
-			fsCustomizations = append(fsCustomizations,
-				blueprint.FilesystemCustomization{
-					Mountpoint: f.Mountpoint,
-					MinSize:    f.MinSize,
-				},
-			)
-		}
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				Filesystem: fsCustomizations,
-			}
-		} else {
-			bp.Customizations.Filesystem = fsCustomizations
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Services != nil {
-		servicesCustomization := &blueprint.ServicesCustomization{}
-		if request.Customizations.Services.Enabled != nil {
-			servicesCustomization.Enabled = make([]string, len(*request.Customizations.Services.Enabled))
-			copy(servicesCustomization.Enabled, *request.Customizations.Services.Enabled)
-		}
-		if request.Customizations.Services.Disabled != nil {
-			servicesCustomization.Disabled = make([]string, len(*request.Customizations.Services.Disabled))
-			copy(servicesCustomization.Disabled, *request.Customizations.Services.Disabled)
-		}
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				Services: servicesCustomization,
-			}
-		} else {
-			bp.Customizations.Services = servicesCustomization
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.Openscap != nil {
-		openSCAPCustomization := &blueprint.OpenSCAPCustomization{
-			ProfileID: request.Customizations.Openscap.ProfileId,
-		}
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				OpenSCAP: openSCAPCustomization,
-			}
-		} else {
-			bp.Customizations.OpenSCAP = openSCAPCustomization
-		}
-	}
-
-	if request.Customizations != nil && request.Customizations.CustomRepositories != nil {
-		repoCustomizations := []blueprint.RepositoryCustomization{}
-		for _, repo := range *request.Customizations.CustomRepositories {
-			repoCustomization := blueprint.RepositoryCustomization{
-				Id: repo.Id,
-			}
-
-			if repo.Name != nil {
-				repoCustomization.Name = *repo.Name
-			}
-
-			if repo.Filename != nil {
-				repoCustomization.Filename = *repo.Filename
-			}
-
-			if repo.Baseurl != nil && len(*repo.Baseurl) > 0 {
-				repoCustomization.BaseURLs = *repo.Baseurl
-			}
-
-			if repo.Gpgkey != nil && len(*repo.Gpgkey) > 0 {
-				repoCustomization.GPGKeys = *repo.Gpgkey
-			}
-
-			if repo.CheckGpg != nil {
-				repoCustomization.GPGCheck = repo.CheckGpg
-			}
-
-			if repo.CheckRepoGpg != nil {
-				repoCustomization.RepoGPGCheck = repo.CheckRepoGpg
-			}
-
-			if repo.Enabled != nil {
-				repoCustomization.Enabled = repo.Enabled
-			}
-
-			if repo.Metalink != nil {
-				repoCustomization.Metalink = *repo.Metalink
-			}
-
-			if repo.Mirrorlist != nil {
-				repoCustomization.Mirrorlist = *repo.Mirrorlist
-			}
-
-			if repo.SslVerify != nil {
-				repoCustomization.SSLVerify = repo.SslVerify
-			}
-
-			if repo.Priority != nil {
-				repoCustomization.Priority = repo.Priority
-			}
-
-			repoCustomizations = append(repoCustomizations, repoCustomization)
-		}
-		if bp.Customizations == nil {
-			bp.Customizations = &blueprint.Customizations{
-				Repositories: repoCustomizations,
-			}
-		} else {
-			bp.Customizations.Repositories = repoCustomizations
-		}
+		return err
 	}
 
 	// add the user-defined repositories only to the depsolve job for the
 	// payload (the packages for the final image)
-	var payloadRepositories []Repository
-	if request.Customizations != nil && request.Customizations.PayloadRepositories != nil {
-		payloadRepositories = *request.Customizations.PayloadRepositories
-	}
+	payloadRepositories := request.GetPayloadRepositories()
 
 	// use the same seed for all images so we get the same IDs
 	bigSeed, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
@@ -447,7 +178,8 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 			return err
 		}
 
-		imageOptions := distro.ImageOptions{Size: imageType.Size(0)}
+		// Get the initial ImageOptions with image size set
+		imageOptions := ir.GetImageOptions(imageType, bp)
 
 		if request.Koji == nil {
 			imageOptions.Facts = &facts.ImageOptions{
@@ -455,46 +187,13 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 			}
 		}
 
-		if request.Customizations != nil && request.Customizations.Subscription != nil {
-			// Rhc is optional, default to false if not included
-			var rhc bool
-			if request.Customizations.Subscription.Rhc != nil {
-				rhc = *request.Customizations.Subscription.Rhc
-			}
-			imageOptions.Subscription = &subscription.ImageOptions{
-				Organization:  request.Customizations.Subscription.Organization,
-				ActivationKey: request.Customizations.Subscription.ActivationKey,
-				ServerUrl:     request.Customizations.Subscription.ServerUrl,
-				BaseUrl:       request.Customizations.Subscription.BaseUrl,
-				Insights:      request.Customizations.Subscription.Insights,
-				Rhc:           rhc,
-			}
-		}
+		// Set Subscription from the compose request
+		imageOptions.Subscription = request.GetSubscription()
 
-		// Add ostree options to image options if they were included in the
-		// request
-		if ir.Ostree != nil {
-			ostreeOptions := &ostree.ImageOptions{}
-			if ir.Ostree.Ref != nil {
-				ostreeOptions.ImageRef = *ir.Ostree.Ref
-			}
-			if ir.Ostree.Url != nil {
-				ostreeOptions.URL = *ir.Ostree.Url
-			}
-			if ir.Ostree.Contenturl != nil {
-				// URL must be set if content url is specified
-				if ir.Ostree.Url == nil {
-					return HTTPError(ErrorInvalidOSTreeParams)
-				}
-				ostreeOptions.ContentURL = *ir.Ostree.Contenturl
-			}
-			if ir.Ostree.Parent != nil {
-				ostreeOptions.ParentRef = *ir.Ostree.Parent
-			}
-			if ir.Ostree.Rhsm != nil {
-				ostreeOptions.RHSM = *ir.Ostree.Rhsm
-			}
-			imageOptions.OSTree = ostreeOptions
+		// Set OSTree options from the image request
+		imageOptions.OSTree, err = ir.GetOSTreeOptions()
+		if err != nil {
+			return err
 		}
 
 		var irTarget *target.Target
@@ -504,207 +203,11 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 				return HTTPError(ErrorJSONUnMarshallingError)
 			}
 		} else {
-			/* oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type */
-			switch ir.ImageType {
-			case ImageTypesAws:
-				fallthrough
-			case ImageTypesAwsRhui:
-				fallthrough
-			case ImageTypesAwsHaRhui:
-				fallthrough
-			case ImageTypesAwsSapRhui:
-				var awsUploadOptions AWSEC2UploadOptions
-				jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONMarshallingError)
-				}
-				err = json.Unmarshal(jsonUploadOptions, &awsUploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONUnMarshallingError)
-				}
-
-				// For service maintenance, images are discovered by the "Name:composer-api-*"
-				// tag filter. Currently all image names in the service are generated, so they're
-				// guaranteed to be unique as well. If users are ever allowed to name their images,
-				// an extra tag should be added.
-				key := fmt.Sprintf("composer-api-%s", uuid.New().String())
-
-				var amiBootMode *string
-				switch imageType.BootMode() {
-				case distro.BOOT_HYBRID:
-					amiBootMode = common.ToPtr(ec2.BootModeValuesUefiPreferred)
-				case distro.BOOT_UEFI:
-					amiBootMode = common.ToPtr(ec2.BootModeValuesUefi)
-				case distro.BOOT_LEGACY:
-					amiBootMode = common.ToPtr(ec2.BootModeValuesLegacyBios)
-				}
-
-				t := target.NewAWSTarget(&target.AWSTargetOptions{
-					Region:            awsUploadOptions.Region,
-					Key:               key,
-					ShareWithAccounts: awsUploadOptions.ShareWithAccounts,
-					BootMode:          amiBootMode,
-				})
-				if awsUploadOptions.SnapshotName != nil {
-					t.ImageName = *awsUploadOptions.SnapshotName
-				} else {
-					t.ImageName = key
-				}
-				t.OsbuildArtifact.ExportFilename = imageType.Filename()
-
-				irTarget = t
-			case ImageTypesGuestImage:
-				fallthrough
-			case ImageTypesVsphere:
-				fallthrough
-			case ImageTypesVsphereOva:
-				fallthrough
-			case ImageTypesImageInstaller:
-				fallthrough
-			case ImageTypesEdgeInstaller:
-				fallthrough
-			case ImageTypesIotInstaller:
-				fallthrough
-			case ImageTypesLiveInstaller:
-				fallthrough
-			case ImageTypesEdgeCommit:
-				fallthrough
-			case ImageTypesIotCommit:
-				fallthrough
-			case ImageTypesIotRawImage:
-				var awsS3UploadOptions AWSS3UploadOptions
-				jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONMarshallingError)
-				}
-				err = json.Unmarshal(jsonUploadOptions, &awsS3UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONUnMarshallingError)
-				}
-
-				public := false
-				if awsS3UploadOptions.Public != nil && *awsS3UploadOptions.Public {
-					public = true
-				}
-
-				key := fmt.Sprintf("composer-api-%s", uuid.New().String())
-				t := target.NewAWSS3Target(&target.AWSS3TargetOptions{
-					Region: awsS3UploadOptions.Region,
-					Key:    key,
-					Public: public,
-				})
-				t.ImageName = key
-				t.OsbuildArtifact.ExportFilename = imageType.Filename()
-
-				irTarget = t
-			case ImageTypesEdgeContainer:
-				fallthrough
-			case ImageTypesIotContainer:
-				var containerUploadOptions ContainerUploadOptions
-				jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONMarshallingError)
-				}
-				err = json.Unmarshal(jsonUploadOptions, &containerUploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONUnMarshallingError)
-				}
-
-				var name = request.Distribution
-				var tag = uuid.New().String()
-				if containerUploadOptions.Name != nil {
-					name = *containerUploadOptions.Name
-					if containerUploadOptions.Tag != nil {
-						tag = *containerUploadOptions.Tag
-					}
-				}
-
-				t := target.NewContainerTarget(&target.ContainerTargetOptions{})
-				t.ImageName = fmt.Sprintf("%s:%s", name, tag)
-				t.OsbuildArtifact.ExportFilename = imageType.Filename()
-
-				irTarget = t
-			case ImageTypesGcp:
-				fallthrough
-			case ImageTypesGcpRhui:
-				var gcpUploadOptions GCPUploadOptions
-				jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONMarshallingError)
-				}
-				err = json.Unmarshal(jsonUploadOptions, &gcpUploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONUnMarshallingError)
-				}
-
-				var share []string
-				if gcpUploadOptions.ShareWithAccounts != nil {
-					share = *gcpUploadOptions.ShareWithAccounts
-				}
-
-				imageName := fmt.Sprintf("composer-api-%s", uuid.New().String())
-				var bucket string
-				if gcpUploadOptions.Bucket != nil {
-					bucket = *gcpUploadOptions.Bucket
-				}
-				t := target.NewGCPTarget(&target.GCPTargetOptions{
-					Region: gcpUploadOptions.Region,
-					Os:     imageType.Arch().Distro().Name(), // not exposed in cloudapi
-					Bucket: bucket,
-					// the uploaded object must have a valid extension
-					Object:            fmt.Sprintf("%s.tar.gz", imageName),
-					ShareWithAccounts: share,
-				})
-				// Import will fail if an image with this name already exists
-				if gcpUploadOptions.ImageName != nil {
-					t.ImageName = *gcpUploadOptions.ImageName
-				} else {
-					t.ImageName = imageName
-				}
-				t.OsbuildArtifact.ExportFilename = imageType.Filename()
-
-				irTarget = t
-			case ImageTypesAzure:
-				fallthrough
-			case ImageTypesAzureRhui:
-				fallthrough
-			case ImageTypesAzureEap7Rhui:
-				fallthrough
-			case ImageTypesAzureSapRhui:
-				var azureUploadOptions AzureUploadOptions
-				jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONMarshallingError)
-				}
-				err = json.Unmarshal(jsonUploadOptions, &azureUploadOptions)
-				if err != nil {
-					return HTTPError(ErrorJSONUnMarshallingError)
-				}
-				rgLocation := ""
-				if azureUploadOptions.Location != nil {
-					rgLocation = *azureUploadOptions.Location
-				}
-				t := target.NewAzureImageTarget(&target.AzureImageTargetOptions{
-					TenantID:       azureUploadOptions.TenantId,
-					Location:       rgLocation,
-					SubscriptionID: azureUploadOptions.SubscriptionId,
-					ResourceGroup:  azureUploadOptions.ResourceGroup,
-				})
-
-				if azureUploadOptions.ImageName != nil {
-					t.ImageName = *azureUploadOptions.ImageName
-				} else {
-					// if ImageName wasn't given, generate a random one
-					t.ImageName = fmt.Sprintf("composer-api-%s", uuid.New().String())
-				}
-				t.OsbuildArtifact.ExportFilename = imageType.Filename()
-
-				irTarget = t
-			default:
-				return HTTPError(ErrorUnsupportedImageType)
+			// Get the target for the selected image type
+			irTarget, err = ir.GetTarget(&request, imageType)
+			if err != nil {
+				return err
 			}
-
-			irTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
 		}
 
 		irs = append(irs, imageRequest{
diff --git a/internal/cloudapi/v2/imagerequest.go b/internal/cloudapi/v2/imagerequest.go
new file mode 100644
index 000000000..f2cd411ed
--- /dev/null
+++ b/internal/cloudapi/v2/imagerequest.go
@@ -0,0 +1,272 @@
+package v2
+
+// ImageTypes methods to make it easier to use and test
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/aws/aws-sdk-go/service/ec2"
+	"github.com/google/uuid"
+	"github.com/osbuild/images/pkg/distro"
+	"github.com/osbuild/images/pkg/ostree"
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/common"
+	"github.com/osbuild/osbuild-composer/internal/target"
+)
+
+// GetImageOptions returns the initial ImageOptions with Size set
+// The size is set to the largest of:
+//   - Default size for the image type
+//   - Blueprint filesystem customizations
+//   - Requested size
+func (ir *ImageRequest) GetImageOptions(imageType distro.ImageType, bp blueprint.Blueprint) distro.ImageOptions {
+	// NOTE: The size is in bytes
+	var size uint64
+	minSize := bp.Customizations.GetFilesystemsMinSize()
+	if ir.Size == nil {
+		size = imageType.Size(minSize)
+	} else if bp.Customizations != nil && minSize > 0 && minSize > *ir.Size {
+		size = imageType.Size(minSize)
+	} else {
+		size = imageType.Size(*ir.Size)
+	}
+	return distro.ImageOptions{Size: size}
+}
+
+// GetImageTarget returns the target for the selected image type
+func (ir *ImageRequest) GetTarget(request *ComposeRequest, imageType distro.ImageType) (irTarget *target.Target, err error) {
+	/* oneOf is not supported by the openapi generator so marshal and unmarshal the uploadrequest based on the type */
+	switch ir.ImageType {
+	case ImageTypesAws:
+		fallthrough
+	case ImageTypesAwsRhui:
+		fallthrough
+	case ImageTypesAwsHaRhui:
+		fallthrough
+	case ImageTypesAwsSapRhui:
+		var awsUploadOptions AWSEC2UploadOptions
+		jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONMarshallingError)
+		}
+		err = json.Unmarshal(jsonUploadOptions, &awsUploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONUnMarshallingError)
+		}
+
+		// For service maintenance, images are discovered by the "Name:composer-api-*"
+		// tag filter. Currently all image names in the service are generated, so they're
+		// guaranteed to be unique as well. If users are ever allowed to name their images,
+		// an extra tag should be added.
+		key := fmt.Sprintf("composer-api-%s", uuid.New().String())
+
+		var amiBootMode *string
+		switch imageType.BootMode() {
+		case distro.BOOT_HYBRID:
+			amiBootMode = common.ToPtr(ec2.BootModeValuesUefiPreferred)
+		case distro.BOOT_UEFI:
+			amiBootMode = common.ToPtr(ec2.BootModeValuesUefi)
+		case distro.BOOT_LEGACY:
+			amiBootMode = common.ToPtr(ec2.BootModeValuesLegacyBios)
+		}
+
+		t := target.NewAWSTarget(&target.AWSTargetOptions{
+			Region:            awsUploadOptions.Region,
+			Key:               key,
+			ShareWithAccounts: awsUploadOptions.ShareWithAccounts,
+			BootMode:          amiBootMode,
+		})
+		if awsUploadOptions.SnapshotName != nil {
+			t.ImageName = *awsUploadOptions.SnapshotName
+		} else {
+			t.ImageName = key
+		}
+		t.OsbuildArtifact.ExportFilename = imageType.Filename()
+
+		irTarget = t
+	case ImageTypesGuestImage:
+		fallthrough
+	case ImageTypesVsphere:
+		fallthrough
+	case ImageTypesVsphereOva:
+		fallthrough
+	case ImageTypesImageInstaller:
+		fallthrough
+	case ImageTypesEdgeInstaller:
+		fallthrough
+	case ImageTypesIotInstaller:
+		fallthrough
+	case ImageTypesLiveInstaller:
+		fallthrough
+	case ImageTypesEdgeCommit:
+		fallthrough
+	case ImageTypesIotCommit:
+		fallthrough
+	case ImageTypesIotRawImage:
+		var awsS3UploadOptions AWSS3UploadOptions
+		jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONMarshallingError)
+		}
+		err = json.Unmarshal(jsonUploadOptions, &awsS3UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONUnMarshallingError)
+		}
+
+		public := false
+		if awsS3UploadOptions.Public != nil && *awsS3UploadOptions.Public {
+			public = true
+		}
+
+		key := fmt.Sprintf("composer-api-%s", uuid.New().String())
+		t := target.NewAWSS3Target(&target.AWSS3TargetOptions{
+			Region: awsS3UploadOptions.Region,
+			Key:    key,
+			Public: public,
+		})
+		t.ImageName = key
+		t.OsbuildArtifact.ExportFilename = imageType.Filename()
+
+		irTarget = t
+	case ImageTypesEdgeContainer:
+		fallthrough
+	case ImageTypesIotContainer:
+		var containerUploadOptions ContainerUploadOptions
+		jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONMarshallingError)
+		}
+		err = json.Unmarshal(jsonUploadOptions, &containerUploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONUnMarshallingError)
+		}
+
+		var name = request.Distribution
+		var tag = uuid.New().String()
+		if containerUploadOptions.Name != nil {
+			name = *containerUploadOptions.Name
+			if containerUploadOptions.Tag != nil {
+				tag = *containerUploadOptions.Tag
+			}
+		}
+
+		t := target.NewContainerTarget(&target.ContainerTargetOptions{})
+		t.ImageName = fmt.Sprintf("%s:%s", name, tag)
+		t.OsbuildArtifact.ExportFilename = imageType.Filename()
+
+		irTarget = t
+	case ImageTypesGcp:
+		fallthrough
+	case ImageTypesGcpRhui:
+		var gcpUploadOptions GCPUploadOptions
+		jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONMarshallingError)
+		}
+		err = json.Unmarshal(jsonUploadOptions, &gcpUploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONUnMarshallingError)
+		}
+
+		var share []string
+		if gcpUploadOptions.ShareWithAccounts != nil {
+			share = *gcpUploadOptions.ShareWithAccounts
+		}
+
+		imageName := fmt.Sprintf("composer-api-%s", uuid.New().String())
+		var bucket string
+		if gcpUploadOptions.Bucket != nil {
+			bucket = *gcpUploadOptions.Bucket
+		}
+		t := target.NewGCPTarget(&target.GCPTargetOptions{
+			Region: gcpUploadOptions.Region,
+			Os:     imageType.Arch().Distro().Name(), // not exposed in cloudapi
+			Bucket: bucket,
+			// the uploaded object must have a valid extension
+			Object:            fmt.Sprintf("%s.tar.gz", imageName),
+			ShareWithAccounts: share,
+		})
+		// Import will fail if an image with this name already exists
+		if gcpUploadOptions.ImageName != nil {
+			t.ImageName = *gcpUploadOptions.ImageName
+		} else {
+			t.ImageName = imageName
+		}
+		t.OsbuildArtifact.ExportFilename = imageType.Filename()
+
+		irTarget = t
+	case ImageTypesAzure:
+		fallthrough
+	case ImageTypesAzureRhui:
+		fallthrough
+	case ImageTypesAzureEap7Rhui:
+		fallthrough
+	case ImageTypesAzureSapRhui:
+		var azureUploadOptions AzureUploadOptions
+		jsonUploadOptions, err := json.Marshal(*ir.UploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONMarshallingError)
+		}
+		err = json.Unmarshal(jsonUploadOptions, &azureUploadOptions)
+		if err != nil {
+			return nil, HTTPError(ErrorJSONUnMarshallingError)
+		}
+		rgLocation := ""
+		if azureUploadOptions.Location != nil {
+			rgLocation = *azureUploadOptions.Location
+		}
+		t := target.NewAzureImageTarget(&target.AzureImageTargetOptions{
+			TenantID:       azureUploadOptions.TenantId,
+			Location:       rgLocation,
+			SubscriptionID: azureUploadOptions.SubscriptionId,
+			ResourceGroup:  azureUploadOptions.ResourceGroup,
+		})
+
+		if azureUploadOptions.ImageName != nil {
+			t.ImageName = *azureUploadOptions.ImageName
+		} else {
+			// if ImageName wasn't given, generate a random one
+			t.ImageName = fmt.Sprintf("composer-api-%s", uuid.New().String())
+		}
+		t.OsbuildArtifact.ExportFilename = imageType.Filename()
+
+		irTarget = t
+	default:
+		return nil, HTTPError(ErrorUnsupportedImageType)
+	}
+	irTarget.OsbuildArtifact.ExportName = imageType.Exports()[0]
+
+	return irTarget, nil
+}
+
+// GetOSTreeOptions returns the image ostree options when included in the request
+// or nil if they are not present.
+func (ir *ImageRequest) GetOSTreeOptions() (ostreeOptions *ostree.ImageOptions, err error) {
+
+	if ir.Ostree == nil {
+		return nil, nil
+	}
+
+	ostreeOptions = &ostree.ImageOptions{}
+	if ir.Ostree.Ref != nil {
+		ostreeOptions.ImageRef = *ir.Ostree.Ref
+	}
+	if ir.Ostree.Url != nil {
+		ostreeOptions.URL = *ir.Ostree.Url
+	}
+	if ir.Ostree.Contenturl != nil {
+		// URL must be set if content url is specified
+		if ir.Ostree.Url == nil {
+			return nil, HTTPError(ErrorInvalidOSTreeParams)
+		}
+		ostreeOptions.ContentURL = *ir.Ostree.Contenturl
+	}
+	if ir.Ostree.Parent != nil {
+		ostreeOptions.ParentRef = *ir.Ostree.Parent
+	}
+	if ir.Ostree.Rhsm != nil {
+		ostreeOptions.RHSM = *ir.Ostree.Rhsm
+	}
+
+	return ostreeOptions, nil
+}
diff --git a/internal/cloudapi/v2/openapi.v2.gen.go b/internal/cloudapi/v2/openapi.v2.gen.go
index ce7d94a8a..aca219658 100644
--- a/internal/cloudapi/v2/openapi.v2.gen.go
+++ b/internal/cloudapi/v2/openapi.v2.gen.go
@@ -407,6 +407,7 @@ type File struct {
 
 // Filesystem defines model for Filesystem.
 type Filesystem struct {
+	// size of the filesystem in bytes
 	MinSize    uint64 `json:"min_size"`
 	Mountpoint string `json:"mountpoint"`
 }
@@ -456,6 +457,10 @@ type ImageRequest struct {
 	Ostree       *OSTree      `json:"ostree,omitempty"`
 	Repositories []Repository `json:"repositories"`
 
+	// Size of image, in bytes. When set to 0 the image size is a minimum
+	// defined by the image type.
+	Size *uint64 `json:"size,omitempty"`
+
 	// This should really be oneOf but AWSS3UploadOptions is a subset of
 	// AWSEC2UploadOptions. This means that all AWSEC2UploadOptions objects
 	// are also valid AWSS3UploadOptionas objects which violates the oneOf
@@ -889,133 +894,134 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
 // Base64 encoded, gzipped, json marshaled Swagger object
 var swaggerSpec = []string{
 
-	"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",
-	"pIqG+QjOH1//fwAAAP//Qp+IaH18AAA=",
+	"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",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file
diff --git a/internal/cloudapi/v2/openapi.v2.yml b/internal/cloudapi/v2/openapi.v2.yml
index d7387369b..469bd349e 100644
--- a/internal/cloudapi/v2/openapi.v2.yml
+++ b/internal/cloudapi/v2/openapi.v2.yml
@@ -760,6 +760,13 @@ components:
           $ref: '#/components/schemas/OSTree'
         upload_options:
           $ref: '#/components/schemas/UploadOptions'
+        size:
+          x-go-type: uint64
+          default: 0
+          example: 4294967296
+          description: |
+            Size of image, in bytes. When set to 0 the image size is a minimum
+            defined by the image type.
     ImageTypes:
       type: string
       enum:
@@ -1200,7 +1207,8 @@ components:
           example: '/var'
         min_size:
           x-go-type: uint64
-          example: 1024
+          example: 2147483648
+          description: 'size of the filesystem in bytes'
     OSTree:
       type: object
       properties:
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
index 8913c9cfb..f3d3fe120 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
@@ -39,6 +39,7 @@ const (
 	EuWest1RegionID      = "eu-west-1"      // Europe (Ireland).
 	EuWest2RegionID      = "eu-west-2"      // Europe (London).
 	EuWest3RegionID      = "eu-west-3"      // Europe (Paris).
+	IlCentral1RegionID   = "il-central-1"   // Israel (Tel Aviv).
 	MeCentral1RegionID   = "me-central-1"   // Middle East (UAE).
 	MeSouth1RegionID     = "me-south-1"     // Middle East (Bahrain).
 	SaEast1RegionID      = "sa-east-1"      // South America (Sao Paulo).
@@ -117,7 +118,7 @@ var awsPartition = partition{
 	DNSSuffix: "amazonaws.com",
 	RegionRegex: regionRegex{
 		Regexp: func() *regexp.Regexp {
-			reg, _ := regexp.Compile("^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$")
+			reg, _ := regexp.Compile("^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$")
 			return reg
 		}(),
 	},
@@ -213,6 +214,9 @@ var awsPartition = partition{
 		"eu-west-3": region{
 			Description: "Europe (Paris)",
 		},
+		"il-central-1": region{
+			Description: "Israel (Tel Aviv)",
+		},
 		"me-central-1": region{
 			Description: "Middle East (UAE)",
 		},
@@ -356,6 +360,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -494,6 +501,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -1439,6 +1449,14 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "api.ecr.il-central-1.amazonaws.com",
+					CredentialScope: credentialScope{
+						Region: "il-central-1",
+					},
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{
@@ -1907,6 +1925,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -2247,6 +2268,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -2390,6 +2414,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -2475,6 +2502,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -2617,6 +2647,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -3387,6 +3420,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -3466,6 +3502,15 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "athena.ap-south-1.api.aws",
 				},
+				endpointKey{
+					Region: "ap-south-2",
+				}: endpoint{},
+				endpointKey{
+					Region:  "ap-south-2",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "athena.ap-south-2.api.aws",
+				},
 				endpointKey{
 					Region: "ap-southeast-1",
 				}: endpoint{},
@@ -3493,6 +3538,15 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "athena.ap-southeast-3.api.aws",
 				},
+				endpointKey{
+					Region: "ap-southeast-4",
+				}: endpoint{},
+				endpointKey{
+					Region:  "ap-southeast-4",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "athena.ap-southeast-4.api.aws",
+				},
 				endpointKey{
 					Region: "ca-central-1",
 				}: endpoint{},
@@ -3511,6 +3565,15 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "athena.eu-central-1.api.aws",
 				},
+				endpointKey{
+					Region: "eu-central-2",
+				}: endpoint{},
+				endpointKey{
+					Region:  "eu-central-2",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "athena.eu-central-2.api.aws",
+				},
 				endpointKey{
 					Region: "eu-north-1",
 				}: endpoint{},
@@ -3529,6 +3592,15 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "athena.eu-south-1.api.aws",
 				},
+				endpointKey{
+					Region: "eu-south-2",
+				}: endpoint{},
+				endpointKey{
+					Region:  "eu-south-2",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "athena.eu-south-2.api.aws",
+				},
 				endpointKey{
 					Region: "eu-west-1",
 				}: endpoint{},
@@ -3812,6 +3884,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -4735,6 +4810,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -4875,6 +4953,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -5040,6 +5121,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -5195,6 +5279,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -5417,6 +5504,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -5733,6 +5823,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -6851,6 +6944,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -7019,6 +7115,12 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-northeast-2",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-south-1",
+				}: endpoint{},
+				endpointKey{
+					Region: "ap-southeast-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-2",
 				}: endpoint{},
@@ -8116,6 +8218,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -8208,6 +8313,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-south-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-south-2",
+				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-1",
 				}: endpoint{},
@@ -8359,6 +8467,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -8756,6 +8867,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -8885,6 +8999,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "local",
 				}: endpoint{
@@ -9090,6 +9207,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -9267,6 +9387,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -9436,6 +9559,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -9614,6 +9740,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -9732,6 +9861,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -9901,6 +10033,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-south-1",
 				}: endpoint{},
@@ -10538,6 +10673,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -10706,6 +10844,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -10919,6 +11060,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-north-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "eu-south-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "eu-west-1",
 				}: endpoint{},
@@ -11235,6 +11379,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -11416,6 +11563,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -11648,6 +11798,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -12913,6 +13066,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -14008,6 +14164,11 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "internetmonitor.eu-west-3.api.aws",
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "internetmonitor.il-central-1.api.aws",
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{
@@ -15481,6 +15642,11 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "kendra-ranking.eu-west-3.api.aws",
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "kendra-ranking.il-central-1.api.aws",
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{
@@ -15634,6 +15800,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -16189,6 +16358,15 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: fipsVariant,
+				}: endpoint{
+					Hostname: "kms-fips.il-central-1.amazonaws.com",
+				},
 				endpointKey{
 					Region: "il-central-1-fips",
 				}: endpoint{
@@ -16196,6 +16374,7 @@ var awsPartition = partition{
 					CredentialScope: credentialScope{
 						Region: "il-central-1",
 					},
+					Deprecated: boxedTrue,
 				},
 				endpointKey{
 					Region: "me-central-1",
@@ -16345,6 +16524,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-south-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-south-2",
+				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-1",
 				}: endpoint{},
@@ -16354,6 +16536,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-southeast-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-southeast-4",
+				}: endpoint{},
 				endpointKey{
 					Region: "ca-central-1",
 				}: endpoint{},
@@ -16417,6 +16602,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -16682,6 +16870,15 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "lambda.il-central-1.api.aws",
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -17317,6 +17514,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -18459,6 +18659,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -18544,6 +18747,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -19007,6 +19213,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -19633,6 +19842,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -20378,6 +20590,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -21317,6 +21532,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -21477,6 +21695,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -21601,6 +21822,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -22041,6 +22265,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -22542,6 +22769,11 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "resource-explorer-2.eu-west-3.api.aws",
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "resource-explorer-2.il-central-1.api.aws",
+				},
 				endpointKey{
 					Region: "sa-east-1",
 				}: endpoint{
@@ -22667,6 +22899,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -23164,6 +23399,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -23535,6 +23773,15 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "s3.dualstack.il-central-1.amazonaws.com",
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -24572,6 +24819,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -25107,6 +25357,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-south-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-south-2",
+				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-1",
 				}: endpoint{},
@@ -25116,6 +25369,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-southeast-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-southeast-4",
+				}: endpoint{},
 				endpointKey{
 					Region: "ca-central-1",
 				}: endpoint{},
@@ -25128,12 +25384,18 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-central-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "eu-central-2",
+				}: endpoint{},
 				endpointKey{
 					Region: "eu-north-1",
 				}: endpoint{},
 				endpointKey{
 					Region: "eu-south-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "eu-south-2",
+				}: endpoint{},
 				endpointKey{
 					Region: "eu-west-1",
 				}: endpoint{},
@@ -25438,6 +25700,15 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "servicediscovery.eu-west-3.api.aws",
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: dualStackVariant,
+				}: endpoint{
+					Hostname: "servicediscovery.il-central-1.api.aws",
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -26463,6 +26734,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -26614,6 +26888,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -26777,6 +27054,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -27376,6 +27656,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -27653,6 +27936,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "local",
 				}: endpoint{
@@ -27756,6 +28042,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -27963,6 +28252,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -28108,6 +28400,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -28217,6 +28512,9 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-3",
 				}: endpoint{},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
@@ -29768,6 +30066,7 @@ var awsPartition = partition{
 					CredentialScope: credentialScope{
 						Region: "il-central-1",
 					},
+					Deprecated: boxedTrue,
 				},
 				endpointKey{
 					Region: "fips-me-central-1",
@@ -29832,6 +30131,23 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "waf-regional.il-central-1.amazonaws.com",
+					CredentialScope: credentialScope{
+						Region: "il-central-1",
+					},
+				},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: fipsVariant,
+				}: endpoint{
+					Hostname: "waf-regional-fips.il-central-1.amazonaws.com",
+					CredentialScope: credentialScope{
+						Region: "il-central-1",
+					},
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{
@@ -30482,6 +30798,7 @@ var awsPartition = partition{
 					CredentialScope: credentialScope{
 						Region: "il-central-1",
 					},
+					Deprecated: boxedTrue,
 				},
 				endpointKey{
 					Region: "fips-me-central-1",
@@ -30546,6 +30863,23 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{
+					Hostname: "wafv2.il-central-1.amazonaws.com",
+					CredentialScope: credentialScope{
+						Region: "il-central-1",
+					},
+				},
+				endpointKey{
+					Region:  "il-central-1",
+					Variant: fipsVariant,
+				}: endpoint{
+					Hostname: "wafv2-fips.il-central-1.amazonaws.com",
+					CredentialScope: credentialScope{
+						Region: "il-central-1",
+					},
+				},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{
@@ -31060,6 +31394,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "il-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "me-central-1",
 				}: endpoint{},
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go
index 2506a58df..644836bc2 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/version.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/version.go
@@ -5,4 +5,4 @@ package aws
 const SDKName = "aws-sdk-go"
 
 // SDKVersion is the version of this SDK
-const SDKVersion = "1.44.313"
+const SDKVersion = "1.44.316"
diff --git a/vendor/github.com/aws/aws-sdk-go/service/autoscaling/api.go b/vendor/github.com/aws/aws-sdk-go/service/autoscaling/api.go
index 9fda71468..b4d7de3c3 100644
--- a/vendor/github.com/aws/aws-sdk-go/service/autoscaling/api.go
+++ b/vendor/github.com/aws/aws-sdk-go/service/autoscaling/api.go
@@ -7043,6 +7043,7 @@ type AlarmSpecification struct {
 	_ struct{} `type:"structure"`
 
 	// The names of one or more CloudWatch alarms to monitor for the instance refresh.
+	// You can specify up to 10 alarms.
 	Alarms []*string `type:"list"`
 }
 
diff --git a/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go b/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
index 062b4df3f..f9de38875 100644
--- a/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
+++ b/vendor/github.com/aws/aws-sdk-go/service/ec2/api.go
@@ -72923,6 +72923,21 @@ type CreateNetworkInterfaceInput struct {
 	// it is UnauthorizedOperation.
 	DryRun *bool `locationName:"dryRun" type:"boolean"`
 
+	// If you’re creating a network interface in a dual-stack or IPv6-only subnet,
+	// you have the option to assign a primary IPv6 IP address. A primary IPv6 address
+	// is an IPv6 GUA address associated with an ENI that you have enabled to use
+	// a primary IPv6 address. Use this option if the instance that this ENI will
+	// be attached to relies on its IPv6 address not changing. Amazon Web Services
+	// will automatically assign an IPv6 address associated with the ENI attached
+	// to your instance to be the primary IPv6 address. Once you enable an IPv6
+	// GUA address to be a primary IPv6, you cannot disable it. When you enable
+	// an IPv6 GUA address to be a primary IPv6, the first IPv6 GUA will be made
+	// the primary IPv6 address until the instance is terminated or the network
+	// interface is detached. If you have multiple IPv6 addresses associated with
+	// an ENI attached to your instance and you enable a primary IPv6 address, the
+	// first IPv6 GUA address associated with the ENI becomes the primary IPv6 address.
+	EnablePrimaryIpv6 *bool `type:"boolean"`
+
 	// The IDs of one or more security groups.
 	Groups []*string `locationName:"SecurityGroupId" locationNameList:"SecurityGroupId" type:"list"`
 
@@ -73060,6 +73075,12 @@ func (s *CreateNetworkInterfaceInput) SetDryRun(v bool) *CreateNetworkInterfaceI
 	return s
 }
 
+// SetEnablePrimaryIpv6 sets the EnablePrimaryIpv6 field's value.
+func (s *CreateNetworkInterfaceInput) SetEnablePrimaryIpv6(v bool) *CreateNetworkInterfaceInput {
+	s.EnablePrimaryIpv6 = &v
+	return s
+}
+
 // SetGroups sets the Groups field's value.
 func (s *CreateNetworkInterfaceInput) SetGroups(v []*string) *CreateNetworkInterfaceInput {
 	s.Groups = v
@@ -112880,8 +112901,7 @@ type EbsBlockDevice struct {
 
 	// The ARN of the Outpost on which the snapshot is stored.
 	//
-	// This parameter is only supported on BlockDeviceMapping objects called by
-	// CreateImage (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html).
+	// This parameter is not supported when using CreateImage (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html).
 	OutpostArn *string `locationName:"outpostArn" type:"string"`
 
 	// The ID of the snapshot.
@@ -130058,6 +130078,13 @@ type InstanceIpv6Address struct {
 
 	// The IPv6 address.
 	Ipv6Address *string `locationName:"ipv6Address" type:"string"`
+
+	// Determines if an IPv6 address associated with a network interface is the
+	// primary IPv6 address. When you enable an IPv6 GUA address to be a primary
+	// IPv6, the first IPv6 GUA will be made the primary IPv6 address until the
+	// instance is terminated or the network interface is detached. For more information,
+	// see RunInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html).
+	IsPrimaryIpv6 *bool `locationName:"isPrimaryIpv6" type:"boolean"`
 }
 
 // String returns the string representation.
@@ -130084,6 +130111,12 @@ func (s *InstanceIpv6Address) SetIpv6Address(v string) *InstanceIpv6Address {
 	return s
 }
 
+// SetIsPrimaryIpv6 sets the IsPrimaryIpv6 field's value.
+func (s *InstanceIpv6Address) SetIsPrimaryIpv6(v bool) *InstanceIpv6Address {
+	s.IsPrimaryIpv6 = &v
+	return s
+}
+
 // Describes an IPv6 address.
 type InstanceIpv6AddressRequest struct {
 	_ struct{} `type:"structure"`
@@ -130922,6 +130955,13 @@ type InstanceNetworkInterfaceSpecification struct {
 	// specify a network interface ID in a launch specification.
 	NetworkInterfaceId *string `locationName:"networkInterfaceId" type:"string"`
 
+	// The primary IPv6 address of the network interface. When you enable an IPv6
+	// GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary
+	// IPv6 address until the instance is terminated or the network interface is
+	// detached. For more information about primary IPv6 addresses, see RunInstances
+	// (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html).
+	PrimaryIpv6 *bool `type:"boolean"`
+
 	// The private IPv4 address of the network interface. Applies only if creating
 	// a network interface when launching an instance. You cannot specify this option
 	// if you're launching more than one instance in a RunInstances (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html)
@@ -131054,6 +131094,12 @@ func (s *InstanceNetworkInterfaceSpecification) SetNetworkInterfaceId(v string)
 	return s
 }
 
+// SetPrimaryIpv6 sets the PrimaryIpv6 field's value.
+func (s *InstanceNetworkInterfaceSpecification) SetPrimaryIpv6(v bool) *InstanceNetworkInterfaceSpecification {
+	s.PrimaryIpv6 = &v
+	return s
+}
+
 // SetPrivateIpAddress sets the PrivateIpAddress field's value.
 func (s *InstanceNetworkInterfaceSpecification) SetPrivateIpAddress(v string) *InstanceNetworkInterfaceSpecification {
 	s.PrivateIpAddress = &v
@@ -137434,6 +137480,13 @@ type LaunchTemplateInstanceNetworkInterfaceSpecification struct {
 	// The ID of the network interface.
 	NetworkInterfaceId *string `locationName:"networkInterfaceId" type:"string"`
 
+	// The primary IPv6 address of the network interface. When you enable an IPv6
+	// GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary
+	// IPv6 address until the instance is terminated or the network interface is
+	// detached. For more information about primary IPv6 addresses, see RunInstances
+	// (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html).
+	PrimaryIpv6 *bool `locationName:"primaryIpv6" type:"boolean"`
+
 	// The primary private IPv4 address of the network interface.
 	PrivateIpAddress *string `locationName:"privateIpAddress" type:"string"`
 
@@ -137555,6 +137608,12 @@ func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetNetworkInterfac
 	return s
 }
 
+// SetPrimaryIpv6 sets the PrimaryIpv6 field's value.
+func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetPrimaryIpv6(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecification {
+	s.PrimaryIpv6 = &v
+	return s
+}
+
 // SetPrivateIpAddress sets the PrivateIpAddress field's value.
 func (s *LaunchTemplateInstanceNetworkInterfaceSpecification) SetPrivateIpAddress(v string) *LaunchTemplateInstanceNetworkInterfaceSpecification {
 	s.PrivateIpAddress = &v
@@ -137648,6 +137707,13 @@ type LaunchTemplateInstanceNetworkInterfaceSpecificationRequest struct {
 	// The ID of the network interface.
 	NetworkInterfaceId *string `type:"string"`
 
+	// The primary IPv6 address of the network interface. When you enable an IPv6
+	// GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary
+	// IPv6 address until the instance is terminated or the network interface is
+	// detached. For more information about primary IPv6 addresses, see RunInstances
+	// (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html).
+	PrimaryIpv6 *bool `type:"boolean"`
+
 	// The primary private IPv4 address of the network interface.
 	PrivateIpAddress *string `type:"string"`
 
@@ -137769,6 +137835,12 @@ func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetNetworkI
 	return s
 }
 
+// SetPrimaryIpv6 sets the PrimaryIpv6 field's value.
+func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetPrimaryIpv6(v bool) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest {
+	s.PrimaryIpv6 = &v
+	return s
+}
+
 // SetPrivateIpAddress sets the PrivateIpAddress field's value.
 func (s *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest) SetPrivateIpAddress(v string) *LaunchTemplateInstanceNetworkInterfaceSpecificationRequest {
 	s.PrivateIpAddress = &v
@@ -144423,6 +144495,21 @@ type ModifyNetworkInterfaceAttributeInput struct {
 	// attached to the instance.
 	EnaSrdSpecification *EnaSrdSpecification `type:"structure"`
 
+	// If you’re modifying a network interface in a dual-stack or IPv6-only subnet,
+	// you have the option to assign a primary IPv6 IP address. A primary IPv6 address
+	// is an IPv6 GUA address associated with an ENI that you have enabled to use
+	// a primary IPv6 address. Use this option if the instance that this ENI will
+	// be attached to relies on its IPv6 address not changing. Amazon Web Services
+	// will automatically assign an IPv6 address associated with the ENI attached
+	// to your instance to be the primary IPv6 address. Once you enable an IPv6
+	// GUA address to be a primary IPv6, you cannot disable it. When you enable
+	// an IPv6 GUA address to be a primary IPv6, the first IPv6 GUA will be made
+	// the primary IPv6 address until the instance is terminated or the network
+	// interface is detached. If you have multiple IPv6 addresses associated with
+	// an ENI attached to your instance and you enable a primary IPv6 address, the
+	// first IPv6 GUA address associated with the ENI becomes the primary IPv6 address.
+	EnablePrimaryIpv6 *bool `type:"boolean"`
+
 	// Changes the security groups for the network interface. The new set of groups
 	// you specify replaces the current set. You must specify at least one group,
 	// even if it's just the default security group in the VPC. You must specify
@@ -144498,6 +144585,12 @@ func (s *ModifyNetworkInterfaceAttributeInput) SetEnaSrdSpecification(v *EnaSrdS
 	return s
 }
 
+// SetEnablePrimaryIpv6 sets the EnablePrimaryIpv6 field's value.
+func (s *ModifyNetworkInterfaceAttributeInput) SetEnablePrimaryIpv6(v bool) *ModifyNetworkInterfaceAttributeInput {
+	s.EnablePrimaryIpv6 = &v
+	return s
+}
+
 // SetGroups sets the Groups field's value.
 func (s *ModifyNetworkInterfaceAttributeInput) SetGroups(v []*string) *ModifyNetworkInterfaceAttributeInput {
 	s.Groups = v
@@ -151911,6 +152004,13 @@ type NetworkInterfaceIpv6Address struct {
 
 	// The IPv6 address.
 	Ipv6Address *string `locationName:"ipv6Address" type:"string"`
+
+	// Determines if an IPv6 address associated with a network interface is the
+	// primary IPv6 address. When you enable an IPv6 GUA address to be a primary
+	// IPv6, the first IPv6 GUA will be made the primary IPv6 address until the
+	// instance is terminated or the network interface is detached. For more information,
+	// see ModifyNetworkInterfaceAttribute (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyNetworkInterfaceAttribute.html).
+	IsPrimaryIpv6 *bool `locationName:"isPrimaryIpv6" type:"boolean"`
 }
 
 // String returns the string representation.
@@ -151937,6 +152037,12 @@ func (s *NetworkInterfaceIpv6Address) SetIpv6Address(v string) *NetworkInterface
 	return s
 }
 
+// SetIsPrimaryIpv6 sets the IsPrimaryIpv6 field's value.
+func (s *NetworkInterfaceIpv6Address) SetIsPrimaryIpv6(v bool) *NetworkInterfaceIpv6Address {
+	s.IsPrimaryIpv6 = &v
+	return s
+}
+
 // Describes a permission for a network interface.
 type NetworkInterfacePermission struct {
 	_ struct{} `type:"structure"`
@@ -164029,6 +164135,21 @@ type RunInstancesInput struct {
 	// are considered current customers and will be able to continue using the service.
 	ElasticInferenceAccelerators []*ElasticInferenceAccelerator `locationName:"ElasticInferenceAccelerator" locationNameList:"item" type:"list"`
 
+	// If you’re launching an instance into a dual-stack or IPv6-only subnet,
+	// you can enable assigning a primary IPv6 address. A primary IPv6 address is
+	// an IPv6 GUA address associated with an ENI that you have enabled to use a
+	// primary IPv6 address. Use this option if an instance relies on its IPv6 address
+	// not changing. When you launch the instance, Amazon Web Services will automatically
+	// assign an IPv6 address associated with the ENI attached to your instance
+	// to be the primary IPv6 address. Once you enable an IPv6 GUA address to be
+	// a primary IPv6, you cannot disable it. When you enable an IPv6 GUA address
+	// to be a primary IPv6, the first IPv6 GUA will be made the primary IPv6 address
+	// until the instance is terminated or the network interface is detached. If
+	// you have multiple IPv6 addresses associated with an ENI attached to your
+	// instance and you enable a primary IPv6 address, the first IPv6 GUA address
+	// associated with the ENI becomes the primary IPv6 address.
+	EnablePrimaryIpv6 *bool `type:"boolean"`
+
 	// Indicates whether the instance is enabled for Amazon Web Services Nitro Enclaves.
 	// For more information, see What is Amazon Web Services Nitro Enclaves? (https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave.html)
 	// in the Amazon Web Services Nitro Enclaves User Guide.
@@ -164366,6 +164487,12 @@ func (s *RunInstancesInput) SetElasticInferenceAccelerators(v []*ElasticInferenc
 	return s
 }
 
+// SetEnablePrimaryIpv6 sets the EnablePrimaryIpv6 field's value.
+func (s *RunInstancesInput) SetEnablePrimaryIpv6(v bool) *RunInstancesInput {
+	s.EnablePrimaryIpv6 = &v
+	return s
+}
+
 // SetEnclaveOptions sets the EnclaveOptions field's value.
 func (s *RunInstancesInput) SetEnclaveOptions(v *EnclaveOptionsRequest) *RunInstancesInput {
 	s.EnclaveOptions = v
diff --git a/vendor/github.com/vmware/govmomi/internal/version/version.go b/vendor/github.com/vmware/govmomi/internal/version/version.go
index dc29e12bf..0ab896cf2 100644
--- a/vendor/github.com/vmware/govmomi/internal/version/version.go
+++ b/vendor/github.com/vmware/govmomi/internal/version/version.go
@@ -21,5 +21,5 @@ const (
 	ClientName = "govmomi"
 
 	// ClientVersion is the version of this SDK
-	ClientVersion = "0.30.6"
+	ClientVersion = "0.30.7"
 )
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 830344e25..4434f0eb8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -119,7 +119,7 @@ github.com/acarl005/stripansi
 # github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
 ## explicit; go 1.13
 github.com/asaskevich/govalidator
-# github.com/aws/aws-sdk-go v1.44.313
+# github.com/aws/aws-sdk-go v1.44.316
 ## explicit; go 1.11
 github.com/aws/aws-sdk-go/aws
 github.com/aws/aws-sdk-go/aws/arn
@@ -644,7 +644,7 @@ github.com/oracle/oci-go-sdk/v54/identity
 github.com/oracle/oci-go-sdk/v54/objectstorage
 github.com/oracle/oci-go-sdk/v54/objectstorage/transfer
 github.com/oracle/oci-go-sdk/v54/workrequests
-# github.com/osbuild/images v0.0.0-20230801094908-157e798fdf8d
+# github.com/osbuild/images v0.0.0-20230804084728-03212162ff49
 ## explicit; go 1.19
 github.com/osbuild/images/internal/common
 github.com/osbuild/images/internal/dnfjson
@@ -784,7 +784,7 @@ github.com/vbauerster/mpb/v8
 github.com/vbauerster/mpb/v8/cwriter
 github.com/vbauerster/mpb/v8/decor
 github.com/vbauerster/mpb/v8/internal
-# github.com/vmware/govmomi v0.30.6
+# github.com/vmware/govmomi v0.30.7
 ## explicit; go 1.19
 github.com/vmware/govmomi/cns
 github.com/vmware/govmomi/cns/methods


Test patch:
diff --git a/internal/cloudapi/v2/compose_test.go b/internal/cloudapi/v2/compose_test.go
new file mode 100644
index 000000000..febc1e15a
--- /dev/null
+++ b/internal/cloudapi/v2/compose_test.go
@@ -0,0 +1,222 @@
+package v2
+
+import (
+	"testing"
+
+	"github.com/osbuild/images/pkg/subscription"
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/common"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestGetBlueprintWithCustomizations(t *testing.T) {
+	// Empty request should return empty blueprint
+	cr := ComposeRequest{}
+	bp, err := cr.GetBlueprintWithCustomizations()
+	require.Nil(t, err)
+	assert.Equal(t, "empty blueprint", bp.Name)
+	assert.Equal(t, "0.0.0", bp.Version)
+	assert.Nil(t, bp.Customizations)
+
+	// Test with customizations
+	expected := blueprint.Blueprint{Name: "empty blueprint"}
+	err = expected.Initialize()
+	require.Nil(t, err)
+
+	// interface{} is a terrible idea. Work around it...
+	var rootStr interface{} = "root"
+
+	// anonymous structs buried in a data type are almost as bad.
+	services := struct {
+		Disabled *[]string `json:"disabled,omitempty"`
+		Enabled  *[]string `json:"enabled,omitempty"`
+	}{
+		Disabled: &[]string{"cleanup"},
+		Enabled:  &[]string{"sshd"},
+	}
+
+	// Construct the compose request with customizations
+	cr = ComposeRequest{Customizations: &Customizations{
+		Users: &[]User{
+			User{
+				Name:   "admin",
+				Key:    common.ToPtr("dummy ssh-key"),
+				Groups: &[]string{"users", "wheel"},
+			}},
+		Packages: &[]string{"bash", "tmux"},
+		Containers: &[]Container{
+			Container{
+				Name:   common.ToPtr("container-name"),
+				Source: "http://some.path.to/a/container/source",
+			},
+		},
+		Directories: &[]Directory{
+			Directory{
+				Path:          "/opt/extra",
+				EnsureParents: common.ToPtr(true),
+				User:          &rootStr,
+				Group:         &rootStr,
+				Mode:          common.ToPtr("0755"),
+			},
+		},
+		Files: &[]File{
+			File{
+				Path:          "/etc/mad.conf",
+				Data:          common.ToPtr("Alfred E. Neuman was here.\n"),
+				EnsureParents: common.ToPtr(true),
+				User:          &rootStr,
+				Group:         &rootStr,
+				Mode:          common.ToPtr("0644"),
+			},
+		},
+		Filesystem: &[]Filesystem{
+			Filesystem{
+				Mountpoint: "/var/lib/wopr/",
+				MinSize:    1099511627776,
+			},
+		},
+		Services: &services,
+		Openscap: &OpenSCAP{ProfileId: "B 263-59"},
+		CustomRepositories: &[]CustomRepository{
+			CustomRepository{
+				Id:       "custom repo",
+				Metalink: common.ToPtr("http://example.org/metalink"),
+				CheckGpg: common.ToPtr(true),
+				Enabled:  common.ToPtr(true),
+			},
+		},
+	}}
+
+	// Construct the expected blueprint result
+	// Packages
+	expected.Packages = []blueprint.Package{
+		{Name: "bash"},
+		{Name: "tmux"},
+	}
+
+	// Containers
+	expected.Containers = []blueprint.Container{
+		blueprint.Container{
+			Name:   "container-name",
+			Source: "http://some.path.to/a/container/source",
+		},
+	}
+
+	// Customizations
+	expected.Customizations = &blueprint.Customizations{
+		User: []blueprint.UserCustomization{
+			blueprint.UserCustomization{
+				Name:   "admin",
+				Key:    common.ToPtr("dummy ssh-key"),
+				Groups: []string{"users", "wheel"},
+			},
+		},
+		Directories: []blueprint.DirectoryCustomization{
+			blueprint.DirectoryCustomization{
+				Path:          "/opt/extra",
+				User:          "root",
+				Group:         "root",
+				Mode:          "0755",
+				EnsureParents: true,
+			},
+		},
+		Files: []blueprint.FileCustomization{
+			blueprint.FileCustomization{
+				Path:  "/etc/mad.conf",
+				User:  "root",
+				Group: "root",
+				Mode:  "0644",
+				Data:  "Alfred E. Neuman was here.\n",
+			},
+		},
+		Filesystem: []blueprint.FilesystemCustomization{
+			blueprint.FilesystemCustomization{
+				Mountpoint: "/var/lib/wopr/",
+				MinSize:    1099511627776,
+			},
+		},
+		Services: &blueprint.ServicesCustomization{
+			Enabled:  []string{"sshd"},
+			Disabled: []string{"cleanup"},
+		},
+		OpenSCAP: &blueprint.OpenSCAPCustomization{
+			ProfileID: "B 263-59",
+		},
+		Repositories: []blueprint.RepositoryCustomization{
+			blueprint.RepositoryCustomization{
+				Id:       "custom repo",
+				Metalink: "http://example.org/metalink",
+				Enabled:  common.ToPtr(true),
+				GPGCheck: common.ToPtr(true),
+			},
+		},
+	}
+
+	bp, err = cr.GetBlueprintWithCustomizations()
+	require.Nil(t, err)
+	assert.Equal(t, bp, expected)
+}
+
+func TestGetPayloadRepositories(t *testing.T) {
+
+	// Empty PayloadRepositories
+	cr := ComposeRequest{}
+	repos := cr.GetPayloadRepositories()
+	assert.Len(t, repos, 0)
+	assert.Equal(t, []Repository(nil), repos)
+
+	// Populated PayloadRepositories
+	cr = ComposeRequest{Customizations: &Customizations{
+		PayloadRepositories: &[]Repository{
+			Repository{
+				Baseurl:     common.ToPtr("http://example.org/pub/linux/repo"),
+				CheckGpg:    common.ToPtr(true),
+				PackageSets: &[]string{"build", "archive"},
+				Rhsm:        common.ToPtr(false),
+			},
+		},
+	}}
+
+	expected := []Repository{
+		Repository{
+			Baseurl:     common.ToPtr("http://example.org/pub/linux/repo"),
+			CheckGpg:    common.ToPtr(true),
+			PackageSets: &[]string{"build", "archive"},
+			Rhsm:        common.ToPtr(false),
+		},
+	}
+	repos = cr.GetPayloadRepositories()
+	assert.Len(t, repos, 1)
+	assert.Equal(t, expected, repos)
+}
+
+func TestGetSubscriptions(t *testing.T) {
+	// Empty Subscription
+	cr := ComposeRequest{}
+	sub := cr.GetSubscription()
+	assert.Equal(t, (*subscription.ImageOptions)(nil), sub)
+
+	// Populated Subscription
+	cr = ComposeRequest{Customizations: &Customizations{
+		Subscription: common.ToPtr(Subscription{
+			ActivationKey: "key",
+			BaseUrl:       "http://example.org/baseurl",
+			Insights:      false,
+			Organization:  "Weyland-Yutani",
+			ServerUrl:     "http://example.org/serverurl",
+		}),
+	}}
+
+	expected := &subscription.ImageOptions{
+		ActivationKey: "key",
+		BaseUrl:       "http://example.org/baseurl",
+		Insights:      false,
+		Organization:  "Weyland-Yutani",
+		ServerUrl:     "http://example.org/serverurl",
+	}
+	sub = cr.GetSubscription()
+	assert.Equal(t, expected, sub)
+
+}
diff --git a/internal/cloudapi/v2/imagerequest_test.go b/internal/cloudapi/v2/imagerequest_test.go
new file mode 100644
index 000000000..2c257d409
--- /dev/null
+++ b/internal/cloudapi/v2/imagerequest_test.go
@@ -0,0 +1,131 @@
+package v2
+
+import (
+	"testing"
+
+	"github.com/osbuild/images/pkg/distro/test_distro"
+	"github.com/osbuild/osbuild-composer/internal/blueprint"
+	"github.com/osbuild/osbuild-composer/internal/common"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestImageRequestSize(t *testing.T) {
+	distro := test_distro.New()
+	arch, err := distro.GetArch(test_distro.TestArchName)
+	if err != nil {
+		panic(err)
+	}
+	imageType, err := arch.GetImageType(test_distro.TestImageTypeName)
+	if err != nil {
+		panic(err)
+	}
+
+	// A blueprint with no filesystem customizations
+	bp := blueprint.Blueprint{
+		Name:        "image-request-test",
+		Description: "Empty Blueprint",
+		Version:     "0.0.1",
+	}
+	// #1 With no size request
+	ir := ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Size:         nil,
+	}
+	imageOptions := ir.GetImageOptions(imageType, bp)
+
+	// The test_distro default size is 1GiB
+	assert.Equal(t, uint64(1073741824), imageOptions.Size)
+
+	// #2 With size request
+	ir = ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Size:         common.ToPtr(uint64(5368709120)),
+	}
+	imageOptions = ir.GetImageOptions(imageType, bp)
+
+	// The test_distro default size is actually 5GiB
+	assert.Equal(t, uint64(5368709120), imageOptions.Size)
+
+	// A blueprint with filesystem customizations
+	bp = blueprint.Blueprint{
+		Name:        "image-request-test",
+		Description: "Customized Filesystem",
+		Version:     "0.0.1",
+		Customizations: &blueprint.Customizations{
+			Filesystem: []blueprint.FilesystemCustomization{
+				blueprint.FilesystemCustomization{
+					Mountpoint: "/",
+					MinSize:    2147483648,
+				},
+			},
+		},
+	}
+
+	// #3 With no size request
+	ir = ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Size:         nil,
+	}
+	imageOptions = ir.GetImageOptions(imageType, bp)
+
+	// The test_distro default size is actually 2GiB
+	assert.Equal(t, uint64(2147483648), imageOptions.Size)
+
+	// #4 With size request
+	ir = ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Size:         common.ToPtr(uint64(5368709120)),
+	}
+	imageOptions = ir.GetImageOptions(imageType, bp)
+
+	// The test_distro default size is actually 5GiB
+	assert.Equal(t, uint64(5368709120), imageOptions.Size)
+}
+
+func TestGetOstreeOptions(t *testing.T) {
+	// No Ostree settings
+	ir := ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+	}
+	options, err := ir.GetOSTreeOptions()
+	assert.Nil(t, options)
+	assert.Nil(t, err)
+
+	// Populated Ostree settings
+	ir = ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Ostree: &OSTree{
+			Contenturl: common.ToPtr("http://url.to.content/"),
+			Parent:     common.ToPtr("02604b2da6e954bd34b8b82a835e5a77d2b60ffa"),
+			Ref:        common.ToPtr("reference"),
+			Url:        common.ToPtr("http://the.url/"),
+		},
+	}
+	options, err = ir.GetOSTreeOptions()
+	assert.Nil(t, err)
+	require.NotNil(t, options)
+	assert.Equal(t, "http://url.to.content/", options.ContentURL)
+	assert.Equal(t, "02604b2da6e954bd34b8b82a835e5a77d2b60ffa", options.ParentRef)
+	assert.Equal(t, "reference", options.ImageRef)
+	assert.Equal(t, "http://the.url/", options.URL)
+
+	// Populated Ostree settings with no url
+	ir = ImageRequest{
+		Architecture: test_distro.TestArchName,
+		ImageType:    test_distro.TestImageTypeName,
+		Ostree: &OSTree{
+			Contenturl: common.ToPtr("http://url.to.content/"),
+		},
+	}
+	_, err = ir.GetOSTreeOptions()
+	require.NotNil(t, err)
+	assert.Error(t, err)
+}
diff --git a/internal/weldr/api_test.go b/internal/weldr/api_test.go
index fa94bae5f..5869b95de 100644
--- a/internal/weldr/api_test.go
+++ b/internal/weldr/api_test.go
@@ -922,6 +922,7 @@ func TestCompose(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   imgType,
+			Size:        imgType.Size(0),
 			Manifest:    mf,
 			Targets: []*target.Target{
 				{
@@ -949,6 +950,7 @@ func TestCompose(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   imgType,
+			Size:        imgType.Size(0),
 			Manifest:    mf,
 			Targets: []*target.Target{
 				{
@@ -993,6 +995,7 @@ func TestCompose(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   ostreeImgType,
+			Size:        ostreeImgType.Size(0),
 			Manifest:    omf,
 			Targets: []*target.Target{
 				{
@@ -1029,6 +1032,7 @@ func TestCompose(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   ostreeImgType,
+			Size:        ostreeImgType.Size(0),
 			Manifest:    omfo,
 			Targets: []*target.Target{
 				{
@@ -1070,6 +1074,7 @@ func TestCompose(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   imgType2,
+			Size:        imgType2.Size(0),
 			Manifest:    mf2,
 			Targets: []*target.Target{
 				{
@@ -2059,6 +2064,7 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   imgType,
+			Size:        imgType.Size(0),
 			Manifest:    mf,
 			Targets: []*target.Target{
 				{
@@ -2087,6 +2093,7 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
 		ImageBuild: store.ImageBuild{
 			QueueStatus: common.IBWaiting,
 			ImageType:   imgType2,
+			Size:        imgType2.Size(0),
 			Manifest:    mf,
 			Targets: []*target.Target{
 				{
diff --git a/vendor/github.com/osbuild/images/pkg/distro/test_distro/distro.go b/vendor/github.com/osbuild/images/pkg/distro/test_distro/distro.go
index 1d1a28cd2..4a6d81c23 100644
--- a/vendor/github.com/osbuild/images/pkg/distro/test_distro/distro.go
+++ b/vendor/github.com/osbuild/images/pkg/distro/test_distro/distro.go
@@ -186,7 +186,10 @@ func (t *TestImageType) OSTreeRef() string {
 }
 
 func (t *TestImageType) Size(size uint64) uint64 {
-	return 0
+	if size == 0 {
+		size = 1073741824
+	}
+	return size
 }
 
 func (t *TestImageType) PartitionType() string {