Java tutorial
/* * Copyright (c) 2016 VMware, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product may include a number of subcomponents with separate copyright notices * and license terms. Your use of these subcomponents is subject to the terms and * conditions of the subcomponent's license, as noted in the LICENSE file. */ package com.vmware.admiral.adapter.docker.service; import static com.vmware.admiral.adapter.docker.service.DockerAdapterCommandExecutor.DOCKER_CONTAINER_NETWORK_DRIVER_PROP_NAME; import static com.vmware.admiral.adapter.docker.service.DockerAdapterCommandExecutor.DOCKER_CONTAINER_NETWORK_ID_PROP_NAME; import static com.vmware.admiral.adapter.docker.service.DockerAdapterCommandExecutor.DOCKER_CONTAINER_NETWORK_IPAM_PROP_NAME; import static com.vmware.admiral.adapter.docker.service.DockerAdapterCommandExecutor.DOCKER_CONTAINER_NETWORK_NAME_PROP_NAME; import static com.vmware.admiral.adapter.docker.service.DockerAdapterCommandExecutor.DOCKER_CONTAINER_NETWORK_OPTIONS_PROP_NAME; import java.net.ProtocolException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import org.apache.commons.lang3.NotImplementedException; import org.apache.http.HttpStatus; import com.vmware.admiral.adapter.common.NetworkOperationType; import com.vmware.admiral.common.ManagementUriParts; import com.vmware.admiral.common.util.AssertUtil; import com.vmware.admiral.compute.container.network.ContainerNetworkDescriptionService.ContainerNetworkDescription; import com.vmware.admiral.compute.container.network.ContainerNetworkService.ContainerNetworkState; import com.vmware.xenon.common.Operation; import com.vmware.xenon.common.TaskState.TaskStage; import com.vmware.xenon.common.UriUtils; import com.vmware.xenon.common.Utils; public class DockerNetworkAdapterService extends AbstractDockerAdapterService { public static final String SELF_LINK = ManagementUriParts.ADAPTER_DOCKER_NETWORK; public static final String DOCKER_NETWORK_TYPE_DEFAULT = ContainerNetworkDescription.NETWORK_DRIVER_BRIDGE; private static final String DELETE_NETWORK_MISSING_ERROR = "error 404 for DELETE"; static final List<String> DOCKER_PREDEFINED_NETWORKS = Arrays.asList("none", "host", "bridge", "docker_gwbridge"); private static final List<Integer> RETRIABLE_HTTP_STATUSES = Arrays.asList(HttpStatus.SC_INTERNAL_SERVER_ERROR); private static final int NETWORK_CREATE_RETRIES_COUNT = Integer .getInteger("com.vmware.admiral.adapter.network.create.retries", 3); private static class RequestContext { public NetworkRequest request; public ContainerNetworkState networkState; public CommandInput commandInput; public DockerAdapterCommandExecutor executor; // Only for direct operations. See DIRECT_OPERATIONS list public Operation operation; } @Override public void handlePatch(Operation op) { RequestContext context = new RequestContext(); context.request = op.getBody(NetworkRequest.class); context.request.validate(); NetworkOperationType operationType = context.request.getOperationType(); logInfo("Processing network operation request %s for resource %s %s", operationType, context.request.resourceReference, context.request.getRequestTrackingLog()); op.complete(); processNetworkRequest(context); } /** * Start processing the request. First fetches the {@link ContainerNetworkState}. Will result in * filling the {@link RequestContext#networkState} property. */ private void processNetworkRequest(RequestContext context) { Operation getNetworkState = Operation.createGet(context.request.getNetworkStateReference()) .setCompletion((o, ex) -> { if (ex != null) { fail(context.request, ex); } else { handleExceptions(context.request, context.operation, () -> { context.networkState = o.getBody(ContainerNetworkState.class); processNetworkState(context); }); } }); handleExceptions(context.request, context.operation, () -> { getHost().log(Level.FINE, "Fetching NetworkState: %s %s", context.request.getRequestTrackingLog(), context.request.getNetworkStateReference()); sendRequest(getNetworkState); }); } /** * Process the {@link ContainerNetworkState}. Will result in filling the * {@link RequestContext#commandInput} and {@link RequestContext#executor} properties. */ private void processNetworkState(RequestContext context) { if (context.networkState.originatingHostLink == null) { fail(context.request, new IllegalArgumentException("originatingHostLink")); return; } getContainerHost(context.request, context.operation, UriUtils.buildUri(getHost(), context.networkState.originatingHostLink), (computeState, commandInput) -> { context.commandInput = commandInput; context.executor = getCommandExecutor(); handleExceptions(context.request, context.operation, () -> processOperation(context)); }); } /** * Process the operation. This method should be called after {@link RequestContext#request}, * {@link RequestContext#networkState}, {@link RequestContext#commandInput} and * {@link RequestContext#executor} have been filled. * * @see #DIRECT_OPERATIONS */ private void processOperation(RequestContext context) { try { switch (context.request.getOperationType()) { case CREATE: processCreateNetwork(context, 0); break; case DELETE: processDeleteNetwork(context); break; case INSPECT: inspectAndUpdateNetwork(context); break; case LIST_NETWORKS: processListNetworks(context); break; case CONNECT: processConnectNetwork(context); break; case DISCONNECT: processDisconnectNetwork(context); break; default: fail(context.request, new IllegalArgumentException("Unexpected request type: " + context.request.getOperationType() + context.request.getRequestTrackingLog())); } } catch (Throwable e) { fail(context.request, e); } } private void processCreateNetwork(RequestContext context, int retriesCount) { AssertUtil.assertNotNull(context.networkState, "networkState"); AssertUtil.assertNotEmpty(context.networkState.name, "networkState.name"); CommandInput createCommandInput = context.commandInput .withPropertyIfNotNull(DOCKER_CONTAINER_NETWORK_NAME_PROP_NAME, context.networkState.name); if (context.networkState.driver != null && !context.networkState.driver.isEmpty()) { createCommandInput.withProperty(DOCKER_CONTAINER_NETWORK_DRIVER_PROP_NAME, context.networkState.driver); } else { createCommandInput.withProperty(DOCKER_CONTAINER_NETWORK_DRIVER_PROP_NAME, DOCKER_NETWORK_TYPE_DEFAULT); } if (context.networkState.options != null && !context.networkState.options.isEmpty()) { createCommandInput.withProperty(DOCKER_CONTAINER_NETWORK_OPTIONS_PROP_NAME, context.networkState.options); } if (context.networkState.ipam != null) { createCommandInput.withProperty(DOCKER_CONTAINER_NETWORK_IPAM_PROP_NAME, DockerAdapterUtils.ipamToMap(context.networkState.ipam)); } context.executor.createNetwork(createCommandInput, (op, ex) -> { if (ex != null) { AtomicInteger retryCount = new AtomicInteger(retriesCount); if (RETRIABLE_HTTP_STATUSES.contains(op.getStatusCode()) && retryCount.getAndIncrement() < NETWORK_CREATE_RETRIES_COUNT) { // retry if failure is retriable logWarning("Create network %s failed with %s. Retries left %d", context.networkState.name, Utils.toString(ex), NETWORK_CREATE_RETRIES_COUNT - retryCount.get()); processCreateNetwork(context, retryCount.get()); } else { fail(context.request, op, ex); } } else { @SuppressWarnings("unchecked") Map<String, Object> body = op.getBody(Map.class); context.networkState.id = (String) body.get(DOCKER_CONTAINER_NETWORK_ID_PROP_NAME); inspectAndUpdateNetwork(context); // transition to TaskStage.FINISHED is done later, after the network state gets // updated } }); } @SuppressWarnings("unchecked") private void inspectAndUpdateNetwork(RequestContext context) { String networkId = context.networkState.id; if (networkId == null) { fail(context.request, new IllegalStateException("network id is required " + context.request.getRequestTrackingLog())); return; } CommandInput inspectCommandInput = new CommandInput(context.commandInput) .withProperty(DOCKER_CONTAINER_NETWORK_ID_PROP_NAME, networkId); getHost().log(Level.FINE, "Executing inspect network: %s %s", context.networkState.documentSelfLink, context.request.getRequestTrackingLog()); context.executor.inspectNetwork(inspectCommandInput, (o, ex) -> { if (ex != null) { fail(context.request, o, ex); } else { handleExceptions(context.request, context.operation, () -> { Map<String, Object> properties = o.getBody(Map.class); patchNetworkState(context.request, context.networkState, properties, context); }); } }); } private void patchNetworkState(NetworkRequest request, ContainerNetworkState networkState, Map<String, Object> properties, RequestContext context) { ContainerNetworkState newNetworkState = new ContainerNetworkState(); newNetworkState.documentSelfLink = networkState.documentSelfLink; newNetworkState.documentExpirationTimeMicros = -1; // make sure the expiration is reset. newNetworkState.adapterManagementReference = networkState.adapterManagementReference; ContainerNetworkStateMapper.propertiesToContainerNetworkState(newNetworkState, properties); getHost().log(Level.FINE, "Patching ContainerNetworkState: %s %s", newNetworkState.documentSelfLink, request.getRequestTrackingLog()); sendRequest(Operation.createPatch(request.getNetworkStateReference()).setBody(newNetworkState) .setCompletion((o, ex) -> { if (ex != null) { fail(context.request, o, ex); } else { patchTaskStage(request, TaskStage.FINISHED, ex); } })); } private void processDeleteNetwork(RequestContext context) { AssertUtil.assertNotNull(context.networkState, "networkState"); AssertUtil.assertNotEmpty(context.networkState.id, "networkState.id"); CommandInput deleteCommandInput = context.commandInput .withPropertyIfNotNull(DOCKER_CONTAINER_NETWORK_ID_PROP_NAME, context.networkState.id); // TODO do verification and stuff context.executor.removeNetwork(deleteCommandInput, (op, ex) -> { if (ex != null) { if (ex instanceof ProtocolException && ex.getMessage().contains(DELETE_NETWORK_MISSING_ERROR)) { logWarning("Container network %s not found", context.networkState.id); patchTaskStage(context.request, TaskStage.FINISHED, null); } else { fail(context.request, op, ex); } } else { patchTaskStage(context.request, TaskStage.FINISHED, null); } }); } private void processListNetworks(RequestContext context) { CommandInput createListNetworkCommandInput = new CommandInput(context.commandInput); context.executor.listNetworks(createListNetworkCommandInput, (op, ex) -> { if (ex != null) { context.operation.fail(ex); } else { if (op.hasBody()) { context.operation.setBody(op.getBody(String.class)); } context.operation.complete(); } }); } private void processConnectNetwork(RequestContext context) { // TODO implement throw new NotImplementedException("connecting containers to networks is not implemented yet"); } private void processDisconnectNetwork(RequestContext context) { // TODO implement throw new NotImplementedException("disconnecting containers from networks is not implemented yet"); } }