diff --git a/examples/communication/communication-service.gyro b/examples/communication/communication-service.gyro new file mode 100644 index 00000000..fe2c5e4e --- /dev/null +++ b/examples/communication/communication-service.gyro @@ -0,0 +1,54 @@ +azure::resource-group resource-group-example + name: "resource-group-example-test" + + tags: { + Name: "resource-group-example-test" + } +end + +azure::identity identity-example + name: "identity-example-test" + resource-group: $(azure::resource-group resource-group-example) + + tags: { + Name: "identity-example-test" + } +end + +azure::email-service email-service-example + resource-group: $(azure::resource-group resource-group-example) + name: "example-email-test" + data-location: "United States" + + tags: { + Name: "example-email-test" + } +end + +azure::domain domain-example + resource-group: $(azure::resource-group resource-group-example) + email-service: $(azure::email-service email-service-example) + domain-management: "CustomerManaged" + name: "cloud.brightspot.dev" + + tags: { + "example": "example" + } +end + +azure::communication-service service-example + resource-group: $(azure::resource-group resource-group-example) + name: "service-example-test" + data-location: "United States" + domains: [ + $(azure::domain domain-example) + ] + + identity + user-assigned-identity: [$(azure::identity identity-example)] + end + + tags: { + Name: "service-example-test" + } +end diff --git a/src/main/java/gyro/azure/communication/CommunicationServiceFinder.java b/src/main/java/gyro/azure/communication/CommunicationServiceFinder.java new file mode 100644 index 00000000..ecd5b08c --- /dev/null +++ b/src/main/java/gyro/azure/communication/CommunicationServiceFinder.java @@ -0,0 +1,105 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.azure.resourcemanager.communication.CommunicationManager; +import gyro.azure.AzureFinder; +import gyro.core.Type; + +/** + * Query communication service. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * service: $(external-query azure::communication-service {id: "/subscriptions/26c9ce65-e0ea-42e8-9e5e-22d5ccd58343/resourceGroups/resource-group-example-test/providers/Microsoft.Communication/communicationServices/service-example-test"}) + */ +@Type("communication-service") +public class CommunicationServiceFinder extends + AzureFinder { + + private String resourceGroup; + private String name; + private String id; + + /** + * The resource group of the service + */ + public String getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(String resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The communication service + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The ID of the service + */ + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + protected List findAllAzure( + CommunicationManager client) { + return client.communicationServices().list().stream().collect(Collectors.toList()); + } + + @Override + protected List findAzure( + CommunicationManager client, Map filters) { + + if (filters.containsKey("id")) { + return Collections.singletonList(client.communicationServices().getById(filters.get("id"))); + } + + if (filters.containsKey("resource-group")) { + if (filters.containsKey("name")) { + return Collections.singletonList(client.communicationServices() + .getByResourceGroup(filters.get("resource-group"), filters.get("name"))); + } + + return client.communicationServices().listByResourceGroup(filters.get("resource-group")).stream() + .collect(Collectors.toList()); + } + + return Collections.emptyList(); + } +} diff --git a/src/main/java/gyro/azure/communication/CommunicationServiceManagedServiceIdentity.java b/src/main/java/gyro/azure/communication/CommunicationServiceManagedServiceIdentity.java new file mode 100644 index 00000000..28aab845 --- /dev/null +++ b/src/main/java/gyro/azure/communication/CommunicationServiceManagedServiceIdentity.java @@ -0,0 +1,127 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import com.azure.resourcemanager.communication.models.ManagedServiceIdentity; +import com.azure.resourcemanager.communication.models.ManagedServiceIdentityType; +import com.azure.resourcemanager.communication.models.UserAssignedIdentity; +import gyro.azure.Copyable; +import gyro.azure.identity.IdentityResource; +import gyro.core.resource.Diffable; +import gyro.core.resource.Output; +import gyro.core.resource.Updatable; +import gyro.core.validation.CollectionMax; +import gyro.core.validation.Required; + +public class CommunicationServiceManagedServiceIdentity extends Diffable implements Copyable { + + private List userAssignedIdentity; + private String tenantId; + private String principalId; + private String type; + + /** + * The identity to be associated with the application gateway. + */ + @Required + public List getUserAssignedIdentity() { + if (userAssignedIdentity == null) { + userAssignedIdentity = new ArrayList<>(); + } + + return userAssignedIdentity; + } + + public void setUserAssignedIdentity(List userAssignedIdentity) { + this.userAssignedIdentity = userAssignedIdentity; + } + + /** + * The tenant id of the service identity. + */ + @Output + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + /** + * The principal id of the service identity. + */ + @Output + public String getPrincipalId() { + return principalId; + } + + public void setPrincipalId(String principalId) { + this.principalId = principalId; + } + + /** + * The type of the service identity. + */ + @Output + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public void copyFrom(ManagedServiceIdentity managedServiceIdentity) { + UUID tenantUuid = managedServiceIdentity.tenantId(); + setTenantId(tenantUuid == null ? null : tenantUuid.toString()); + + UUID principalUuid = managedServiceIdentity.principalId(); + setPrincipalId(principalUuid == null ? null : principalUuid.toString()); + + setUserAssignedIdentity( + managedServiceIdentity.userAssignedIdentities() != null ? managedServiceIdentity.userAssignedIdentities() + .keySet() + .stream() + .map(o -> findById(IdentityResource.class, o)) + .collect(Collectors.toList()) : null); + + setType(managedServiceIdentity.type().toString()); + } + + @Override + public String primaryKey() { + return ""; + } + + ManagedServiceIdentity toManagedServiceIdentity() { + UserAssignedIdentity userAssignedIdentity = new UserAssignedIdentity(); + Map map = new HashMap<>(); + + getUserAssignedIdentity().forEach(o -> map.put(o.getId(), userAssignedIdentity)); + return new ManagedServiceIdentity().withType(ManagedServiceIdentityType.USER_ASSIGNED) + .withUserAssignedIdentities(map); + } +} diff --git a/src/main/java/gyro/azure/communication/CommunicationServiceResource.java b/src/main/java/gyro/azure/communication/CommunicationServiceResource.java new file mode 100644 index 00000000..9848285d --- /dev/null +++ b/src/main/java/gyro/azure/communication/CommunicationServiceResource.java @@ -0,0 +1,307 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.azure.core.management.exception.ManagementException; +import com.azure.resourcemanager.communication.CommunicationManager; +import com.azure.resourcemanager.communication.fluent.models.CommunicationServiceResourceInner; +import gyro.azure.AzureResource; +import gyro.azure.Copyable; +import gyro.azure.resources.ResourceGroupResource; +import gyro.core.GyroUI; +import gyro.core.Type; +import gyro.core.resource.Id; +import gyro.core.resource.Output; +import gyro.core.resource.Resource; +import gyro.core.resource.Updatable; +import gyro.core.scope.State; +import gyro.core.validation.Required; + +/** + * Creates a communication service. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * azure::communication-service service-example + * resource-group: $(azure::resource-group resource-group-example) + * name: "service-example-test" + * data-location: "United States" + * domains: [ + * $(azure::domain domain-example) + * ] + * + * identity + * user-assigned-identity: [$(azure::identity identity-example)] + * end + * + * tags: { + * Name: "service-example-test" + * } + * end + */ +@Type("communication-service") +public class CommunicationServiceResource extends AzureResource + implements Copyable { + + private ResourceGroupResource resourceGroup; + private String name; + private CommunicationServiceManagedServiceIdentity identity; + private String dataLocation; + private List domains; + private Map tags; + + // Read-only + private String id; + private String hostName; + + /** + * The resource group in which to build the service + */ + @Required + public ResourceGroupResource getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(ResourceGroupResource resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The name of the service + */ + @Required + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The managed service identity for the communication service + */ + public CommunicationServiceManagedServiceIdentity getIdentity() { + return identity; + } + + public void setIdentity(CommunicationServiceManagedServiceIdentity identity) { + this.identity = identity; + } + + /** + * The tags for the service + */ + @Updatable + public Map getTags() { + if (tags == null) { + tags = new HashMap<>(); + } + + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + /** + * The location where the service stores its data at rest + */ + @Required + public String getDataLocation() { + return dataLocation; + } + + public void setDataLocation(String dataLocation) { + this.dataLocation = dataLocation; + } + + /** + * List of email Domain resources. These domain have to be verified for them to be connected ot the service. + */ + @Updatable + public List getDomains() { + if (domains == null) { + domains = new ArrayList<>(); + } + + return domains; + } + + public void setDomains(List domains) { + this.domains = domains; + } + + /** + * The FQDN of the service instance. + */ + @Output + public String getHostName() { + return hostName; + } + + public void setHostName(String hostName) { + this.hostName = hostName; + } + + /** + * The Id of the service + */ + @Output + @Id + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public void copyFrom(com.azure.resourcemanager.communication.models.CommunicationServiceResource model) { + setResourceGroup(findById(ResourceGroupResource.class, model.resourceGroupName())); + setName(model.name()); + setDataLocation(model.dataLocation()); + setHostName(model.hostname()); + setId(model.id()); + + getDomains().clear(); + if (model.linkedDomains() != null) { + getDomains().addAll(model.linkedDomains().stream().map(r -> findById(DomainResource.class, r)).collect( + Collectors.toList())); + } + + getTags().clear(); + if (model.tags() != null) { + getTags().putAll(model.tags()); + } + + setIdentity(null); + if (model.identity() != null) { + CommunicationServiceManagedServiceIdentity serviceIdentity = + newSubresource(CommunicationServiceManagedServiceIdentity.class); + serviceIdentity.copyFrom(model.identity()); + setIdentity(serviceIdentity); + } + } + + @Override + public boolean refresh() { + CommunicationManager client = createClient(CommunicationManager.class); + + com.azure.resourcemanager.communication.models.CommunicationServiceResource service = + client.communicationServices().getById(getId()); + + if (service == null) { + return false; + } + + copyFrom(service); + + return true; + } + + @Override + public void create(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + CommunicationServiceResourceInner service = new CommunicationServiceResourceInner(); + + if (getIdentity() != null) { + service.withIdentity(getIdentity().toManagedServiceIdentity()); + } + + if (!getTags().isEmpty()) { + service.withTags(getTags()); + } + + if (getDataLocation() != null) { + service.withDataLocation(getDataLocation()); + } + + service.withLocation("global"); + setId(client.serviceClient().getCommunicationServices() + .createOrUpdate(getResourceGroup().getName(), getName(), service).id()); + + state.save(); + + // Add domains in the update call + // If domains are not verified but are added to the create call, the api errors out and the service is not saved to the state + if (!getDomains().isEmpty()) { + service.withLinkedDomains(getDomains().stream().map(DomainResource::getId).collect(Collectors.toList())); + } + + try { + client.serviceClient().getCommunicationServices() + .createOrUpdate(getResourceGroup().getName(), getName(), service); + + } catch (ManagementException ex) { + if (ex.getMessage() != null && ex.getMessage().contains("InvalidLinkedDomains")) { + // Domains should be added but the API will error out in case the domains were not verified. + // The refresh will only keep added domains in the state + refresh(); + + } else { + throw ex; + } + } + } + + @Override + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + CommunicationServiceResourceInner service = client.serviceClient().getCommunicationServices() + .getByResourceGroup(getResourceGroup().getName(), getName()); + + service.withTags(getTags()); + service.withLinkedDomains(getDomains().stream().map(DomainResource::getId).collect(Collectors.toList())); + + try { + client.serviceClient().getCommunicationServices() + .createOrUpdate(getResourceGroup().getName(), getName(), service); + + } catch (ManagementException ex) { + if (ex.getMessage() != null && ex.getMessage().contains("InvalidLinkedDomains")) { + // Domains should be added but the API will error out in case the domains were not verified. + // The refresh will only keep added domains in the state + refresh(); + + } else { + throw ex; + } + } + } + + @Override + public void delete(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + client.communicationServices().deleteByResourceGroup(getResourceGroup().getName(), getName()); + } +} diff --git a/src/main/java/gyro/azure/communication/DomainDnsRecord.java b/src/main/java/gyro/azure/communication/DomainDnsRecord.java new file mode 100644 index 00000000..a43ef17d --- /dev/null +++ b/src/main/java/gyro/azure/communication/DomainDnsRecord.java @@ -0,0 +1,90 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import com.azure.resourcemanager.communication.models.DnsRecord; +import gyro.azure.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Output; + +public class DomainDnsRecord extends Diffable implements Copyable { + private String name; + private Integer ttl; + private String type; + private String value; + + /** + * The name of the dns record. + */ + @Output + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The ttl of the dns record. + */ + @Output + public Integer getTtl() { + return ttl; + } + + public void setTtl(Integer ttl) { + this.ttl = ttl; + } + + /** + * The type of the dns record. + */ + @Output + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * The value of the dns record. + */ + @Output + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public void copyFrom(DnsRecord model) { + setName(model.name()); + setTtl(model.ttl()); + setType(model.type()); + setValue(model.value()); + } + + @Override + public String primaryKey() { + return ""; + } +} diff --git a/src/main/java/gyro/azure/communication/DomainFinder.java b/src/main/java/gyro/azure/communication/DomainFinder.java new file mode 100644 index 00000000..a55cd2d3 --- /dev/null +++ b/src/main/java/gyro/azure/communication/DomainFinder.java @@ -0,0 +1,100 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.azure.resourcemanager.communication.CommunicationManager; +import gyro.azure.AzureFinder; +import gyro.core.GyroException; +import gyro.core.Type; + +/** + * Query domains. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * domain: $(external-query azure::domain {id: "/subscriptions/26c9ce65-e0ea-42e8-9e5e-22d5ccd58343/resourceGroups/resource-group-example-test/providers/Microsoft.Communication/emailServices/example-email-test/domains/cloud.brightspot.dev"}) + */ +@Type("domain") +public class DomainFinder extends + AzureFinder { + private String resourceGroup; + private String emailService; + private String id; + + /** + * The resource group of the service + */ + public String getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(String resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The email service + */ + public String getEmailService() { + return emailService; + } + + public void setEmailService(String emailService) { + this.emailService = emailService; + } + + /** + * The ID of the domain + */ + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + protected List findAllAzure( + CommunicationManager client) { + throw new GyroException("Cannot list All domains in subscription."); + } + + @Override + protected List findAzure(CommunicationManager client, + Map filters) { + if (filters.containsKey("id")) { + return Collections.singletonList(client.domains().getById(filters.get("id"))); + } + + if (filters.containsKey("resource-group") && filters.containsKey("email-service")) { + return client.domains() + .listByEmailServiceResource(filters.get("resource-group"), filters.get("email-service")).stream() + .collect(Collectors.toList()); + } + + throw new GyroException("If the `id` is not provided, both `resource-group` and `email-service` are required"); + } +} diff --git a/src/main/java/gyro/azure/communication/DomainResource.java b/src/main/java/gyro/azure/communication/DomainResource.java new file mode 100644 index 00000000..2b976f6c --- /dev/null +++ b/src/main/java/gyro/azure/communication/DomainResource.java @@ -0,0 +1,271 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.azure.resourcemanager.communication.CommunicationManager; +import com.azure.resourcemanager.communication.fluent.models.DomainResourceInner; +import com.azure.resourcemanager.communication.models.DomainManagement; +import gyro.azure.AzureResource; +import gyro.azure.Copyable; +import gyro.azure.resources.ResourceGroupResource; +import gyro.core.GyroUI; +import gyro.core.Type; +import gyro.core.resource.Id; +import gyro.core.resource.Output; +import gyro.core.resource.Resource; +import gyro.core.resource.Updatable; +import gyro.core.scope.State; +import gyro.core.validation.Required; +import gyro.core.validation.ValidStrings; + +/** + * Creates a Domain + * + * Example + * ------- + * + * .. code-block:: gyro + * + * azure::domain domain-example + * resource-group: $(azure::resource-group resource-group-example) + * email-service: $(azure::email-service email-service-example) + * domain-management: "CustomerManaged" + * name: "cloud.brightspot.dev" + * + * tags: { + * "example": "example" + * } + * end + */ +@Type("domain") +public class DomainResource extends AzureResource + implements Copyable { + + private ResourceGroupResource resourceGroup; + private EmailServiceResource emailService; + private String domainManagement; + private String name; + private Map tags; + + // Read-only + private String dataLocation; + private String id; + private VerificationRecords verificationRecords; + private VerificationStates verificationStates; + + /** + * The resource group in which to build the service + */ + @Required + public ResourceGroupResource getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(ResourceGroupResource resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The email service where the domain is + */ + @Required + public EmailServiceResource getEmailService() { + return emailService; + } + + public void setEmailService(EmailServiceResource emailService) { + this.emailService = emailService; + } + + /** + * The domain name + */ + @Required + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The domain management type. Defaults to ``CUSTOMER_MANAGED``. + */ + @ValidStrings({"AzureManaged", "CustomerManaged", "CustomerManagedInExchangeOnline"}) + public String getDomainManagement() { + if (domainManagement == null) { + domainManagement = DomainManagement.CUSTOMER_MANAGED.toString(); + } + + return domainManagement; + } + + public void setDomainManagement(String domainManagement) { + this.domainManagement = domainManagement; + } + + /** + * The tags associated with this resource + */ + @Updatable + public Map getTags() { + if (tags == null) { + tags = new HashMap<>(); + } + + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + /** + * The location where the email service stores its data at rest + */ + @Output + public String getDataLocation() { + return dataLocation; + } + + public void setDataLocation(String dataLocation) { + this.dataLocation = dataLocation; + } + + @Output + @Id + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + /** + * The verification records for this domain + */ + @Output + public VerificationRecords getVerificationRecords() { + return verificationRecords; + } + + public void setVerificationRecords(VerificationRecords verificationRecords) { + this.verificationRecords = verificationRecords; + } + + /** + * The verification status records for this domain + */ + @Output + public VerificationStates getVerificationStates() { + return verificationStates; + } + + public void setVerificationStates(VerificationStates verificationStates) { + this.verificationStates = verificationStates; + } + + @Override + public void copyFrom(com.azure.resourcemanager.communication.models.DomainResource model) { + setDomainManagement(model.domainManagement().toString()); + setId(model.id()); + setName(model.name()); + setDataLocation(model.dataLocation()); + + getTags().clear(); + if (model.tags() != null) { + getTags().putAll(model.tags()); + } + + setVerificationRecords(null); + if (model.verificationRecords() != null) { + VerificationRecords records = newSubresource(VerificationRecords.class); + records.copyFrom(model.verificationRecords()); + setVerificationRecords(records); + } + + setVerificationStates(null); + if (model.verificationStates() != null) { + VerificationStates states = newSubresource(VerificationStates.class); + states.copyFrom(model.verificationStates()); + setVerificationStates(states); + } + } + + @Override + public boolean refresh() { + CommunicationManager client = createClient(CommunicationManager.class); + + com.azure.resourcemanager.communication.models.DomainResource domain = client.domains().getById(getId()); + + if (domain == null) { + return false; + } + + copyFrom(domain); + + return true; + } + + @Override + public void create(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + DomainResourceInner service = new DomainResourceInner(); + service.withLocation("global"); + + if (!getTags().isEmpty()) { + service.withTags(getTags()); + } + + if (getDomainManagement() != null) { + service.withDomainManagement(DomainManagement.fromString(getDomainManagement())); + } + + service = client.serviceClient().getDomains() + .createOrUpdate(getResourceGroup().getName(), getEmailService().getName(), getName(), service); + + setId(service.id()); + } + + @Override + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + DomainResourceInner service = client.serviceClient().getDomains() + .get(getResourceGroup().getName(), getEmailService().getName(), getName()); + + service.withTags(getTags()); + + client.serviceClient().getDomains() + .createOrUpdate(getResourceGroup().getName(), getEmailService().getName(), getName(), service); + } + + @Override + public void delete(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + client.serviceClient().getDomains() + .delete(getResourceGroup().getName(), getEmailService().getName(), getName()); + } +} diff --git a/src/main/java/gyro/azure/communication/DomainVerificationStatusRecord.java b/src/main/java/gyro/azure/communication/DomainVerificationStatusRecord.java new file mode 100644 index 00000000..fa8dfcac --- /dev/null +++ b/src/main/java/gyro/azure/communication/DomainVerificationStatusRecord.java @@ -0,0 +1,66 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import com.azure.resourcemanager.communication.models.VerificationStatusRecord; +import gyro.azure.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Output; +import gyro.core.validation.ValidStrings; + +public class DomainVerificationStatusRecord extends Diffable implements Copyable { + + private String status; + private String errorCode; + + @ValidStrings({ + "NotStarted", + "VerificationRequested", + "VerificationInProgress", + "VerificationFailed", + "Verified", + "CancellationRequested" + }) + @Output + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Output + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(String errorCode) { + this.errorCode = errorCode; + } + + @Override + public void copyFrom(VerificationStatusRecord model) { + setStatus(model.status().toString()); + setErrorCode(model.errorCode()); + } + + @Override + public String primaryKey() { + return ""; + } +} diff --git a/src/main/java/gyro/azure/communication/EmailServiceFinder.java b/src/main/java/gyro/azure/communication/EmailServiceFinder.java new file mode 100644 index 00000000..8ea0f831 --- /dev/null +++ b/src/main/java/gyro/azure/communication/EmailServiceFinder.java @@ -0,0 +1,104 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.azure.resourcemanager.communication.CommunicationManager; +import gyro.azure.AzureFinder; +import gyro.core.Type; + +/** + * Query email service. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * service: $(external-query azure::email-service {id: "/subscriptions/26c9ce65-e0ea-42e8-9e5e-22d5ccd58343/resourceGroups/resource-group-example-test/providers/Microsoft.Communication/emailServices/example-email-test"}) + */ +@Type("email-service") +public class EmailServiceFinder extends + AzureFinder { + + private String id; + private String resourceGroup; + private String name; + + /** + * The Id of the service + */ + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + /** + * The resource group of the service + */ + public String getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(String resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The name of the service + */ + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + protected List findAllAzure( + CommunicationManager client) { + return client.emailServices().list().stream().collect(Collectors.toList()); + } + + @Override + protected List findAzure( + CommunicationManager client, Map filters) { + if (filters.containsKey("id")) { + return Collections.singletonList(client.emailServices().getById(filters.get("id"))); + } + + if (filters.containsKey("resource-group")) { + if (filters.containsKey("name")) { + return Collections.singletonList(client.emailServices().getByResourceGroup( + filters.get("resource-group"), filters.get("name"))); + } + + return client.emailServices().listByResourceGroup(filters.get("resource-group")).stream() + .collect(Collectors.toList()); + } + + return Collections.emptyList(); + } +} diff --git a/src/main/java/gyro/azure/communication/EmailServiceResource.java b/src/main/java/gyro/azure/communication/EmailServiceResource.java new file mode 100644 index 00000000..95cab9dc --- /dev/null +++ b/src/main/java/gyro/azure/communication/EmailServiceResource.java @@ -0,0 +1,197 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.azure.resourcemanager.communication.CommunicationManager; +import com.azure.resourcemanager.communication.fluent.models.EmailServiceResourceInner; +import gyro.azure.AzureResource; +import gyro.azure.Copyable; +import gyro.azure.resources.ResourceGroupResource; +import gyro.core.GyroUI; +import gyro.core.Type; +import gyro.core.resource.Id; +import gyro.core.resource.Output; +import gyro.core.resource.Resource; +import gyro.core.resource.Updatable; +import gyro.core.scope.State; +import gyro.core.validation.Required; + +/** + * Creates an email service. + * + * Example + * ------- + * + * .. code-block:: gyro + * + * azure::email-service email-service-example + * resource-group: $(azure::resource-group resource-group-example) + * name: "example-email-test" + * data-location: "United States" + * + * tags: { + * Name: "example-email-test" + * } + * end + */ +@Type("email-service") +public class EmailServiceResource extends AzureResource + implements Copyable { + + private ResourceGroupResource resourceGroup; + private String name; + private String dataLocation; + private Map tags; + + // Read-Only + private String id; + + /** + * The resource group in which to build the client + */ + @Required + public ResourceGroupResource getResourceGroup() { + return resourceGroup; + } + + public void setResourceGroup(ResourceGroupResource resourceGroup) { + this.resourceGroup = resourceGroup; + } + + /** + * The name of the email client + */ + @Required + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * The location where the email service stores its data at rest + */ + @Required + public String getDataLocation() { + return dataLocation; + } + + public void setDataLocation(String dataLocation) { + this.dataLocation = dataLocation; + } + + /** + * The tags associated to the email service + */ + @Updatable + public Map getTags() { + if (tags == null) { + tags = new HashMap<>(); + } + + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + /** + * The ID of the email service + */ + @Id + @Output + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public void copyFrom(com.azure.resourcemanager.communication.models.EmailServiceResource model) { + setId(model.id()); + setName(model.name()); + setDataLocation(model.dataLocation()); + + getTags().clear(); + if (model.tags() != null) { + getTags().putAll(model.tags()); + } + } + + @Override + public boolean refresh() { + CommunicationManager client = createClient(CommunicationManager.class); + + com.azure.resourcemanager.communication.models.EmailServiceResource service = client.emailServices() + .getById(getId()); + + if (service == null) { + return false; + } + + copyFrom(service); + + return true; + } + + @Override + public void create(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + EmailServiceResourceInner service = new EmailServiceResourceInner(); + service.withLocation("global"); + + if (getDataLocation() != null) { + service.withDataLocation(getDataLocation()); + } + + if (!getTags().isEmpty()) { + service.withTags(getTags()); + } + + setId(client.serviceClient().getEmailServices().createOrUpdate(getResourceGroup().getName(), getName(), service) + .id()); + } + + @Override + public void update(GyroUI ui, State state, Resource current, Set changedFieldNames) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + EmailServiceResourceInner service = client.serviceClient().getEmailServices() + .getByResourceGroup(getResourceGroup().getName(), getName()); + + service.withTags(getTags()); + + client.serviceClient().getEmailServices().createOrUpdate(getResourceGroup().getName(), getName(), service); + } + + @Override + public void delete(GyroUI ui, State state) throws Exception { + CommunicationManager client = createClient(CommunicationManager.class); + + client.serviceClient().getEmailServices().delete(getResourceGroup().getName(), getName()); + } +} diff --git a/src/main/java/gyro/azure/communication/VerificationRecords.java b/src/main/java/gyro/azure/communication/VerificationRecords.java new file mode 100644 index 00000000..a589d846 --- /dev/null +++ b/src/main/java/gyro/azure/communication/VerificationRecords.java @@ -0,0 +1,135 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import com.azure.resourcemanager.communication.models.DomainPropertiesVerificationRecords; +import gyro.azure.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Output; + +public class VerificationRecords extends Diffable implements Copyable { + + private DomainDnsRecord dkim; + private DomainDnsRecord spf; + private DomainDnsRecord dkim2; + private DomainDnsRecord dmarc; + private DomainDnsRecord domain; + + /** + * The dkim verification record. + */ + @Output + public DomainDnsRecord getDkim() { + return dkim; + } + + public void setDkim(DomainDnsRecord dkim) { + this.dkim = dkim; + } + + /** + * The spf verification record. + */ + @Output + public DomainDnsRecord getSpf() { + return spf; + } + + public void setSpf(DomainDnsRecord spf) { + this.spf = spf; + } + + /** + * The dkim2 verification record. + */ + @Output + public DomainDnsRecord getDkim2() { + return dkim2; + } + + public void setDkim2(DomainDnsRecord dkim2) { + this.dkim2 = dkim2; + } + + /** + * The dmarc verification record. + */ + @Output + public DomainDnsRecord getDmarc() { + return dmarc; + } + + public void setDmarc(DomainDnsRecord dmarc) { + this.dmarc = dmarc; + } + + /** + * The domain verification record. + */ + @Output + public DomainDnsRecord getDomain() { + return domain; + } + + public void setDomain(DomainDnsRecord domain) { + this.domain = domain; + } + + @Override + public void copyFrom(DomainPropertiesVerificationRecords model) { + setDkim(null); + if (model.dkim() != null) { + DomainDnsRecord dkimRecord = new DomainDnsRecord(); + dkimRecord.copyFrom(model.dkim()); + setDkim(dkimRecord); + } + + setSpf(null); + if (model.spf() != null) { + DomainDnsRecord spfRecord = new DomainDnsRecord(); + spfRecord.copyFrom(model.spf()); + setSpf(spfRecord); + } + + setDkim2(null); + if (model.dkim2() != null) { + DomainDnsRecord dkim2Record = new DomainDnsRecord(); + dkim2Record.copyFrom(model.dkim2()); + setDkim2(dkim2Record); + } + + setDmarc(null); + if (model.dmarc() != null) { + DomainDnsRecord dmarcRecord = new DomainDnsRecord(); + dmarcRecord.copyFrom(model.dmarc()); + setDmarc(dmarcRecord); + } + + setDomain(null); + if (model.domain() != null) { + DomainDnsRecord domainRecord = new DomainDnsRecord(); + domainRecord.copyFrom(model.domain()); + setDomain(domainRecord); + } + + } + + @Override + public String primaryKey() { + return ""; + } +} diff --git a/src/main/java/gyro/azure/communication/VerificationStates.java b/src/main/java/gyro/azure/communication/VerificationStates.java new file mode 100644 index 00000000..96bbb573 --- /dev/null +++ b/src/main/java/gyro/azure/communication/VerificationStates.java @@ -0,0 +1,135 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gyro.azure.communication; + +import com.azure.resourcemanager.communication.models.DomainPropertiesVerificationStates; +import gyro.azure.Copyable; +import gyro.core.resource.Diffable; +import gyro.core.resource.Output; + +public class VerificationStates extends Diffable implements Copyable { + + private DomainVerificationStatusRecord dkim; + private DomainVerificationStatusRecord spf; + private DomainVerificationStatusRecord dkim2; + private DomainVerificationStatusRecord dmarc; + private DomainVerificationStatusRecord domain; + + /** + * The dkim verification state record. + */ + @Output + public DomainVerificationStatusRecord getDkim() { + return dkim; + } + + public void setDkim(DomainVerificationStatusRecord dkim) { + this.dkim = dkim; + } + + /** + * The spf verification state record. + */ + @Output + public DomainVerificationStatusRecord getSpf() { + return spf; + } + + public void setSpf(DomainVerificationStatusRecord spf) { + this.spf = spf; + } + + /** + * The dkim2 verification state record. + */ + @Output + public DomainVerificationStatusRecord getDkim2() { + return dkim2; + } + + public void setDkim2(DomainVerificationStatusRecord dkim2) { + this.dkim2 = dkim2; + } + + /** + * The dmarc verification state record. + */ + @Output + public DomainVerificationStatusRecord getDmarc() { + return dmarc; + } + + public void setDmarc(DomainVerificationStatusRecord dmarc) { + this.dmarc = dmarc; + } + + /** + * The domain verification state record. + */ + @Output + public DomainVerificationStatusRecord getDomain() { + return domain; + } + + public void setDomain(DomainVerificationStatusRecord domain) { + this.domain = domain; + } + + @Override + public void copyFrom(DomainPropertiesVerificationStates model) { + setDkim(null); + if (model.dkim() != null) { + DomainVerificationStatusRecord dkimRecord = new DomainVerificationStatusRecord(); + dkimRecord.copyFrom(model.dkim()); + setDkim(dkimRecord); + } + + setSpf(null); + if (model.spf() != null) { + DomainVerificationStatusRecord spfRecord = new DomainVerificationStatusRecord(); + spfRecord.copyFrom(model.spf()); + setSpf(spfRecord); + } + + setDkim2(null); + if (model.dkim2() != null) { + DomainVerificationStatusRecord dkim2Record = new DomainVerificationStatusRecord(); + dkim2Record.copyFrom(model.dkim2()); + setDkim2(dkim2Record); + } + + setDmarc(null); + if (model.dmarc() != null) { + DomainVerificationStatusRecord dmarcRecord = new DomainVerificationStatusRecord(); + dmarcRecord.copyFrom(model.dmarc()); + setDmarc(dmarcRecord); + } + + setDomain(null); + if (model.domain() != null) { + DomainVerificationStatusRecord domainRecord = new DomainVerificationStatusRecord(); + domainRecord.copyFrom(model.domain()); + setDomain(domainRecord); + } + + } + + @Override + public String primaryKey() { + return ""; + } +} diff --git a/src/main/java/gyro/azure/communication/package-info.java b/src/main/java/gyro/azure/communication/package-info.java new file mode 100644 index 00000000..3702e6a1 --- /dev/null +++ b/src/main/java/gyro/azure/communication/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2024, Brightspot, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@DocGroup("Communication") +package gyro.azure.communication; + +import gyro.core.resource.DocGroup;