diff --git a/build.gradle b/build.gradle index af970e26..bd939965 100644 --- a/build.gradle +++ b/build.gradle @@ -68,15 +68,17 @@ dependencies { implementation 'com.psddev:dari-util:3.3.607-xe0f27a' implementation 'com.google.guava:guava:31.1-jre' - implementation 'com.azure.resourcemanager:azure-resourcemanager:2.15.0' - implementation 'com.azure:azure-security-keyvault-certificates:4.3.2' - implementation 'com.azure:azure-data-tables:12.3.0' - implementation 'com.azure:azure-storage-queue:12.12.2' - implementation 'com.azure:azure-storage-file-share:12.12.2' - implementation 'com.azure:azure-storage-blob:12.16.1' - implementation 'com.azure:azure-security-keyvault-certificates:4.3.2' - implementation 'com.azure:azure-identity:1.5.1' - implementation 'com.azure:azure-core-http-okhttp:1.9.0' + implementation enforcedPlatform('com.azure:azure-sdk-bom:1.2.25') + implementation 'com.azure.resourcemanager:azure-resourcemanager:2.40.0' + implementation 'com.azure:azure-security-keyvault-certificates' + implementation 'com.azure:azure-security-keyvault-keys' + implementation 'com.azure:azure-security-keyvault-secrets' + implementation 'com.azure:azure-data-tables' + implementation 'com.azure:azure-storage-queue' + implementation 'com.azure:azure-storage-file-share' + implementation 'com.azure:azure-storage-blob' + implementation 'com.azure:azure-identity' + implementation 'com.azure:azure-core-http-okhttp' runtimeOnly 'com.nimbusds:oauth2-oidc-sdk:9.35' gyroDoclet 'gyro:gyro-doclet:1.0.0' diff --git a/examples/containerservice/kubernetes-cluster.gyro b/examples/containerservice/kubernetes-cluster.gyro index 0c7dacfa..feafeb43 100644 --- a/examples/containerservice/kubernetes-cluster.gyro +++ b/examples/containerservice/kubernetes-cluster.gyro @@ -84,7 +84,6 @@ azure::kubernetes-cluster kubernetes-cluster-example network-profile dns-service-ip: "10.0.0.10" - docker-bridge-cidr: "172.17.0.1/16" service-cidr: "10.0.0.0/16" load-balancer-sku: "Standard" outbound-type: "loadBalancer" diff --git a/examples/sql/sql.gyro b/examples/sql/sql.gyro index 763c2f54..53a9484d 100644 --- a/examples/sql/sql.gyro +++ b/examples/sql/sql.gyro @@ -148,7 +148,7 @@ azure::sql-failover-group failover-example database-ids: [$(azure::sql-database sql-database-example).id] sql-server: $(azure::sql-server sql-server-example) manual-read-and-write-policy: false - read-write-grace-period: 2 + read-write-grace-period: 60 partner-server-ids: [$(azure::sql-server sql-server-example-partner-server).id] read-only-policy-enabled: false end diff --git a/src/main/java/gyro/azure/cdn/CdnProfileResource.java b/src/main/java/gyro/azure/cdn/CdnProfileResource.java index f908dadb..2aa44830 100644 --- a/src/main/java/gyro/azure/cdn/CdnProfileResource.java +++ b/src/main/java/gyro/azure/cdn/CdnProfileResource.java @@ -106,7 +106,7 @@ public void setResourceGroup(ResourceGroupResource resourceGroup) { * The sku of the CDN Profile. */ @Required - @ValidStrings({ "Premium_Verizon", "Standard_Verizon", "Standard_Akamai" }) + @ValidStrings({"Premium_Verizon", "Standard_Verizon", "Standard_Akamai", "Standard_Microsoft"}) public String getSku() { return sku; } @@ -193,6 +193,8 @@ public void create(GyroUI ui, State state) { cdnProfile = withSku.withStandardVerizonSku().withTags(getTags()).create(); } else if ("Standard_Akamai".equalsIgnoreCase(getSku())) { cdnProfile = withSku.withStandardAkamaiSku().withTags(getTags()).create(); + } else if ("Standard_Microsoft".equalsIgnoreCase(getSku())) { + cdnProfile = withSku.withStandardMicrosoftSku().withTags(getTags()).create(); } copyFrom(cdnProfile); diff --git a/src/main/java/gyro/azure/compute/VirtualMachineResource.java b/src/main/java/gyro/azure/compute/VirtualMachineResource.java index 5b1bc9a5..c30af8cd 100644 --- a/src/main/java/gyro/azure/compute/VirtualMachineResource.java +++ b/src/main/java/gyro/azure/compute/VirtualMachineResource.java @@ -704,6 +704,7 @@ public void copyFrom(VirtualMachine virtualMachine) { PublicIpAddressResource.class, virtualMachine.getPrimaryPublicIPAddressId()) : null); setOsType(virtualMachine.osType().name()); + setStorageAccountTypeOsDisk(virtualMachine.osDiskStorageAccountType().toString()); setNetworkInterface( findById( @@ -737,7 +738,8 @@ public void copyFrom(VirtualMachine virtualMachine) { setDataDisks(dataDisks); - setEnableSystemManagedServiceIdentity(!ObjectUtils.isBlank(virtualMachine.systemAssignedManagedServiceIdentityPrincipalId())); + setEnableSystemManagedServiceIdentity( + !ObjectUtils.isBlank(virtualMachine.systemAssignedManagedServiceIdentityPrincipalId())); setSystemManagedServiceIdentityPrincipalId(virtualMachine.systemAssignedManagedServiceIdentityPrincipalId()); getIdentities().clear(); @@ -828,8 +830,9 @@ private WithCreate doVMFluentWorkflow(AzureResourceManager client) { } for (IdentityResource identity : getIdentities()) { - osConfiguredVMBuilder = osConfiguredVMBuilder.withExistingUserAssignedManagedServiceIdentity(client.identities() - .getById(identity.getId())); + osConfiguredVMBuilder = + osConfiguredVMBuilder.withExistingUserAssignedManagedServiceIdentity(client.identities() + .getById(identity.getId())); } return osConfiguredVMBuilder @@ -1017,7 +1020,8 @@ private WithFromImageCreateOptionsManaged configureLinuxAdmin(WithLinuxRootUsern * Fourth step in Virtual Machine Fluent workflow. Configures Admin User for ManagedOrUnmanaged Disk types * @return {@link WithFromImageCreateOptionsManagedOrUnmanaged} VM Definition object ready for data disk configurations */ - private WithFromImageCreateOptionsManagedOrUnmanaged configureLinuxAdmin(WithLinuxRootUsernameManagedOrUnmanaged vmImageTypeConfigured) { + private WithFromImageCreateOptionsManagedOrUnmanaged configureLinuxAdmin( + WithLinuxRootUsernameManagedOrUnmanaged vmImageTypeConfigured) { WithLinuxCreateManagedOrUnmanaged adminConfigured = null; WithLinuxRootPasswordOrPublicKeyManagedOrUnmanaged rootUserConfigured = vmImageTypeConfigured.withRootUsername( getAdminUserName()); @@ -1040,7 +1044,8 @@ private WithFromImageCreateOptionsManagedOrUnmanaged configureLinuxAdmin(WithLin * Fourth step in Virtual Machine Fluent workflow. Configures Admin User for Unmanaged Disk types * @return {@link WithFromImageCreateOptionsUnmanaged} VM Definition object ready for data disk configurations */ - private WithFromImageCreateOptionsUnmanaged configureLinuxAdmin(WithLinuxRootUsernameUnmanaged vmImageTypeConfigured) { + private WithFromImageCreateOptionsUnmanaged configureLinuxAdmin( + WithLinuxRootUsernameUnmanaged vmImageTypeConfigured) { WithLinuxCreateUnmanaged adminConfigured = null; WithLinuxRootPasswordOrPublicKeyUnmanaged rootUserConfigured = vmImageTypeConfigured.withRootUsername( getAdminUserName()); @@ -1168,7 +1173,8 @@ private WithWindowsCreateManaged configureWindowsAdmin(WithWindowsAdminUsernameM * Fourth step in Virtual Machine Fluent workflow. Configures Admin User for ManagedOrUnmanaged Disk types * @return {@link WithWindowsCreateManagedOrUnmanaged} VM Definition object ready for data disk configurations */ - private WithWindowsCreateManagedOrUnmanaged configureWindowsAdmin(WithWindowsAdminUsernameManagedOrUnmanaged vmImageTypeConfigured) { + private WithWindowsCreateManagedOrUnmanaged configureWindowsAdmin( + WithWindowsAdminUsernameManagedOrUnmanaged vmImageTypeConfigured) { return vmImageTypeConfigured.withAdminUsername(getAdminUserName()) .withAdminPassword(getAdminPassword()); } diff --git a/src/main/java/gyro/azure/containerservice/KubernetesClusterResource.java b/src/main/java/gyro/azure/containerservice/KubernetesClusterResource.java index 11ff1b1d..b7b2581e 100644 --- a/src/main/java/gyro/azure/containerservice/KubernetesClusterResource.java +++ b/src/main/java/gyro/azure/containerservice/KubernetesClusterResource.java @@ -105,7 +105,6 @@ * * network-profile * dns-service-ip: "10.0.0.10" - * docker-bridge-cidr: "172.17.0.1/16" * service-cidr: "10.0.0.0/16" * load-balancer-sku: "Standard" * outbound-type: "loadBalancer" @@ -592,9 +591,6 @@ public void create(GyroUI ui, State state) throws Exception { if (!StringUtils.isBlank(network.getPodCidr())) { withAttach = withAttach.withPodCidr(network.getPodCidr()); } - if (!StringUtils.isBlank(network.getDockerBridgeCidr())) { - withAttach = withAttach.withDockerBridgeCidr(network.getDockerBridgeCidr()); - } if (!StringUtils.isBlank(network.getServiceCidr())) { withAttach = withAttach.withServiceCidr(network.getServiceCidr()); diff --git a/src/main/java/gyro/azure/containerservice/NetworkProfile.java b/src/main/java/gyro/azure/containerservice/NetworkProfile.java index eab6072d..6bb5d354 100644 --- a/src/main/java/gyro/azure/containerservice/NetworkProfile.java +++ b/src/main/java/gyro/azure/containerservice/NetworkProfile.java @@ -32,7 +32,6 @@ public class NetworkProfile extends Diffable implements Copyable { private String dnsServiceIp; - private String dockerBridgeCidr; private String networkPlugin; private String networkMode; private String networkPolicy; @@ -55,18 +54,6 @@ public void setDnsServiceIp(String dnsServiceIp) { this.dnsServiceIp = dnsServiceIp; } - /** - * The docker bridge cidr for the network profile. - */ - @Updatable - public String getDockerBridgeCidr() { - return dockerBridgeCidr; - } - - public void setDockerBridgeCidr(String dockerBridgeCidr) { - this.dockerBridgeCidr = dockerBridgeCidr; - } - /** * The network plugin for the network profile. */ @@ -187,7 +174,6 @@ public void setServiceCidr(String serviceCidr) { @Override public void copyFrom(ContainerServiceNetworkProfile model) { setDnsServiceIp(model.dnsServiceIp()); - setDockerBridgeCidr(model.dockerBridgeCidr()); setNetworkPlugin(model.networkPlugin().toString()); setNetworkMode(model.networkMode() != null ? model.networkMode().toString() : null); setNetworkPolicy(model.networkPolicy() != null ? model.networkPolicy().toString() : null); @@ -243,10 +229,6 @@ protected ContainerServiceNetworkProfile toNetworkProfile() { networkProfile.withOutboundType(OutboundType.fromString(getOutboundType())); } - if (!StringUtils.isBlank(getDockerBridgeCidr())) { - networkProfile.withDockerBridgeCidr(getDockerBridgeCidr()); - } - if (!StringUtils.isBlank(getServiceCidr())) { networkProfile.withServiceCidr(getServiceCidr()); } diff --git a/src/main/java/gyro/azure/keyvault/KeyVaultCertificatePolicy.java b/src/main/java/gyro/azure/keyvault/KeyVaultCertificatePolicy.java index 6f8008d0..ebf5b13d 100644 --- a/src/main/java/gyro/azure/keyvault/KeyVaultCertificatePolicy.java +++ b/src/main/java/gyro/azure/keyvault/KeyVaultCertificatePolicy.java @@ -110,7 +110,7 @@ public void setSubject(String subject) { /** * The key type. */ - @ValidStrings({"RSA", "RSA-HSM", "EC", "EC-HSM"}) + // @ValidStrings({"RSA", "RSA-HSM", "EC", "EC-HSM"}) public String getKeyType() { return keyType; } @@ -193,7 +193,7 @@ public void setValidityInMonths(Integer validityInMonths) { /** * The key size. */ - @ValidNumbers({2048, 3072, 4096}) + @ValidNumbers({256, 384, 521}) public Integer getKeySize() { return keySize; } @@ -332,7 +332,7 @@ public void copyFrom(CertificatePolicy certificatePolicy) { @Override public String primaryKey() { - return ""; + return "policy"; } CertificatePolicy toCertificatePolicy() { diff --git a/src/main/java/gyro/azure/keyvault/KeyVaultKeyAttribute.java b/src/main/java/gyro/azure/keyvault/KeyVaultKeyAttribute.java index 7e032694..cc55231c 100644 --- a/src/main/java/gyro/azure/keyvault/KeyVaultKeyAttribute.java +++ b/src/main/java/gyro/azure/keyvault/KeyVaultKeyAttribute.java @@ -2,6 +2,8 @@ import java.time.OffsetDateTime; +import com.azure.security.keyvault.keys.models.CreateEcKeyOptions; +import com.azure.security.keyvault.keys.models.CreateKeyOptions; import com.azure.security.keyvault.keys.models.KeyProperties; import gyro.azure.Copyable; import gyro.core.resource.Diffable; @@ -91,11 +93,4 @@ public void copyFrom(KeyProperties properties) { setCreated(properties.getCreatedOn() != null ? properties.getCreatedOn().toString() : null); setUpdated(properties.getUpdatedOn() != null ? properties.getUpdatedOn().toString() : null); } - - KeyProperties toKeyProperties() { - return new KeyProperties() - .setEnabled(getEnabled()) - .setExpiresOn(getExpires() != null ? OffsetDateTime.parse(getExpires()) : null) - .setNotBefore(getNotBefore() != null ? OffsetDateTime.parse(getNotBefore()) : null); - } } diff --git a/src/main/java/gyro/azure/keyvault/KeyVaultKeyResource.java b/src/main/java/gyro/azure/keyvault/KeyVaultKeyResource.java index d4967809..82d7edbd 100644 --- a/src/main/java/gyro/azure/keyvault/KeyVaultKeyResource.java +++ b/src/main/java/gyro/azure/keyvault/KeyVaultKeyResource.java @@ -1,5 +1,6 @@ package gyro.azure.keyvault; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -7,11 +8,18 @@ import java.util.Set; import java.util.stream.Collectors; -import com.azure.core.util.ExpandableStringEnum; -import com.azure.resourcemanager.keyvault.models.Key; -import com.azure.resourcemanager.keyvault.models.Vault; +import com.azure.core.util.polling.SyncPoller; +import com.azure.security.keyvault.keys.KeyClient; +import com.azure.security.keyvault.keys.KeyClientBuilder; +import com.azure.security.keyvault.keys.models.CreateEcKeyOptions; +import com.azure.security.keyvault.keys.models.CreateKeyOptions; +import com.azure.security.keyvault.keys.models.CreateOctKeyOptions; +import com.azure.security.keyvault.keys.models.CreateRsaKeyOptions; +import com.azure.security.keyvault.keys.models.DeletedKey; +import com.azure.security.keyvault.keys.models.KeyCurveName; import com.azure.security.keyvault.keys.models.KeyOperation; import com.azure.security.keyvault.keys.models.KeyType; +import com.azure.security.keyvault.keys.models.KeyVaultKey; import gyro.azure.AzureResource; import gyro.azure.Copyable; import gyro.core.GyroUI; @@ -51,7 +59,7 @@ * end */ @Type("key-vault-key") -public class KeyVaultKeyResource extends AzureResource implements Copyable { +public class KeyVaultKeyResource extends AzureResource implements Copyable { private String name; private KeyVaultResource vault; @@ -59,6 +67,7 @@ public class KeyVaultKeyResource extends AzureResource implements Copyable private KeyVaultKeyAttribute attribute; private Integer size; private List operations; + private KeyCurveName curveName; private String version; private String id; private Map tags; @@ -66,6 +75,7 @@ public class KeyVaultKeyResource extends AzureResource implements Copyable /** * The name of the key. */ + @Id @Required public String getName() { return name; @@ -129,7 +139,6 @@ public void setSize(Integer size) { /** * A set of key operations that you want to enable. */ - @Updatable @ValidStrings({"encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey", "import"}) public List getOperations() { if (operations == null) { @@ -143,6 +152,19 @@ public void setOperations(List operations) { this.operations = operations; } + /** + * The elliptic curve name + */ + @Updatable + @ValidStrings({"P-256", "P-384", "P-521", "P-256K"}) + public KeyCurveName getCurveName() { + return curveName; + } + + public void setCurveName(KeyCurveName curveName) { + this.curveName = curveName; + } + /** * The current version of the key. */ @@ -158,7 +180,6 @@ public void setVersion(String version) { /** * The id of the key. */ - @Id @Output public String getId() { return id; @@ -185,17 +206,16 @@ public void setTags(Map tags) { } @Override - public void copyFrom(Key key) { - setTags(key.tags()); - - setOperations(key.getJsonWebKey().getKeyOps().stream().map(ExpandableStringEnum::toString).collect(Collectors.toList())); + public void copyFrom(KeyVaultKey key) { KeyVaultKeyAttribute attribute = newSubresource(KeyVaultKeyAttribute.class); - attribute.copyFrom(key.attributes()); + attribute.copyFrom(key.getProperties()); setAttribute(attribute); + setTags(key.getProperties().getTags()); + setVersion(key.getProperties().getVersion()); - setId(key.id()); - setName(key.name()); - setVersion(key.innerModel().getVersion()); + setOperations(key.getKeyOperations().stream().map(KeyOperation::toString).collect(Collectors.toList())); + setId(key.getId()); + setName(key.getName()); String vaultName = getId().split(".vault.azure.net")[0].split("://")[1]; setVault(findById(KeyVaultResource.class, vaultName)); @@ -203,9 +223,9 @@ public void copyFrom(Key key) { @Override public boolean refresh() { - Vault vault = getVault().getKeyVault(); + KeyClient keyClient = getKeyClient(); - Key key = vault.keys().getById(getId()); + KeyVaultKey key = keyClient.getKey(getName()); if (key == null) { return false; @@ -218,62 +238,130 @@ public boolean refresh() { @Override public void create(GyroUI ui, State state) throws Exception { - Vault vault = getVault().getKeyVault(); - - Key.DefinitionStages.WithCreate withCreate = vault.keys().define(getName()) - .withKeyTypeToCreate(KeyType.fromString(getType())); - - if (getSize() != null) { - withCreate = withCreate.withKeySize(getSize()); + KeyClient keyClient = getKeyClient(); + KeyVaultKey key = null; + + if (getType().equals("EC") || getType().equals("EC-HSM")) { + CreateEcKeyOptions createKeyOptions = new CreateEcKeyOptions(getName()); + + if (getAttribute() != null) { + createKeyOptions = createKeyOptions.setEnabled(getAttribute().getEnabled()); + createKeyOptions = createKeyOptions.setExpiresOn( + getAttribute().getExpires() != null ? OffsetDateTime.parse(getAttribute().getExpires()) : null); + createKeyOptions = createKeyOptions.setNotBefore( + getAttribute().getNotBefore() != null ? OffsetDateTime.parse(getAttribute().getNotBefore()) : null); + } + + if (getOperations() != null) { + createKeyOptions = createKeyOptions.setKeyOperations( + getOperations().stream().map(KeyOperation::fromString).toArray(KeyOperation[]::new)); + } + + if (getTags() != null) { + createKeyOptions = createKeyOptions.setTags(getTags()); + } + + if (getType().equals("EC-HSM")) { + createKeyOptions = createKeyOptions.setHardwareProtected(true); + } + + if (getCurveName() != null) { + createKeyOptions = createKeyOptions.setCurveName(getCurveName()); + } + + key = keyClient.createEcKey(createKeyOptions); + + } else if (getType().equals("RSA") || getType().equals("RSA-HSM")) { + CreateRsaKeyOptions createKeyOptions = new CreateRsaKeyOptions(getName()); + + if (getAttribute() != null) { + createKeyOptions = createKeyOptions.setEnabled(getAttribute().getEnabled()); + createKeyOptions = createKeyOptions.setExpiresOn( + getAttribute().getExpires() != null ? OffsetDateTime.parse(getAttribute().getExpires()) : null); + createKeyOptions = createKeyOptions.setNotBefore( + getAttribute().getNotBefore() != null ? OffsetDateTime.parse(getAttribute().getNotBefore()) : null); + } + + if (getOperations() != null) { + createKeyOptions = createKeyOptions.setKeyOperations( + getOperations().stream().map(KeyOperation::fromString).toArray(KeyOperation[]::new)); + } + + if (getTags() != null) { + createKeyOptions = createKeyOptions.setTags(getTags()); + } + + if (getType().equals("RSA-HSM")) { + createKeyOptions = createKeyOptions.setHardwareProtected(true); + } + + if (getSize() != null) { + createKeyOptions = createKeyOptions.setKeySize(getSize()); + } + + key = keyClient.createRsaKey(createKeyOptions); + + } else { + CreateOctKeyOptions createKeyOptions = new CreateOctKeyOptions(getName()); + + if (getAttribute() != null) { + createKeyOptions = createKeyOptions.setEnabled(getAttribute().getEnabled()); + createKeyOptions = createKeyOptions.setExpiresOn( + getAttribute().getExpires() != null ? OffsetDateTime.parse(getAttribute().getExpires()) : null); + createKeyOptions = createKeyOptions.setNotBefore( + getAttribute().getNotBefore() != null ? OffsetDateTime.parse(getAttribute().getNotBefore()) : null); + } + + if (getOperations() != null) { + createKeyOptions = createKeyOptions.setKeyOperations( + getOperations().stream().map(KeyOperation::fromString).toArray(KeyOperation[]::new)); + } + + if (getTags() != null) { + createKeyOptions = createKeyOptions.setTags(getTags()); + } + + if (getType().equals("OCT-HSM")) { + createKeyOptions = createKeyOptions.setHardwareProtected(true); + } + + key = keyClient.createOctKey(createKeyOptions); } - if (getAttribute() != null) { - withCreate = withCreate.withAttributes(getAttribute().toKeyProperties()); - } - - if (getOperations() != null) { - withCreate = withCreate.withKeyOperations(getOperations().stream() - .map(KeyOperation::fromString).collect(Collectors.toList())); - } - - if (getTags() != null) { - withCreate = withCreate.withTags(getTags()); - } - - Key key = withCreate.create(); - copyFrom(key); } @Override - public void update( - GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { - Vault vault = getVault().getKeyVault(); - - Key key = vault.keys().getById(getId()); + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + KeyClient keyClient = getKeyClient(); - Key.Update update = key.update(); + KeyVaultKey key = keyClient.getKey(getName()); if (changedFieldNames.contains("attribute")) { - update = update.withAttributes(getAttribute().toKeyProperties()); - } - - if (changedFieldNames.contains("operations")) { - update = update.withKeyOperations(getOperations().stream() - .map(KeyOperation::fromString).collect(Collectors.toList())); + key.getProperties().setEnabled(getAttribute().getEnabled()); + key.getProperties().setExpiresOn( + getAttribute().getExpires() != null ? OffsetDateTime.parse(getAttribute().getExpires()) : null); + key.getProperties().setNotBefore( + getAttribute().getNotBefore() != null ? OffsetDateTime.parse(getAttribute().getNotBefore()) : null); } if (changedFieldNames.contains("tags")) { - update = update.withTags(getTags()); + key.getProperties().setTags(getTags()); } - update.apply(); + keyClient.updateKeyProperties(key.getProperties()); } @Override public void delete(GyroUI ui, State state) throws Exception { - Vault vault = getVault().getKeyVault(); + KeyClient keyClient = getKeyClient(); + + SyncPoller deletedKeyPoller = keyClient.beginDeleteKey(getName()); + deletedKeyPoller.poll(); + deletedKeyPoller.waitForCompletion(); + } - vault.keys().deleteById(getId()); + public KeyClient getKeyClient() { + return new KeyClientBuilder().credential(getTokenCredential()).vaultUrl(getVault().getUrl()).buildClient(); } } diff --git a/src/main/java/gyro/azure/keyvault/KeyVaultResource.java b/src/main/java/gyro/azure/keyvault/KeyVaultResource.java index 39f58f7d..efe2edcd 100644 --- a/src/main/java/gyro/azure/keyvault/KeyVaultResource.java +++ b/src/main/java/gyro/azure/keyvault/KeyVaultResource.java @@ -24,6 +24,8 @@ import com.azure.core.management.Region; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.resourcemanager.keyvault.models.Sku; +import com.azure.resourcemanager.keyvault.models.SkuName; import com.azure.resourcemanager.keyvault.models.Vault; import gyro.azure.AzureResource; import gyro.azure.Copyable; @@ -181,6 +183,7 @@ public class KeyVaultResource extends AzureResource implements Copyable { private Boolean enableDiskEncryption; private Boolean enablePurgeVault; private Boolean enableSoftDelete; + private SkuName skuTier; private String id; private String url; private String location; @@ -324,6 +327,21 @@ public void setEnableSoftDelete(Boolean enableSoftDelete) { this.enableSoftDelete = enableSoftDelete; } + /** + * The SKU tier for the key vault. + */ + public SkuName getSkuTier() { + if (skuTier == null) { + skuTier = SkuName.STANDARD; + } + + return skuTier; + } + + public void setSkuTier(SkuName skuTier) { + this.skuTier = skuTier; + } + /** * The ID of the key vault. */ @@ -367,6 +385,7 @@ public void copyFrom(Vault vault) { setUrl(vault.vaultUri()); setResourceGroup(findById(ResourceGroupResource.class, vault.resourceGroupName())); setTags(vault.tags()); + setSkuTier(vault.sku().name()); getAccessPolicy().clear(); if (vault.accessPolicies() != null) { @@ -405,7 +424,8 @@ public void create(GyroUI ui, State state) throws Exception { Vault.DefinitionStages.WithCreate withCreate = client.vaults().define(getName()) .withRegion(Region.fromName(getRegion())) - .withExistingResourceGroup(getResourceGroup().getName()).withEmptyAccessPolicy(); + .withExistingResourceGroup(getResourceGroup().getName()).withEmptyAccessPolicy() + .withSku(getSkuTier()); if (!getAccessPolicy().isEmpty()) { for (KeyVaultAccessPolicy accessPolicy : getAccessPolicy()) { diff --git a/src/main/java/gyro/azure/keyvault/KeyVaultSecretResource.java b/src/main/java/gyro/azure/keyvault/KeyVaultSecretResource.java index e128c96c..4577339a 100644 --- a/src/main/java/gyro/azure/keyvault/KeyVaultSecretResource.java +++ b/src/main/java/gyro/azure/keyvault/KeyVaultSecretResource.java @@ -1,11 +1,16 @@ package gyro.azure.keyvault; +import java.time.OffsetDateTime; import java.util.HashMap; import java.util.Map; import java.util.Set; -import com.azure.resourcemanager.keyvault.models.Secret; -import com.azure.resourcemanager.keyvault.models.Vault; +import com.azure.core.util.polling.SyncPoller; +import com.azure.security.keyvault.secrets.SecretClient; +import com.azure.security.keyvault.secrets.SecretClientBuilder; +import com.azure.security.keyvault.secrets.models.DeletedSecret; +import com.azure.security.keyvault.secrets.models.KeyVaultSecret; +import com.azure.security.keyvault.secrets.models.SecretProperties; import gyro.azure.AzureResource; import gyro.azure.Copyable; import gyro.core.GyroUI; @@ -43,7 +48,7 @@ * end */ @Type("key-vault-secret") -public class KeyVaultSecretResource extends AzureResource implements Copyable { +public class KeyVaultSecretResource extends AzureResource implements Copyable { private String name; private KeyVaultResource vault; @@ -59,6 +64,7 @@ public class KeyVaultSecretResource extends AzureResource implements Copyable tags) { } @Override - public void copyFrom(Secret secret) { - setName(secret.name()); - setId(secret.id()); - setKid(secret.kid()); - setTags(secret.tags()); + public void copyFrom(KeyVaultSecret secret) { + setName(secret.getName()); + setId(secret.getId()); + setKid(secret.getProperties().getKeyId()); + setTags(secret.getProperties().getTags()); setValue(secret.getValue()); - setContentType(secret.contentType()); + setContentType(secret.getProperties().getContentType()); KeyVaultSecretAttribute attribute = newSubresource(KeyVaultSecretAttribute.class); - attribute.copyFrom(secret.attributes()); + attribute.copyFrom(secret.getProperties()); setAttribute(attribute); String vaultName = getId().split(".vault.azure.net")[0].split("://")[1]; @@ -190,9 +195,9 @@ public void copyFrom(Secret secret) { @Override public boolean refresh() { - Vault vault = getVault().getKeyVault(); + SecretClient client = getSecretClient(); - Secret secret = vault.secrets().getById(getId()); + KeyVaultSecret secret = client.getSecret(getName()); if (secret == null) { return false; @@ -205,57 +210,59 @@ public boolean refresh() { @Override public void create(GyroUI ui, State state) throws Exception { - Vault vault = getVault().getKeyVault(); + SecretClient client = getSecretClient(); - Secret.DefinitionStages.WithCreate withCreate = vault.secrets() - .define(getName()) - .withValue(getValue()); + KeyVaultSecret keyVaultSecret = new KeyVaultSecret(getName(), getValue()); - if (getAttribute() != null) { - withCreate = withCreate.withAttributes(getAttribute().toSecretProperties()); - } + SecretProperties secretProperties = getAttribute().toSecretProperties(); if (!StringUtils.isBlank(getContentType())) { - withCreate = withCreate.withContentType(getContentType()); + secretProperties = secretProperties.setContentType(getContentType()); } if (!getTags().isEmpty()) { - withCreate = withCreate.withTags(getTags()); + secretProperties = secretProperties.setTags(getTags()); } - Secret secret = withCreate.create(); + keyVaultSecret = keyVaultSecret.setProperties(secretProperties); - copyFrom(secret); + copyFrom(client.setSecret(keyVaultSecret)); } @Override - public void update( - GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { - Vault vault = getVault().getKeyVault(); - - Secret secret = vault.secrets().getById(getId()); + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + SecretClient client = getSecretClient(); - Secret.Update update = secret.update(); + KeyVaultSecret secret = client.getSecret(getName()); if (changedFieldNames.contains("attribute")) { - update = update.withAttributes(getAttribute().toSecretProperties()); + secret.getProperties().setEnabled(getAttribute().getEnabled()); + secret.getProperties().setExpiresOn( + getAttribute().getExpires() != null ? OffsetDateTime.parse(getAttribute().getExpires()) : null); + secret.getProperties().setNotBefore( + getAttribute().getNotBefore() != null ? OffsetDateTime.parse(getAttribute().getNotBefore()) : null); } if (changedFieldNames.contains("content-type")) { - update = update.withContentType(getContentType()); + secret.getProperties().setContentType(getContentType()); } if (changedFieldNames.contains("tags")) { - update = update.withTags(getTags()); + secret.getProperties().setTags(getTags()); } - update.apply(); + client.updateSecretProperties(secret.getProperties()); } @Override public void delete(GyroUI ui, State state) throws Exception { - Vault vault = getVault().getKeyVault(); + SecretClient client = getSecretClient(); + SyncPoller deletedSecretPoller = client.beginDeleteSecret(getName()); + deletedSecretPoller.poll(); + deletedSecretPoller.waitForCompletion(); + } - vault.secrets().deleteById(getId()); + public SecretClient getSecretClient() { + return new SecretClientBuilder().credential(getTokenCredential()).vaultUrl(getVault().getUrl()).buildClient(); } } diff --git a/src/main/java/gyro/azure/sql/SqlElasticPoolResource.java b/src/main/java/gyro/azure/sql/SqlElasticPoolResource.java index f0095378..11221b73 100644 --- a/src/main/java/gyro/azure/sql/SqlElasticPoolResource.java +++ b/src/main/java/gyro/azure/sql/SqlElasticPoolResource.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.resourcemanager.sql.models.SqlDatabase; import com.azure.resourcemanager.sql.models.SqlDatabaseStandardStorage; import com.azure.resourcemanager.sql.models.SqlElasticPool; import com.azure.resourcemanager.sql.models.SqlElasticPoolBasicEDTUs; @@ -153,7 +154,7 @@ public void setDtuReserved(String dtuReserved) { * The edition of the elastic pool. Valid values are ``Basic``, ``Premium``, or ``Standard`` */ @Required - @ValidStrings({ "Basic", "Premium", "Standard" }) + @ValidStrings({"Basic", "Premium", "Standard"}) @Updatable public String getEdition() { return edition; @@ -340,6 +341,8 @@ public void delete(GyroUI ui, State state) { AzureResourceManager client = createClient(); SqlElasticPool sqlElasticPool = getSqlElasticPool(client); + sqlElasticPool.listDatabases().stream().map(SqlDatabase::name).forEach(sqlElasticPool::removeDatabase); + sqlElasticPool.update(); if (sqlElasticPool != null) { sqlElasticPool.delete(); diff --git a/src/main/java/gyro/azure/sql/SqlFailoverGroupResource.java b/src/main/java/gyro/azure/sql/SqlFailoverGroupResource.java index f5bd9528..bc20471d 100644 --- a/src/main/java/gyro/azure/sql/SqlFailoverGroupResource.java +++ b/src/main/java/gyro/azure/sql/SqlFailoverGroupResource.java @@ -36,6 +36,7 @@ import gyro.core.resource.Resource; import gyro.core.resource.Updatable; import gyro.core.scope.State; +import gyro.core.validation.Min; import gyro.core.validation.Required; /** @@ -51,7 +52,7 @@ * database-ids: [$(azure::sql-database sql-database-example).id] * sql-server: $(azure::sql-server sql-server-example) * manual-read-and-write-policy: false - * read-write-grace-period: 2 + * read-write-grace-period: 60 * partner-server-ids: [$(azure::sql-server sql-server-example-partner-server).id] * read-only-policy-enabled: false * end @@ -158,6 +159,7 @@ public void setReadOnlyPolicyEnabled(Boolean readOnlyPolicyEnabled) { * Determines the grace period. Required when used with the automatic read and write policy. */ @Updatable + @Min(60) public Integer getReadWriteGracePeriod() { return readWriteGracePeriod; } diff --git a/src/main/java/gyro/azure/storage/CloudBlobContainerResource.java b/src/main/java/gyro/azure/storage/CloudBlobContainerResource.java index 4f52cf14..9b5d098d 100644 --- a/src/main/java/gyro/azure/storage/CloudBlobContainerResource.java +++ b/src/main/java/gyro/azure/storage/CloudBlobContainerResource.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; import com.azure.storage.blob.BlobContainerClient; import com.azure.storage.blob.BlobServiceClient; @@ -28,6 +29,7 @@ import gyro.azure.Copyable; import gyro.core.GyroUI; import gyro.core.Type; +import gyro.core.Wait; import gyro.core.resource.Id; import gyro.core.resource.Output; import gyro.core.resource.Resource; diff --git a/src/main/java/gyro/azure/storage/CloudQueueResource.java b/src/main/java/gyro/azure/storage/CloudQueueResource.java index 32ce7856..5bd1934b 100644 --- a/src/main/java/gyro/azure/storage/CloudQueueResource.java +++ b/src/main/java/gyro/azure/storage/CloudQueueResource.java @@ -129,15 +129,7 @@ private QueueClient cloudQueue() { .connectionString(getStorageAccount().getConnection()) .buildClient(); - QueueClient queueClient = client.getQueueClient(getName()); - - try { - queueClient.getProperties(); - } catch (QueueStorageException ex) { - queueClient = null; - } - - return queueClient; + return client.getQueueClient(getName()); } private QueueClient verifiedCloudQueue() { diff --git a/src/main/java/gyro/azure/storage/CloudTableResource.java b/src/main/java/gyro/azure/storage/CloudTableResource.java index d4bd6afe..1ab79be1 100644 --- a/src/main/java/gyro/azure/storage/CloudTableResource.java +++ b/src/main/java/gyro/azure/storage/CloudTableResource.java @@ -113,22 +113,14 @@ private TableClient cloudTable() { .connectionString(getStorageAccount().getConnection()) .buildClient(); - TableClient tableClient = client.getTableClient(getName()); - - try { - tableClient.getAccessPolicies(); - } catch (TableServiceException ex) { - tableClient = null; - } - - return tableClient; + return client.getTableClient(getName()); } private TableClient verifiedCloudTable() { TableClient tableClient = cloudTable(); try { - tableClient.getAccessPolicies(); + tableClient.getTableEndpoint(); } catch (TableServiceException ex) { tableClient = null; }