Skip to content

Commit c6868ea

Browse files
Add support for aliases like airflow-2 in Composer image version field (#5885) (#11422)
* Add support for Airflow major version aliases This covers the new aliases for Airflow major version ('airflow-1', 'airflow-2') in image version field, and updates to the related documentation. * Use image version aliases in Composer tests Instead of finding the latest available image version for the given Composer and Airflow major versions, the new image version aliases are used to let Composer resolve them on the server side: 'composer-1-airflow-1', 'composer-1-airflow-2', 'composer-2-airflow-2'. Signed-off-by: Modular Magician <[email protected]>
1 parent 26c25af commit c6868ea

File tree

4 files changed

+40
-81
lines changed

4 files changed

+40
-81
lines changed

.changelog/5885.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
composer: Added support for `airflow-1` and `airflow-2` aliases in image version argument
3+
```

google/resource_composer_environment.go

+19-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
const (
1818
composerEnvironmentEnvVariablesRegexp = "[a-zA-Z_][a-zA-Z0-9_]*."
1919
composerEnvironmentReservedAirflowEnvVarRegexp = "AIRFLOW__[A-Z0-9_]+__[A-Z0-9_]+"
20-
composerEnvironmentVersionRegexp = `composer-(([0-9]+)(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-(([0-9]+\.[0-9]+)(\.[0-9]+)?)`
20+
composerEnvironmentVersionRegexp = `composer-(([0-9]+)(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-(([0-9]+)((\.[0-9]+)(\.[0-9]+)?)?)`
2121
)
2222

2323
var composerEnvironmentReservedEnvVar = map[string]struct{}{
@@ -323,7 +323,7 @@ func resourceComposerEnvironment() *schema.Resource {
323323
AtLeastOneOf: composerSoftwareConfigKeys,
324324
ValidateFunc: validateRegexp(composerEnvironmentVersionRegexp),
325325
DiffSuppressFunc: composerImageVersionDiffSuppress,
326-
Description: `The version of the software running in the environment. This encapsulates both the version of Cloud Composer functionality and the version of Apache Airflow. It must match the regular expression composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+\.[0-9]+(\.[0-9]+)?). The Cloud Composer portion of the image version is a full semantic version, or an alias in the form of major version number or 'latest'. The Apache Airflow portion of the image version is a full semantic version that points to one of the supported Apache Airflow versions, or an alias in the form of only major and minor versions specified. See documentation for more details and version list.`,
326+
Description: `The version of the software running in the environment. This encapsulates both the version of Cloud Composer functionality and the version of Apache Airflow. It must match the regular expression composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+(\.[0-9]+(\.[0-9]+)?)?). The Cloud Composer portion of the image version is a full semantic version, or an alias in the form of major version number or 'latest'. The Apache Airflow portion of the image version is a full semantic version that points to one of the supported Apache Airflow versions, or an alias in the form of only major or major.minor versions specified. See documentation for more details and version list.`,
327327
},
328328
"python_version": {
329329
Type: schema.TypeString,
@@ -1889,7 +1889,7 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData
18891889
versionRe := regexp.MustCompile(composerEnvironmentVersionRegexp)
18901890
oldVersions := versionRe.FindStringSubmatch(old)
18911891
newVersions := versionRe.FindStringSubmatch(new)
1892-
if oldVersions == nil || len(oldVersions) < 8 {
1892+
if oldVersions == nil || len(oldVersions) < 10 {
18931893
// Somehow one of the versions didn't match the regexp or didn't
18941894
// have values in the capturing groups. In that case, fall back to
18951895
// an equality check.
@@ -1898,7 +1898,7 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData
18981898
}
18991899
return old == new
19001900
}
1901-
if newVersions == nil || len(newVersions) < 8 {
1901+
if newVersions == nil || len(newVersions) < 10 {
19021902
// Somehow one of the versions didn't match the regexp or didn't
19031903
// have values in the capturing groups. In that case, fall back to
19041904
// an equality check.
@@ -1909,11 +1909,23 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData
19091909
}
19101910

19111911
oldAirflow := oldVersions[5]
1912-
oldAirflowMajorMinor := oldVersions[6]
1912+
oldAirflowMajor := oldVersions[6]
1913+
oldAirflowMajorMinor := oldVersions[6] + oldVersions[8]
19131914
newAirflow := newVersions[5]
1914-
newAirflowMajorMinor := newVersions[6]
1915+
newAirflowMajor := newVersions[6]
1916+
newAirflowMajorMinor := newVersions[6] + newVersions[8]
19151917
// Check Airflow versions.
1916-
if oldAirflow == oldAirflowMajorMinor || newAirflow == newAirflowMajorMinor {
1918+
if oldAirflow == oldAirflowMajor || newAirflow == newAirflowMajor {
1919+
// If one of the Airflow versions specifies only major version
1920+
// (like 1), we can only compare major versions.
1921+
eq, err := versionsEqual(oldAirflowMajor, newAirflowMajor)
1922+
if err != nil {
1923+
log.Printf("[WARN] Could not parse airflow version, %s", err)
1924+
}
1925+
if !eq {
1926+
return false
1927+
}
1928+
} else if oldAirflow == oldAirflowMajorMinor || newAirflow == newAirflowMajorMinor {
19171929
// If one of the Airflow versions specifies only major and minor version
19181930
// (like 1.10), we can only compare major and minor versions.
19191931
eq, err := versionsEqual(oldAirflowMajorMinor, newAirflowMajorMinor)

google/resource_composer_environment_test.go

+12-68
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ func TestComposerImageVersionDiffSuppress(t *testing.T) {
3838
{"preview matches", "composer-1.17.0-preview.0-airflow-2.0.1", "composer-1.17.0-preview.0-airflow-2.0.1", true},
3939
{"old latest", "composer-latest-airflow-1.10.0", "composer-1.4.1-airflow-1.10.0", true},
4040
{"new latest", "composer-1.4.1-airflow-1.10.0", "composer-latest-airflow-1.10.0", true},
41-
{"composer alias equivalent", "composer-1.4.0-airflow-1.10.0", "composer-1-airflow-1.10", true},
42-
{"composer alias different", "composer-1.4.0-airflow-2.1.4", "composer-2-airflow-2.2", false},
41+
{"composer major alias equivalent", "composer-1.4.0-airflow-1.10.0", "composer-1-airflow-1.10", true},
42+
{"composer major alias different", "composer-1.4.0-airflow-2.1.4", "composer-2-airflow-2.2", false},
4343
{"composer different", "composer-1.4.0-airflow-1.10.0", "composer-1.4.1-airflow-1.10.0", false},
44-
{"airflow alias equivalent", "composer-1.4.0-airflow-1.10.0", "composer-1.4.0-airflow-1.10", true},
45-
{"airflow alias different", "composer-1.4.0-airflow-2.1.4", "composer-1.4.0-airflow-2.2", false},
44+
{"airflow major alias equivalent", "composer-1.4.0-airflow-1.10.0", "composer-1.4.0-airflow-1", true},
45+
{"airflow major alias different", "composer-1.4.0-airflow-1.10.0", "composer-1.4.0-airflow-2", false},
46+
{"airflow major.minor alias equivalent", "composer-1.4.0-airflow-1.10.0", "composer-1.4.0-airflow-1.10", true},
47+
{"airflow major.minor alias different", "composer-1.4.0-airflow-2.1.4", "composer-1.4.0-airflow-2.2", false},
4648
{"airflow different", "composer-1.4.0-airflow-1.10.0", "composer-1.4.0-airflow-1.9.0", false},
4749
}
4850

@@ -1099,15 +1101,6 @@ resource "google_compute_subnetwork" "test" {
10991101

11001102
func testAccComposerEnvironment_composerV2(envName, network, subnetwork string) string {
11011103
return fmt.Sprintf(`
1102-
data "google_composer_image_versions" "all" {
1103-
}
1104-
1105-
locals {
1106-
composer_version = "2" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1107-
airflow_version = "2" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1108-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1109-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1110-
}
11111104
resource "google_composer_environment" "test" {
11121105
name = "%s"
11131106
region = "us-east1"
@@ -1122,7 +1115,7 @@ resource "google_composer_environment" "test" {
11221115
}
11231116
11241117
software_config {
1125-
image_version = local.matching_images[0]
1118+
image_version = "composer-2-airflow-2"
11261119
}
11271120
11281121
workloads_config {
@@ -1174,15 +1167,6 @@ resource "google_compute_subnetwork" "test" {
11741167

11751168
func testAccComposerEnvironment_composerV2PrivateServiceConnect(envName, network, subnetwork string) string {
11761169
return fmt.Sprintf(`
1177-
data "google_composer_image_versions" "all" {
1178-
}
1179-
1180-
locals {
1181-
composer_version = "2" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1182-
airflow_version = "2" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1183-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1184-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1185-
}
11861170
resource "google_composer_environment" "test" {
11871171
name = "%s"
11881172
region = "us-central1"
@@ -1194,7 +1178,7 @@ resource "google_composer_environment" "test" {
11941178
}
11951179
11961180
software_config {
1197-
image_version = local.matching_images[0]
1181+
image_version = "composer-2-airflow-2"
11981182
}
11991183
private_environment_config {
12001184
cloud_composer_connection_subnetwork = google_compute_subnetwork.test.self_link
@@ -1221,16 +1205,6 @@ resource "google_compute_subnetwork" "test" {
12211205

12221206
func testAccComposerEnvironment_update(name, network, subnetwork string) string {
12231207
return fmt.Sprintf(`
1224-
data "google_composer_image_versions" "all" {
1225-
}
1226-
1227-
locals {
1228-
composer_version = "1" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1229-
airflow_version = "1" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1230-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1231-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1232-
}
1233-
12341208
resource "google_composer_environment" "test" {
12351209
name = "%s"
12361210
region = "us-central1"
@@ -1249,7 +1223,7 @@ resource "google_composer_environment" "test" {
12491223
}
12501224
12511225
software_config {
1252-
image_version = local.matching_images[0]
1226+
image_version = "composer-1-airflow-1"
12531227
12541228
airflow_config_overrides = {
12551229
core-load_example = "True"
@@ -1289,15 +1263,6 @@ resource "google_compute_subnetwork" "test" {
12891263

12901264
func testAccComposerEnvironment_updateComposerV2(name, network, subnetwork string) string {
12911265
return fmt.Sprintf(`
1292-
data "google_composer_image_versions" "all" {
1293-
}
1294-
1295-
locals {
1296-
composer_version = "2" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1297-
airflow_version = "2" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1298-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1299-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1300-
}
13011266
resource "google_composer_environment" "test" {
13021267
name = "%s"
13031268
region = "us-east1"
@@ -1312,7 +1277,7 @@ resource "google_composer_environment" "test" {
13121277
}
13131278
13141279
software_config {
1315-
image_version = local.matching_images[0]
1280+
image_version = "composer-2-airflow-2"
13161281
}
13171282
13181283
workloads_config {
@@ -1411,16 +1376,6 @@ resource "google_project_iam_member" "composer-worker" {
14111376

14121377
func testAccComposerEnvironment_softwareCfg(name, network, subnetwork string) string {
14131378
return fmt.Sprintf(`
1414-
data "google_composer_image_versions" "all" {
1415-
}
1416-
1417-
locals {
1418-
composer_version = "1" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1419-
airflow_version = "1" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1420-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1421-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1422-
}
1423-
14241379
resource "google_composer_environment" "test" {
14251380
name = "%s"
14261381
region = "us-central1"
@@ -1431,7 +1386,7 @@ resource "google_composer_environment" "test" {
14311386
zone = "us-central1-a"
14321387
}
14331388
software_config {
1434-
image_version = local.matching_images[0]
1389+
image_version = "composer-1-airflow-1"
14351390
python_version = "3"
14361391
}
14371392
}
@@ -1490,17 +1445,6 @@ resource "google_compute_subnetwork" "test" {
14901445

14911446
func testAccComposerEnvironment_airflow2SoftwareCfg(name, network, subnetwork string) string {
14921447
return fmt.Sprintf(`
1493-
data "google_composer_image_versions" "all" {
1494-
}
1495-
1496-
locals {
1497-
composer_version = "1" # both composer_version and airflow_version are parts of regex, so if either 1 or 2 version is ok "[12]" should be used,
1498-
airflow_version = "2" # if sub-version is needed remember to escape "." with "\\." for example 1.2 should be written as "1\\.2"
1499-
reg_ex = join("", ["composer-", local.composer_version, "\\.[\\d+\\.]*\\d+.*-airflow-", local.airflow_version, "\\.[\\d+\\.]*\\d+"])
1500-
matching_images = [for v in data.google_composer_image_versions.all.image_versions[*].image_version_id: v if length(regexall(local.reg_ex, v)) > 0]
1501-
}
1502-
1503-
15041448
resource "google_composer_environment" "test" {
15051449
name = "%s"
15061450
region = "us-central1"
@@ -1511,7 +1455,7 @@ resource "google_composer_environment" "test" {
15111455
zone = "us-central1-a"
15121456
}
15131457
software_config {
1514-
image_version = local.matching_images[0]
1458+
image_version = "composer-1-airflow-2"
15151459
scheduler_count = 2
15161460
}
15171461
}

website/docs/r/composer_environment.html.markdown

+6-6
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ resource "google_composer_environment" "test" {
6060
6161
config {
6262
software_config {
63-
image_version = "composer-2-airflow-2.2.3"
63+
image_version = "composer-2-airflow-2"
6464
}
6565
}
6666
}
@@ -157,7 +157,7 @@ resource "google_composer_environment" "test" {
157157
config {
158158
159159
software_config {
160-
image_version = "composer-2-airflow-2.2.3"
160+
image_version = "composer-2-airflow-2"
161161
}
162162
163163
workloads_config {
@@ -451,11 +451,11 @@ The following arguments are supported:
451451

452452
The version of the software running in the environment. This encapsulates both the version of Cloud Composer
453453
functionality and the version of Apache Airflow. It must match the regular expression
454-
`composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+\.[0-9]+(\.[0-9]+)?)`.
454+
`composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+(\.[0-9]+(\.[0-9]+)?)?)`.
455455
The Cloud Composer portion of the image version is a full semantic version, or an alias in the form of major
456456
version number or 'latest'.
457457
The Apache Airflow portion of the image version is a full semantic version that points to one of the
458-
supported Apache Airflow versions, or an alias in the form of only major and minor versions specified.
458+
supported Apache Airflow versions, or an alias in the form of only major or major.minor versions specified.
459459
For more information about Cloud Composer images, see
460460
[Cloud Composer version list](https://cloud.google.com/composer/docs/concepts/versioning/composer-versions).
461461

@@ -765,11 +765,11 @@ The `software_config` block supports:
765765

766766
The version of the software running in the environment. This encapsulates both the version of Cloud Composer
767767
functionality and the version of Apache Airflow. It must match the regular expression
768-
`composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+\.[0-9]+(\.[0-9]+)?)`.
768+
`composer-([0-9]+(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-([0-9]+(\.[0-9]+(\.[0-9]+)?)?)`.
769769
The Cloud Composer portion of the image version is a full semantic version, or an alias in the form of major
770770
version number or 'latest'.
771771
The Apache Airflow portion of the image version is a full semantic version that points to one of the
772-
supported Apache Airflow versions, or an alias in the form of only major and minor versions specified.
772+
supported Apache Airflow versions, or an alias in the form of only major or major.minor versions specified.
773773
**Important**: You can only upgrade in-place between minor or patch versions of Cloud Composer or Apache
774774
Airflow. For example, you can upgrade your environment from `composer-1.16.x` to `composer-1.17.x`, or from
775775
`airflow-2.1.x` to `airflow-2.2.x`. You cannot upgrade between major Cloud Composer or Apache Airflow

0 commit comments

Comments
 (0)