diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-02-15 17:20:53 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-02-15 17:25:58 +0200 |
commit | 9205135a977cacebb79df1309ef5eaab57127f06 (patch) | |
tree | fd9ed7ba7476d8d9c4272238119bcd644150463d /src | |
parent | 62f22e19e0953022d68f220463104117a1a5b7e2 (diff) | |
download | eclat-9205135a977cacebb79df1309ef5eaab57127f06.tar.gz eclat-9205135a977cacebb79df1309ef5eaab57127f06.tar.bz2 |
Implement DescribeImages and RunInstances.
* TODO: Update.
* etc/describe-images.fln: New file.
* etc/run-instances.fln: New file.
* etc/Makefile.am: Add new files.
* lib/q2url.c (add_param): Accept NULL values.
* lib/qaddparm.c (eclat_query_add_param): Likewise.
* lib/qencode.c (encode_param): Likewise.
* lib/reqsign.c (eclat_query_signature): Likewise.
* src/dscrimgs-cl.opt: New file.
* src/dscrimgs.c: New file.
* src/runinsts-cl.opt: New file.
* src/runinsts.c: New file.
* src/Makefile.am: Add new files.
* src/eclat.c (cmdtab): Register new commands.
* src/eclat.h (eclat_run_instances)
(eclat_describe_images): New protos.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/dscrimgs-cl.opt | 104 | ||||
-rw-r--r-- | src/dscrimgs.c | 34 | ||||
-rw-r--r-- | src/eclat.c | 4 | ||||
-rw-r--r-- | src/eclat.h | 2 | ||||
-rw-r--r-- | src/runinsts-cl.opt | 231 | ||||
-rw-r--r-- | src/runinsts.c | 374 |
7 files changed, 754 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 10c5cf0..0492bd9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,6 +36,7 @@ eclat_SOURCES=\ dscrsnapattr.c\ dscrregs.c\ dscrtags.c\ + dscrimgs.c\ dscrinstattr.c\ dscrinsts.c\ dscrinststat.c\ @@ -47,6 +48,7 @@ eclat_SOURCES=\ getconout.c\ modinstattr.c\ reladdr.c\ + runinsts.c\ startinst.c\ util.c @@ -66,12 +68,14 @@ OPTFILES=\ detvol-cl.opt\ disassaddr-cl.opt\ dscraddrs-cl.opt\ + dscrimgs-cl.opt\ dscrinststat-cl.opt\ dscrsecgrps-cl.opt\ dscrsnap-cl.opt\ dscrtags-cl.opt\ generic-cl.opt\ - reladdr-cl.opt + reladdr-cl.opt\ + runinsts-cl.opt eclat_SOURCES += $(OPTFILES:.opt=.h) diff --git a/src/dscrimgs-cl.opt b/src/dscrimgs-cl.opt new file mode 100644 index 0000000..b358058 --- /dev/null +++ b/src/dscrimgs-cl.opt @@ -0,0 +1,104 @@ +/* This file is part of Eclat. + Copyright (C) 2013 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +static int owner_n; +static int xby_n; + +OPTIONS_BEGIN("eclat describe-images", + [<describe Amazon images>], + [<[FILTER...] [AMI...]>], + [<gnu>], + [<nousage>], + [<noversion>]) + +OPTION(all,a,, + [<describe all images>]) +BEGIN + grecs_asprintf(&bufptr, &bufsize, "Owner.%d", ++owner_n); + eclat_query_add_param(q, bufptr, "all"); +END + +OPTION(owner,o,[<ID|amazon|aws-marketplace|self|all>], + [<select AMIs with a particular owner>]) +BEGIN + grecs_asprintf(&bufptr, &bufsize, "Owner.%d", ++owner_n); + eclat_query_add_param(q, bufptr, optarg); +END + +OPTION(executable-by, x, [<ID|all|self>], + [<select images executable by the given user>]) +BEGIN + grecs_asprintf(&bufptr, &bufsize, "ExecutableBy.%d", ++xby_n); + eclat_query_add_param(q, bufptr, optarg); +END + +OPTIONS_END + +static void +parse_options(struct ec2_query *q, int argc, char *argv[], int *idx) +{ + char *bufptr = NULL; + size_t bufsize = 0; + static char *arch[] = { "i386", "x86_64", NULL }; + static char *voltype[] = { "standard", "io1", NULL }; + static char *imgtype[] = { "machine", "kernel", "ramdisk", NULL }; + static char *prodcode[] = { "devpay", "marketplace", NULL }; + static char *rootdevtype[] = { "ebs", "instance-store", NULL }; + static char *states[] = { "available", "pending", "failed", NULL }; + static char *virttype[] = { "paravirtual", "hvm", NULL }; + static char *hvstype[] = { "ovm", "xen", NULL }; + static struct filter_descr filters[] = { + { "architecture", FILTER_ENUM, arch }, + { "block-device-mapping.delete-on-termination", FILTER_BOOL }, + { "block-device-mapping.device-name", FILTER_STRING }, + { "block-device-mapping.snapshot-id", FILTER_STRING }, + { "block-device-mapping.volume-size", FILTER_INT }, + { "block-device-mapping.volume-type", FILTER_ENUM, voltype }, + { "description", FILTER_STRING }, + { "image-id", FILTER_STRING }, + { "image-type", FILTER_ENUM, imgtype }, + { "is-public", FILTER_BOOL }, + { "kernel-id", FILTER_STRING }, + { "manifest-location", FILTER_STRING }, + { "name", FILTER_STRING }, + { "owner-alias", FILTER_STRING }, + { "owner-id", FILTER_STRING }, + { "platform", FILTER_STRING }, + { "product-code", FILTER_STRING }, + { "product-code.type", FILTER_ENUM, prodcode }, + { "ramdisk-id", FILTER_STRING }, + { "root-device-name", FILTER_STRING }, + { "root-device-type", FILTER_ENUM, rootdevtype }, + { "state", FILTER_ENUM, states }, + { "state-reason-code", FILTER_STRING }, + { "state-reason-message", FILTER_STRING }, + { "tag-key", FILTER_STRING }, + { "tag-value", FILTER_STRING }, + { "tag:<key>", FILTER_STRING }, + { "virtualization-type", FILTER_ENUM, virttype }, + { "hypervisor", FILTER_ENUM, hvstype }, + { NULL } + }; + + available_filters = filters; + proginfo.print_help_hook = list_filters; + GETOPT(argc, argv, *idx, exit(EX_USAGE)) + free(bufptr); +} + + + + diff --git a/src/dscrimgs.c b/src/dscrimgs.c new file mode 100644 index 0000000..51d85b1 --- /dev/null +++ b/src/dscrimgs.c @@ -0,0 +1,34 @@ +/* This file is part of Eclat. + Copyright (C) 2013 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "eclat.h" +#include "dscrimgs-cl.h" + +int +eclat_describe_images(eclat_command_env_t *env, int argc, char **argv) +{ + int i; + + parse_options(env->query, argc, argv, &i); + + argc -= i; + argv += i; + + translate_ids(argc, argv, "ImageId"); + describe_query_create(env, argc, argv, "ImageId"); + + return 0; +} diff --git a/src/eclat.c b/src/eclat.c index eca1b71..d198345 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -272,6 +272,10 @@ struct command cmdtab[] = { eclat_detach_volume, CMD_MOD|CMD_DESTR }, { "modify-instance-attribute", "ModifyInstanceAttribute", eclat_modify_instance_attribute, CMD_MOD }, + { "describe-images", "DescribeImages", + eclat_describe_images }, + { "run-instances", "RunInstances", + eclat_run_instances, CMD_MOD }, }; size_t cmdcnt = sizeof(cmdtab) / sizeof(cmdtab[0]); diff --git a/src/eclat.h b/src/eclat.h index ba5d57b..011b666 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -107,6 +107,8 @@ int eclat_attach_volume(eclat_command_env_t *env, int argc, char **argv); int eclat_detach_volume(eclat_command_env_t *env, int argc, char **argv); int eclat_modify_instance_attribute(eclat_command_env_t *env, int argc, char **argv); +int eclat_run_instances(eclat_command_env_t *env, int argc, char **argv); +int eclat_describe_images(eclat_command_env_t *env, int argc, char **argv); char *region_to_endpoint(const char *region); diff --git a/src/runinsts-cl.opt b/src/runinsts-cl.opt new file mode 100644 index 0000000..9852e70 --- /dev/null +++ b/src/runinsts-cl.opt @@ -0,0 +1,231 @@ +/* This file is part of Eclat. + Copyright (C) 2013 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include <sys/stat.h> +#include <stdio.h> + +static char *ami; +static char *instance_count = "1"; +static struct grecs_list *secgrp, *devmap, *iface, *privip; +static char *keypair; +static char *user_data; +static char *type; +static char *zone; +static char *kernel; +static char *ramdisk; +static char *shutdown_behavior; +static char *placement_group; +static char *tenancy; +static char *subnet; +static char *private_ip; +static char *secipcount; +static char *profile_name; + +static int monitor; +static int disable_term; +static int ebs_opt; + +static void +read_user_data(const char *file) +{ + struct stat st; + FILE *fp; + + if (stat(file, &st)) + die(EX_USAGE, "cannot stat file %s: %s", file, + strerror(errno)); + + /* FIXME: Use limits.h to check st.st_size */ + user_data = grecs_malloc(st.st_size+1); + fp = fopen(file, "r"); + if (!fp) + die(EX_UNAVAILABLE, "cannot open file %s: %s", file, + strerror(errno)); + if (fread(user_data, st.st_size, 1, fp) != 1) + die(EX_UNAVAILABLE, "error reading from %s: %s", file, + strerror(errno)); + fclose(fp); + user_data[st.st_size] = 0; +} + +OPTIONS_BEGIN("eclat run-instances", + [<launch new instances>], + [<AMI-ID>], + [<gnu>], + [<nousage>], + [<noversion>]) + +OPTION(,n,[<N>], + [<number of instances to launch>]) +BEGIN + /* FIXME: check if it's a valid number */ + instance_count = optarg; +END + +OPTION(security-group,g,[<STRING>], + [<The name of the security group>]) +BEGIN + if (!secgrp) + secgrp = grecs_list_create(); + grecs_list_append(secgrp, optarg); +END + +OPTION(keypair,k,[<ID>], + [<Key pair name>]) +BEGIN + keypair = optarg; +END + +OPTION(data,d,[<STRING>], + [<user data to pass to the instance>]) +BEGIN + user_data = optarg; +END + +OPTION(data-file,f,[<FILE>], + [<read user data from FILE>]) +BEGIN + read_user_data(optarg); +END + +OPTION(type,t,[<TYPE>], + [<instance type>]) +ALIAS(instance-type) +BEGIN + type = optarg; +END + +OPTION(zone,z,[<ZONE>], + [<set availablility zone>]) +ALIAS(availability-zone) +BEGIN + zone = optarg; +END + +OPTION(kernel,,[<ID>], + [<select kernel ID>]) +BEGIN + kernel = optarg; +END + +OPTION(ramdisk,,[<ID>], + [<select ramdisk ID>]) +BEGIN + ramdisk = optarg; +END + +OPTION(devmap,m,[<DEV=SPEC>], + [<set block device mapping>]) +ALIAS(block-device-mapping) +BEGIN + if (!devmap) + devmap = grecs_list_create(); + grecs_list_append(devmap, optarg); +END + +OPTION(monitor,,, + [<enable monitoring>]) +BEGIN + monitor = 1; +END + +OPTION(disable-api-termination,,, + [<disable API termination>]) +BEGIN + disable_term = 1; +END + +OPTION(shutdown,,[<stop|terminate>], + [<what to do on shutdown>]) +ALIAS(instance-initiated-shutdown-behavior) +BEGIN + shutdown_behavior = optarg; +END + +OPTION(placement-group,,[<NAME>], + [<name of the placement group>]) +BEGIN + placement_group = optarg; +END + +OPTION(tenancy,,[<STRING>], + [<placement tenancy>]) +BEGIN + tenancy = optarg; +END + +OPTION(subnet,s,[<ID>], + [<subnet to launch the instance into>]) +BEGIN + subnet = optarg; +END + +OPTION(private-ip-address,,[<IP>], + [<assign a specific private IP to the VPC instance>]) +BEGIN + private_ip = optarg; +END + +dnl [--client-token token] + +OPTION(network-interface,a,[<IFACE>], + [<specify the network attachment for a VPC instance>]) +ALIAS(iface) +BEGIN + if (!iface) + iface = grecs_list_create(); + grecs_list_append(iface, optarg); +END + +OPTION(secondary-ip,,[<IP>], + [<assign the IP as a secondary private IP address>]) +ALIAS(secondary-private-ip-address) +BEGIN + if (!privip) + privip = grecs_list_create(); + grecs_list_append(privip, privip); +END + +OPTION(number-secondary-ip,,[<N>], + [<number of secondary IP addresses to assign>]) +ALIAS(secondary-private-ip-address-count) +BEGIN + secipcount = optarg; +END + +OPTION(iam-profile,p,[<NAME>], + [<IAM instance profile to associate with the launched instances>]) +BEGIN + profile_name = optarg; +END + +OPTION(ebs-optimized,,, + [<optimize the instances for EBS I/O>]) +BEGIN + ebs_opt = 1; +END + +OPTIONS_END + +static void +parse_options(int argc, char *argv[]) +{ + int idx; + GETOPT(argc, argv, idx, exit(EX_USAGE)) + if (idx != argc-1) + die(EX_USAGE, "bad number of arguments"); + ami = argv[idx]; +} diff --git a/src/runinsts.c b/src/runinsts.c new file mode 100644 index 0000000..826377d --- /dev/null +++ b/src/runinsts.c @@ -0,0 +1,374 @@ +/* This file is part of Eclat. + Copyright (C) 2013 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "eclat.h" +#include "runinsts-cl.h" + +static int +isnumstr(const char *p) +{ + for (; *p; p++) + if (!isdigit(*p)) + return 0; + return 1; +} + +static void +encode_devmap(struct ec2_query *q) +{ + int i; + char *bufptr = NULL; + size_t bufsize = 0; + struct grecs_list_entry *ep; + + for (i = 1, ep = devmap->head; ep; ep = ep->next, i++) { + char *dev = ep->data; + char *p = strchr(dev, '='); + + if (!p) + die(EX_USAGE, "malformed device mapping: %s", dev); + *p++ = 0; + + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d.DeviceName", + i); + eclat_query_add_param(q, bufptr, dev); + + if (strcmp(p, "none") == 0) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d.NoDevice", + i); + eclat_query_add_param(q, bufptr, NULL); + } else if (strncmp(p, "ephemeral", 9) == 0) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d.VirtualName", + i); + eclat_query_add_param(q, bufptr, p); + } else { + struct wordsplit ws; + + /* [snapshot-id]:[volume-size]:[true|false]:[standard|io1[:iops]] */ + ws.ws_delim = ":"; + if (wordsplit(p, &ws, + WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM)) + die(EX_SOFTWARE, + "failed to split string %s: %s", + p, + wordsplit_strerror(&ws)); + if (ws.ws_wordc == 1) { + if (strncmp(ws.ws_wordv[0], "snap-", 5) == 0) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d." + "Ebs.SnapshotId", + i); + } else if (isnumstr(ws.ws_wordv[0])) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d." + "Ebs.VolumeSize", + i); + } else + die(EX_USAGE, + "unrecognized word \"%s\", " + "expected either a snapshot ID, " + "or disk size", + ws.ws_wordv[0]); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[0]); + } else { + if (ws.ws_wordv[0]) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d." + "Ebs.SnapshotId", + i); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[0]); + } + + if (ws.ws_wordv[1]) { + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d." + "Ebs.VolumeSize", + i); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[1]); + } + } + + switch (ws.ws_wordc) { + default: + die(EX_USAGE, + "too many parts in device mapping \"%s\"", + p); + case 5: + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d.Ebs.Iops", + i); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[4]); + /* fall through */ + case 4: + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d.Ebs.VolumeType", + i); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[3]); + /* fall through */ + case 3: + if (strcmp(ws.ws_wordv[2], "false") && + strcmp(ws.ws_wordv[2], "true")) + die(EX_USAGE, + "expected \"true\" or \"false\", " + "but found \"%s\"", + ws.ws_wordv[2]); + grecs_asprintf(&bufptr, &bufsize, + "BlockDeviceMapping.%d." + "Ebs.DeleteOnTermination", + i); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[2]); + } + wordsplit_free(&ws); + } + } + free(bufptr); +} + +/* format: + + dev-index:subnet:description:priv-ip:sgs:DOT:sip-count:sips + 0 1 2 3 4 5 6 7 + + where: + + dev-index device index + subnet subnet ID + sgs a comma-separated list of security group IDs + DOT delete the interface on termination: true or false + sip-count number of secondary IP addresses to assign + sips a comma-separated list of secondary IP addresses + + only dev-index and subnet are mandatory; + either sip-count or sips can be specified, but not both. +*/ +void +add_iface(struct ec2_query *q, int ifno, char *ifspec) +{ + struct wordsplit ws; + char *bufptr = NULL; + size_t bufsize = 0; + char *p; + int i; + + ws.ws_delim = ":"; + if (wordsplit(ifspec, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM)) + die(EX_SOFTWARE, + "failed to split string %s: %s", + p, + wordsplit_strerror(&ws)); + + switch (ws.ws_wordc) { + default: + die(EX_USAGE, + "bad number of parts in interface specification \"%s\": %d", + ifspec, ws.ws_wordc); + case 8: + for (i = 1, p = strtok(ws.ws_wordv[7], ","); p; + i++, p = strtok(NULL, ",")) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d." + "PrivateIpAddresses.%d.PrivateIpAddress", + ifno, i); + eclat_query_add_param(q, bufptr, p); + } + /* fall through */ + case 7: + if (ws.ws_wordv[6][0]) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d." + "SecondaryPrivateIpAddressCount", + ifno); + eclat_query_add_param(q, bufptr, ws.ws_wordv[6]); + } + case 6: + if (ws.ws_wordv[5][0]) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d." + "DeleteOnTermination", + ifno); + eclat_query_add_param(q, bufptr, ws.ws_wordv[5]); + } + case 5: + if (ws.ws_wordv[4]) + for (i = 1, p = strtok(ws.ws_wordv[4], ","); p; + i++, p = strtok(NULL, ",")) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d." + "SecurityGroupId.%d", + ifno, i); + eclat_query_add_param(q, bufptr, p); + } + case 4: + if (ws.ws_wordv[3]) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d.PrivateIpAddress", + ifno); + eclat_query_add_param(q, bufptr, ws.ws_wordv[3]); + } + case 3: + if (ws.ws_wordv[2]) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d.Description", + ifno); + eclat_query_add_param(q, bufptr, ws.ws_wordv[2]); + } + case 2: + if (!ws.ws_wordv[1][0]) + die(EX_USAGE, + "no subnet ID in interface specification \"%s\"", + ifspec); + } + grecs_asprintf(&bufptr, &bufsize, "NetworkInterface.%d.SubnetId", + ifno); + eclat_query_add_param(q, bufptr, + ws.ws_wordv[1][0] ? ws.ws_wordv[1] : "0"); + + if (ws.ws_wordv[0][0]) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.%d.DeviceIndex", + ifno); + eclat_query_add_param(q, bufptr, ws.ws_wordv[0]); + } + + wordsplit_free(&ws); + free(bufptr); +} + +int +eclat_run_instances(eclat_command_env_t *env, int argc, char **argv) +{ + int i; + char *bufptr = NULL; + size_t bufsize = 0; + struct grecs_list_entry *ep; + struct ec2_query *q = env->query; + char *p; + int iface_no = 1; + + parse_options(argc, argv); + + eclat_query_add_param(q, "ImageId", ami); + p = strchr(instance_count, '-'); + eclat_query_add_param(q, "MinCount", instance_count); + if (p) { + *p++ = 0; + eclat_query_add_param(q, "MaxCount", p); + } else + eclat_query_add_param(q, "MaxCount", instance_count); + + if (keypair) + eclat_query_add_param(q, "KeyName", keypair); + + if (secgrp) { + for (i = 1, ep = secgrp->head; ep; ep = ep->next, i++) { + grecs_asprintf(&bufptr, &bufsize, + "SecurityGroup.%d", i); + eclat_query_add_param(q, bufptr, ep->data); + } + } + + if (type) + eclat_query_add_param(q, "InstanceType", type); + + if (zone) + eclat_query_add_param(q, "Placement.AvailabilityZone", zone); + + if (kernel) + eclat_query_add_param(q, "KernelId", kernel); + + if (ramdisk) + eclat_query_add_param(q, "RamdiskId", ramdisk); + + if (devmap) + encode_devmap(q); + + if (monitor) + eclat_query_add_param(q, "Monitoring.Enabled", "true"); + + if (disable_term) + eclat_query_add_param(q, "DisableApiTermination", "true"); + + if (shutdown_behavior) + eclat_query_add_param(q, "InstanceInitiatedShutdownBehavior", + "true"); + if (placement_group) + eclat_query_add_param(q, "Placement.GroupName", + placement_group); + + if (tenancy) + eclat_query_add_param(q, "Placement.Tenancy", tenancy); + + if (subnet) + eclat_query_add_param(q, "SubnetId", subnet); + + if (private_ip) + eclat_query_add_param(q, "PrivateIpAddress", private_ip); + + /* FIXME: I'm not at all sure whether this is the right way of + doing it. */ + if (privip) { + for (i = 1, ep = privip->head; ep; i++, ep = ep->next) { + grecs_asprintf(&bufptr, &bufsize, + "NetworkInterface.1." + "PrivateIpAddresses.%d.PrivateIpAddress", + i); + eclat_query_add_param(q, bufptr, ep->data); + } + iface_no++; + } else if (secipcount) { + eclat_query_add_param(q, + "NetworkInterface.1." + "SecondaryPrivateIpAddressCount", + secipcount); + iface_no++; + } + + if (iface) + for (ep = iface->head; ep; ep = ep->next) + add_iface(q, iface_no++, ep->data); + + if (profile_name) + eclat_query_add_param(q, + strncmp(profile_name, "arn:", 4) == 0 ? + "IamInstanceProfile.Arn" : + "IamInstanceProfile.Name", + profile_name); + + if (ebs_opt) + eclat_query_add_param(q, "EbsOptimized", "true"); + + if (user_data) { + size_t enclen; + + eclat_base64_encode((unsigned char *)user_data, + strlen(user_data), + (unsigned char**) &p, &enclen); + + eclat_query_add_param(q, "UserData", p); + free(p); + } + + return 0; +} |