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
e479c521
Commit
e479c521
authored
Jul 01, 2015
by
Zach Loafman
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #10618 from marekbiskup/namespaces-in-addon-update
Namespaces in addon update
parents
9db58ff2
8df3a9ca
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
114 additions
and
80 deletions
+114
-80
kube-addon-update.sh
cluster/saltbase/salt/kube-addons/kube-addon-update.sh
+84
-54
addon_update.go
test/e2e/addon_update.go
+30
-26
No files found.
cluster/saltbase/salt/kube-addons/kube-addon-update.sh
View file @
e479c521
...
...
@@ -113,9 +113,11 @@ except Exception, ex:
}
# $1 yaml file path
function
get-object-name-from-file
()
{
# returns a string of the form <namespace>/<name> (we call it nsnames)
function
get-object-nsname-from-file
()
{
# prints to stdout, so log cannot be used
#WARNING: only yaml is supported
#addons that do not specify a namespace are assumed to be in "default".
cat
$1
| python
-c
'''
try:
import pipes,sys,yaml
...
...
@@ -126,7 +128,10 @@ try:
# Otherwise we are ignoring them (the update will not work anyway)
print "ERROR"
else:
print y["metadata"]["name"]
try:
print "%s/%s" % (y["metadata"]["namespace"], y["metadata"]["name"])
except Exception, ex:
print "default/%s" % y["metadata"]["name"]
except Exception, ex:
print "ERROR"
'''
...
...
@@ -136,7 +141,7 @@ except Exception, ex:
# $2 addon type (e.g. ReplicationController)
# echoes the string with paths to files containing addon for the given type
# works only for yaml files (!) (ignores json files)
function
get-addons-from-disk
()
{
function
get-addon
-path
s-from-disk
()
{
# prints to stdout, so log cannot be used
local
-r
addon_dir
=
$1
local
-r
obj_type
=
$2
...
...
@@ -184,9 +189,10 @@ function run-until-success() {
}
# $1 object type
function
get-addons-from-server
()
{
# returns a list of <namespace>/<name> pairs (nsnames)
function
get-addon-nsnames-from-server
()
{
local
-r
obj_type
=
$1
"
${
KUBECTL
}
"
get
"
${
obj_type
}
"
-
o
template
-t
"{{range.items}}
{{.metadata.name}} {{end}}"
--api-version
=
v1beta3
-l
kubernetes.io/cluster-service
=
true
"
${
KUBECTL
}
"
get
"
${
obj_type
}
"
-
-all-namespaces
-o
template
-t
"{{range.items}}{{.metadata.namespace}}/
{{.metadata.name}} {{end}}"
--api-version
=
v1beta3
-l
kubernetes.io/cluster-service
=
true
}
# returns the characters after the last separator (including)
...
...
@@ -228,38 +234,52 @@ function get-basename() {
function
stop-object
()
{
local
-r
obj_type
=
$1
local
-r
obj_name
=
$2
log INFO
"Stopping
${
obj_type
}
${
obj_name
}
"
run-until-success
"
${
KUBECTL
}
stop
${
obj_type
}
${
obj_name
}
"
${
NUM_TRIES
}
${
DELAY_AFTER_ERROR_SEC
}
local
-r
namespace
=
$2
local
-r
obj_name
=
$3
log INFO
"Stopping
${
obj_type
}
${
namespace
}
/
${
obj_name
}
"
run-until-success
"
${
KUBECTL
}
stop --namespace=
${
namespace
}
${
obj_type
}
${
obj_name
}
"
${
NUM_TRIES
}
${
DELAY_AFTER_ERROR_SEC
}
}
function
create-object
()
{
local
-r
obj_type
=
$1
local
-r
file_path
=
$2
log INFO
"Creating new
${
obj_type
}
from file
${
file_path
}
"
local
nsname_from_file
nsname_from_file
=
$(
get-object-nsname-from-file
${
file_path
})
if
[[
"
${
nsname_from_file
}
"
==
"ERROR"
]]
;
then
log INFO
"Cannot read object name from
${
file_path
}
. Ignoring"
return
1
fi
IFS
=
'/'
read
namespace obj_name
<<<
"
${
nsname_from_file
}
"
log INFO
"Creating new
${
obj_type
}
from file
${
file_path
}
in namespace
${
namespace
}
, name:
${
obj_name
}
"
# this will keep on failing if the ${file_path} disappeared in the meantime.
# Do not use too many retries.
run-until-success
"
${
KUBECTL
}
create -f
${
file_path
}
"
${
NUM_TRIES
}
${
DELAY_AFTER_ERROR_SEC
}
run-until-success
"
${
KUBECTL
}
create -
-namespace=
${
namespace
}
-
f
${
file_path
}
"
${
NUM_TRIES
}
${
DELAY_AFTER_ERROR_SEC
}
}
function
update-object
()
{
local
-r
obj_type
=
$1
local
-r
obj_name
=
$2
local
-r
file_path
=
$3
log INFO
"updating the
${
obj_type
}
${
obj_name
}
with the new definition
${
file_path
}
"
stop-object
${
obj_type
}
${
obj_name
}
local
-r
namespace
=
$2
local
-r
obj_name
=
$3
local
-r
file_path
=
$4
log INFO
"updating the
${
obj_type
}
${
namespace
}
/
${
obj_name
}
with the new definition
${
file_path
}
"
stop-object
${
obj_type
}
${
namespace
}
${
obj_name
}
create-object
${
obj_type
}
${
file_path
}
}
# deletes the objects from the server
# $1 object type
# $2 a list of object names
# $2 a list of object n
sn
ames
function
stop-objects
()
{
local
-r
obj_type
=
$1
local
-r
obj_names
=
$2
local
-r
obj_nsnames
=
$2
local
namespace
local
obj_name
for
obj_name
in
${
obj_names
}
;
do
stop-object
${
obj_type
}
${
obj_names
}
&
for
nsname
in
${
obj_nsnames
}
;
do
IFS
=
'/'
read
namespace obj_name
<<<
"
${
nsname
}
"
stop-object
${
obj_type
}
${
namespace
}
${
obj_name
}
&
done
}
...
...
@@ -284,22 +304,28 @@ function create-objects() {
# updates objects
# $1 object type
# $2 a list of update specifications
# each update specification is a ';' separated pair: <
object
name>;<file path>
# each update specification is a ';' separated pair: <
ns
name>;<file path>
function
update-objects
()
{
local
-r
obj_type
=
$1
# ignored
local
-r
update_spec
=
$2
local
objdesc
local
nsname
local
obj_name
local
namespace
for
objdesc
in
${
update_spec
}
;
do
IFS
=
';'
read
-a
array
<<<
${
objdesc
}
update-object
${
obj_type
}
${
array
[0]
}
${
array
[1]
}
&
IFS
=
';'
read
nsname file_path
<<<
"
${
objdesc
}
"
IFS
=
'/'
read
namespace obj_name
<<<
"
${
nsname
}
"
update-object
${
obj_type
}
${
namespace
}
${
obj_name
}
${
file_path
}
&
done
}
# Global variables set by function match-objects.
for_delete
=
""
# a list of object
names to be deleted
for_update
=
""
# a list of pairs <obj_
name>;<filePath> for objects that should be updated
for_ignore
=
""
# a list of object nanes that can
be ignored
new_files
=
""
# a list of file paths that weren't matched by any existing objects (these objects must be created now)
nsnames_for_delete
=
""
# a list of object ns
names to be deleted
for_update
=
""
# a list of pairs <ns
name>;<filePath> for objects that should be updated
nsnames_for_ignore
=
""
# a list of object nsnames that will
be ignored
new_files
=
""
# a list of file paths that weren't matched by any existing objects (these objects must be created now)
# $1 path to files with objects
...
...
@@ -311,32 +337,36 @@ function match-objects() {
local
-r
separator
=
$3
# output variables (globals)
for_delete
=
""
nsnames_
for_delete
=
""
for_update
=
""
for_ignore
=
""
nsnames_
for_ignore
=
""
new_files
=
""
addon_n
ames_on_server
=
$(
get-addon
s-from-server
"
${
obj_type
}
"
)
addon_paths_in_files
=
$(
get-addons-from-disk
"
${
addon_dir
}
"
"
${
obj_type
}
"
)
addon_n
snames_on_server
=
$(
get-addon-nsname
s-from-server
"
${
obj_type
}
"
)
addon_paths_in_files
=
$(
get-addon
-path
s-from-disk
"
${
addon_dir
}
"
"
${
obj_type
}
"
)
log DB2
"addon_n
ames_on_server=
${
addon_
names_on_server
}
"
log DB2
"addon_n
snames_on_server=
${
addon_ns
names_on_server
}
"
log DB2
"addon_paths_in_files=
${
addon_paths_in_files
}
"
local
matched_files
=
""
local
basename_on_server
=
""
local
name_on_server
=
""
local
basen
sn
ame_on_server
=
""
local
n
sn
ame_on_server
=
""
local
suffix_on_server
=
""
local
name_from_file
=
""
local
n
sn
ame_from_file
=
""
local
suffix_from_file
=
""
local
found
=
0
local
addon_path
=
""
for
name_on_server
in
${
addon_names_on_server
}
;
do
basename_on_server
=
$(
get-basename
${
name_on_server
}
${
separator
})
suffix_on_server
=
"
$(
get-suffix
${
name_on_server
}
${
separator
})
"
# objects that were moved between namespaces will have different nsname
# because the namespace is included. So they will be treated
# like different objects and not updated but deleted and created again
# (in the current version update is also delete+create, so it does not matter)
for
nsname_on_server
in
${
addon_nsnames_on_server
}
;
do
basensname_on_server
=
$(
get-basename
${
nsname_on_server
}
${
separator
})
suffix_on_server
=
"
$(
get-suffix
${
nsname_on_server
}
${
separator
})
"
log DB3
"Found existing addon
${
n
ame_on_server
}
, basename=
${
base
name_on_server
}
"
log DB3
"Found existing addon
${
n
sname_on_server
}
, basename=
${
basens
name_on_server
}
"
# check if the addon is present in the directory and decide
# what to do with it
...
...
@@ -344,31 +374,31 @@ function match-objects() {
# again. But for small number of addons it doesn't matter so much.
found
=
0
for
addon_path
in
${
addon_paths_in_files
}
;
do
n
ame_from_file
=
$(
get-object-
name-from-file
${
addon_path
})
if
[[
"
${
name_from_file
}
"
==
"ERROR"
]]
;
then
n
sname_from_file
=
$(
get-object-ns
name-from-file
${
addon_path
})
if
[[
"
${
n
sn
ame_from_file
}
"
==
"ERROR"
]]
;
then
log INFO
"Cannot read object name from
${
addon_path
}
. Ignoring"
continue
else
log DB2
"Found object name '
${
name_from_file
}
' in file
${
addon_path
}
"
log DB2
"Found object name '
${
n
sn
ame_from_file
}
' in file
${
addon_path
}
"
fi
suffix_from_file
=
"
$(
get-suffix
${
name_from_file
}
${
separator
})
"
suffix_from_file
=
"
$(
get-suffix
${
n
sn
ame_from_file
}
${
separator
})
"
log DB3
"matching:
${
basen
ame_on_server
}${
suffix_from_file
}
==
${
name_from_file
}
"
if
[[
"
${
basen
ame_on_server
}${
suffix_from_file
}
"
==
"
${
name_from_file
}
"
]]
;
then
log DB3
"matched existing
${
obj_type
}
${
name_on_server
}
to file
${
addon_path
}
; suffix_on_server=
${
suffix_on_server
}
, suffix_from_file=
${
suffix_from_file
}
"
log DB3
"matching:
${
basen
sname_on_server
}${
suffix_from_file
}
==
${
ns
name_from_file
}
"
if
[[
"
${
basen
sname_on_server
}${
suffix_from_file
}
"
==
"
${
ns
name_from_file
}
"
]]
;
then
log DB3
"matched existing
${
obj_type
}
${
n
sn
ame_on_server
}
to file
${
addon_path
}
; suffix_on_server=
${
suffix_on_server
}
, suffix_from_file=
${
suffix_from_file
}
"
found
=
1
matched_files
=
"
${
matched_files
}
${
addon_path
}
"
if
[[
"
${
suffix_on_server
}
"
==
"
${
suffix_from_file
}
"
]]
;
then
for_ignore
=
"
${
for_ignore
}
${
name_from_file
}
"
nsnames_for_ignore
=
"
${
nsnames_for_ignore
}
${
ns
name_from_file
}
"
else
for_update
=
"
${
for_update
}
${
name_on_server
}
;
${
addon_path
}
"
for_update
=
"
${
for_update
}
${
n
sn
ame_on_server
}
;
${
addon_path
}
"
fi
break
fi
done
if
[[
${
found
}
-eq
0
]]
;
then
log DB2
"No definition file found for replication controller
${
name_on_server
}
. Scheduling for deletion"
for_delete
=
"
${
for_delete
}
${
name_on_server
}
"
log DB2
"No definition file found for replication controller
${
n
sn
ame_on_server
}
. Scheduling for deletion"
nsnames_for_delete
=
"
${
nsnames_for_delete
}
${
ns
name_on_server
}
"
fi
done
...
...
@@ -395,12 +425,12 @@ function reconcile-objects() {
local
-r
separator
=
$3
# name separator
match-objects
${
addon_path
}
${
obj_type
}
${
separator
}
log DBG
"
${
obj_type
}
:
for_delete=
${
for_delete
}
"
log DBG
"
${
obj_type
}
:
nsnames_for_delete=
${
nsnames_
for_delete
}
"
log DBG
"
${
obj_type
}
: for_update=
${
for_update
}
"
log DBG
"
${
obj_type
}
:
for_ignore=
${
for_ignore
}
"
log DBG
"
${
obj_type
}
:
nsnames_for_ignore=
${
nsnames_
for_ignore
}
"
log DBG
"
${
obj_type
}
: new_files=
${
new_files
}
"
stop-objects
"
${
obj_type
}
"
"
${
for_delete
}
"
stop-objects
"
${
obj_type
}
"
"
${
nsnames_
for_delete
}
"
# wait for jobs below is a protection against changing the basename
# of a replication controllerm without changing the selector.
# If we don't wait, the new rc may be created before the old one is deleted
...
...
@@ -414,9 +444,9 @@ function reconcile-objects() {
create-objects
"
${
obj_type
}
"
"
${
new_files
}
"
update-objects
"
${
obj_type
}
"
"
${
for_update
}
"
local
obj
for
obj
in
${
for_ignore
}
;
do
log DB2
"The
${
obj_type
}
${
obj
}
is already up to date"
local
nsname
for
nsname
in
${
nsnames_
for_ignore
}
;
do
log DB2
"The
${
obj_type
}
${
nsname
}
is already up to date"
done
wait-for-jobs
...
...
test/e2e/addon_update.go
View file @
e479c521
...
...
@@ -39,7 +39,7 @@ apiVersion: v1
kind: ReplicationController
metadata:
name: addon-test-v1
namespace:
default
namespace:
%s
labels:
k8s-app: addon-test
version: v1
...
...
@@ -69,7 +69,7 @@ apiVersion: v1
kind: ReplicationController
metadata:
name: addon-test-v2
namespace:
default
namespace:
%s
labels:
k8s-app: addon-test
version: v2
...
...
@@ -99,7 +99,7 @@ apiVersion: v1
kind: Service
metadata:
name: addon-test
namespace:
default
namespace:
%s
labels:
k8s-app: addon-test
kubernetes.io/cluster-service: "true"
...
...
@@ -118,7 +118,7 @@ apiVersion: v1
kind: Service
metadata:
name: addon-test-updated
namespace:
default
namespace:
%s
labels:
k8s-app: addon-test
kubernetes.io/cluster-service: "true"
...
...
@@ -138,7 +138,7 @@ apiVersion: v1
kind: ReplicationController
metadata:
name: invalid-addon-test-v1
namespace:
default
namespace:
%s
labels:
k8s-app: invalid-addon-test
version: v1
...
...
@@ -167,7 +167,7 @@ apiVersion: v1
kind: Service
metadata:
name: ivalid-addon-test
namespace:
default
namespace:
%s
labels:
k8s-app: invalid-addon-test
kubernetes.io/name: invalid-addon-test
...
...
@@ -181,8 +181,8 @@ spec:
`
var
addonTestPollInterval
=
3
*
time
.
Second
var
addonTestPollTimeout
=
1
*
time
.
Minute
var
addonNamespace
=
api
.
NamespaceDefault
// addons are in the default namespace
var
addonTestPollTimeout
=
5
*
time
.
Minute
var
defaultNsName
=
api
.
NamespaceDefault
type
stringPair
struct
{
data
,
fileName
string
...
...
@@ -260,12 +260,12 @@ var _ = Describe("Addon update", func() {
svcInvalid
:=
"invalid-addon-service-v1.yaml"
var
remoteFiles
[]
stringPair
=
[]
stringPair
{
{
addon_controller_v1
,
rcv1
},
{
addon_controller_v2
,
rcv2
},
{
addon_service_v1
,
svcv1
},
{
addon_service_v2
,
svcv2
},
{
invalid_addon_controller_v1
,
rcInvalid
},
{
invalid_addon_service_v1
,
svcInvalid
},
{
fmt
.
Sprintf
(
addon_controller_v1
,
defaultNsName
)
,
rcv1
},
{
fmt
.
Sprintf
(
addon_controller_v2
,
namespace
.
Name
)
,
rcv2
},
{
fmt
.
Sprintf
(
addon_service_v1
,
namespace
.
Name
)
,
svcv1
},
{
fmt
.
Sprintf
(
addon_service_v2
,
namespace
.
Name
)
,
svcv2
},
{
fmt
.
Sprintf
(
invalid_addon_controller_v1
,
namespace
.
Name
)
,
rcInvalid
},
{
fmt
.
Sprintf
(
invalid_addon_service_v1
,
defaultNsName
)
,
svcInvalid
},
}
for
_
,
p
:=
range
remoteFiles
{
...
...
@@ -293,8 +293,8 @@ var _ = Describe("Addon update", func() {
sshExecAndVerify
(
sshClient
,
fmt
.
Sprintf
(
"sudo cp %s/%s %s/%s"
,
temporaryRemotePath
,
rcv1
,
destinationDir
,
rcv1
))
sshExecAndVerify
(
sshClient
,
fmt
.
Sprintf
(
"sudo cp %s/%s %s/%s"
,
temporaryRemotePath
,
svcv1
,
destinationDir
,
svcv1
))
waitForServiceInAddonTest
(
c
,
"addon-test"
,
true
)
waitForReplicationControllerInAddonTest
(
c
,
"addon-test-v1"
,
true
)
waitForServiceInAddonTest
(
c
,
namespace
.
Name
,
"addon-test"
,
true
)
waitForReplicationControllerInAddonTest
(
c
,
defaultNsName
,
"addon-test-v1"
,
true
)
By
(
"update manifests"
)
sshExecAndVerify
(
sshClient
,
fmt
.
Sprintf
(
"sudo cp %s/%s %s/%s"
,
temporaryRemotePath
,
rcv2
,
destinationDir
,
rcv2
))
...
...
@@ -307,34 +307,38 @@ var _ = Describe("Addon update", func() {
* But it is ok - as long as we don't have rolling update, the result will be the same
*/
waitForServiceInAddonTest
(
c
,
"addon-test-updated"
,
true
)
waitForReplicationControllerInAddonTest
(
c
,
"addon-test-v2"
,
true
)
waitForServiceInAddonTest
(
c
,
namespace
.
Name
,
"addon-test-updated"
,
true
)
waitForReplicationControllerInAddonTest
(
c
,
namespace
.
Name
,
"addon-test-v2"
,
true
)
waitForServiceInAddonTest
(
c
,
"addon-test"
,
false
)
waitForReplicationControllerInAddonTest
(
c
,
"addon-test-v1"
,
false
)
waitForServiceInAddonTest
(
c
,
namespace
.
Name
,
"addon-test"
,
false
)
waitForReplicationControllerInAddonTest
(
c
,
defaultNsName
,
"addon-test-v1"
,
false
)
By
(
"remove manifests"
)
sshExecAndVerify
(
sshClient
,
fmt
.
Sprintf
(
"sudo rm %s/%s"
,
destinationDir
,
rcv2
))
sshExecAndVerify
(
sshClient
,
fmt
.
Sprintf
(
"sudo rm %s/%s"
,
destinationDir
,
svcv2
))
waitForServiceInAddonTest
(
c
,
"addon-test-updated"
,
false
)
waitForReplicationControllerInAddonTest
(
c
,
"invalid-addon-test-v1
"
,
false
)
waitForServiceInAddonTest
(
c
,
namespace
.
Name
,
"addon-test-updated"
,
false
)
waitForReplicationControllerInAddonTest
(
c
,
namespace
.
Name
,
"addon-test-v2
"
,
false
)
By
(
"verify invalid API addons weren't created"
)
_
,
err
=
c
.
ReplicationControllers
(
addonNamespac
e
)
.
Get
(
"invalid-addon-test-v1"
)
_
,
err
=
c
.
ReplicationControllers
(
namespace
.
Nam
e
)
.
Get
(
"invalid-addon-test-v1"
)
Expect
(
err
)
.
To
(
HaveOccurred
())
_
,
err
=
c
.
Services
(
addonNamespace
)
.
Get
(
"ivalid-addon-test"
)
_
,
err
=
c
.
ReplicationControllers
(
defaultNsName
)
.
Get
(
"invalid-addon-test-v1"
)
Expect
(
err
)
.
To
(
HaveOccurred
())
_
,
err
=
c
.
Services
(
namespace
.
Name
)
.
Get
(
"ivalid-addon-test"
)
Expect
(
err
)
.
To
(
HaveOccurred
())
_
,
err
=
c
.
Services
(
defaultNsName
)
.
Get
(
"ivalid-addon-test"
)
Expect
(
err
)
.
To
(
HaveOccurred
())
// invalid addons will be deleted by the deferred function
})
})
func
waitForServiceInAddonTest
(
c
*
client
.
Client
,
name
string
,
exist
bool
)
{
func
waitForServiceInAddonTest
(
c
*
client
.
Client
,
addonNamespace
,
name
string
,
exist
bool
)
{
expectNoError
(
waitForService
(
c
,
addonNamespace
,
name
,
exist
,
addonTestPollInterval
,
addonTestPollTimeout
))
}
func
waitForReplicationControllerInAddonTest
(
c
*
client
.
Client
,
name
string
,
exist
bool
)
{
func
waitForReplicationControllerInAddonTest
(
c
*
client
.
Client
,
addonNamespace
,
name
string
,
exist
bool
)
{
expectNoError
(
waitForReplicationController
(
c
,
addonNamespace
,
name
,
exist
,
addonTestPollInterval
,
addonTestPollTimeout
))
}
...
...
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