package com.sequenceiq.it.cloudbreak;
import static com.sequenceiq.it.cloudbreak.GcpCreateVirtualNetworkTest.NetworkType.EXISTING_SUBNET_IN_EXISTING_NETWORK;
import static com.sequenceiq.it.cloudbreak.GcpCreateVirtualNetworkTest.NetworkType.LAGACY_NETWORK;
import static com.sequenceiq.it.cloudbreak.GcpCreateVirtualNetworkTest.NetworkType.NEW_SUBNET_IN_EXISTING_NETWORK;
import java.io.ByteArrayInputStream;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.SecurityUtils;
import com.google.api.services.compute.Compute;
import com.google.api.services.compute.ComputeScopes;
import com.google.api.services.compute.model.Network;
import com.google.api.services.compute.model.Operation;
import com.google.api.services.compute.model.Subnetwork;
import com.sequenceiq.cloudbreak.api.model.NetworkRequest;
import com.sequenceiq.it.util.ResourceUtil;
public class GcpCreateVirtualNetworkTest extends AbstractCloudbreakIntegrationTest {
private static final int MAX_TRY = 30;
private static final Logger LOGGER = LoggerFactory.getLogger(GcpCreateVirtualNetworkTest.class);
@Value("${integrationtest.gcpcredential.name}")
private String defaultName;
@Value("${integrationtest.gcpcredential.projectId}")
private String defaultProjectId;
@Value("${integrationtest.gcpcredential.serviceAccountId}")
private String defaultServiceAccountId;
@Value("${integrationtest.gcpcredential.p12File}")
private String defaultP12File;
private JacksonFactory jsonFactory;
@Test
@Parameters({"networkName", "description", "publicInAccount", "resourceGroupName", "vpcName", "vpcSubnet", "subnetCIDR", "networkType"})
public void createNetwork(String networkName, @Optional("") String description, @Optional("false") boolean publicInAccount,
@Optional("europe-west1") String subnetRegion, @Optional("it-vpc") String vpcName,
@Optional("it-vpc-subnet") String vpcSubnet, @Optional("10.0.36.0/24") String subnetCIDR, NetworkType networkType) throws Exception {
String serviceAccountPrivateKey = ResourceUtil.readBase64EncodedContentFromResource(applicationContext, defaultP12File);
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(),
new ByteArrayInputStream(Base64.decodeBase64(serviceAccountPrivateKey)), "notasecret", "privatekey", "notasecret");
jsonFactory = JacksonFactory.getDefaultInstance();
GoogleCredential googleCredential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(defaultServiceAccountId)
.setServiceAccountScopes(Collections.singletonList(ComputeScopes.COMPUTE))
.setServiceAccountPrivateKey(privateKey)
.build();
Compute compute = new Compute.Builder(httpTransport, jsonFactory, null)
.setApplicationName(defaultName)
.setHttpRequestInitializer(googleCredential)
.build();
Network gcpNetwork = new Network();
gcpNetwork.setName(vpcName);
if (!LAGACY_NETWORK.equals(networkType)) {
gcpNetwork.setAutoCreateSubnetworks(false);
}
Compute.Networks.Insert networkInsert = compute.networks().insert(defaultProjectId, gcpNetwork);
Operation networkInsertResponse = networkInsert.execute();
if (networkInsertResponse.getHttpErrorStatusCode() != null) {
throw new IllegalStateException("gcp network operation failed: " + networkInsertResponse.getHttpErrorMessage());
}
waitOperation(compute, networkInsertResponse);
if (EXISTING_SUBNET_IN_EXISTING_NETWORK.equals(networkType)) {
Subnetwork gcpSubnet = new Subnetwork();
gcpSubnet.setName(vpcSubnet);
gcpSubnet.setIpCidrRange(subnetCIDR);
gcpSubnet.setNetwork(String.format("https://www.googleapis.com/compute/v1/projects/%s/global/networks/%s", defaultProjectId, vpcName));
Compute.Subnetworks.Insert subNetworkInsert = compute.subnetworks().insert(defaultProjectId, subnetRegion, gcpSubnet);
Operation subNetInsertResponse = subNetworkInsert.execute();
if (subNetInsertResponse.getHttpErrorStatusCode() != null) {
throw new IllegalStateException("gcp subnetwork operation failed: " + subNetInsertResponse.getHttpErrorMessage());
}
}
NetworkRequest networkRequest = new NetworkRequest();
networkRequest.setName(networkName);
networkRequest.setDescription(description);
if (NEW_SUBNET_IN_EXISTING_NETWORK.equals(networkType)) {
networkRequest.setSubnetCIDR(subnetCIDR);
}
Map<String, Object> map = new HashMap<>();
map.put("networkId", vpcName);
if (EXISTING_SUBNET_IN_EXISTING_NETWORK.equals(networkType)) {
map.put("subnetId", vpcSubnet);
}
networkRequest.setParameters(map);
networkRequest.setCloudPlatform("GCP");
String id = getCloudbreakClient().networkEndpoint().postPrivate(networkRequest).getId().toString();
getItContext().putContextParam(CloudbreakITContextConstants.NETWORK_ID, id, true);
}
private void waitOperation(Compute compute, Operation operation) throws java.io.IOException {
int tried = 0;
while (tried < MAX_TRY) {
LOGGER.info("check operation: " + operation.getName() + ", tried: " + tried);
Operation checkResponse = compute.globalOperations().get(defaultProjectId, operation.getName()).execute();
if ("DONE".equals(checkResponse.getStatus())) {
break;
}
tried++;
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
LOGGER.error("thread sleep interrupted", e);
}
}
if (tried == MAX_TRY) {
throw new RuntimeException("wait for operation exceeded maximum retry number, operation: " + operation.getName());
}
}
public enum NetworkType {
NEW_SUBNET_IN_EXISTING_NETWORK,
EXISTING_SUBNET_IN_EXISTING_NETWORK,
LAGACY_NETWORK
}
}