org.zalando.stups.fullstop.plugin.RegistryPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.zalando.stups.fullstop.plugin.RegistryPlugin.java

Source

/**
 * Copyright 2015 Zalando SE
 *
 * 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.zalando.stups.fullstop.plugin;

import static java.lang.String.format;

import static org.zalando.stups.fullstop.events.CloudtrailEventSupport.getInstanceIds;

import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.yaml.snakeyaml.Yaml;

import org.zalando.stups.clients.kio.Application;
import org.zalando.stups.clients.kio.KioOperations;
import org.zalando.stups.clients.kio.Version;
import org.zalando.stups.fullstop.aws.ClientProvider;
import org.zalando.stups.fullstop.clients.pierone.PieroneOperations;
import org.zalando.stups.fullstop.violation.ViolationStore;
import org.zalando.stups.fullstop.violation.entity.ViolationBuilder;

import com.amazonaws.AmazonServiceException;

import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;

import com.amazonaws.services.cloudtrail.processinglibrary.model.CloudTrailEvent;
import com.amazonaws.services.cloudtrail.processinglibrary.model.CloudTrailEventData;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DescribeInstanceAttributeRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceAttributeResult;

import com.amazonaws.util.Base64;

/**
 * @author  mrandi
 */

@Component
public class RegistryPlugin extends AbstractFullstopPlugin {

    private static final Logger LOG = LoggerFactory.getLogger(RegistryPlugin.class);

    private static final String EC2_SOURCE_EVENTS = "ec2.amazonaws.com";
    private static final String EVENT_NAME = "RunInstances";
    public static final String USER_DATA = "userData";

    private static String APPLICATION_ID = "application_id";
    private static String APPLICATION_VERSION = "application_version";
    private static String SOURCE = "source";

    private final ClientProvider cachingClientProvider;

    private final ViolationStore violationStore;

    // private final RestTemplate restTemplate = new RestTemplate();

    // @Value("${fullstop.plugins.kio.url}/apps/{appId}")
    // private String kioApplicationUrl;

    // @Value("${fullstop.plugins.kio.url}/apps/{appId}/versions/{version_id}")
    // private String kioApplicationVersionUrl;

    // @Value("${fullstop.plugins.pierone.url}/v1/repositories/{team}/{application}/tags")
    // private String pieroneApplicationUrl;

    private final PieroneOperations pieroneOperations;

    private final KioOperations kioOperations;

    @Autowired
    public RegistryPlugin(final ClientProvider cachingClientProvider, final ViolationStore violationStore,
            final PieroneOperations pieroneOperations, final KioOperations kioOperations) {
        this.cachingClientProvider = cachingClientProvider;
        this.violationStore = violationStore;
        this.pieroneOperations = pieroneOperations;
        this.kioOperations = kioOperations;
    }

    @Override
    public boolean supports(final CloudTrailEvent event) {
        CloudTrailEventData cloudTrailEventData = event.getEventData();
        String eventSource = cloudTrailEventData.getEventSource();
        String eventName = cloudTrailEventData.getEventName();

        return eventSource.equals(EC2_SOURCE_EVENTS) && eventName.equals(EVENT_NAME);
    }

    @Override
    public void processEvent(final CloudTrailEvent event) {
        List<String> instanceIds = getInstanceIds(event);

        for (String instanceId : instanceIds) {
            Map userData = getUserData(event, instanceId);

            if (userData == null) {
                return;
            }

            String applicationId = getApplicationId(event, userData, instanceId);

            String applicationVersion = getApplicationVersion(event, userData, instanceId);

            String source = getSource(event, userData, instanceId);

            if (applicationId != null) {

                Application applicationFromKio = getAndValidateApplicationFromKio(event, applicationId);

                if (applicationFromKio != null) {

                    Version applicationVersionFromKio = getAndValidateApplicationVersionFromKio(event,
                            applicationId, applicationVersion);

                    if (applicationVersionFromKio != null) {

                        validateSourceWithKio(event, applicationId, applicationVersion,
                                applicationFromKio.getTeamId(), source, applicationVersionFromKio.getArtifact());
                    }
                }

                // if (applicationFromKio != null && applicationFromKio.getBody() != null && applicationVersion != null) {
                // ResponseEntity<JsonNode> versionFromKio = getAndValidateApplicationVersionFromKio(event,
                // applicationId, applicationVersion);
                //
                // if (versionFromKio != null && versionFromKio.getBody() != null && source != null) {
                // validateSourceWithKio(event, applicationId, applicationVersion,
                // applicationFromKio.getBody().get("team_id").asText(), source,
                // versionFromKio.getBody().get("artifact").asText());
                // }
                // }

            }
        }
    }

    private void validateSourceWithKio(final CloudTrailEvent event, final String applicationId,
            final String applicationVersion, final String team, final String source, final String artifact) {

        if (!source.equals(artifact)) {
            violationStore
                    .save(new ViolationBuilder(format("Application: %s has not a valid artifact for version: %s.",
                            applicationId, applicationVersion)).withEvent(event).build());
        }

        Map<String, String> tags = this.pieroneOperations.listTags(team, applicationId);
        if (tags.isEmpty()) {
            violationStore.save(new ViolationBuilder(format("Source: %s is not present in pierone.", source))
                    .withEvent(event).build());
        } else {
            String value = tags.get(applicationVersion);
            if (value == null) {
                violationStore.save(new ViolationBuilder(format("Source: %s is not present in pierone.", source))
                        .withEvent(event).build());
            }
        }

        // TODO, this code is hard to read, please refactor it

        // ResponseEntity<JsonNode> response = null;
        // try {
        // response = restTemplate.exchange(get(
        // fromHttpUrl(pieroneApplicationUrl).buildAndExpand(team, applicationId).toUri()).accept(
        // APPLICATION_JSON).build(), JsonNode.class);
        // } catch (HttpClientErrorException e) {
        // if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
        // violationStore.save(new ViolationBuilder(format("Source: %s is not present in pierone.", source))
        // .withEvent(event).build());
        // return;
        // }
        // }
        //
        // if (response != null && !response.getStatusCode().is2xxSuccessful()) {
        // violationStore.save(new ViolationBuilder(format("Source: %s is not present in pierone.", source)).withEvent(
        // event).build());
        // } else if (response != null && response.getBody().get(applicationVersion) == null) {
        // violationStore.save(new ViolationBuilder(format("Source: %s is not present in pierone.", source)).withEvent(
        // event).build());
        // }
    }

    private Application getAndValidateApplicationFromKio(final CloudTrailEvent event, final String applicationId) {

        Application application = kioOperations.getApplicationById(applicationId);

        return application;

        // TODO, don't get the point, hard to read

        // ResponseEntity<JsonNode> response = null;
        // try {
        // response = restTemplate.exchange(get(fromHttpUrl(kioApplicationUrl).buildAndExpand(applicationId).toUri())
        // .accept(APPLICATION_JSON).build(), JsonNode.class);
        // } catch (HttpClientErrorException e) {
        // if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
        // violationStore.save(
        // new ViolationBuilder(format("Application: %s is not registered in kio.", applicationId)).withEvent(
        // event).build());
        // return null;
        // }
        // }
        //
        // if (response != null && !response.getStatusCode().is2xxSuccessful()) {
        // violationStore.save(new ViolationBuilder(
        // format("Application: %s is not registered in kio.", applicationId)).withEvent(event).build());
        // }
        //
        // return response;
    }

    private Version getAndValidateApplicationVersionFromKio(final CloudTrailEvent event, final String applicationId,
            final String applicationVersion) {

        Version version = kioOperations.getApplicationVersion(applicationId, applicationVersion);

        return version;

        // TODO, same as above

        // ResponseEntity<JsonNode> response = null;
        // try {
        // response = restTemplate.exchange(get(
        // fromHttpUrl(kioApplicationVersionUrl).buildAndExpand(applicationId, applicationVersion).toUri())
        // .accept(APPLICATION_JSON).build(), JsonNode.class);
        // } catch (HttpClientErrorException e) {
        // if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
        // violationStore.save(
        // new ViolationBuilder(
        // format("Version: %s for Application: %s is not registered in kio.", applicationVersion,
        // applicationId)).withEvent(event).build());
        // return null;
        // }
        //
        // }
        //
        // if (response != null && !response.getStatusCode().is2xxSuccessful()) {
        // violationStore.save(
        // new ViolationBuilder(
        // format("Version: %s for Application: %s is not registered in kio.", applicationVersion,
        // applicationId)).withEvent(event).build());
        // }
        //
        // return response;
    }

    private Map getUserData(final CloudTrailEvent event, final String instanceId) {

        AmazonEC2Client ec2Client = cachingClientProvider.getClient(AmazonEC2Client.class,
                event.getEventData().getUserIdentity().getAccountId(),
                Region.getRegion(Regions.fromName(event.getEventData().getAwsRegion())));

        DescribeInstanceAttributeRequest describeInstanceAttributeRequest = new DescribeInstanceAttributeRequest();
        describeInstanceAttributeRequest.setInstanceId(instanceId);
        describeInstanceAttributeRequest.setAttribute(USER_DATA);

        DescribeInstanceAttributeResult describeInstanceAttributeResult;
        try {
            describeInstanceAttributeResult = ec2Client.describeInstanceAttribute(describeInstanceAttributeRequest);
        } catch (AmazonServiceException e) {
            LOG.error(e.getMessage());
            violationStore
                    .save(new ViolationBuilder(format("InstanceId: %s doesn't have any userData.", instanceId))
                            .withEvent(event).build());
            return null;
        }

        String userData = describeInstanceAttributeResult.getInstanceAttribute().getUserData();

        if (userData == null) {
            violationStore
                    .save(new ViolationBuilder(format("InstanceId: %s doesn't have any userData.", instanceId))
                            .withEvent(event).build());
            return null;
        }

        byte[] bytesUserData = Base64.decode(userData);
        String decodedUserData = new String(bytesUserData);

        Yaml yaml = new Yaml();

        return (Map) yaml.load(decodedUserData);
    }

    private String getApplicationId(final CloudTrailEvent event, final Map userDataMap, final String instanceId) {
        String applicationId = (String) userDataMap.get(APPLICATION_ID);

        if (applicationId == null) {
            violationStore.save(new ViolationBuilder(format("No 'application_id' defined for this instance %s, "
                    + "please change the userData configuration for this instance and add this information.",
                    instanceId)).withEvent(event).build());
            return null;
        }

        return applicationId;
    }

    private String getApplicationVersion(final CloudTrailEvent event, final Map userDataMap,
            final String instanceId) {
        String applicationVersion = (String) userDataMap.get(APPLICATION_VERSION);

        if (applicationVersion == null) {
            violationStore.save(new ViolationBuilder(format(
                    "No 'application_version' defined for this instance %s, "
                            + "please change the userData configuration for this instance and add this information.",
                    instanceId)).withEvent(event).build());
            return null;
        }

        return applicationVersion;
    }

    private String getSource(final CloudTrailEvent event, final Map userDataMap, final String instanceId) {

        String source = (String) userDataMap.get(SOURCE);

        if (source == null) {
            violationStore.save(new ViolationBuilder(format("No 'source' defined for this instance %s, "
                    + "please change the userData configuration for this instance and add this information.",
                    instanceId)).withEvent(event).build());
            return null;
        }

        return source;
    }
}