Skip to content
This repository has been archived by the owner on Mar 4, 2021. It is now read-only.

Commit

Permalink
Add region to janitor RDS operations. Add file headers to clear some …
Browse files Browse the repository at this point in the history
…warnings.
  • Loading branch information
ebukoski committed Sep 14, 2016
1 parent e786031 commit 164ae81
Show file tree
Hide file tree
Showing 15 changed files with 251 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public Object emailValue(String email) {
@Override
public void addOrUpdate(Cluster cluster) {
Cluster orig = getCluster(cluster.getName(), cluster.getRegion());
LOGGER.debug(String.format("Saving cluster %s to RDB table %s", cluster.getName(), table));
LOGGER.debug(String.format("Saving cluster %s to RDB table %s in region %s", cluster.getName(), cluster.getRegion(), table));
Map<String, String> map = cluster.getFieldToValueMap();

String conformityJson;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,13 @@ public Object emailValue(String email) {
/** {@inheritDoc} */
@Override
public void addOrUpdate(Resource resource) {
Resource orig = getResource(resource.getId());
LOGGER.debug(String.format("Saving resource %s to RDB table %s", resource.getId(), table));
Resource orig = getResource(resource.getId(), resource.getRegion());
LOGGER.debug(String.format("Saving resource %s to RDB table %s in region %s", resource.getId(), table, resource.getRegion()));
String json;
try {
json = new ObjectMapper().writeValueAsString(additionalFieldsAsMap(resource));
} catch (JsonProcessingException e) {
LOGGER.error("ERROR generating additonal field JSON when saving resource " + resource.getId(), e);
LOGGER.error("ERROR generating additional field JSON when saving resource " + resource.getId(), e);
return;
}

Expand Down Expand Up @@ -166,7 +166,8 @@ public void addOrUpdate(Resource resource) {
sb.append(AWSResource.FIELD_MARK_TIME).append("=?,");
sb.append(AWSResource.FIELD_OPT_OUT_OF_JANITOR).append("=?,");
sb.append("additionalFields").append("=? where ");
sb.append(AWSResource.FIELD_RESOURCE_ID).append("=?");
sb.append(AWSResource.FIELD_RESOURCE_ID).append("=? and ");
sb.append(AWSResource.FIELD_REGION).append("=?");

LOGGER.debug(String.format("Update statement is '%s'", sb));
int updated = this.jdbcTemplate.update(sb.toString(),
Expand All @@ -183,7 +184,8 @@ public void addOrUpdate(Resource resource) {
value(resource.getMarkTime()),
value(resource.isOptOutOfJanitor()),
json,
resource.getId());
resource.getId(),
resource.getRegion());
LOGGER.debug(String.format("%d rows updated", updated));
}
LOGGER.debug("Successfully saved.");
Expand Down Expand Up @@ -309,9 +311,33 @@ public Resource mapRow(ResultSet rs, int rowNum) throws SQLException {
resource = resources.get(0);
}
return resource;
}

/**
}

@Override
public Resource getResource(String resourceId, String region) {
Validate.notEmpty(resourceId);
Validate.notEmpty(region);
StringBuilder query = new StringBuilder();
query.append(String.format("select * from %s where resourceId=? and region=?", table));

LOGGER.debug(String.format("Query is '%s'", query));
List<Resource> resources = jdbcTemplate.query(query.toString(), new String[]{resourceId,region}, new RowMapper<Resource>() {
public Resource mapRow(ResultSet rs, int rowNum) throws SQLException {
return mapResource(rs);
}
});

Resource resource = null;
Validate.isTrue(resources.size() <= 1);
if (resources.size() == 0) {
LOGGER.info(String.format("Not found resource with id %s", resourceId));
} else {
resource = resources.get(0);
}
return resource;
}

/**
* Creates the RDS table, if it does not already exist.
*/
public void init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,22 @@
*/
package com.netflix.simianarmy.aws.janitor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.simpledb.AmazonSimpleDB;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.SelectRequest;
import com.amazonaws.services.simpledb.model.SelectResult;
import com.amazonaws.services.simpledb.model.*;
import com.netflix.simianarmy.Resource;
import com.netflix.simianarmy.Resource.CleanupState;
import com.netflix.simianarmy.ResourceType;
import com.netflix.simianarmy.aws.AWSResource;
import com.netflix.simianarmy.client.aws.AWSClient;
import com.netflix.simianarmy.janitor.JanitorResourceTracker;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* The JanitorResourceTracker implementation in SimpleDB.
Expand Down Expand Up @@ -151,6 +145,32 @@ public Resource getResource(String resourceId) {
}
}

@Override
public Resource getResource(String resourceId, String region) {
Validate.notEmpty(resourceId);
Validate.notEmpty(region);
StringBuilder query = new StringBuilder();
query.append(String.format("select * from `%s` where resourceId = '%s' and region = '%s'", domain, resourceId, region));

LOGGER.debug(String.format("Query is '%s'", query));

List<Item> items = querySimpleDBItems(query.toString());
Validate.isTrue(items.size() <= 1);
if (items.size() == 0) {
LOGGER.info(String.format("Not found resource with id %s and region %s", resourceId, region));
return null;
} else {
Resource resource = null;
try {
resource = parseResource(items.get(0));
} catch (Exception e) {
// Ignore the item that cannot be parsed.
LOGGER.error(String.format("SimpleDB item %s cannot be parsed into a resource.", items.get(0)));
}
return resource;
}
}

/**
* Parses a SimpleDB item into an AWS resource.
* @param item the item from SimpleDB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,38 @@ public void doMonkeyBusiness() {

@Override
public Event optInResource(String resourceId) {
return optInOrOutResource(resourceId, true);
return optInOrOutResource(resourceId, true, region);
}

@Override
public Event optOutResource(String resourceId) {
return optInOrOutResource(resourceId, false);
return optInOrOutResource(resourceId, false, region);
}

private Event optInOrOutResource(String resourceId, boolean optIn) {
Resource resource = resourceTracker.getResource(resourceId);
@Override
public Event optInResource(String resourceId, String resourceRegion) {
return optInOrOutResource(resourceId, true, resourceRegion);
}

@Override
public Event optOutResource(String resourceId, String resourceRegion) {
return optInOrOutResource(resourceId, false, resourceRegion);
}

private Event optInOrOutResource(String resourceId, boolean optIn, String resourceRegion) {
if (resourceRegion == null) {
resourceRegion = region;
}

Resource resource = resourceTracker.getResource(resourceId, resourceRegion);
if (resource == null) {
return null;
}

EventTypes eventType = optIn ? EventTypes.OPT_IN_RESOURCE : EventTypes.OPT_OUT_RESOURCE;
long timestamp = calendar.now().getTimeInMillis();
// The same resource can have multiple events, so we add the timestamp to the id.
Event evt = recorder.newEvent(Type.JANITOR, eventType, region, resourceId + "@" + timestamp);
Event evt = recorder.newEvent(Type.JANITOR, eventType, resourceRegion, resourceId + "@" + timestamp);
recorder.recordEvent(evt);
resource.setOptOutOfJanitor(!optIn);
resourceTracker.addOrUpdate(resource);
Expand Down
20 changes: 18 additions & 2 deletions src/main/java/com/netflix/simianarmy/janitor/JanitorMonkey.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@
*/
package com.netflix.simianarmy.janitor;

import java.util.List;

import com.netflix.simianarmy.EventType;
import com.netflix.simianarmy.Monkey;
import com.netflix.simianarmy.MonkeyConfiguration;
import com.netflix.simianarmy.MonkeyRecorder.Event;
import com.netflix.simianarmy.MonkeyType;

import java.util.List;

/**
* The abstract class for a Janitor Monkey.
*/
Expand Down Expand Up @@ -150,4 +150,20 @@ public Context context() {
*/
public abstract Event optOutResource(String resourceId);

/**
* Opt in a resource for Janitor Monkey.
* @param resourceId the resource id
* @param region the region of the resource
* @return the opt-in event
*/
public abstract Event optInResource(String resourceId, String region);

/**
* Opt out a resource for Janitor Monkey.
* @param resourceId the resource id
* @param region the region of the resource
* @return the opt-out event
*/
public abstract Event optOutResource(String resourceId, String region);

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
*/
package com.netflix.simianarmy.janitor;

import java.util.List;

import com.netflix.simianarmy.Resource;
import com.netflix.simianarmy.ResourceType;

import java.util.List;

/**
* The interface to track the resources marked/cleaned by the Janitor Monkey.
*
Expand Down Expand Up @@ -52,4 +52,12 @@ public interface JanitorResourceTracker {
*/
Resource getResource(String resourceId);

/** Gets the resource of a specific id.
*
* @param resourceId the resource id
* @param regionId the region id
* @return the resource that matches the resource id and region
*/
Resource getResource(String resourceId, String regionId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public JanitorMonkeyResource() {
* @throws IOException
*/
@GET @Path("addEvent")
public Response addEventThroughHttpGet( @QueryParam("eventType") String eventType, @QueryParam("resourceId") String resourceId) throws IOException {
public Response addEventThroughHttpGet( @QueryParam("eventType") String eventType, @QueryParam("resourceId") String resourceId, @QueryParam("region") String region) throws IOException {
Response.Status responseStatus;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("<html><body style=\"text-align:center\"><img src=\"https://raw.githubusercontent.com/Netflix/SimianArmy/master/assets/janitor.png\" height=\"300\" width=\"300\"><br/>".getBytes());
Expand All @@ -101,9 +101,9 @@ public Response addEventThroughHttpGet( @QueryParam("eventType") String eventTyp
gen.writeStringField("resourceId", resourceId);

if (eventType.equals("OPTIN")) {
responseStatus = optInResource(resourceId, true, gen);
responseStatus = optInResource(resourceId, true, region, gen);
} else if (eventType.equals("OPTOUT")) {
responseStatus = optInResource(resourceId, false, gen);
responseStatus = optInResource(resourceId, false, region, gen);
} else {
responseStatus = Response.Status.BAD_REQUEST;
gen.writeStringField("message", String.format("Unrecognized event type: %s", eventType));
Expand Down Expand Up @@ -141,6 +141,7 @@ public Response addEvent(String content) throws IOException {

String eventType = getStringField(input, "eventType");
String resourceId = getStringField(input, "resourceId");
String region = getStringField(input, "region");

Response.Status responseStatus;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Expand All @@ -154,9 +155,9 @@ public Response addEvent(String content) throws IOException {
gen.writeStringField("message", "eventType and resourceId parameters are all required");
} else {
if (eventType.equals("OPTIN")) {
responseStatus = optInResource(resourceId, true, gen);
responseStatus = optInResource(resourceId, true, region, gen);
} else if (eventType.equals("OPTOUT")) {
responseStatus = optInResource(resourceId, false, gen);
responseStatus = optInResource(resourceId, false, region, gen);
} else {
responseStatus = Response.Status.BAD_REQUEST;
gen.writeStringField("message", String.format("Unrecognized event type: %s", eventType));
Expand Down Expand Up @@ -191,16 +192,16 @@ public Response getJanitorStatus(@Context UriInfo uriInfo) throws IOException {
return Response.status(Response.Status.OK).entity(baos.toString("UTF-8")).build();
}

private Response.Status optInResource(String resourceId, boolean optIn, JsonGenerator gen)
private Response.Status optInResource(String resourceId, boolean optIn, String region, JsonGenerator gen)
throws IOException {
String op = optIn ? "in" : "out";
LOGGER.info(String.format("Opt %s resource %s for Janitor Monkey.", op, resourceId));
Response.Status responseStatus;
Event evt;
if (optIn) {
evt = monkey.optInResource(resourceId);
evt = monkey.optInResource(resourceId, region);
} else {
evt = monkey.optOutResource(resourceId);
evt = monkey.optOutResource(resourceId, region);
}
if (evt != null) {
responseStatus = Response.Status.OK;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
*
* Copyright 2012 Netflix, Inc.
*
* 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.netflix.simianarmy.tunable;

import com.amazonaws.services.autoscaling.model.TagDescription;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
*
* Copyright 2012 Netflix, Inc.
*
* 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.netflix.simianarmy.tunable;

import com.netflix.simianarmy.basic.chaos.BasicChaosMonkey;
Expand Down
17 changes: 17 additions & 0 deletions src/test/java/com/netflix/simianarmy/aws/TestAWSEmailNotifier.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
*
* Copyright 2012 Netflix, Inc.
*
* 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.netflix.simianarmy.aws;

import org.testng.Assert;
Expand Down
Loading

0 comments on commit 164ae81

Please sign in to comment.