这是indexloc提供的服务,不要输入任何密码
Skip to content
This repository was archived by the owner on Mar 4, 2021. It is now read-only.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ dependencies {
compile 'org.apache.jclouds.api:ec2:1.9.0'
compile 'org.apache.jclouds.provider:aws-ec2:1.9.0'
compile 'com.netflix.servo:servo-core:0.9.4'
compile 'org.springframework:spring-jdbc:4.2.5.RELEASE'
compile 'com.zaxxer:HikariCP:2.4.7'

testCompile 'org.testng:testng:6.3.1'
testCompile 'org.mockito:mockito-core:1.8.5'
Expand Down
241 changes: 241 additions & 0 deletions src/main/java/com/netflix/simianarmy/aws/RDSRecorder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
*
* 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 com.amazonaws.AmazonClientException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.simianarmy.EventType;
import com.netflix.simianarmy.MonkeyRecorder;
import com.netflix.simianarmy.MonkeyType;
import com.netflix.simianarmy.basic.BasicRecorderEvent;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* The Class RDSRecorder. Records events to and fetched events from a RDS table (default SIMIAN_ARMY)
*/
@SuppressWarnings("serial")
public class RDSRecorder implements MonkeyRecorder {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(RDSRecorder.class);

private final String region;

/** The table. */
private final String table;

/** the jdbcTemplate */
JdbcTemplate jdbcTemplate = null;

public static final String FIELD_ID = "eventId";
public static final String FIELD_EVENT_TIME = "eventTime";
public static final String FIELD_MONKEY_TYPE = "monkeyType";
public static final String FIELD_EVENT_TYPE = "eventType";
public static final String FIELD_REGION = "region";
public static final String FIELD_DATA_JSON = "dataJson";

/**
* Instantiates a new RDS recorder.
*
*/
public RDSRecorder(String dbDriver, String dbUser,
String dbPass, String dbUrl, String dbTable, String region) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setDriverClassName(dbDriver);
dataSource.setJdbcUrl(dbUrl);
dataSource.setUsername(dbUser);
dataSource.setPassword(dbPass);
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.table = dbTable;
this.region = region;
}

/**
* Instantiates a new RDS recorder. This constructor is intended
* for unit testing.
*
*/
public RDSRecorder(JdbcTemplate jdbcTemplate, String table, String region) {
this.jdbcTemplate = jdbcTemplate;
this.table = table;
this.region = region;
}

public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}

/** {@inheritDoc} */
@Override
public Event newEvent(MonkeyType monkeyType, EventType eventType, String reg, String id) {
return new BasicRecorderEvent(monkeyType, eventType, reg, id);
}

/** {@inheritDoc} */
@Override
public void recordEvent(Event evt) {
String evtTime = String.valueOf(evt.eventTime().getTime());
String name = String.format("%s-%s-%s-%s", evt.monkeyType().name(), evt.id(), region, evtTime);
String json;
try {
json = new ObjectMapper().writeValueAsString(evt.fields());
} catch (JsonProcessingException e) {
LOGGER.error("ERROR generating JSON when saving resource " + name, e);
return;
}

LOGGER.debug(String.format("Saving event %s to RDS table %s", name, table));
StringBuilder sb = new StringBuilder();
sb.append("insert into ").append(table);
sb.append(" (");
sb.append(FIELD_ID).append(",");
sb.append(FIELD_EVENT_TIME).append(",");
sb.append(FIELD_MONKEY_TYPE).append(",");
sb.append(FIELD_EVENT_TYPE).append(",");
sb.append(FIELD_REGION).append(",");
sb.append(FIELD_DATA_JSON).append(") values (?,?,?,?,?,?)");

LOGGER.debug(String.format("Insert statement is '%s'", sb));
int updated = this.jdbcTemplate.update(sb.toString(),
evt.id(),
evt.eventTime().getTime(),
SimpleDBRecorder.enumToValue(evt.monkeyType()),
SimpleDBRecorder.enumToValue(evt.eventType()),
evt.region(),
json);
LOGGER.debug(String.format("%d rows inserted", updated));
}

/** {@inheritDoc} */
@Override
public List<Event> findEvents(Map<String, String> query, Date after) {
return findEvents(null, null, query, after);
}

/** {@inheritDoc} */
@Override
public List<Event> findEvents(MonkeyType monkeyType, Map<String, String> query, Date after) {
return findEvents(monkeyType, null, query, after);
}

/** {@inheritDoc} */
@Override
public List<Event> findEvents(MonkeyType monkeyType, EventType eventType, Map<String, String> query, Date after) {
ArrayList<Object> args = new ArrayList<>();
StringBuilder sqlquery = new StringBuilder(
String.format("select * from %s where region = ?", table, region));
args.add(table);

if (monkeyType != null) {
sqlquery.append(String.format(" and %s = ?", FIELD_MONKEY_TYPE));
args.add(SimpleDBRecorder.enumToValue(monkeyType));
}

if (eventType != null) {
sqlquery.append(String.format(" and %s = ?", FIELD_EVENT_TYPE));
args.add(SimpleDBRecorder.enumToValue(eventType));
}

for (Map.Entry<String, String> pair : query.entrySet()) {
sqlquery.append(String.format(" and %s like ?", FIELD_DATA_JSON));
args.add((String.format("%s: \"%s\"", pair.getKey(), pair.getValue())));
}
sqlquery.append(String.format(" and %s > ? order by %s desc", FIELD_EVENT_TIME, FIELD_EVENT_TIME));
args.add(new Long(after.getTime()));

LOGGER.debug(String.format("Query is '%s'", sqlquery));
List<Event> events = jdbcTemplate.query(sqlquery.toString(), args.toArray(), new RowMapper<Event>() {
public Event mapRow(ResultSet rs, int rowNum) throws SQLException {
return mapEvent(rs);
}
});
return events;
}

private Event mapEvent(ResultSet rs) throws SQLException {
String json = rs.getString("dataJson");
ObjectMapper mapper = new ObjectMapper();
Event event = null;
try {
String id = rs.getString(FIELD_ID);
MonkeyType monkeyType = SimpleDBRecorder.valueToEnum(MonkeyType.class, rs.getString(FIELD_MONKEY_TYPE));
EventType eventType = SimpleDBRecorder.valueToEnum(EventType.class, rs.getString(FIELD_EVENT_TYPE));
String region = rs.getString(FIELD_REGION);
long time = rs.getLong(FIELD_EVENT_TIME);
event = new BasicRecorderEvent(monkeyType, eventType, region, id, time);

TypeReference<Map<String,String>> typeRef = new TypeReference<Map<String,String>>() {};
Map<String, String> map = mapper.readValue(json, typeRef);
for(String key : map.keySet()) {
event.addField(key, map.get(key));
}

}catch(IOException ie) {
LOGGER.error("Error parsing resource from json", ie);
}
return event;
}


/**
* Creates the RDS table, if it does not already exist.
*/
public void init() {
try {
if (this.region == null || this.region.equals("region-null")) {
// This is a mock with an invalid region; avoid a slow timeout
LOGGER.debug("Region=null; skipping RDS table creation");
return;
}

LOGGER.info("Creating RDS table: {}", table);
String sql = String.format("create table if not exists %s ("
+ " %s varchar(255),"
+ " %s BIGINT,"
+ " %s varchar(255),"
+ " %s varchar(255),"
+ " %s varchar(255),"
+ " %s varchar(4096) )",
table,
FIELD_ID,
FIELD_EVENT_TIME,
FIELD_MONKEY_TYPE,
FIELD_EVENT_TYPE,
FIELD_REGION,
FIELD_DATA_JSON);
LOGGER.debug("Create SQL is: '{}'", sql);
jdbcTemplate.execute(sql);

} catch (AmazonClientException e) {
LOGGER.warn("Error while trying to auto-create RDS table", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ protected AmazonSimpleDB sdbClient() {
* the e
* @return the string
*/
private static String enumToValue(NamedType e) {
public static String enumToValue(NamedType e) {
return String.format("%s|%s", e.name(), e.getClass().getName());
}

Expand All @@ -134,7 +134,7 @@ private static String enumToValue(NamedType e) {
* the value
* @return the enum
*/
private static <T extends NamedType> T valueToEnum(
public static <T extends NamedType> T valueToEnum(
Class<T> type, String value) {
// parts = [enum value, enum class type]
String[] parts = value.split("\\|", 2);
Expand Down
Loading