Java tutorial
/* * <!-- * * Copyright (C) 2015 Orange * 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 com.orange.cloud.servicebroker.filter.securitygroups.filter; import com.orange.cloud.servicebroker.filter.core.filters.CreateServiceInstanceBindingPostFilter; import com.orange.cloud.servicebroker.filter.core.filters.ServiceBrokerPostFilter; import com.orange.cloud.servicebroker.filter.securitygroups.domain.Destination; import com.orange.cloud.servicebroker.filter.securitygroups.domain.TrustedDestinationSpecification; import lombok.extern.slf4j.Slf4j; import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.client.v2.applications.ApplicationEntity; import org.cloudfoundry.client.v2.applications.GetApplicationRequest; import org.cloudfoundry.client.v2.applications.GetApplicationResponse; import org.cloudfoundry.client.v2.securitygroups.CreateSecurityGroupRequest; import org.cloudfoundry.client.v2.securitygroups.Protocol; import org.cloudfoundry.client.v2.securitygroups.RuleEntity; import org.cloudfoundry.client.v2.securitygroups.SecurityGroupEntity; import org.cloudfoundry.client.v2.servicebrokers.GetServiceBrokerRequest; import org.cloudfoundry.client.v2.servicebrokers.ServiceBrokerEntity; import org.cloudfoundry.client.v2.serviceinstances.GetServiceInstanceRequest; import org.cloudfoundry.client.v2.serviceinstances.ServiceInstanceEntity; import org.cloudfoundry.client.v2.serviceplans.GetServicePlanRequest; import org.cloudfoundry.client.v2.serviceplans.ServicePlanEntity; import org.cloudfoundry.client.v2.services.GetServiceRequest; import org.cloudfoundry.client.v2.services.ServiceEntity; import org.cloudfoundry.util.ResourceUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.servicebroker.model.CreateServiceInstanceAppBindingResponse; import org.springframework.cloud.servicebroker.model.CreateServiceInstanceBindingRequest; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import reactor.core.publisher.Mono; import reactor.util.function.Tuples; import java.util.List; import java.util.stream.Collectors; import static org.cloudfoundry.util.tuple.TupleUtils.function; @Slf4j @Component public class CreateSecurityGroup implements CreateServiceInstanceBindingPostFilter, ServiceBrokerPostFilter<CreateServiceInstanceBindingRequest, CreateServiceInstanceAppBindingResponse> { static final Protocol DEFAULT_PROTOCOL = Protocol.TCP; private CloudFoundryClient cloudFoundryClient; private TrustedDestinationSpecification trustedDestinationSpecification; @Autowired public CreateSecurityGroup(CloudFoundryClient cloudFoundryClient, TrustedDestinationSpecification trustedDestinationSpecification) { this.cloudFoundryClient = cloudFoundryClient; this.trustedDestinationSpecification = trustedDestinationSpecification; } private static Mono<ServiceEntity> getService(CloudFoundryClient cloudFoundryClient, String serviceId) { return cloudFoundryClient.services().get(GetServiceRequest.builder().serviceId(serviceId).build()) .map(ResourceUtils::getEntity); } private static Mono<ServiceBrokerEntity> getServiceBroker(CloudFoundryClient cloudFoundryClient, String serviceBrokerId) { return cloudFoundryClient.serviceBrokers() .get(GetServiceBrokerRequest.builder().serviceBrokerId(serviceBrokerId).build()) .map(ResourceUtils::getEntity); } private static Mono<ServiceInstanceEntity> getServiceInstance(CloudFoundryClient cloudFoundryClient, String serviceInstanceId) { return cloudFoundryClient.serviceInstances() .get(GetServiceInstanceRequest.builder().serviceInstanceId(serviceInstanceId).build()) .map(ResourceUtils::getEntity); } private static Mono<String> getRuleDescription(CloudFoundryClient cloudFoundryClient, String bindingId, String serviceInstanceId) { return getServiceInstance(cloudFoundryClient, serviceInstanceId) .then(serviceInstance -> Mono.when(Mono.just(bindingId), Mono.just(serviceInstance), getPlan(cloudFoundryClient, serviceInstance.getServicePlanId()) .map(ServicePlanEntity::getServiceId))) .then(function( (serviceBindingId, serviceInstance, serviceId) -> getService(cloudFoundryClient, serviceId) .map(ServiceEntity::getServiceBrokerId) .map(serviceBrokerId -> Tuples.of(serviceBindingId, serviceInstance, serviceBrokerId)))) .then(function((serviceBindingId, serviceInstance, serviceBrokerId) -> getServiceBrokerName(cloudFoundryClient, serviceBrokerId) .map(serviceBrokerName -> Tuples.of(serviceBindingId, serviceInstance, serviceBrokerName)))) .map(function((servicebindingId, serviceInstance, serviceBrokerName) -> ImmutableRuleDescription .builder().servicebindingId(servicebindingId).serviceInstanceName(serviceInstance.getName()) .serviceBrokerName(serviceBrokerName).build().value())); } private static Mono<ServicePlanEntity> getPlan(CloudFoundryClient cloudFoundryClient, String planId) { return cloudFoundryClient.servicePlans().get(GetServicePlanRequest.builder().servicePlanId(planId).build()) .map(ResourceUtils::getEntity); } private static Mono<String> getServiceBrokerName(CloudFoundryClient cloudFoundryClient, String serviceBrokerId) { return getServiceBroker(cloudFoundryClient, serviceBrokerId).map(ServiceBrokerEntity::getName); } @Override public void run(CreateServiceInstanceBindingRequest request, CreateServiceInstanceAppBindingResponse response) { Assert.notNull(response); Assert.notNull(response.getCredentials()); final Destination destination = ConnectionInfoFactory.fromCredentials(response.getCredentials()); if (!trustedDestinationSpecification.isSatisfiedBy(destination)) { log.warn("Cannot open security group for destination {}. Destination is out of allowed range [{}].", destination, trustedDestinationSpecification); throw new NotAllowedDestination(destination); } log.debug("creating security group for credentials {}.", response.getCredentials()); try { final SecurityGroupEntity securityGroup = Mono .when(getRuleDescription(cloudFoundryClient, request.getBindingId(), request.getServiceInstanceId()), getSpaceId(cloudFoundryClient, request.getBoundAppGuid())) .then(function((description, spaceId) -> create(getSecurityGroupName(request), destination, description, spaceId))) .doOnError(t -> log.error("Fail to create security group. Error details {}", t)).block(); log.debug("Security Group {} created", securityGroup.getName()); } catch (Exception e) { log.error("Fail to create Security Group. Error details {}", e); ReflectionUtils.rethrowRuntimeException(e); } } private Mono<SecurityGroupEntity> create(String securityGroupName, Destination destination, String description, String spaceId) { return getRules(destination, description) .then(rules -> cloudFoundryClient.securityGroups().create(CreateSecurityGroupRequest.builder() .name(securityGroupName).rules(rules).spaceId(spaceId).build())) .map(ResourceUtils::getEntity).checkpoint(); } private Mono<List<RuleEntity>> getRules(Destination destination, String description) { return Mono.justOrEmpty(destination.getIPs() .map(ip -> RuleEntity.builder().protocol(DEFAULT_PROTOCOL).destination(ip).description(description) .ports(String.valueOf(destination.getPort().value())).build()) .collect(Collectors.toList())).checkpoint(); } private String getSecurityGroupName(CreateServiceInstanceBindingRequest request) { return request.getBindingId(); } private Mono<String> getSpaceId(CloudFoundryClient cloudFoundryClient, String appId) { return cloudFoundryClient.applicationsV2().get(GetApplicationRequest.builder().applicationId(appId).build()) .map(GetApplicationResponse::getEntity).map(ApplicationEntity::getSpaceId).checkpoint(); } public class NotAllowedDestination extends RuntimeException { public NotAllowedDestination(Destination destination) { super(String.format( "Cannot open security group for destination %s. Destination is out of allowed range.", destination)); } } }