package core.aws.local; import core.aws.client.AWS; import core.aws.env.Environment; import core.aws.local.as.ASGroupLoader; import core.aws.local.ec2.InstanceLoader; import core.aws.local.ec2.InstanceProfileLoader; import core.aws.local.ec2.SGLoader; import core.aws.local.elb.ELBLoader; import core.aws.local.elb.ServerCertLoader; import core.aws.local.env.EnvLoader; import core.aws.local.image.AMILoader; import core.aws.local.image.AMIsLoader; import core.aws.local.s3.S3Loader; import core.aws.local.vpc.SubnetLoader; import core.aws.resource.Resource; import core.aws.resource.Resources; import core.aws.util.Asserts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yaml.snakeyaml.Yaml; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author neo */ public class ResourcesLoader { private final Logger logger = LoggerFactory.getLogger(getClass()); private final Map<String, LocalResourceLoader> localResourceLoaders = new HashMap<>(); private final Pattern resourceNamePattern = Pattern.compile("(.*)\\[(.*)\\]"); public ResourcesLoader() { localResourceLoaders.put("amis", new AMIsLoader()); localResourceLoaders.put("ami", new AMILoader()); localResourceLoaders.put("security-group", new SGLoader()); localResourceLoaders.put("instance", new InstanceLoader()); localResourceLoaders.put("s3", new S3Loader()); localResourceLoaders.put("subnet", new SubnetLoader()); localResourceLoaders.put("cert", new ServerCertLoader()); localResourceLoaders.put("elb", new ELBLoader()); localResourceLoaders.put("instance-profile", new InstanceProfileLoader()); localResourceLoaders.put("auto-scaling", new ASGroupLoader()); } public Resources load(Environment env) throws IOException { Resources resources = new Resources(); DependencyResolvers resolvers = new DependencyResolvers(); List<ResourceNode> nodes = new ArrayList<>(); Files.list(env.envDir) .filter(path -> path.getFileName().toString().endsWith(".yml")) .forEach(path -> { logger.info("load env config, file={}", path); String yml = core.aws.util.Files.text(path); nodes.addAll(load(yml, path)); }); nodes.stream() .filter(node -> "env".equals(node.type)) .forEach(node -> new EnvLoader().load(node, env)); AWS.initialize(env); //TODO: AWS clients need to be init after env.region is determined, refactor this into more clear flow nodes.stream() .filter(node -> !"env".equals(node.type)) .forEach(node -> { LocalResourceLoader loader = Asserts.notNull(localResourceLoaders.get(node.type), "unknown resource type, type={}", node.type); try { loader.load(node, resources, resolvers, env); } catch (Exception e) { logger.error("failed to parse resource node, file={}, node=\n{}", node.path, node.yml); throw e; } }); resolvers.resolve(); resources.stream().forEach(Resource::foundInLocal); return resources; } private List<ResourceNode> load(String config, Path path) { List<ResourceNode> results = new ArrayList<>(); Yaml yaml = new Yaml(); Object nodes = yaml.load(config); if (!(nodes instanceof List<?>)) throw new IllegalArgumentException("config must be in list, config=" + nodes); for (Object node : (List<?>) nodes) { if (!(node instanceof Map<?, ?>)) throw new IllegalArgumentException("config node must be in map, node=" + node); Map<?, ?> map = (Map<?, ?>) node; if (map.size() > 1) throw new IllegalArgumentException("invalid node format, node=" + node); String name = String.valueOf(map.keySet().iterator().next()); Matcher matcher = resourceNamePattern.matcher(name); if (matcher.matches()) { String resourceType = matcher.group(1); String resourceId = matcher.group(2); ResourceNode result = new ResourceNode(resourceType, resourceId, (Map<?, ?>) map.get(name), yaml.dump(node), path); results.add(result); } else { throw new IllegalArgumentException("invalid resource name format, name=" + name); } } return results; } }