Skip to content

Commit b656433

Browse files
white0utlesv
authored andcommitted
KMS: Add set-primary-version to KMS snippets (GoogleCloudPlatform#821)
This also fixes failing integration tests. I've executed the tests on my personal project to confirm. Important changes are: * Each test execution creates a CryptoKey. * CryptoKeys are free, and creating a new CryptoKey fixes the caching problem of creating a key version, setting it as primary, then relying on the new primary in a subsequent call. * Destruction tests now destroy keys that they created rather than the primary key set for the execution. * Added the setPrimaryVersion snippet w/ tests.
1 parent bd53b6c commit b656433

File tree

3 files changed

+89
-28
lines changed

3 files changed

+89
-28
lines changed

kms/src/main/java/com/example/SnippetCommands.java

+26-15
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ public void run() throws IOException {
109109
}
110110
}
111111

112+
public static class SetPrimaryVersionCommand extends KeyVersionArgs implements Command {
113+
114+
public void run() throws IOException {
115+
Snippets.setPrimaryVersion(projectId, locationId, keyRingId, cryptoKeyId, version);
116+
}
117+
}
118+
112119
public static class GetKeyRingPolicyCommand extends KeyRingArgs implements Command {
113120
public void run() throws IOException {
114121
Snippets.getKeyRingPolicy(projectId, locationId, keyRingId);
@@ -124,12 +131,12 @@ public void run() throws IOException {
124131
public static class AddMemberToKeyRingPolicyCommand extends KeyRingArgs implements Command {
125132
@Argument(metaVar = "member", required = true, index = 1,
126133
usage = "The member to add.\n"
127-
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
128-
+ "for valid values.")
134+
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
135+
+ "for valid values.")
129136
String member;
130137
@Argument(metaVar = "role", required = true, index = 2,
131138
usage = "The role for the member.\n"
132-
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
139+
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
133140
String role;
134141

135142
public void run() throws IOException {
@@ -140,28 +147,29 @@ public void run() throws IOException {
140147
public static class AddMemberToCryptoKeyPolicyCommand extends KeyArgs implements Command {
141148
@Argument(metaVar = "member", required = true, index = 2,
142149
usage = "The member to add.\n"
143-
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
144-
+ "for valid values.")
150+
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
151+
+ "for valid values.")
145152
String member;
146153
@Argument(metaVar = "role", required = true, index = 3,
147154
usage = "The role for the member.\n"
148-
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
155+
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
149156
String role;
150157

151158
public void run() throws IOException {
152-
Snippets.addMemberToCryptoKeyPolicy(projectId, locationId, keyRingId, cryptoKeyId, member, role);
159+
Snippets
160+
.addMemberToCryptoKeyPolicy(projectId, locationId, keyRingId, cryptoKeyId, member, role);
153161
}
154162
}
155163

156164
public static class RemoveMemberFromKeyRingPolicyCommand extends KeyRingArgs implements Command {
157165
@Argument(metaVar = "member", required = true, index = 1,
158166
usage = "The member to add.\n"
159-
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
160-
+ "for valid values.")
167+
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
168+
+ "for valid values.")
161169
String member;
162170
@Argument(metaVar = "role", required = true, index = 2,
163171
usage = "The role for the member.\n"
164-
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
172+
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
165173
String role;
166174

167175
public void run() throws IOException {
@@ -172,16 +180,18 @@ public void run() throws IOException {
172180
public static class RemoveMemberFromCryptoKeyPolicyCommand extends KeyArgs implements Command {
173181
@Argument(metaVar = "member", required = true, index = 2,
174182
usage = "The member to add.\n"
175-
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
176-
+ "for valid values.")
183+
+ "See https://g.co/cloud/kms/docs/reference/rest/v1/Policy#binding "
184+
+ "for valid values.")
177185
String member;
178186
@Argument(metaVar = "role", required = true, index = 3,
179187
usage = "The role for the member.\n"
180-
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
188+
+ "See https://g.co/cloud/iam/docs/understanding-roles for valid values.")
181189
String role;
182190

183191
public void run() throws IOException {
184-
Snippets.removeMemberFromCryptoKeyPolicy(projectId, locationId, keyRingId, cryptoKeyId, member, role);
192+
Snippets
193+
.removeMemberFromCryptoKeyPolicy(projectId, locationId, keyRingId, cryptoKeyId, member,
194+
role);
185195
}
186196
}
187197

@@ -198,13 +208,14 @@ public void run() throws IOException {
198208
@SubCommand(name = "destroyCryptoKeyVersion", impl = DestroyCryptoKeyVersionCommand.class),
199209
@SubCommand(name = "getKeyRingPolicy", impl = GetKeyRingPolicyCommand.class),
200210
@SubCommand(name = "getCryptoKeyPolicy", impl = GetCryptoKeyPolicyCommand.class),
211+
@SubCommand(name = "setPrimaryVersion", impl = SetPrimaryVersionCommand.class),
201212
@SubCommand(name = "addMemberToKeyRingPolicy", impl = AddMemberToKeyRingPolicyCommand.class),
202213
@SubCommand(name = "addMemberToCryptoKeyPolicy",
203214
impl = AddMemberToCryptoKeyPolicyCommand.class),
204215
@SubCommand(name = "removeMemberFromKeyRingPolicy",
205216
impl = RemoveMemberFromKeyRingPolicyCommand.class),
206217
@SubCommand(name = "removeMemberFromCryptoKeyPolicy",
207218
impl = RemoveMemberFromCryptoKeyPolicyCommand.class)
208-
})
219+
})
209220
Command command;
210221
}

kms/src/main/java/com/example/Snippets.java

+23
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.api.client.json.JsonFactory;
2121
import com.google.api.client.json.jackson2.JacksonFactory;
2222
import com.google.api.services.cloudkms.v1.CloudKMS;
23+
import com.google.api.services.cloudkms.v1.CloudKMS.Projects.Locations.KeyRings.CryptoKeys.UpdatePrimaryVersion;
2324
import com.google.api.services.cloudkms.v1.CloudKMSScopes;
2425
import com.google.api.services.cloudkms.v1.model.Binding;
2526
import com.google.api.services.cloudkms.v1.model.CryptoKey;
@@ -31,6 +32,7 @@
3132
import com.google.api.services.cloudkms.v1.model.ListKeyRingsResponse;
3233
import com.google.api.services.cloudkms.v1.model.Policy;
3334
import com.google.api.services.cloudkms.v1.model.SetIamPolicyRequest;
35+
import com.google.api.services.cloudkms.v1.model.UpdateCryptoKeyPrimaryVersionRequest;
3436
import java.io.IOException;
3537
import java.util.Collections;
3638
import java.util.List;
@@ -525,6 +527,27 @@ public static void listCryptoKeyVersions(
525527
}
526528
}
527529

530+
/**
531+
* Sets a version as the primary version for a crypto key.
532+
*/
533+
public static void setPrimaryVersion(String projectId, String locationId, String keyRingId,
534+
String cryptoKeyId, String versionId) throws IOException {
535+
// Create the Cloud KMS client.
536+
CloudKMS kms = createAuthorizedClient();
537+
538+
// Resource name of the key version.
539+
String resourceName = String
540+
.format("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s",
541+
projectId, locationId, keyRingId, cryptoKeyId);
542+
543+
CryptoKey key = kms.projects().locations().keyRings().cryptoKeys()
544+
.updatePrimaryVersion(resourceName,
545+
new UpdateCryptoKeyPrimaryVersionRequest().setCryptoKeyVersionId(versionId)).execute();
546+
547+
System.out.println(key);
548+
549+
}
550+
528551

529552
public static void main(String[] args) throws IOException, CmdLineException {
530553
SnippetCommands commands = new SnippetCommands();

kms/src/test/java/com/example/SnippetsIT.java

+40-13
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
import com.google.api.client.googleapis.json.GoogleJsonError;
2121
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
22-
22+
import java.io.ByteArrayOutputStream;
23+
import java.io.PrintStream;
24+
import java.util.UUID;
25+
import java.util.regex.Matcher;
26+
import java.util.regex.Pattern;
2327
import org.junit.After;
2428
import org.junit.AfterClass;
2529
import org.junit.Before;
@@ -28,11 +32,6 @@
2832
import org.junit.runner.RunWith;
2933
import org.junit.runners.JUnit4;
3034

31-
import java.io.ByteArrayOutputStream;
32-
import java.io.PrintStream;
33-
import java.util.regex.Matcher;
34-
import java.util.regex.Pattern;
35-
3635
/**
3736
* Integration (system) tests for {@link Snippets}.
3837
*/
@@ -43,7 +42,7 @@ public class SnippetsIT {
4342
static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
4443
static final String LOCATION_ID = "global";
4544
static final String KEY_RING_ID = "test-snippets-key-ring";
46-
static final String CRYPTO_KEY_ID = "test-snippets-crypto-key";
45+
static final String CRYPTO_KEY_ID = UUID.randomUUID().toString();
4746
static final String TEST_USER = "serviceAccount:"
4847
+ "131304031188-compute@developer.gserviceaccount.com";
4948
static final String TEST_ROLE = "roles/viewer";
@@ -64,7 +63,7 @@ public static void setUpClass() throws Exception {
6463
// Since you can't delete keyrings & cryptokeys atm, these tests assume they already exist.
6564
// Use the snippets functions to create them.
6665
try {
67-
Snippets.createKeyRing(PROJECT_ID,LOCATION_ID, KEY_RING_ID);
66+
Snippets.createKeyRing(PROJECT_ID, LOCATION_ID, KEY_RING_ID);
6867

6968
// Since there's no way to delete keyrings atm, have two branches - one for the first time the
7069
// test is run, one for after the key already exists
@@ -90,6 +89,17 @@ public static void setUpClass() throws Exception {
9089
assertThat(error.getMessage()).contains(String.format(
9190
"keyRings/%s/cryptoKeys/%s", KEY_RING_ID, CRYPTO_KEY_ID));
9291
}
92+
93+
// Create a CryptoKeyVersion and set it as primary.
94+
Snippets.createCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
95+
Matcher matcher = Pattern.compile(
96+
".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
97+
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
98+
assertTrue(matcher.matches());
99+
100+
String primaryVersion = matcher.group(1);
101+
102+
Snippets.setPrimaryVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID, primaryVersion);
93103
}
94104

95105
/**
@@ -121,7 +131,8 @@ public static void tearDownClass() throws Exception {
121131
}
122132

123133
String version = matcher.group(1);
124-
Snippets.destroyCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
134+
Snippets
135+
.destroyCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
125136
}
126137
}
127138

@@ -130,8 +141,6 @@ public void setUp() throws Exception {
130141
bout = new ByteArrayOutputStream();
131142
out = new PrintStream(bout);
132143
System.setOut(out);
133-
134-
Snippets.createCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
135144
}
136145

137146
@After
@@ -165,7 +174,7 @@ public void listCryptoKeyVersions_printsVersions() throws Exception {
165174

166175
@Test
167176
public void disableCryptoKeyVersion_disables() throws Exception {
168-
Snippets.listCryptoKeyVersions(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
177+
Snippets.createCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
169178

170179
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
171180
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
@@ -180,7 +189,7 @@ public void disableCryptoKeyVersion_disables() throws Exception {
180189

181190
@Test
182191
public void destroyCryptoKeyVersion_destroys() throws Exception {
183-
Snippets.listCryptoKeyVersions(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
192+
Snippets.createCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
184193

185194
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
186195
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
@@ -195,6 +204,24 @@ public void destroyCryptoKeyVersion_destroys() throws Exception {
195204
KEY_RING_ID, CRYPTO_KEY_ID, version));
196205
}
197206

207+
@Test
208+
public void setPrimaryVersion_createKeyAndSetPrimaryVersion() throws Exception {
209+
// We can't test that setPrimaryVersion actually took effect via a list call because of
210+
// caching. So we test that the call was successful.
211+
Snippets.createCryptoKeyVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID);
212+
213+
Matcher matcher = Pattern.compile(".*cryptoKeyVersions/(\\d+)\",\"state\":\"ENABLED\".*",
214+
Pattern.DOTALL | Pattern.MULTILINE).matcher(bout.toString().trim());
215+
assertTrue(matcher.matches());
216+
217+
String version = matcher.group(1);
218+
219+
Snippets.setPrimaryVersion(PROJECT_ID, LOCATION_ID, KEY_RING_ID, CRYPTO_KEY_ID, version);
220+
assertThat(bout.toString()).containsMatch(String.format(
221+
"primary.*keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s",
222+
KEY_RING_ID, CRYPTO_KEY_ID, version));
223+
}
224+
198225
@Test
199226
public void addAndRemoveMemberToCryptoKeyPolicy_addsDisplaysAndRemoves() throws Exception {
200227
// Make sure the policy doesn't already have our test user

0 commit comments

Comments
 (0)