/*
* Copyright 2013-2017 the original author or authors.
*
* 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 org.cloudfoundry.operations.domains;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.organizations.AssociateOrganizationPrivateDomainRequest;
import org.cloudfoundry.client.v2.organizations.AssociateOrganizationPrivateDomainResponse;
import org.cloudfoundry.client.v2.organizations.ListOrganizationsRequest;
import org.cloudfoundry.client.v2.organizations.OrganizationResource;
import org.cloudfoundry.client.v2.organizations.RemoveOrganizationPrivateDomainRequest;
import org.cloudfoundry.client.v2.privatedomains.CreatePrivateDomainRequest;
import org.cloudfoundry.client.v2.privatedomains.CreatePrivateDomainResponse;
import org.cloudfoundry.client.v2.privatedomains.ListPrivateDomainsRequest;
import org.cloudfoundry.client.v2.privatedomains.PrivateDomainEntity;
import org.cloudfoundry.client.v2.privatedomains.PrivateDomainResource;
import org.cloudfoundry.client.v2.shareddomains.CreateSharedDomainResponse;
import org.cloudfoundry.client.v2.shareddomains.ListSharedDomainsRequest;
import org.cloudfoundry.client.v2.shareddomains.SharedDomainEntity;
import org.cloudfoundry.client.v2.shareddomains.SharedDomainResource;
import org.cloudfoundry.operations.util.OperationsLogging;
import org.cloudfoundry.routing.RoutingClient;
import org.cloudfoundry.routing.v1.routergroups.ListRouterGroupsResponse;
import org.cloudfoundry.util.ExceptionUtils;
import org.cloudfoundry.util.PaginationUtils;
import org.cloudfoundry.util.ResourceUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.NoSuchElementException;
import static org.cloudfoundry.util.tuple.TupleUtils.function;
public final class DefaultDomains implements Domains {
private final Mono<CloudFoundryClient> cloudFoundryClient;
private final Mono<RoutingClient> routingClient;
public DefaultDomains(Mono<CloudFoundryClient> cloudFoundryClient, Mono<RoutingClient> routingClient) {
this.cloudFoundryClient = cloudFoundryClient;
this.routingClient = routingClient;
}
@Override
public Mono<Void> create(CreateDomainRequest request) {
return this.cloudFoundryClient
.then(cloudFoundryClient -> Mono
.when(
Mono.just(cloudFoundryClient),
getOrganizationId(cloudFoundryClient, request.getOrganization())
))
.then(function((cloudFoundryClient, organizationId) -> requestCreateDomain(cloudFoundryClient, request.getDomain(), organizationId)))
.then()
.transform(OperationsLogging.log("Create Domain"))
.checkpoint();
}
@Override
public Mono<Void> createShared(CreateSharedDomainRequest request) {
if (request.getRouterGroup() == null) {
return this.cloudFoundryClient
.then(cloudFoundryClient -> requestCreateSharedDomain(cloudFoundryClient, request.getDomain(), null))
.then()
.transform(OperationsLogging.log("Create Shared Domain"))
.checkpoint();
} else {
return Mono.when(this.cloudFoundryClient, this.routingClient)
.then(function((cloudFoundryClient, routingClient) -> Mono
.when(
Mono.just(cloudFoundryClient),
getRouterGroupId(routingClient, request.getRouterGroup())
)))
.then(function((cloudFoundryClient, routerGroupId) -> requestCreateSharedDomain(cloudFoundryClient, request.getDomain(), routerGroupId)))
.then()
.transform(OperationsLogging.log("Create Shared Domain"))
.checkpoint();
}
}
@Override
public Flux<Domain> list() {
return this.cloudFoundryClient
.flatMapMany(cloudFoundryClient -> requestListPrivateDomains(cloudFoundryClient)
.map(DefaultDomains::toDomain)
.mergeWith(requestListSharedDomains(cloudFoundryClient)
.map(DefaultDomains::toDomain)))
.transform(OperationsLogging.log("List Domains"))
.checkpoint();
}
@Override
public Flux<RouterGroup> listRouterGroups() {
return this.routingClient
.flatMapMany(DefaultDomains::requestListRouterGroups)
.flatMapIterable(ListRouterGroupsResponse::getRouterGroups)
.map(DefaultDomains::toRouterGroup)
.transform(OperationsLogging.log("List Router Groups"))
.checkpoint();
}
@Override
public Mono<Void> share(ShareDomainRequest request) {
return this.cloudFoundryClient
.then(cloudFoundryClient -> Mono.when(
Mono.just(cloudFoundryClient),
getPrivateDomainId(cloudFoundryClient, request.getDomain()),
getOrganizationId(cloudFoundryClient, request.getOrganization())
))
.then(function(DefaultDomains::requestAssociateOrganizationPrivateDomainRequest))
.then()
.transform(OperationsLogging.log("Share Domain"))
.checkpoint();
}
@Override
public Mono<Void> unshare(UnshareDomainRequest request) {
return this.cloudFoundryClient
.then(cloudFoundryClient -> Mono.when(
Mono.just(cloudFoundryClient),
getPrivateDomainId(cloudFoundryClient, request.getDomain()),
getOrganizationId(cloudFoundryClient, request.getOrganization())
))
.then(function(DefaultDomains::requestRemoveOrganizationPrivateDomainRequest))
.transform(OperationsLogging.log("Unshare Domain"))
.checkpoint();
}
private static Mono<OrganizationResource> getOrganization(CloudFoundryClient cloudFoundryClient, String organization) {
return requestOrganizations(cloudFoundryClient, organization)
.single()
.onErrorResume(NoSuchElementException.class, t -> ExceptionUtils.illegalArgument("Organization %s does not exist", organization));
}
private static Mono<String> getOrganizationId(CloudFoundryClient cloudFoundryClient, String organization) {
return getOrganization(cloudFoundryClient, organization)
.map(ResourceUtils::getId);
}
private static Mono<PrivateDomainResource> getPrivateDomain(CloudFoundryClient cloudFoundryClient, String domain) {
return requestListPrivateDomains(cloudFoundryClient, domain)
.single()
.onErrorResume(NoSuchElementException.class, t -> ExceptionUtils.illegalArgument("Private domain %s does not exist", domain));
}
private static Mono<String> getPrivateDomainId(CloudFoundryClient cloudFoundryClient, String domain) {
return getPrivateDomain(cloudFoundryClient, domain)
.map(ResourceUtils::getId);
}
private static Mono<String> getRouterGroupId(RoutingClient routingClient, String routerGroup) {
return requestListRouterGroups(routingClient)
.flatMapIterable(ListRouterGroupsResponse::getRouterGroups)
.filter(group -> routerGroup.equals(group.getName()))
.single()
.map(org.cloudfoundry.routing.v1.routergroups.RouterGroup::getRouterGroupId);
}
private static Mono<AssociateOrganizationPrivateDomainResponse> requestAssociateOrganizationPrivateDomainRequest(CloudFoundryClient cloudFoundryClient, String domainId, String organizationId) {
return cloudFoundryClient.organizations()
.associatePrivateDomain(AssociateOrganizationPrivateDomainRequest.builder()
.organizationId(organizationId)
.privateDomainId(domainId)
.build());
}
private static Mono<CreatePrivateDomainResponse> requestCreateDomain(CloudFoundryClient cloudFoundryClient, String domain, String organizationId) {
return cloudFoundryClient.privateDomains()
.create(CreatePrivateDomainRequest.builder()
.name(domain)
.owningOrganizationId(organizationId)
.build());
}
private static Mono<CreateSharedDomainResponse> requestCreateSharedDomain(CloudFoundryClient cloudFoundryClient, String domain, String routerGroupId) {
return cloudFoundryClient.sharedDomains()
.create(org.cloudfoundry.client.v2.shareddomains.CreateSharedDomainRequest.builder()
.name(domain)
.routerGroupId(routerGroupId)
.build());
}
private static Flux<PrivateDomainResource> requestListPrivateDomains(CloudFoundryClient cloudFoundryClient, String domain) {
return PaginationUtils
.requestClientV2Resources(page -> cloudFoundryClient.privateDomains()
.list(ListPrivateDomainsRequest.builder()
.name(domain)
.page(page)
.build()));
}
private static Flux<PrivateDomainResource> requestListPrivateDomains(CloudFoundryClient cloudFoundryClient) {
return PaginationUtils
.requestClientV2Resources(page -> cloudFoundryClient.privateDomains()
.list(ListPrivateDomainsRequest.builder()
.page(page)
.build()));
}
private static Mono<ListRouterGroupsResponse> requestListRouterGroups(RoutingClient routingClient) {
return routingClient.routerGroups()
.list(org.cloudfoundry.routing.v1.routergroups.ListRouterGroupsRequest.builder()
.build());
}
private static Flux<SharedDomainResource> requestListSharedDomains(CloudFoundryClient cloudFoundryClient) {
return PaginationUtils
.requestClientV2Resources(page -> cloudFoundryClient.sharedDomains()
.list(ListSharedDomainsRequest.builder()
.page(page)
.build()));
}
private static Flux<OrganizationResource> requestOrganizations(CloudFoundryClient cloudFoundryClient, String organization) {
return PaginationUtils
.requestClientV2Resources(page -> cloudFoundryClient.organizations().list(
ListOrganizationsRequest.builder()
.name(organization)
.page(page)
.build()));
}
private static Mono<Void> requestRemoveOrganizationPrivateDomainRequest(CloudFoundryClient cloudFoundryClient, String domainId, String organizationId) {
return cloudFoundryClient.organizations()
.removePrivateDomain(RemoveOrganizationPrivateDomainRequest.builder()
.organizationId(organizationId)
.privateDomainId(domainId)
.build());
}
private static Domain toDomain(PrivateDomainResource resource) {
PrivateDomainEntity entity = ResourceUtils.getEntity(resource);
return Domain.builder()
.id(ResourceUtils.getId(resource))
.name(entity.getName())
.status(Status.OWNED)
.build();
}
private static Domain toDomain(SharedDomainResource resource) {
SharedDomainEntity entity = ResourceUtils.getEntity(resource);
return Domain.builder()
.id(ResourceUtils.getId(resource))
.name(entity.getName())
.status(Status.SHARED)
.type(entity.getRouterGroupType())
.build();
}
private static RouterGroup toRouterGroup(org.cloudfoundry.routing.v1.routergroups.RouterGroup group) {
return RouterGroup.builder()
.id(group.getRouterGroupId())
.name(group.getName())
.type(group.getType())
.build();
}
}