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
057be1fc
Commit
057be1fc
authored
Aug 10, 2015
by
Alex Robinson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12406 from smarterclayton/namespace_estimate_delete
Namespace must estimate and requeue content deletions
parents
f195a80e
62b6ca16
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
93 additions
and
26 deletions
+93
-26
controller.go
pkg/controller/framework/controller.go
+10
-0
namespace_controller.go
pkg/controller/namespace/namespace_controller.go
+83
-26
No files found.
pkg/controller/framework/controller.go
View file @
057be1fc
...
@@ -106,6 +106,16 @@ func (c *Controller) HasSynced() bool {
...
@@ -106,6 +106,16 @@ func (c *Controller) HasSynced() bool {
return
c
.
reflector
.
LastSyncResourceVersion
()
!=
""
return
c
.
reflector
.
LastSyncResourceVersion
()
!=
""
}
}
// Requeue adds the provided object back into the queue if it does not already exist.
func
(
c
*
Controller
)
Requeue
(
obj
interface
{})
error
{
return
c
.
config
.
Queue
.
AddIfNotPresent
(
cache
.
Deltas
{
cache
.
Delta
{
Type
:
cache
.
Sync
,
Object
:
obj
,
},
})
}
// processLoop drains the work queue.
// processLoop drains the work queue.
// TODO: Consider doing the processing in parallel. This will require a little thought
// TODO: Consider doing the processing in parallel. This will require a little thought
// to make sure that we don't end up processing the same object multiple times
// to make sure that we don't end up processing the same object multiple times
...
...
pkg/controller/namespace/namespace_controller.go
View file @
057be1fc
...
@@ -17,6 +17,7 @@ limitations under the License.
...
@@ -17,6 +17,7 @@ limitations under the License.
package
namespacecontroller
package
namespacecontroller
import
(
import
(
"fmt"
"time"
"time"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api"
...
@@ -41,7 +42,8 @@ type NamespaceController struct {
...
@@ -41,7 +42,8 @@ type NamespaceController struct {
// NewNamespaceController creates a new NamespaceController
// NewNamespaceController creates a new NamespaceController
func
NewNamespaceController
(
kubeClient
client
.
Interface
,
resyncPeriod
time
.
Duration
)
*
NamespaceController
{
func
NewNamespaceController
(
kubeClient
client
.
Interface
,
resyncPeriod
time
.
Duration
)
*
NamespaceController
{
_
,
controller
:=
framework
.
NewInformer
(
var
controller
*
framework
.
Controller
_
,
controller
=
framework
.
NewInformer
(
&
cache
.
ListWatch
{
&
cache
.
ListWatch
{
ListFunc
:
func
()
(
runtime
.
Object
,
error
)
{
ListFunc
:
func
()
(
runtime
.
Object
,
error
)
{
return
kubeClient
.
Namespaces
()
.
List
(
labels
.
Everything
(),
fields
.
Everything
())
return
kubeClient
.
Namespaces
()
.
List
(
labels
.
Everything
(),
fields
.
Everything
())
...
@@ -55,16 +57,41 @@ func NewNamespaceController(kubeClient client.Interface, resyncPeriod time.Durat
...
@@ -55,16 +57,41 @@ func NewNamespaceController(kubeClient client.Interface, resyncPeriod time.Durat
framework
.
ResourceEventHandlerFuncs
{
framework
.
ResourceEventHandlerFuncs
{
AddFunc
:
func
(
obj
interface
{})
{
AddFunc
:
func
(
obj
interface
{})
{
namespace
:=
obj
.
(
*
api
.
Namespace
)
namespace
:=
obj
.
(
*
api
.
Namespace
)
err
:=
syncNamespace
(
kubeClient
,
*
namespace
)
if
err
:=
syncNamespace
(
kubeClient
,
*
namespace
);
err
!=
nil
{
if
err
!=
nil
{
if
estimate
,
ok
:=
err
.
(
*
contentRemainingError
);
ok
{
glog
.
Error
(
err
)
go
func
()
{
// Estimate is the aggregate total of TerminationGracePeriodSeconds, which defaults to 30s
// for pods. However, most processes will terminate faster - within a few seconds, probably
// with a peak within 5-10s. So this division is a heuristic that avoids waiting the full
// duration when in many cases things complete more quickly. The extra second added is to
// ensure we never wait 0 seconds.
t
:=
estimate
.
Estimate
/
2
+
1
glog
.
V
(
4
)
.
Infof
(
"Content remaining in namespace %s, waiting %d seconds"
,
namespace
.
Name
,
t
)
time
.
Sleep
(
time
.
Duration
(
t
)
*
time
.
Second
)
if
err
:=
controller
.
Requeue
(
namespace
);
err
!=
nil
{
util
.
HandleError
(
err
)
}
}()
return
}
util
.
HandleError
(
err
)
}
}
},
},
UpdateFunc
:
func
(
oldObj
,
newObj
interface
{})
{
UpdateFunc
:
func
(
oldObj
,
newObj
interface
{})
{
namespace
:=
newObj
.
(
*
api
.
Namespace
)
namespace
:=
newObj
.
(
*
api
.
Namespace
)
err
:=
syncNamespace
(
kubeClient
,
*
namespace
)
if
err
:=
syncNamespace
(
kubeClient
,
*
namespace
);
err
!=
nil
{
if
err
!=
nil
{
if
estimate
,
ok
:=
err
.
(
*
contentRemainingError
);
ok
{
glog
.
Error
(
err
)
go
func
()
{
t
:=
estimate
.
Estimate
/
2
+
1
glog
.
V
(
4
)
.
Infof
(
"Content remaining in namespace %s, waiting %d seconds"
,
namespace
.
Name
,
t
)
time
.
Sleep
(
time
.
Duration
(
t
)
*
time
.
Second
)
if
err
:=
controller
.
Requeue
(
namespace
);
err
!=
nil
{
util
.
HandleError
(
err
)
}
}()
return
}
util
.
HandleError
(
err
)
}
}
},
},
},
},
...
@@ -114,45 +141,56 @@ func finalize(kubeClient client.Interface, namespace api.Namespace) (*api.Namesp
...
@@ -114,45 +141,56 @@ func finalize(kubeClient client.Interface, namespace api.Namespace) (*api.Namesp
return
kubeClient
.
Namespaces
()
.
Finalize
(
&
namespaceFinalize
)
return
kubeClient
.
Namespaces
()
.
Finalize
(
&
namespaceFinalize
)
}
}
// deleteAllContent will delete all content known to the system in a namespace
type
contentRemainingError
struct
{
func
deleteAllContent
(
kubeClient
client
.
Interface
,
namespace
string
)
(
err
error
)
{
Estimate
int64
}
func
(
e
*
contentRemainingError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"some content remains in the namespace, estimate %d seconds before it is removed"
,
e
.
Estimate
)
}
// deleteAllContent will delete all content known to the system in a namespace. It returns an estimate
// of the time remaining before the remaining resources are deleted. If estimate > 0 not all resources
// are guaranteed to be gone.
func
deleteAllContent
(
kubeClient
client
.
Interface
,
namespace
string
,
before
util
.
Time
)
(
estimate
int64
,
err
error
)
{
err
=
deleteServiceAccounts
(
kubeClient
,
namespace
)
err
=
deleteServiceAccounts
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteServices
(
kubeClient
,
namespace
)
err
=
deleteServices
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteReplicationControllers
(
kubeClient
,
namespace
)
err
=
deleteReplicationControllers
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
e
rr
=
deletePods
(
kubeClient
,
namespac
e
)
e
stimate
,
err
=
deletePods
(
kubeClient
,
namespace
,
befor
e
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteSecrets
(
kubeClient
,
namespace
)
err
=
deleteSecrets
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deletePersistentVolumeClaims
(
kubeClient
,
namespace
)
err
=
deletePersistentVolumeClaims
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteLimitRanges
(
kubeClient
,
namespace
)
err
=
deleteLimitRanges
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteResourceQuotas
(
kubeClient
,
namespace
)
err
=
deleteResourceQuotas
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
err
=
deleteEvents
(
kubeClient
,
namespace
)
err
=
deleteEvents
(
kubeClient
,
namespace
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
e
stimate
,
e
rr
}
}
return
nil
return
estimate
,
nil
}
}
// syncNamespace makes namespace life-cycle decisions
// syncNamespace makes namespace life-cycle decisions
...
@@ -160,6 +198,7 @@ func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err er
...
@@ -160,6 +198,7 @@ func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err er
if
namespace
.
DeletionTimestamp
==
nil
{
if
namespace
.
DeletionTimestamp
==
nil
{
return
nil
return
nil
}
}
glog
.
V
(
4
)
.
Infof
(
"Syncing namespace %s"
,
namespace
.
Name
)
// if there is a deletion timestamp, and the status is not terminating, then update status
// if there is a deletion timestamp, and the status is not terminating, then update status
if
!
namespace
.
DeletionTimestamp
.
IsZero
()
&&
namespace
.
Status
.
Phase
!=
api
.
NamespaceTerminating
{
if
!
namespace
.
DeletionTimestamp
.
IsZero
()
&&
namespace
.
Status
.
Phase
!=
api
.
NamespaceTerminating
{
...
@@ -185,10 +224,13 @@ func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err er
...
@@ -185,10 +224,13 @@ func syncNamespace(kubeClient client.Interface, namespace api.Namespace) (err er
}
}
// there may still be content for us to remove
// there may still be content for us to remove
e
rr
=
deleteAllContent
(
kubeClient
,
namespace
.
Name
)
e
stimate
,
err
:=
deleteAllContent
(
kubeClient
,
namespace
.
Name
,
*
namespace
.
DeletionTimestamp
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
estimate
>
0
{
return
&
contentRemainingError
{
estimate
}
}
// we have removed content, so mark it finalized by us
// we have removed content, so mark it finalized by us
result
,
err
:=
finalize
(
kubeClient
,
namespace
)
result
,
err
:=
finalize
(
kubeClient
,
namespace
)
...
@@ -277,18 +319,33 @@ func deleteReplicationControllers(kubeClient client.Interface, ns string) error
...
@@ -277,18 +319,33 @@ func deleteReplicationControllers(kubeClient client.Interface, ns string) error
return
nil
return
nil
}
}
func
deletePods
(
kubeClient
client
.
Interface
,
ns
string
)
error
{
func
deletePods
(
kubeClient
client
.
Interface
,
ns
string
,
before
util
.
Time
)
(
int64
,
error
)
{
items
,
err
:=
kubeClient
.
Pods
(
ns
)
.
List
(
labels
.
Everything
(),
fields
.
Everything
())
items
,
err
:=
kubeClient
.
Pods
(
ns
)
.
List
(
labels
.
Everything
(),
fields
.
Everything
())
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
0
,
err
}
}
expired
:=
util
.
Now
()
.
After
(
before
.
Time
)
var
deleteOptions
*
api
.
DeleteOptions
if
expired
{
deleteOptions
=
api
.
NewDeleteOptions
(
0
)
}
estimate
:=
int64
(
0
)
for
i
:=
range
items
.
Items
{
for
i
:=
range
items
.
Items
{
err
:=
kubeClient
.
Pods
(
ns
)
.
Delete
(
items
.
Items
[
i
]
.
Name
,
nil
)
if
items
.
Items
[
i
]
.
Spec
.
TerminationGracePeriodSeconds
!=
nil
{
grace
:=
*
items
.
Items
[
i
]
.
Spec
.
TerminationGracePeriodSeconds
if
grace
>
estimate
{
estimate
=
grace
}
}
err
:=
kubeClient
.
Pods
(
ns
)
.
Delete
(
items
.
Items
[
i
]
.
Name
,
deleteOptions
)
if
err
!=
nil
&&
!
errors
.
IsNotFound
(
err
)
{
if
err
!=
nil
&&
!
errors
.
IsNotFound
(
err
)
{
return
err
return
0
,
err
}
}
}
}
return
nil
if
expired
{
estimate
=
0
}
return
estimate
,
nil
}
}
func
deleteEvents
(
kubeClient
client
.
Interface
,
ns
string
)
error
{
func
deleteEvents
(
kubeClient
client
.
Interface
,
ns
string
)
error
{
...
...
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