1 /* This file is part of Eclat.
2 Copyright (C) 2013-2018 Sergey Poznyakoff.
3
4 Eclat is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Eclat is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "eclat.h"
18 #include "mkinst-cl.h"
19
20 /* format:
21
22 dev-index:subnet:description:priv-ip:sgs:DOT:sip-count:sips
23 0 1 2 3 4 5 6 7
24
25 where:
26
27 dev-index device index
28 subnet subnet ID
29 sgs a comma-separated list of security group IDs
30 DOT delete the interface on termination: true or false
31 sip-count number of secondary IP addresses to assign
32 sips a comma-separated list of secondary IP addresses
33
34 only dev-index and subnet are mandatory;
35 either sip-count or sips can be specified, but not both.
36 */
37 void
add_iface(struct ec2_request * q,int ifno,char * ifspec)38 add_iface(struct ec2_request *q, int ifno, char *ifspec)
39 {
40 struct wordsplit ws;
41 char *bufptr = NULL;
42 size_t bufsize = 0;
43 char *p;
44 int i;
45
46 ws.ws_delim = ":";
47 if (wordsplit(ifspec, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM))
48 die(EX_SOFTWARE,
49 "failed to split string %s: %s",
50 ifspec,
51 wordsplit_strerror(&ws));
52
53 switch (ws.ws_wordc) {
54 default:
55 die(EX_USAGE,
56 "bad number of parts in interface specification \"%s\": %d",
57 ifspec, ws.ws_wordc);
58 case 8:
59 for (i = 1, p = strtok(ws.ws_wordv[7], ","); p;
60 i++, p = strtok(NULL, ",")) {
61 grecs_asprintf(&bufptr, &bufsize,
62 "NetworkInterface.%d."
63 "PrivateIpAddresses.%d.PrivateIpAddress",
64 ifno, i);
65 eclat_request_add_param(q, bufptr, p);
66 }
67 /* fall through */
68 case 7:
69 if (ws.ws_wordv[6][0]) {
70 grecs_asprintf(&bufptr, &bufsize,
71 "NetworkInterface.%d."
72 "SecondaryPrivateIpAddressCount",
73 ifno);
74 eclat_request_add_param(q, bufptr, ws.ws_wordv[6]);
75 }
76 case 6:
77 if (ws.ws_wordv[5][0]) {
78 grecs_asprintf(&bufptr, &bufsize,
79 "NetworkInterface.%d."
80 "DeleteOnTermination",
81 ifno);
82 eclat_request_add_param(q, bufptr, ws.ws_wordv[5]);
83 }
84 case 5:
85 if (ws.ws_wordv[4])
86 for (i = 1, p = strtok(ws.ws_wordv[4], ","); p;
87 i++, p = strtok(NULL, ",")) {
88 grecs_asprintf(&bufptr, &bufsize,
89 "NetworkInterface.%d."
90 "SecurityGroupId.%d",
91 ifno, i);
92 eclat_request_add_param(q, bufptr, p);
93 }
94 case 4:
95 if (ws.ws_wordv[3]) {
96 grecs_asprintf(&bufptr, &bufsize,
97 "NetworkInterface.%d.PrivateIpAddress",
98 ifno);
99 eclat_request_add_param(q, bufptr, ws.ws_wordv[3]);
100 }
101 case 3:
102 if (ws.ws_wordv[2]) {
103 grecs_asprintf(&bufptr, &bufsize,
104 "NetworkInterface.%d.Description",
105 ifno);
106 eclat_request_add_param(q, bufptr, ws.ws_wordv[2]);
107 }
108 case 2:
109 if (!ws.ws_wordv[1][0])
110 die(EX_USAGE,
111 "no subnet ID in interface specification \"%s\"",
112 ifspec);
113 }
114 grecs_asprintf(&bufptr, &bufsize, "NetworkInterface.%d.SubnetId",
115 ifno);
116 eclat_request_add_param(q, bufptr,
117 ws.ws_wordv[1][0] ? ws.ws_wordv[1] : "0");
118
119 if (ws.ws_wordv[0][0]) {
120 grecs_asprintf(&bufptr, &bufsize,
121 "NetworkInterface.%d.DeviceIndex",
122 ifno);
123 eclat_request_add_param(q, bufptr, ws.ws_wordv[0]);
124 }
125
126 wordsplit_free(&ws);
127 free(bufptr);
128 }
129
130 int
eclat_run_instances(eclat_command_env_t * env,int argc,char ** argv)131 eclat_run_instances(eclat_command_env_t *env, int argc, char **argv)
132 {
133 int i;
134 char *bufptr = NULL;
135 size_t bufsize = 0;
136 struct grecs_list_entry *ep;
137 struct ec2_request *q = env->request;
138 char *p;
139 int iface_no = 1;
140
141 parse_options(env, argc, argv);
142
143 eclat_request_add_param(q, "ImageId", ami);
144 p = strchr(instance_count, '-');
145 eclat_request_add_param(q, "MinCount", instance_count);
146 if (p) {
147 *p++ = 0;
148 eclat_request_add_param(q, "MaxCount", p);
149 } else
150 eclat_request_add_param(q, "MaxCount", instance_count);
151
152 if (keypair)
153 eclat_request_add_param(q, "KeyName", keypair);
154
155 if (secgrp) {
156 for (i = 1, ep = secgrp->head; ep; ep = ep->next, i++) {
157 grecs_asprintf(&bufptr, &bufsize,
158 "SecurityGroup.%d", i);
159 eclat_request_add_param(q, bufptr, ep->data);
160 }
161 }
162
163 if (type)
164 eclat_request_add_param(q, "InstanceType", type);
165
166 if (zone)
167 eclat_request_add_param(q, "Placement.AvailabilityZone", zone);
168
169 if (kernel)
170 eclat_request_add_param(q, "KernelId", kernel);
171
172 if (ramdisk)
173 eclat_request_add_param(q, "RamdiskId", ramdisk);
174
175 if (devmap)
176 eclat_encode_devmap(q, devmap);
177
178 if (monitor)
179 eclat_request_add_param(q, "Monitoring.Enabled", "true");
180
181 if (disable_term)
182 eclat_request_add_param(q, "DisableApiTermination", "true");
183
184 if (shutdown_behavior)
185 eclat_request_add_param(q, "InstanceInitiatedShutdownBehavior",
186 "true");
187 if (placement_group)
188 eclat_request_add_param(q, "Placement.GroupName",
189 placement_group);
190
191 if (tenancy)
192 eclat_request_add_param(q, "Placement.Tenancy", tenancy);
193
194 if (subnet)
195 eclat_request_add_param(q, "SubnetId", subnet);
196
197 if (private_ip)
198 eclat_request_add_param(q, "PrivateIpAddress", private_ip);
199
200 /* FIXME: I'm not at all sure whether this is the right way of
201 doing it. */
202 if (privip) {
203 for (i = 1, ep = privip->head; ep; i++, ep = ep->next) {
204 grecs_asprintf(&bufptr, &bufsize,
205 "NetworkInterface.1."
206 "PrivateIpAddresses.%d.PrivateIpAddress",
207 i);
208 eclat_request_add_param(q, bufptr, ep->data);
209 }
210 iface_no++;
211 } else if (secipcount) {
212 eclat_request_add_param(q,
213 "NetworkInterface.1."
214 "SecondaryPrivateIpAddressCount",
215 secipcount);
216 iface_no++;
217 }
218
219 if (iface)
220 for (ep = iface->head; ep; ep = ep->next)
221 add_iface(q, iface_no++, ep->data);
222
223 if (profile_name)
224 eclat_request_add_param(q,
225 strncmp(profile_name, "arn:", 4) == 0 ?
226 "IamInstanceProfile.Arn" :
227 "IamInstanceProfile.Name",
228 profile_name);
229
230 if (ebs_opt)
231 eclat_request_add_param(q, "EbsOptimized", "true");
232
233 if (user_data) {
234 size_t enclen;
235
236 eclat_base64_encode((unsigned char *)user_data,
237 strlen(user_data),
238 (unsigned char**) &p, &enclen);
239
240 eclat_request_add_param(q, "UserData", p);
241 free(p);
242 }
243
244 return 0;
245 }
246