1package egoscale
2
3import (
4	"context"
5	"fmt"
6	"net/url"
7	"strconv"
8	"strings"
9)
10
11// SecurityGroup represent a firewalling set of rules
12type SecurityGroup struct {
13	Account     string        `json:"account,omitempty" doc:"the account owning the security group"`
14	Description string        `json:"description,omitempty" doc:"the description of the security group"`
15	EgressRule  []EgressRule  `json:"egressrule,omitempty" doc:"the list of egress rules associated with the security group"`
16	ID          *UUID         `json:"id" doc:"the ID of the security group"`
17	IngressRule []IngressRule `json:"ingressrule,omitempty" doc:"the list of ingress rules associated with the security group"`
18	Name        string        `json:"name,omitempty" doc:"the name of the security group"`
19}
20
21// UserSecurityGroup converts a SecurityGroup to a UserSecurityGroup
22func (sg SecurityGroup) UserSecurityGroup() UserSecurityGroup {
23	return UserSecurityGroup{
24		Group: sg.Name,
25	}
26}
27
28// ListRequest builds the ListSecurityGroups request
29func (sg SecurityGroup) ListRequest() (ListCommand, error) {
30	req := &ListSecurityGroups{
31		ID:                sg.ID,
32		SecurityGroupName: sg.Name,
33	}
34
35	return req, nil
36}
37
38// Delete deletes the given Security Group
39func (sg SecurityGroup) Delete(ctx context.Context, client *Client) error {
40	if sg.ID == nil && sg.Name == "" {
41		return fmt.Errorf("a SecurityGroup may only be deleted using ID or Name")
42	}
43
44	req := &DeleteSecurityGroup{}
45
46	if sg.ID != nil {
47		req.ID = sg.ID
48	} else {
49		req.Name = sg.Name
50	}
51
52	return client.BooleanRequestWithContext(ctx, req)
53}
54
55// RuleByID returns IngressRule or EgressRule by a rule ID
56func (sg SecurityGroup) RuleByID(ruleID UUID) (*IngressRule, *EgressRule) {
57	for i, in := range sg.IngressRule {
58		if in.RuleID.Equal(ruleID) {
59			return &sg.IngressRule[i], nil
60		}
61	}
62
63	for i, out := range sg.EgressRule {
64		if out.RuleID.Equal(ruleID) {
65			return nil, &sg.EgressRule[i]
66		}
67	}
68
69	return nil, nil
70}
71
72// IngressRule represents the ingress rule
73type IngressRule struct {
74	CIDR              *CIDR  `json:"cidr,omitempty" doc:"the CIDR notation for the base IP address of the security group rule"`
75	Description       string `json:"description,omitempty" doc:"description of the security group rule"`
76	EndPort           uint16 `json:"endport,omitempty" doc:"the ending port of the security group rule "`
77	IcmpCode          int    `json:"icmpcode,omitempty" doc:"the code for the ICMP message response"`
78	IcmpType          int    `json:"icmptype,omitempty" doc:"the type of the ICMP message response"`
79	Protocol          string `json:"protocol,omitempty" doc:"the protocol of the security group rule"`
80	RuleID            *UUID  `json:"ruleid" doc:"the id of the security group rule"`
81	SecurityGroupName string `json:"securitygroupname,omitempty" doc:"security group name"`
82	StartPort         uint16 `json:"startport,omitempty" doc:"the starting port of the security group rule"`
83}
84
85// EgressRule represents the ingress rule
86type EgressRule IngressRule
87
88// UserSecurityGroup represents the traffic of another security group
89type UserSecurityGroup struct {
90	Group string `json:"group,omitempty"`
91}
92
93// String gives the UserSecurityGroup name
94func (usg UserSecurityGroup) String() string {
95	return usg.Group
96}
97
98// CreateSecurityGroup represents a security group creation
99type CreateSecurityGroup struct {
100	Name        string `json:"name" doc:"name of the security group"`
101	Description string `json:"description,omitempty" doc:"the description of the security group"`
102	_           bool   `name:"createSecurityGroup" description:"Creates a security group"`
103}
104
105// Response returns the struct to unmarshal
106func (CreateSecurityGroup) Response() interface{} {
107	return new(SecurityGroup)
108}
109
110// DeleteSecurityGroup represents a security group deletion
111type DeleteSecurityGroup struct {
112	ID   *UUID  `json:"id,omitempty" doc:"The ID of the security group. Mutually exclusive with name parameter"`
113	Name string `json:"name,omitempty" doc:"The ID of the security group. Mutually exclusive with id parameter"`
114	_    bool   `name:"deleteSecurityGroup" description:"Deletes security group"`
115}
116
117// Response returns the struct to unmarshal
118func (DeleteSecurityGroup) Response() interface{} {
119	return new(BooleanResponse)
120}
121
122// AuthorizeSecurityGroupIngress (Async) represents the ingress rule creation
123type AuthorizeSecurityGroupIngress struct {
124	CIDRList              []CIDR              `json:"cidrlist,omitempty" doc:"the cidr list associated"`
125	Description           string              `json:"description,omitempty" doc:"the description of the ingress/egress rule"`
126	EndPort               uint16              `json:"endport,omitempty" doc:"end port for this ingress/egress rule"`
127	IcmpCode              int                 `json:"icmpcode,omitempty" doc:"error code for this icmp message"`
128	IcmpType              int                 `json:"icmptype,omitempty" doc:"type of the icmp message being sent"`
129	Protocol              string              `json:"protocol,omitempty" doc:"TCP is default. UDP, ICMP, ICMPv6, AH, ESP, GRE, IPIP are the other supported protocols"`
130	SecurityGroupID       *UUID               `json:"securitygroupid,omitempty" doc:"The ID of the security group. Mutually exclusive with securitygroupname parameter"`
131	SecurityGroupName     string              `json:"securitygroupname,omitempty" doc:"The name of the security group. Mutually exclusive with securitygroupid parameter"`
132	StartPort             uint16              `json:"startport,omitempty" doc:"start port for this ingress/egress rule"`
133	UserSecurityGroupList []UserSecurityGroup `json:"usersecuritygrouplist,omitempty" doc:"user to security group mapping"`
134	_                     bool                `name:"authorizeSecurityGroupIngress" description:"Authorize a particular ingress/egress rule for this security group"`
135}
136
137// Response returns the struct to unmarshal
138func (AuthorizeSecurityGroupIngress) Response() interface{} {
139	return new(AsyncJobResult)
140}
141
142// AsyncResponse returns the struct to unmarshal the async job
143func (AuthorizeSecurityGroupIngress) AsyncResponse() interface{} {
144	return new(SecurityGroup)
145}
146
147func (req AuthorizeSecurityGroupIngress) onBeforeSend(params url.Values) error {
148	// ICMP code and type may be zero but can also be omitted...
149	if strings.HasPrefix(strings.ToLower(req.Protocol), "icmp") {
150		params.Set("icmpcode", strconv.FormatInt(int64(req.IcmpCode), 10))
151		params.Set("icmptype", strconv.FormatInt(int64(req.IcmpType), 10))
152	}
153	// StartPort may be zero but can also be omitted...
154	if req.EndPort != 0 && req.StartPort == 0 {
155		params.Set("startport", "0")
156	}
157	return nil
158}
159
160// AuthorizeSecurityGroupEgress (Async) represents the egress rule creation
161type AuthorizeSecurityGroupEgress AuthorizeSecurityGroupIngress
162
163// Response returns the struct to unmarshal
164func (AuthorizeSecurityGroupEgress) Response() interface{} {
165	return new(AsyncJobResult)
166}
167
168// AsyncResponse returns the struct to unmarshal the async job
169func (AuthorizeSecurityGroupEgress) AsyncResponse() interface{} {
170	return new(SecurityGroup)
171}
172
173func (req AuthorizeSecurityGroupEgress) onBeforeSend(params url.Values) error {
174	return (AuthorizeSecurityGroupIngress)(req).onBeforeSend(params)
175}
176
177// RevokeSecurityGroupIngress (Async) represents the ingress/egress rule deletion
178type RevokeSecurityGroupIngress struct {
179	ID *UUID `json:"id" doc:"The ID of the ingress rule"`
180	_  bool  `name:"revokeSecurityGroupIngress" description:"Deletes a particular ingress rule from this security group"`
181}
182
183// Response returns the struct to unmarshal
184func (RevokeSecurityGroupIngress) Response() interface{} {
185	return new(AsyncJobResult)
186}
187
188// AsyncResponse returns the struct to unmarshal the async job
189func (RevokeSecurityGroupIngress) AsyncResponse() interface{} {
190	return new(BooleanResponse)
191}
192
193// RevokeSecurityGroupEgress (Async) represents the ingress/egress rule deletion
194type RevokeSecurityGroupEgress struct {
195	ID *UUID `json:"id" doc:"The ID of the egress rule"`
196	_  bool  `name:"revokeSecurityGroupEgress" description:"Deletes a particular egress rule from this security group"`
197}
198
199// Response returns the struct to unmarshal
200func (RevokeSecurityGroupEgress) Response() interface{} {
201	return new(AsyncJobResult)
202}
203
204// AsyncResponse returns the struct to unmarshal the async job
205func (RevokeSecurityGroupEgress) AsyncResponse() interface{} {
206	return new(BooleanResponse)
207}
208
209//go:generate go run generate/main.go -interface=Listable ListSecurityGroups
210
211// ListSecurityGroups represents a search for security groups
212type ListSecurityGroups struct {
213	ID                *UUID  `json:"id,omitempty" doc:"list the security group by the id provided"`
214	Keyword           string `json:"keyword,omitempty" doc:"List by keyword"`
215	Page              int    `json:"page,omitempty"`
216	PageSize          int    `json:"pagesize,omitempty"`
217	SecurityGroupName string `json:"securitygroupname,omitempty" doc:"lists security groups by name"`
218	VirtualMachineID  *UUID  `json:"virtualmachineid,omitempty" doc:"lists security groups by virtual machine id"`
219	_                 bool   `name:"listSecurityGroups" description:"Lists security groups"`
220}
221
222// ListSecurityGroupsResponse represents a list of security groups
223type ListSecurityGroupsResponse struct {
224	Count         int             `json:"count"`
225	SecurityGroup []SecurityGroup `json:"securitygroup"`
226}
227