Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
8d5a6b06
Commit
8d5a6b06
authored
Jul 27, 2015
by
Daniel Smith
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #11029 from justinsb/fix_aws_security_group_races
AWS: Fix security group races
parents
6c36f0df
23a190cd
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
77 additions
and
27 deletions
+77
-27
aws.go
pkg/cloudprovider/aws/aws.go
+77
-27
No files found.
pkg/cloudprovider/aws/aws.go
View file @
8d5a6b06
...
@@ -50,6 +50,12 @@ const ProviderName = "aws"
...
@@ -50,6 +50,12 @@ const ProviderName = "aws"
// The tag name we use to differentiate multiple logically independent clusters running in the same AZ
// The tag name we use to differentiate multiple logically independent clusters running in the same AZ
const
TagNameKubernetesCluster
=
"KubernetesCluster"
const
TagNameKubernetesCluster
=
"KubernetesCluster"
// We sometimes read to see if something exists; then try to create it if we didn't find it
// This can fail once in a consistent system if done in parallel
// In an eventually consistent system, it could fail unboundedly
// MaxReadThenCreateRetries sets the maxiumum number of attempts we will make
const
MaxReadThenCreateRetries
=
30
// Abstraction over AWS, to allow mocking/other implementations
// Abstraction over AWS, to allow mocking/other implementations
type
AWSServices
interface
{
type
AWSServices
interface
{
Compute
(
region
string
)
(
EC2
,
error
)
Compute
(
region
string
)
(
EC2
,
error
)
...
@@ -1656,37 +1662,56 @@ func (s *AWSCloud) removeSecurityGroupIngress(securityGroupId string, removePerm
...
@@ -1656,37 +1662,56 @@ func (s *AWSCloud) removeSecurityGroupIngress(securityGroupId string, removePerm
// Makes sure the security group exists
// Makes sure the security group exists
// Returns the security group id or error
// Returns the security group id or error
func
(
s
*
AWSCloud
)
ensureSecurityGroup
(
name
string
,
description
string
,
vpcID
string
)
(
string
,
error
)
{
func
(
s
*
AWSCloud
)
ensureSecurityGroup
(
name
string
,
description
string
,
vpcID
string
)
(
string
,
error
)
{
request
:=
&
ec2
.
DescribeSecurityGroupsInput
{}
groupID
:=
""
filters
:=
[]
*
ec2
.
Filter
{
attempt
:=
0
newEc2Filter
(
"group-name"
,
name
),
for
{
newEc2Filter
(
"vpc-id"
,
vpcID
),
attempt
++
}
request
.
Filters
=
s
.
addFilters
(
filters
)
securityGroups
,
err
:=
s
.
ec2
.
DescribeSecurityGroups
(
request
)
request
:=
&
ec2
.
DescribeSecurityGroupsInput
{}
if
err
!=
nil
{
filters
:=
[]
*
ec2
.
Filter
{
return
""
,
err
newEc2Filter
(
"group-name"
,
name
),
}
newEc2Filter
(
"vpc-id"
,
vpcID
),
}
request
.
Filters
=
s
.
addFilters
(
filters
)
if
len
(
securityGroups
)
>=
1
{
securityGroups
,
err
:=
s
.
ec2
.
DescribeSecurityGroups
(
request
)
if
len
(
securityGroups
)
>
1
{
if
err
!=
nil
{
glog
.
Warning
(
"Found multiple security groups with name:"
,
name
)
return
""
,
err
}
}
return
orEmpty
(
securityGroups
[
0
]
.
GroupID
),
nil
}
createRequest
:=
&
ec2
.
CreateSecurityGroupInput
{}
if
len
(
securityGroups
)
>=
1
{
createRequest
.
VPCID
=
&
vpcID
if
len
(
securityGroups
)
>
1
{
createRequest
.
GroupName
=
&
name
glog
.
Warning
(
"Found multiple security groups with name:"
,
name
)
createRequest
.
Description
=
&
description
}
return
orEmpty
(
securityGroups
[
0
]
.
GroupID
),
nil
}
createResponse
,
err
:=
s
.
ec2
.
CreateSecurityGroup
(
createRequest
)
createRequest
:=
&
ec2
.
CreateSecurityGroupInput
{}
if
err
!=
nil
{
createRequest
.
VPCID
=
&
vpcID
glog
.
Error
(
"error creating security group: "
,
err
)
createRequest
.
GroupName
=
&
name
return
""
,
err
createRequest
.
Description
=
&
description
}
groupID
:=
orEmpty
(
createResponse
.
GroupID
)
createResponse
,
err
:=
s
.
ec2
.
CreateSecurityGroup
(
createRequest
)
if
err
!=
nil
{
ignore
:=
false
switch
err
.
(
type
)
{
case
awserr
.
Error
:
awsError
:=
err
.
(
awserr
.
Error
)
if
awsError
.
Code
()
==
"InvalidGroup.Duplicate"
&&
attempt
<
MaxReadThenCreateRetries
{
glog
.
V
(
2
)
.
Infof
(
"Got InvalidGroup.Duplicate while creating security group (race?); will retry"
)
ignore
=
true
}
}
if
!
ignore
{
glog
.
Error
(
"error creating security group: "
,
err
)
return
""
,
err
}
time
.
Sleep
(
1
*
time
.
Second
)
}
else
{
groupID
=
orEmpty
(
createResponse
.
GroupID
)
break
}
}
if
groupID
==
""
{
if
groupID
==
""
{
return
""
,
fmt
.
Errorf
(
"created security group, but id was not returned: %s"
,
name
)
return
""
,
fmt
.
Errorf
(
"created security group, but id was not returned: %s"
,
name
)
}
}
...
@@ -1702,14 +1727,39 @@ func (s *AWSCloud) ensureSecurityGroup(name string, description string, vpcID st
...
@@ -1702,14 +1727,39 @@ func (s *AWSCloud) ensureSecurityGroup(name string, description string, vpcID st
tagRequest
:=
&
ec2
.
CreateTagsInput
{}
tagRequest
:=
&
ec2
.
CreateTagsInput
{}
tagRequest
.
Resources
=
[]
*
string
{
&
groupID
}
tagRequest
.
Resources
=
[]
*
string
{
&
groupID
}
tagRequest
.
Tags
=
tags
tagRequest
.
Tags
=
tags
_
,
err
=
s
.
ec2
.
CreateTags
(
tagRequest
)
if
_
,
err
:=
s
.
createTags
(
tagRequest
);
err
!=
nil
{
if
err
!=
nil
{
// Not clear how to recover fully from this; we're OK because we don't match on tags, but that is a little odd
// Not clear how to recover fully from this; we're OK because we don't match on tags, but that is a little odd
return
""
,
fmt
.
Errorf
(
"error tagging security group: %v"
,
err
)
return
""
,
fmt
.
Errorf
(
"error tagging security group: %v"
,
err
)
}
}
return
groupID
,
nil
return
groupID
,
nil
}
}
// createTags calls EC2 CreateTags, but adds retry-on-failure logic
// We retry mainly because if we create an object, we cannot tag it until it is "fully created" (eventual consistency)
// The error code varies though (depending on what we are tagging), so we simply retry on all errors
func
(
s
*
AWSCloud
)
createTags
(
request
*
ec2
.
CreateTagsInput
)
(
*
ec2
.
CreateTagsOutput
,
error
)
{
// TODO: We really should do exponential backoff here
attempt
:=
0
maxAttempts
:=
60
for
{
response
,
err
:=
s
.
ec2
.
CreateTags
(
request
)
if
err
==
nil
{
return
response
,
err
}
// We could check that the error is retryable, but the error code changes based on what we are tagging
// SecurityGroup: InvalidGroup.NotFound
attempt
++
if
attempt
>
maxAttempts
{
glog
.
Warningf
(
"Failed to create tags (too many attempts): %v"
,
err
)
return
response
,
err
}
glog
.
V
(
2
)
.
Infof
(
"Failed to create tags; will retry. Error was %v"
,
err
)
time
.
Sleep
(
1
*
time
.
Second
)
}
}
// CreateTCPLoadBalancer implements TCPLoadBalancer.CreateTCPLoadBalancer
// CreateTCPLoadBalancer implements TCPLoadBalancer.CreateTCPLoadBalancer
// TODO(justinsb): This must be idempotent
// TODO(justinsb): This must be idempotent
// TODO(justinsb) It is weird that these take a region. I suspect it won't work cross-region anwyay.
// TODO(justinsb) It is weird that these take a region. I suspect it won't work cross-region anwyay.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment