diff options
-rw-r--r-- | etc/Makefile.am | 1 | ||||
-rw-r--r-- | etc/describe-security-groups.fln | 59 | ||||
-rw-r--r-- | lib/forlan.c | 170 | ||||
-rw-r--r-- | lib/forlan.h | 5 | ||||
-rw-r--r-- | lib/forlangrm.y | 15 | ||||
-rw-r--r-- | lib/forlanlex.l | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/cretags.c | 2 | ||||
-rw-r--r-- | src/deltags.c | 1 | ||||
-rw-r--r-- | src/dscrsecgrps-cl.opt | 37 | ||||
-rw-r--r-- | src/dscrsecgrps.c | 35 | ||||
-rw-r--r-- | src/eclat.c | 4 | ||||
-rw-r--r-- | src/eclat.h | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/describe-security-groups.at | 82 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
16 files changed, 366 insertions, 52 deletions
diff --git a/etc/Makefile.am b/etc/Makefile.am index 514993c..3ccb0f4 100644 --- a/etc/Makefile.am +++ b/etc/Makefile.am @@ -24,6 +24,7 @@ FLNFILES=\ describe-instance-attribute.fln\ describe-instance-status.fln\ describe-instances.fln\ + describe-security-groups.fln\ describe-tags.fln\ describe-volumes.fln\ disassociate-address.fln\ diff --git a/etc/describe-security-groups.fln b/etc/describe-security-groups.fln new file mode 100644 index 0000000..55e2921 --- /dev/null +++ b/etc/describe-security-groups.fln @@ -0,0 +1,59 @@ +/* This file is part of Eclat. + Copyright (C) 2012 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/>. */ + +if (.DescribeSecurityGroupsResponse.securityGroupInfo) { + for (grp in .DescribeSecurityGroupsResponse.securityGroupInfo.item) { + print("Group ", grp.groupId,"\t", grp.groupName, "\t", + grp.groupDescription, "\n"); + print("VPC ID: ", grp.vpcId, "\n"); + for (var in grp.tagSet.item) { + print("TAG ", var.key, "\t", var.value, "\n"); + } + print("Incoming:\n"); + for (var in grp.ipPermissions.item) { + for (range in var.ipRanges.item) { + print(var.ipProtocol,"\t",range.cidrIp,"\t",var.fromPort); + if (var.fromPort != var.toPort) + print("-",var.toPort); + print("\n"); + } + for (usr in var.groups.item) { + print("user ", usr.userId, ", group ", usr.groupId, " (", usr.groupName, + ")\t", var.fromPort); + if (var.fromPort != var.toPort) + print("-",var.toPort); + print("\n"); + } + } + + print("Outgoing:\n"); + for (var in grp.ipPermissionsEgress.item) { + for (range in var.ipRanges.item) { + print(var.ipProtocol,"\t",range.cidrIp,"\t",var.fromPort); + if (var.fromPort != var.toPort) + print("-",var.toPort); + print("\n"); + } + for (usr in var.groups.item) { + print("user ", usr.userId, ", group ", usr.groupId, " (", usr.groupName, + ")\t", var.fromPort); + if (var.fromPort != var.toPort) + print("-",var.toPort); + print("\n"); + } + } + } +}
\ No newline at end of file diff --git a/lib/forlan.c b/lib/forlan.c index 74b03a3..f1d49d7 100644 --- a/lib/forlan.c +++ b/lib/forlan.c @@ -97,103 +97,161 @@ valtypestr(enum forlan_value_type t) } } -static void -coerce_retval(forlan_eval_env_t env, int c) +static int +value_boolean(struct forlan_value *val) { - enum forlan_value_type t; - struct grecs_node *node; + int res; - switch (c) { - case 's': - t = forlan_value_literal; + switch (val->type) { + case forlan_value_void: + err("controlling expression returned void, aborting"); + abort(); + + case forlan_value_node: + res = val->v.node != NULL; break; - case 'n': - t = forlan_value_node; + + case forlan_value_literal: + res = val->v.string != NULL && val->v.string[0] != 0; break; - case 'b': - t = forlan_value_boolean; + + case forlan_value_boolean: + res = val->v.num; break; - case ' ': - t = forlan_value_void; + + default: + abort(); } + return res; +} + +int +retval_boolean(forlan_eval_env_t env) +{ + return value_boolean(&env->retval); +} - if (t == env->retval.type) +static void +coerce_value(forlan_eval_env_t env, struct forlan_value *val, + enum forlan_value_type t) +{ + struct grecs_node *node; + + if (t == val->type) return; if (t == forlan_value_void) { - free_value(&env->retval); - env->retval.type = forlan_value_void; + free_value(val); + val->type = forlan_value_void; return; } - if (env->retval.type == forlan_value_void) { + if (val->type == forlan_value_void) { err("can't coerce %s to %s", - valtypestr(env->retval.type), + valtypestr(val->type), valtypestr(t)); abort(); } if (t == forlan_value_boolean) { - int res = retval_boolean(env); - free_value(&env->retval); - env->retval.type = forlan_value_boolean; - env->retval.v.num = res; + int res = value_boolean(val); + free_value(val); + val->type = forlan_value_boolean; + val->v.num = res; return; } /* Convert between string and node */ - switch (env->retval.type) { + switch (val->type) { case forlan_value_literal: - node = grecs_find_node(env->tree, env->retval.v.string); - free(env->retval.v.string); - env->retval.v.node = node; + node = grecs_find_node(env->tree, val->v.string); + free(val->v.string); + val->v.node = node; break; case forlan_value_node: - if (env->retval.v.node->type == grecs_node_stmt) { + if (val->v.node->type == grecs_node_stmt) { struct grecs_txtacc *acc = grecs_txtacc_create(); - grecs_txtacc_format_value(env->retval.v.node->v.value, + grecs_txtacc_format_value(val->v.node->v.value, 0, acc); - env->retval.v.string = grecs_txtacc_finish(acc, 1); + grecs_txtacc_grow_char(acc, 0); + val->v.string = grecs_txtacc_finish(acc, 1); grecs_txtacc_free(acc); } else - env->retval.v.string = grecs_strdup(""); + val->v.string = grecs_strdup(""); break; default: abort(); } - env->retval.type = t; + val->type = t; } + +static void +coerce_retval(forlan_eval_env_t env, int c) +{ + enum forlan_value_type t; + + switch (c) { + case 's': + t = forlan_value_literal; + break; + case 'n': + t = forlan_value_node; + break; + case 'b': + t = forlan_value_boolean; + break; + case ' ': + t = forlan_value_void; + } + coerce_value(env, &env->retval, t); +} + +#define T_E -1 +#define T_V forlan_value_void +#define T_N forlan_value_node +#define T_S forlan_value_literal +#define T_B forlan_value_boolean + +enum forlan_value_type convtab[FORLAN_NTYPES][FORLAN_NTYPES] = { + /* T_V T_N T_S T_B */ +/* T_V */ { T_E, T_E, T_E, T_E }, +/* T_N */ { T_E, T_S, T_S, T_B }, +/* T_S */ { T_E, T_S, T_S, T_B }, +/* T_B */ { T_E, T_B, T_B, T_B } +}; -int -retval_boolean(forlan_eval_env_t env) +static int +values_equal(forlan_eval_env_t env, + struct forlan_value *a, struct forlan_value *b) { int res; - - switch (env->retval.type) { - case forlan_value_void: - err("controlling expression returned void, aborting"); - abort(); + enum forlan_value_type t; - case forlan_value_node: - res = env->retval.v.node != NULL; - break; + t = convtab[a->type][b->type]; + if (t == T_E) { + err("incompatible values for comparison: %s, %s", + valtypestr(a->type), + valtypestr(b->type)); + abort(); + } + coerce_value(env, a, t); + coerce_value(env, b, t); - case forlan_value_literal: - res = env->retval.v.string != NULL && - env->retval.v.string[0] != 0; + switch (t) { + case T_S: + res = strcmp(a->v.string, b->v.string) == 0; break; - - case forlan_value_boolean: - res = env->retval.v.num; + case T_B: + res = !!a->v.num == !!b->v.num; break; - default: abort(); } return res; } + void eval_func(forlan_eval_env_t env, union forlan_node *node); void eval_last(forlan_eval_env_t env, union forlan_node *node); @@ -460,6 +518,7 @@ void eval_expr(forlan_eval_env_t env, union forlan_node *node) { int res; + struct forlan_value lval; free_value(&env->retval); switch (node->expr.opcode) { @@ -486,7 +545,20 @@ eval_expr(forlan_eval_env_t env, union forlan_node *node) env->retval.type = forlan_value_boolean; env->retval.v.num = !res; break; - + + case forlan_opcode_eq: + case forlan_opcode_ne: + forlan_eval(env, node->expr.arg[0]); + copy_value(&lval, &env->retval); + forlan_eval(env, node->expr.arg[1]); + res = values_equal(env, &lval, &env->retval); + free_value(&lval); + free_value(&env->retval); + env->retval.type = forlan_value_boolean; + env->retval.v.num = node->expr.opcode == forlan_opcode_eq ? + res : !res; + break; + default: abort(); } diff --git a/lib/forlan.h b/lib/forlan.h index 424cea8..0670480 100644 --- a/lib/forlan.h +++ b/lib/forlan.h @@ -123,7 +123,9 @@ enum forlan_opcode { forlan_opcode_node, /* Evaluate node, set 'last' */ forlan_opcode_and, /* Boolean AND */ forlan_opcode_or, /* Boolean OR */ - forlan_opcode_not /* Boolean NOT */ + forlan_opcode_not, /* Boolean NOT */ + forlan_opcode_eq, /* Equality */ + forlan_opcode_ne /* Inequality */ }; /* Boolean expression */ @@ -164,6 +166,7 @@ enum forlan_value_type { forlan_value_literal, forlan_value_boolean }; +#define FORLAN_NTYPES 4 struct forlan_value { enum forlan_value_type type; diff --git a/lib/forlangrm.y b/lib/forlangrm.y index eb7fc6f..5c91f1a 100644 --- a/lib/forlangrm.y +++ b/lib/forlangrm.y @@ -64,6 +64,7 @@ free_comp(void *p) %left OR %left AND +%nonassoc EQ NE %left NOT %type <node> stmt stmt_cond stmt_expr stmt_blk cond bool node funcall arg rval @@ -152,6 +153,20 @@ bool : node $$->expr.opcode = forlan_opcode_not; $$->expr.arg[0] = $2; } + | node EQ node + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_eq; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } + | node NE node + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_ne; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } | '(' bool ')' { $$ = $2; diff --git a/lib/forlanlex.l b/lib/forlanlex.l index 8b3d29a..8df6d80 100644 --- a/lib/forlanlex.l +++ b/lib/forlanlex.l @@ -83,6 +83,8 @@ continue return CONTINUE; ! return NOT; "&&" return AND; "||" return OR; +"==" return EQ; +"!=" return NE; {IDC}{IDC}* { grecs_line_begin(); grecs_line_add(yytext, yyleng); yylval.string = grecs_line_finish(); diff --git a/src/Makefile.am b/src/Makefile.am index de1c17b..1f533ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,6 +29,7 @@ eclat_SOURCES=\ dscrinstattr.c\ dscrinsts.c\ dscrinststat.c\ + dscrsecgrps.c\ dscrvols.c\ eclat.c\ eclat.h\ @@ -50,6 +51,7 @@ OPTFILES=\ disassaddr-cl.opt\ dscraddrs-cl.opt\ dscrinststat-cl.opt\ + dscrsecgrps-cl.opt\ generic-cl.opt eclat_SOURCES += $(OPTFILES:.opt=.h) diff --git a/src/cretags.c b/src/cretags.c index 1831839..b46d02a 100644 --- a/src/cretags.c +++ b/src/cretags.c @@ -49,7 +49,7 @@ eclat_create_tags(CURL *curl, int argc, char **argv) grecs_asprintf(&bufptr, &bufsize, "Tag.%d.Value", rno); eclat_query_add_param(q, bufptr, argv[i + 2]); } - + free(bufptr); return eclat_send_query(curl, q); } diff --git a/src/deltags.c b/src/deltags.c index 924d94d..e599570 100644 --- a/src/deltags.c +++ b/src/deltags.c @@ -55,6 +55,7 @@ eclat_delete_tags(CURL *curl, int argc, char **argv) eclat_query_add_param(q, bufptr, p); } } + free(bufptr); return eclat_send_query(curl, q); } diff --git a/src/dscrsecgrps-cl.opt b/src/dscrsecgrps-cl.opt new file mode 100644 index 0000000..9aa657d --- /dev/null +++ b/src/dscrsecgrps-cl.opt @@ -0,0 +1,37 @@ +/* This file is part of Eclat. + Copyright (C) 2012 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/>. */ + +OPTIONS_BEGIN("eclat describe-security-groups", + [<returns information about security groups>], + [<[FILTER...]>], + [<gnu>], + [<nousage>], + [<noversion>]) + +OPTION(group-name,n,, + [<treat non-filter arguments as group names, instead of group IDs>]) +BEGIN + name_option = 1; +END + +OPTIONS_END + +static void +parse_options(int argc, char *argv[], int *index) +{ + GETOPT(argc, argv, *index, exit(EX_USAGE)) +} + diff --git a/src/dscrsecgrps.c b/src/dscrsecgrps.c new file mode 100644 index 0000000..7049ddb --- /dev/null +++ b/src/dscrsecgrps.c @@ -0,0 +1,35 @@ +/* This file is part of Eclat. + Copyright (C) 2012 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" +static int name_option; +#include "dscrsecgrps-cl.h" + +int +eclat_describe_security_groups(CURL *curl, int argc, char **argv) +{ + int i; + struct ec2_query *q; + + parse_options(argc, argv, &i); + argv += i; + argc -= i; + + q = describe_query_create(curl, "DescribeSecurityGroups", argc, argv, + name_option ? "GroupName" : "GroupId"); + return eclat_send_query(curl, q); +} + diff --git a/src/eclat.c b/src/eclat.c index 2b0047e..f229e77 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -244,7 +244,9 @@ struct command cmdtab[] = { { "delete-tags", "DeleteTags", eclat_delete_tags }, { "get-console-output", "GetConsoleOutput", - eclat_get_console_output } + eclat_get_console_output }, + { "describe-security-groups", "DescribeSecurityGroups", + eclat_describe_security_groups } }; size_t cmdcnt = sizeof(cmdtab) / sizeof(cmdtab[0]); diff --git a/src/eclat.h b/src/eclat.h index 8d488f9..a82a28a 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -71,6 +71,7 @@ int eclat_get_console_output(CURL *curl, int argc, char **argv); int eclat_describe_instance_attribute(CURL *curl, int argc, char **argv); int eclat_create_tags(CURL *curl, int argc, char **argv); int eclat_delete_tags(CURL *curl, int argc, char **argv); +int eclat_describe_security_groups(CURL *curl, int argc, char **argv); char *region_to_endpoint(const char *region); diff --git a/tests/Makefile.am b/tests/Makefile.am index c03730f..abe8f98 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -46,6 +46,7 @@ TESTSUITE_AT = \ describe-instance-attribute.at\ describe-instance-status.at\ describe-instances.at\ + describe-security-groups.at\ describe-tags.at\ describe-volumes.at\ dump01.at\ diff --git a/tests/describe-security-groups.at b/tests/describe-security-groups.at new file mode 100644 index 0000000..4b424d8 --- /dev/null +++ b/tests/describe-security-groups.at @@ -0,0 +1,82 @@ +# This file is part of Eclat -*- Autotest -*- +# Copyright (C) 2012 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/>. + +ECLAT_TEST_FORMAT([DescribeSecurityGroups], +[DescribeSecurityGroups], +[describe-security-groups.fln], +[<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2012-08-15/"> + <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId> + <securityGroupInfo> + <item> + <ownerId>111122223333</ownerId> + <groupId>sg-443d0a12</groupId> + <groupName>WebServers</groupName> + <groupDescription>Web Servers</groupDescription> + <vpcId/> + <ipPermissions> + <item> + <ipProtocol>tcp</ipProtocol> + <fromPort>80</fromPort> + <toPort>80</toPort> + <groups/> + <ipRanges> + <item> + <cidrIp>0.0.0.0/0</cidrIp> + </item> + </ipRanges> + </item> + </ipPermissions> + <ipPermissionsEgress/> + <tagSet/> + </item> + <item> + <ownerId>111122223333</ownerId> + <groupId>sg-5ff8a023</groupId> + <groupName>RangedPortsBySource</groupName> + <groupDescription>Group A</groupDescription> + <ipPermissions> + <item> + <ipProtocol>tcp</ipProtocol> + <fromPort>6000</fromPort> + <toPort>7000</toPort> + <groups> + <item> + <userId>111122223333</userId> + <groupId>sg-99gh4012</groupId> + <groupName>Group B</groupName> + </item> + </groups> + <ipRanges/> + </item> + </ipPermissions> + <ipPermissionsEgress/> + <tagSet/> + </item> + </securityGroupInfo> +</DescribeSecurityGroupsResponse> +], +[Group sg-443d0a12 WebServers "Web Servers" +VPC ID: +Incoming: +tcp 0.0.0.0/0 80 +Outgoing: +Group sg-5ff8a023 RangedPortsBySource "Group A" +VPC ID: +Incoming: +user 111122223333, group sg-99gh4012 ("Group B") 6000-7000 +Outgoing: +]) + diff --git a/tests/testsuite.at b/tests/testsuite.at index b47591f..c740e1f 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -60,6 +60,7 @@ m4_include([describe-addresses.at]) m4_include([describe-instance-attribute.at]) m4_include([describe-instance-status.at]) m4_include([describe-instances.at]) +m4_include([describe-security-groups.at]) m4_include([describe-tags.at]) m4_include([describe-volumes.at]) m4_include([get-console-output.at]) |