com.amazonaws.auth.EC2MetadataServiceMock.java Source code

Java tutorial

Introduction

Here is the source code for com.amazonaws.auth.EC2MetadataServiceMock.java

Source

/*
 * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights
 * Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.amazonaws.auth;

import static com.amazonaws.SDKGlobalConfiguration.EC2_METADATA_SERVICE_OVERRIDE_SYSTEM_PROPERTY;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;

import org.apache.commons.io.IOUtils;

import com.amazonaws.internal.EC2MetadataClient;

/**
 * Mock server for imitating the Amazon EC2 Instance Metadata Service. Tests can
 * use this class to start up a server on a localhost port, and control what
 * response the server will send when a connection is made.
 */
public class EC2MetadataServiceMock {

    private EC2MockMetadataServiceListenerThread hosmMockServerThread;

    private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n"
            + "Content-Length: ";

    private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

    /**
     * Sets the name of the file that should be sent back as the response from
     * this mock server. The files are loaded from the com/amazonaws/auth
     * directory of the tst folder, and no file extension should be specified.
     *
     * @param responseFileName
     *            The name of the file that should be sent back as the response
     *            from this mock server.
     */
    public void setResponseFileName(String responseFileName) {
        hosmMockServerThread.setResponseFileName(responseFileName);
    }

    /**
     * Accepts a newline delimited list of security credential names that the
     * mock metadata service should advertise as available.
     *
     * @param securityCredentialNames
     *            A newline delimited list of security credentials that the
     *            metadata service will advertise as available.
     */
    public void setAvailableSecurityCredentials(String securityCredentialNames) {
        hosmMockServerThread.setAvailableSecurityCredentials(securityCredentialNames);
    }

    public void start() throws IOException {
        hosmMockServerThread = new EC2MockMetadataServiceListenerThread(startServerSocket());
        hosmMockServerThread.start();
    }

    public void stop() {
        hosmMockServerThread.stopServer();
    }

    private ServerSocket startServerSocket() {
        try {
            ServerSocket serverSocket = new ServerSocket(0);

            System.setProperty(EC2_METADATA_SERVICE_OVERRIDE_SYSTEM_PROPERTY,
                    "http://localhost:" + serverSocket.getLocalPort());
            System.out.println("Started mock metadata service at: "
                    + System.getProperty(EC2_METADATA_SERVICE_OVERRIDE_SYSTEM_PROPERTY));

            return serverSocket;
        } catch (IOException ioe) {
            throw new RuntimeException("Unable to start mock EC2 metadata server", ioe);
        }
    }

    /**
     * Thread subclass that listens for connections on an opened server socket
     * and response with a predefined response file.
     */
    private static class EC2MockMetadataServiceListenerThread extends Thread {
        private ServerSocket serverSocket;
        private String responseFileName;
        private String securityCredentialNames;

        public EC2MockMetadataServiceListenerThread(ServerSocket serverSocket) {
            this.serverSocket = serverSocket;
        }

        public void setResponseFileName(String responseFileName) {
            this.responseFileName = responseFileName;
        }

        public void setAvailableSecurityCredentials(String securityCredentialNames) {
            this.securityCredentialNames = securityCredentialNames;
        }

        @Override
        public void run() {
            while (true) {
                Socket socket = null;
                try {
                    socket = serverSocket.accept();
                } catch (IOException e) {
                    // Just exit if the socket gets shut down while we're waiting
                    return;
                }

                OutputStream outputStream = null;
                try {
                    outputStream = socket.getOutputStream();
                    InputStream inputStream = socket.getInputStream();

                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    String requestLine = reader.readLine();

                    String[] strings = requestLine.split(" ");
                    String resourcePath = strings[1];

                    String httpResponse = null;

                    if (resourcePath.equals(EC2MetadataClient.SECURITY_CREDENTIALS_RESOURCE)) {
                        httpResponse = formHttpResponse(securityCredentialNames);
                        outputStream.write(httpResponse.getBytes());

                    } else if (resourcePath.startsWith(EC2MetadataClient.SECURITY_CREDENTIALS_RESOURCE)) {
                        String responseFilePath = "/com/amazonaws/auth/" + responseFileName + ".json";
                        System.out.println("Serving: " + responseFilePath);

                        InputStream responseFileInputStream = this.getClass().getResourceAsStream(responseFilePath);

                        List<String> dataFromFile = IOUtils.readLines(responseFileInputStream);

                        StringBuilder credentialsString = new StringBuilder();

                        for (String line : dataFromFile)
                            credentialsString.append(line);

                        httpResponse = formHttpResponse(credentialsString.toString());
                        outputStream.write(httpResponse.getBytes());

                    } else {
                        throw new RuntimeException("Unknown resource requested: " + resourcePath);
                    }
                } catch (IOException e) {
                    throw new RuntimeException("Unable to respond to request", e);
                } finally {
                    try {
                        outputStream.close();
                    } catch (Exception e) {
                    }
                }
            }
        }

        private String formHttpResponse(String content) {

            StringBuilder outputStringToWrite = new StringBuilder(OUTPUT_HEADERS);
            outputStringToWrite.append(content.length());
            outputStringToWrite.append(OUTPUT_END_OF_HEADERS);
            outputStringToWrite.append(content);
            return outputStringToWrite.toString();
        }

        public void stopServer() {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    throw new RuntimeException("Unable to stop server", e);
                }
            }
        }
    }
}