mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #1142 from jbeda/tweak-demo
Improve update demo, support rolling template update
This commit is contained in:
commit
ee1c0838d8
@ -17,8 +17,8 @@
|
||||
source $(dirname $0)/kube-env.sh
|
||||
source $(dirname $0)/$KUBERNETES_PROVIDER/util.sh
|
||||
|
||||
CLOUDCFG=$(dirname $0)/../_output/go/bin/kubecfg
|
||||
if [ ! -x $CLOUDCFG ]; then
|
||||
KUBECFG=$(dirname $0)/../_output/go/bin/kubecfg
|
||||
if [ ! -x $KUBECFG ]; then
|
||||
echo "Could not find kubecfg binary. Run hack/build-go.sh to build it."
|
||||
exit 1
|
||||
fi
|
||||
@ -40,4 +40,4 @@ if [ "$KUBE_MASTER_IP" != "" ] && [ "$KUBERNETES_MASTER" == "" ]; then
|
||||
export KUBERNETES_MASTER=https://${KUBE_MASTER_IP}
|
||||
fi
|
||||
|
||||
$CLOUDCFG $AUTH_CONFIG "$@"
|
||||
$KUBECFG $AUTH_CONFIG "$@"
|
||||
|
@ -55,6 +55,7 @@ var (
|
||||
www = flag.String("www", "", "If -proxy is true, use this directory to serve static files")
|
||||
templateFile = flag.String("template_file", "", "If present, load this file as a golang template and use it for output printing")
|
||||
templateStr = flag.String("template", "", "If present, parse this string as a golang template and use it for output printing")
|
||||
imageName = flag.String("image", "", "Image used when updating a replicationController. Will apply to the first container in the pod template.")
|
||||
)
|
||||
|
||||
var parser = kubecfg.NewParser(map[string]interface{}{
|
||||
@ -65,17 +66,24 @@ var parser = kubecfg.NewParser(map[string]interface{}{
|
||||
})
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, `usage: kubecfg -h [-c config/file.json] [-p :,..., :] <method>
|
||||
fmt.Fprintf(os.Stderr, `Usage: kubecfg -h [-c config/file.json] <method>
|
||||
|
||||
Kubernetes REST API:
|
||||
|
||||
Kubernetes REST API:
|
||||
kubecfg [OPTIONS] get|list|create|delete|update <%s>[/<id>]
|
||||
|
||||
Manage replication controllers:
|
||||
kubecfg [OPTIONS] stop|rm|rollingupdate <controller>
|
||||
kubecfg [OPTIONS] run <image> <replicas> <controller>
|
||||
Manage replication controllers:
|
||||
|
||||
kubecfg [OPTIONS] stop|rm <controller>
|
||||
kubecfg [OPTIONS] [-u <time>] [-image <image>] rollingupdate <controller>
|
||||
kubecfg [OPTIONS] resize <controller> <replicas>
|
||||
|
||||
Options:
|
||||
Launch a simple ReplicationController with a single container based
|
||||
on the given image:
|
||||
|
||||
kubecfg [OPTIONS] [-p <port spec>] run <image> <replicas> <controller>
|
||||
|
||||
Options:
|
||||
`, prettyWireStorage())
|
||||
flag.PrintDefaults()
|
||||
|
||||
@ -337,7 +345,7 @@ func executeControllerRequest(method string, c *client.Client) bool {
|
||||
case "rm":
|
||||
err = kubecfg.DeleteController(parseController(), c)
|
||||
case "rollingupdate":
|
||||
err = kubecfg.Update(parseController(), c, *updatePeriod)
|
||||
err = kubecfg.Update(parseController(), c, *updatePeriod, *imageName)
|
||||
case "run":
|
||||
if len(flag.Args()) != 4 {
|
||||
glog.Fatal("usage: kubecfg [OPTIONS] run <image> <replicas> <controller>")
|
||||
|
@ -81,6 +81,7 @@ The pod that you created in Step One has the label `name=redis-master`. The sele
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1beta1",
|
||||
"port": 10000,
|
||||
"containerPort": 6379,
|
||||
"selector": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
@ -169,6 +170,7 @@ Just like the master, we want to have a service to proxy connections to the read
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1beta1",
|
||||
"port": 10001,
|
||||
"containerPort": 6379,
|
||||
"labels": {
|
||||
"name": "redisslave"
|
||||
},
|
||||
|
@ -3,6 +3,7 @@
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1beta1",
|
||||
"port": 9998,
|
||||
"containerPort": 80,
|
||||
"selector": {
|
||||
"name": "frontend"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1beta1",
|
||||
"port": 10000,
|
||||
"containerPort": 6379,
|
||||
"selector": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1beta1",
|
||||
"port": 10001,
|
||||
"containerPort": 6379,
|
||||
"labels": {
|
||||
"name": "redisslave"
|
||||
},
|
||||
|
22
examples/update-demo/0-run-web-proxy.sh
Executable file
22
examples/update-demo/0-run-web-proxy.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
echo "Running local proxy to Kubernetes API Server. Run this in a "
|
||||
echo "separate terminal or run it in the background."
|
||||
echo
|
||||
echo " http://localhost:8001/static/"
|
||||
echo
|
||||
../../cluster/kubecfg.sh -proxy -www local/
|
27
examples/update-demo/1-create-replication-controller.sh
Executable file
27
examples/update-demo/1-create-replication-controller.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if [ -z "$DOCKER_HUB_USER" ] ; then
|
||||
echo "Please set DOCKER_HUB_USER to your Docker hub account"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
|
||||
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
|
||||
|
||||
set -x
|
||||
|
||||
$KUBECFG -p 8080:80 run $DOCKER_HUB_USER/update-demo:nautilus 2 update-demo
|
24
examples/update-demo/2-scale.sh
Executable file
24
examples/update-demo/2-scale.sh
Executable file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
NEW_SIZE=${1:-4}
|
||||
|
||||
export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
|
||||
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
|
||||
|
||||
set -x
|
||||
|
||||
$KUBECFG resize update-demo $NEW_SIZE
|
29
examples/update-demo/3-rolling-update.sh
Executable file
29
examples/update-demo/3-rolling-update.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if [ -z "$DOCKER_HUB_USER" ] ; then
|
||||
echo "Please set DOCKER_HUB_USER to your Docker hub account"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_IMAGE=${1:-kitten}
|
||||
TIMING=${2:-10s}
|
||||
export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
|
||||
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
|
||||
|
||||
set -x
|
||||
|
||||
$KUBECFG -image $DOCKER_HUB_USER/update-demo:$NEW_IMAGE -u $TIMING rollingupdate update-demo
|
23
examples/update-demo/4-down.sh
Executable file
23
examples/update-demo/4-down.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
export KUBE_REPO_ROOT=${KUBE_REPO_ROOT-$(dirname $0)/../..}
|
||||
export KUBECFG=${KUBECFG-$KUBE_REPO_ROOT/cluster/kubecfg.sh}
|
||||
|
||||
set -x
|
||||
|
||||
$KUBECFG stop update-demo
|
||||
$KUBECFG rm update-demo
|
@ -27,7 +27,7 @@ This example assumes that you have forked the repository and [turned up a Kubern
|
||||
|
||||
This example also assumes that you have [Docker](http://docker.io) installed on your local machine.
|
||||
|
||||
It also assumes that ```$DOCKER_USER``` is set to your docker user id.
|
||||
It also assumes that `$DOCKER_HUB_USER` is set to your Docker user id. We use this to upload the docker images that are used in the demo.
|
||||
|
||||
You may need to open the firewall for port 8080 using the [console][cloud-console] or the `gcutil` tool. The following command will allow traffic from any source to instances tagged `kubernetes-minion`:
|
||||
|
||||
@ -37,57 +37,66 @@ $ gcutil addfirewall --allowed=tcp:8080 --target_tags=kubernetes-minion kubernet
|
||||
|
||||
### Step One: Build the image
|
||||
|
||||
$ cd kubernetes/examples/update-demo/image
|
||||
$ docker build -t $DOCKER_USER/data .
|
||||
$ docker push $DOCKER_USER/data
|
||||
```shell
|
||||
$ cd kubernetes/examples/update-demo
|
||||
$ ./build-images.sh
|
||||
```
|
||||
|
||||
### Step Two: Run the controller
|
||||
Now we will turn up two replicas of that image. They all serve on port 8080, mapped to internal port 80
|
||||
### Step Two: Turn up the UX for the demo
|
||||
|
||||
$ cd kubernetes
|
||||
$ cluster/kubecfg.sh -p 8080:80 run $DOCKER_USER/data 2 dataController
|
||||
```shell
|
||||
$ ./0-run-web-proxy.sh &
|
||||
```
|
||||
|
||||
### Step Three: Turn up the UX for the demo
|
||||
In a different terminal:
|
||||
This can sometimes spew to the output so you could also run it in a different terminal.
|
||||
|
||||
$ cd kubernetes
|
||||
$ cluster/kubecfg.sh -proxy -www examples/update-demo/local/
|
||||
Now visit the the [demo website](http://localhost:8001/static). You won't see anything much quite yet.
|
||||
|
||||
Now visit the the [demo website](http://localhost:8001/static/index.html). You should see two light blue squares with pod IDs and ip addresses.
|
||||
### Step Three: Run the controller
|
||||
Now we will turn up two replicas of an image. They all serve on port 8080, mapped to internal port 80
|
||||
|
||||
```shell
|
||||
$ ./1-create-replication-controller.sh
|
||||
```
|
||||
|
||||
After these pull the image (which may take a minute or so) you'll see a couple of squares in the UI detailing the pods that are running along with the image that they are serving up. A cute little nautilus.
|
||||
|
||||
### Step Four: Try resizing the controller
|
||||
|
||||
Now we will increase the number of replicas from two to four:
|
||||
|
||||
$ cd kubernetes
|
||||
$ cluster/kubecfg.sh resize dataController 4
|
||||
```shell
|
||||
$ ./2-scale.sh
|
||||
```
|
||||
|
||||
If you go back to the [demo website](http://localhost:8001/static/index.html) you should eventually see four boxes, one for each pod.
|
||||
|
||||
### Step Five: Update the docker image
|
||||
We will now update the docker image to serve a different color.
|
||||
We will now update the docker image to serve a different image by doing a rolling update to a new Docker image.
|
||||
|
||||
$ cd kubernetes/examples/update-demo/image
|
||||
$ ${EDITOR} data.json
|
||||
|
||||
Edit the ```color``` value so that it is a new color. For example:
|
||||
```js
|
||||
{
|
||||
"color": "#F00"
|
||||
}
|
||||
```shell
|
||||
$ ./3-rolling-update
|
||||
```
|
||||
Will set the color to red.
|
||||
The rollingUpdate command in kubecfg will do 2 things:
|
||||
|
||||
Once you are happy with the color, build a new image:
|
||||
1. Update the template in the replication controller to the new image (`$DOCKER_HUB_USER/update-demo:kitten`)
|
||||
2. Kill each of the pods one by one. It'll let the replication controller create new pods to replace those that were killed.
|
||||
|
||||
$ docker build -t $DOCKER_USER/data .
|
||||
$ docker push $DOCKER_USER/data
|
||||
Watch the UX, it will update one pod every 10 seconds until all of the pods have the new image.
|
||||
|
||||
### Step Six: Roll the update out to your servers
|
||||
We will now update the servers that are running out in your cluster.
|
||||
### Step Five: Bring down the pods
|
||||
|
||||
$ cd kubernetes
|
||||
$ cluster/kubecfg.sh -u=30s rollingupdate dataController
|
||||
```shell
|
||||
$ ./4-down.sh
|
||||
```
|
||||
|
||||
Watch the UX, it will update one pod every 30 seconds until all of the pods have the new color.
|
||||
This will first 'stop' the replication controller by turning the target number of replicas to 0. It'll then delete that controller.
|
||||
|
||||
[cloud-console]: https://console.developer.google.com
|
||||
|
||||
### Image Copyright
|
||||
|
||||
Note that he images included here are public domain.
|
||||
|
||||
* [kitten](http://commons.wikimedia.org/wiki/File:Kitten-stare.jpg)
|
||||
* [nautilus](http://commons.wikimedia.org/wiki/File:Nautilus_pompilius.jpg)
|
||||
|
@ -1,7 +0,0 @@
|
||||
FROM dockerfile/nginx
|
||||
|
||||
ADD data.json /usr/share/nginx/html/data.json
|
||||
ADD default /etc/nginx/sites-available/default
|
||||
RUN chmod a+r /usr/share/nginx/html/data.json
|
||||
|
||||
CMD ["nginx"]
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"color": "#0FF"
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server ipv6only=on;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
# Make site accessible from http://localhost/
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
if ($request_method = 'GET') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Credentials' 'true';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
|
||||
}
|
||||
}
|
||||
}
|
22
examples/update-demo/images/base/Dockerfile
Normal file
22
examples/update-demo/images/base/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM dockerfile/nginx
|
||||
|
||||
ADD default /etc/nginx/sites-available/default
|
||||
|
||||
ONBUILD ADD html /usr/share/nginx/html
|
||||
ONBUILD RUN chmod -R a+r /usr/share/nginx/html
|
||||
|
||||
CMD ["nginx"]
|
37
examples/update-demo/images/base/default
Normal file
37
examples/update-demo/images/base/default
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server ipv6only=on;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
# Make site accessible from http://localhost/
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
expires 0;
|
||||
add_header Cache-Control private;
|
||||
|
||||
if ($request_method = 'GET') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Credentials' 'true';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
|
||||
}
|
||||
}
|
||||
}
|
32
examples/update-demo/images/build-images.sh
Executable file
32
examples/update-demo/images/build-images.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This script will build and push the images necessary for the demo.
|
||||
|
||||
if (( $# != 1 )); then
|
||||
echo "Usage: $0 <docker hub user name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DOCKER_USER=$1
|
||||
|
||||
set -x
|
||||
|
||||
docker build -t update-demo-base base
|
||||
docker build -t $DOCKER_USER/update-demo:kitten kitten
|
||||
docker build -t $DOCKER_USER/update-demo:nautilus nautilus
|
||||
|
||||
docker push $DOCKER_USER/update-demo
|
15
examples/update-demo/images/kitten/Dockerfile
Normal file
15
examples/update-demo/images/kitten/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM update-demo-base
|
3
examples/update-demo/images/kitten/html/data.json
Normal file
3
examples/update-demo/images/kitten/html/data.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"image": "kitten.jpg"
|
||||
}
|
BIN
examples/update-demo/images/kitten/html/kitten.jpg
Normal file
BIN
examples/update-demo/images/kitten/html/kitten.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
15
examples/update-demo/images/nautilus/Dockerfile
Normal file
15
examples/update-demo/images/nautilus/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM update-demo-base
|
3
examples/update-demo/images/nautilus/html/data.json
Normal file
3
examples/update-demo/images/nautilus/html/data.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"image": "nautilus.jpg"
|
||||
}
|
BIN
examples/update-demo/images/nautilus/html/nautilus.jpg
Normal file
BIN
examples/update-demo/images/nautilus/html/nautilus.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
@ -13,17 +13,23 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<html ng-app>
|
||||
<head>
|
||||
<script src="angular.min.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<link rel="stylesheet" href="style.css"></link>
|
||||
<script src="angular.min.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<link rel="stylesheet" href="style.css"></link>
|
||||
</head>
|
||||
<body ng-controller="ButtonsCtrl">
|
||||
<div ng-repeat="server in servers" class="server" style="background: #FFF">
|
||||
<b>{{server.id}}</b>
|
||||
<div class="img" style="background: {{server.color}};"> </div>
|
||||
<a href="http://{{server.ip}}:8080/data.json">{{server.ip}}</a>
|
||||
</div>
|
||||
<div ng-repeat="server in servers" class="pod">
|
||||
<img src="http://{{server.ip}}:8080/{{server.image}}" height="100px" width="100px" />
|
||||
<b>ID:</b> {{server.id}}<br>
|
||||
<b>Host:</b> <a href="http://{{server.ip}}:8080/data.json">{{server.host}}</a><br>
|
||||
<b>Image:</b> {{server.dockerImage}}<br>
|
||||
<b>Labels:</b>
|
||||
<ul>
|
||||
<li ng-repeat="(key,value) in server.labels">{{key}}={{value}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -16,72 +16,77 @@ limitations under the License.
|
||||
|
||||
var base = "http://localhost:8001/api/v1beta1/";
|
||||
|
||||
var updateColor = function($http, server) {
|
||||
$http.get("http://" + server.ip + ":8080/data.json")
|
||||
var updateImage = function($http, server) {
|
||||
$http.get("http://" + server.ip + ":8080/data.json")
|
||||
.success(function(data) {
|
||||
server.color = data.color;
|
||||
console.log(data);
|
||||
})
|
||||
server.image = data.image;
|
||||
console.log(data);
|
||||
})
|
||||
.error(function(data) {
|
||||
server.color = "#000";
|
||||
console.log(data);
|
||||
});
|
||||
server.image = ""
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
var updateServer = function($http, server) {
|
||||
$http.get(base + "pods/" + server.id)
|
||||
.success(function(data) {
|
||||
console.log(data);
|
||||
server.ip = data.currentState.hostIP;
|
||||
updateColor($http, server);
|
||||
})
|
||||
.error(function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
$http.get(base + "pods/" + server.id)
|
||||
.success(function(data) {
|
||||
console.log(data);
|
||||
server.ip = data.currentState.hostIP;
|
||||
server.labels = data.labels;
|
||||
server.host = data.currentState.host.split('.')[0]
|
||||
server.dockerImage = data.currentState.info["update-demo-container"].Config.Image
|
||||
updateImage($http, server);
|
||||
})
|
||||
.error(function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
};
|
||||
|
||||
var updateData = function($scope, $http) {
|
||||
var servers = $scope.servers
|
||||
for (var i = 0; i < servers.length; ++i) {
|
||||
var server = servers[i];
|
||||
updateServer($http, server);
|
||||
}
|
||||
var servers = $scope.servers
|
||||
for (var i = 0; i < servers.length; ++i) {
|
||||
var server = servers[i];
|
||||
updateServer($http, server);
|
||||
}
|
||||
};
|
||||
|
||||
var ButtonsCtrl = function ($scope, $http, $interval) {
|
||||
$scope.servers = [];
|
||||
update($scope, $http);
|
||||
$interval(angular.bind({}, update, $scope, $http), 2000);
|
||||
$scope.servers = [];
|
||||
update($scope, $http);
|
||||
$interval(angular.bind({}, update, $scope, $http), 2000);
|
||||
};
|
||||
|
||||
var getServer = function($scope, id) {
|
||||
var servers = $scope.servers;
|
||||
for (var i = 0; i < servers.length; ++i) {
|
||||
if (servers[i].id == id) {
|
||||
return servers[i];
|
||||
}
|
||||
var servers = $scope.servers;
|
||||
for (var i = 0; i < servers.length; ++i) {
|
||||
if (servers[i].id == id) {
|
||||
return servers[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var update = function($scope, $http) {
|
||||
if (!$http) {
|
||||
console.log("No HTTP!");
|
||||
return;
|
||||
}
|
||||
$http.get(base + "pods")
|
||||
.success(function(data) {
|
||||
console.log(data);
|
||||
var newServers = [];
|
||||
for (var i = 0; i < data.items.length; ++i) {
|
||||
var server = getServer($scope, data.items[i].id);
|
||||
if (server == null) {
|
||||
server = { "id": data.items[i].id };
|
||||
}
|
||||
newServers.push(server);
|
||||
}
|
||||
$scope.servers = newServers;
|
||||
updateData($scope, $http)
|
||||
if (!$http) {
|
||||
console.log("No HTTP!");
|
||||
return;
|
||||
}
|
||||
$http.get(base + "pods")
|
||||
.success(function(data) {
|
||||
console.log(data);
|
||||
var newServers = [];
|
||||
for (var i = 0; i < data.items.length; ++i) {
|
||||
var server = getServer($scope, data.items[i].id);
|
||||
if (server == null) {
|
||||
server = { "id": data.items[i].id };
|
||||
}
|
||||
newServers.push(server);
|
||||
}
|
||||
$scope.servers = newServers;
|
||||
updateData($scope, $http)
|
||||
})
|
||||
.error(function(data) {
|
||||
console.log("ERROR: " + data);
|
||||
})
|
||||
.error(function(data) { console.log("ERROR: " + data); })
|
||||
};
|
||||
|
@ -14,19 +14,27 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.img {
|
||||
img {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
background-size: 100px 100px;
|
||||
margin-left: 25px;
|
||||
float: right;
|
||||
background-size: 100px 100px;
|
||||
background-color: black;
|
||||
margin-left: 10px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.server {
|
||||
ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.pod {
|
||||
font-family: Roboto, Open Sans, arial;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
background-color: #D1D1D1;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ source "${KUBE_REPO_ROOT}/cluster/kube-env.sh"
|
||||
source "${KUBE_REPO_ROOT}/cluster/$KUBERNETES_PROVIDER/util.sh"
|
||||
|
||||
# Launch a container
|
||||
$CLOUDCFG -p 8080:80 run dockerfile/nginx 2 myNginx
|
||||
$KUBECFG -p 8080:80 run dockerfile/nginx 2 myNginx
|
||||
|
||||
function remove-quotes() {
|
||||
local in=$1
|
||||
@ -35,13 +35,13 @@ function remove-quotes() {
|
||||
|
||||
function teardown() {
|
||||
echo "Cleaning up test artifacts"
|
||||
$CLOUDCFG stop myNginx
|
||||
$CLOUDCFG rm myNginx
|
||||
$KUBECFG stop myNginx
|
||||
$KUBECFG rm myNginx
|
||||
}
|
||||
|
||||
trap "teardown" EXIT
|
||||
|
||||
POD_ID_LIST=$($CLOUDCFG '-template={{range.Items}}{{.ID}} {{end}}' -l name=myNginx list pods)
|
||||
POD_ID_LIST=$($KUBECFG '-template={{range.Items}}{{.ID}} {{end}}' -l name=myNginx list pods)
|
||||
# Container turn up on a clean cluster can take a while for the docker image pull.
|
||||
ALL_RUNNING=0
|
||||
while [ $ALL_RUNNING -ne 1 ]; do
|
||||
@ -49,7 +49,7 @@ while [ $ALL_RUNNING -ne 1 ]; do
|
||||
sleep 5
|
||||
ALL_RUNNING=1
|
||||
for id in $POD_ID_LIST; do
|
||||
CURRENT_STATUS=$($CLOUDCFG -template '{{and .CurrentState.Info.mynginx.State.Running .CurrentState.Info.net.State.Running}}' get pods/$id)
|
||||
CURRENT_STATUS=$($KUBECFG -template '{{and .CurrentState.Info.mynginx.State.Running .CurrentState.Info.net.State.Running}}' get pods/$id)
|
||||
if [ "$CURRENT_STATUS" != "true" ]; then
|
||||
ALL_RUNNING=0
|
||||
fi
|
||||
|
@ -26,23 +26,23 @@ source "${KUBE_REPO_ROOT}/cluster/$KUBERNETES_PROVIDER/util.sh"
|
||||
GUESTBOOK="${KUBE_REPO_ROOT}/examples/guestbook"
|
||||
|
||||
# Launch the guestbook example
|
||||
$CLOUDCFG -c "${GUESTBOOK}/redis-master.json" create /pods
|
||||
$CLOUDCFG -c "${GUESTBOOK}/redis-master-service.json" create /services
|
||||
$CLOUDCFG -c "${GUESTBOOK}/redis-slave-controller.json" create /replicationControllers
|
||||
$KUBECFG -c "${GUESTBOOK}/redis-master.json" create /pods
|
||||
$KUBECFG -c "${GUESTBOOK}/redis-master-service.json" create /services
|
||||
$KUBECFG -c "${GUESTBOOK}/redis-slave-controller.json" create /replicationControllers
|
||||
|
||||
sleep 5
|
||||
|
||||
POD_LIST_1=$($CLOUDCFG '-template={{range.Items}}{{.ID}} {{end}}' list pods)
|
||||
POD_LIST_1=$($KUBECFG '-template={{range.Items}}{{.ID}} {{end}}' list pods)
|
||||
echo "Pods running: ${POD_LIST_1}"
|
||||
|
||||
$CLOUDCFG stop redisSlaveController
|
||||
$KUBECFG stop redisSlaveController
|
||||
# Needed until issue #103 gets fixed
|
||||
sleep 25
|
||||
$CLOUDCFG rm redisSlaveController
|
||||
$CLOUDCFG delete services/redismaster
|
||||
$CLOUDCFG delete pods/redis-master-2
|
||||
$KUBECFG rm redisSlaveController
|
||||
$KUBECFG delete services/redismaster
|
||||
$KUBECFG delete pods/redis-master-2
|
||||
|
||||
POD_LIST_2=$($CLOUDCFG '-template={{range.Items}}{{.ID}} {{end}}' list pods)
|
||||
POD_LIST_2=$($KUBECFG '-template={{range.Items}}{{.ID}} {{end}}' list pods)
|
||||
echo "Pods running after shutdown: ${POD_LIST_2}"
|
||||
|
||||
exit 0
|
||||
|
@ -16,65 +16,72 @@
|
||||
|
||||
# Launches an nginx container and verifies it can be reached. Assumes that
|
||||
# we're being called by hack/e2e-test.sh (we use some env vars it sets up).
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
set -x
|
||||
|
||||
source "${KUBE_REPO_ROOT}/cluster/kube-env.sh"
|
||||
source "${KUBE_REPO_ROOT}/cluster/$KUBERNETES_PROVIDER/util.sh"
|
||||
|
||||
function validate() {
|
||||
POD_ID_LIST=$($CLOUDCFG '-template={{range.Items}}{{.ID}} {{end}}' -l name=$controller list pods)
|
||||
# Container turn up on a clean cluster can take a while for the docker image pull.
|
||||
ALL_RUNNING=0
|
||||
while [ $ALL_RUNNING -ne 1 ]; do
|
||||
echo "Waiting for all containers in pod to come up."
|
||||
sleep 5
|
||||
ALL_RUNNING=1
|
||||
for id in $POD_ID_LIST; do
|
||||
CURRENT_STATUS=$($CLOUDCFG -template '{{and .CurrentState.Info.datacontroller.State.Running .CurrentState.Info.net.State.Running}}' get pods/$id)
|
||||
if [ "$CURRENT_STATUS" != "true" ]; then
|
||||
ALL_RUNNING=0
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
ids=($POD_ID_LIST)
|
||||
if [ ${#ids[@]} -ne $1 ]; then
|
||||
echo "Unexpected number of pods: ${#ids[@]}. Expected $1"
|
||||
exit 1
|
||||
fi
|
||||
CONTROLLER_NAME=update-demo
|
||||
|
||||
function validate() {
|
||||
NUM_REPLICAS=$1
|
||||
CONTAINER_IMAGE_VERSION=$2
|
||||
POD_ID_LIST=$($KUBECFG '-template={{range.Items}}{{.ID}} {{end}}' -l replicationController=${CONTROLLER_NAME} list pods)
|
||||
# Container turn up on a clean cluster can take a while for the docker image pull.
|
||||
ALL_RUNNING=0
|
||||
while [ $ALL_RUNNING -ne 1 ]; do
|
||||
echo "Waiting for all containers in pod to come up."
|
||||
sleep 5
|
||||
ALL_RUNNING=1
|
||||
for id in $POD_ID_LIST; do
|
||||
TEMPLATE_STRING="{{and ((index .CurrentState.Info \"${CONTROLLER_NAME}\").State.Running) .CurrentState.Info.net.State.Running}}"
|
||||
CURRENT_STATUS=$($KUBECFG -template "${TEMPLATE_STRING}" get pods/$id)
|
||||
if [ "$CURRENT_STATUS" != "true" ]; then
|
||||
ALL_RUNNING=0
|
||||
fi
|
||||
|
||||
CURRENT_IMAGE=$($KUBECFG -template "{{(index .CurrentState.Info \"${CONTROLLER_NAME}\").Config.Image}}" get pods/$id)
|
||||
if [ "$CURRENT_IMAGE" != "${DOCKER_HUB_USER}/update-demo:${CONTAINER_IMAGE_VERSION}" ]; then
|
||||
ALL_RUNNING=0
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
ids=($POD_ID_LIST)
|
||||
if [ ${#ids[@]} -ne $NUM_REPLICAS ]; then
|
||||
echo "Unexpected number of pods: ${#ids[@]}. Expected $NUM_REPLICAS"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
controller=dataController
|
||||
DOCKER_HUB_USER=jbeda
|
||||
|
||||
# Launch a container
|
||||
$CLOUDCFG -p 8080:80 run brendanburns/data 2 $controller
|
||||
${KUBE_REPO_ROOT}/examples/update-demo/1-create-replication-controller.sh
|
||||
|
||||
function teardown() {
|
||||
echo "Cleaning up test artifacts"
|
||||
$CLOUDCFG stop $controller
|
||||
$CLOUDCFG rm $controller
|
||||
${KUBE_REPO_ROOT}/examples/update-demo/4-down.sh
|
||||
}
|
||||
|
||||
trap "teardown" EXIT
|
||||
|
||||
validate 2
|
||||
validate 2 nautilus
|
||||
|
||||
$CLOUDCFG resize $controller 1
|
||||
${KUBE_REPO_ROOT}/examples/update-demo/2-scale.sh 1
|
||||
sleep 2
|
||||
validate 1
|
||||
validate 1 nautilus
|
||||
|
||||
$CLOUDCFG resize $controller 2
|
||||
${KUBE_REPO_ROOT}/examples/update-demo/2-scale.sh 2
|
||||
sleep 2
|
||||
validate 2
|
||||
validate 2 nautilus
|
||||
|
||||
# TODO: test rolling update here, but to do so, we need to make the update blocking
|
||||
# $CLOUDCFG -u=20s rollingupdate $controller
|
||||
#
|
||||
# Wait for the replica controller to recreate
|
||||
# sleep 10
|
||||
#
|
||||
# validate 2
|
||||
${KUBE_REPO_ROOT}/examples/update-demo/3-rolling-update.sh kitten 1s
|
||||
sleep 2
|
||||
validate 2 kitten
|
||||
|
||||
exit 0
|
||||
|
@ -32,7 +32,7 @@ set -e
|
||||
# Use testing config
|
||||
export KUBE_CONFIG_FILE="config-test.sh"
|
||||
export KUBE_REPO_ROOT="$(dirname $0)/.."
|
||||
export CLOUDCFG="${KUBE_REPO_ROOT}/cluster/kubecfg.sh -expect_version_match"
|
||||
export KUBECFG="${KUBE_REPO_ROOT}/cluster/kubecfg.sh -expect_version_match"
|
||||
|
||||
if [[ $TEAR_DOWN -ne 0 ]]; then
|
||||
detect-project
|
||||
|
@ -19,6 +19,7 @@ package client
|
||||
import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
)
|
||||
@ -43,7 +44,7 @@ type Fake struct {
|
||||
|
||||
func (c *Fake) ListPods(selector labels.Selector) (api.PodList, error) {
|
||||
c.Actions = append(c.Actions, FakeAction{Action: "list-pods"})
|
||||
return c.Pods, nil
|
||||
return *runtime.CopyOrDie(c.Pods).(*api.PodList), nil
|
||||
}
|
||||
|
||||
func (c *Fake) GetPod(name string) (api.Pod, error) {
|
||||
@ -73,7 +74,7 @@ func (c *Fake) ListReplicationControllers(selector labels.Selector) (api.Replica
|
||||
|
||||
func (c *Fake) GetReplicationController(name string) (api.ReplicationController, error) {
|
||||
c.Actions = append(c.Actions, FakeAction{Action: "get-controller", Value: name})
|
||||
return c.Ctrl, nil
|
||||
return *runtime.CopyOrDie(c.Ctrl).(*api.ReplicationController), nil
|
||||
}
|
||||
|
||||
func (c *Fake) CreateReplicationController(controller api.ReplicationController) (api.ReplicationController, error) {
|
||||
|
@ -78,11 +78,24 @@ func LoadAuthInfo(path string, r io.Reader) (*client.AuthInfo, error) {
|
||||
// 'name' points to a replication controller.
|
||||
// 'client' is used for updating pods.
|
||||
// 'updatePeriod' is the time between pod updates.
|
||||
func Update(name string, client client.Interface, updatePeriod time.Duration) error {
|
||||
// 'imageName' is the new image to update for the template. This will work
|
||||
// with the first container in the pod. There is no support yet for
|
||||
// updating more complex replication controllers. If this is blank then no
|
||||
// update of the image is performed.
|
||||
func Update(name string, client client.Interface, updatePeriod time.Duration, imageName string) error {
|
||||
controller, err := client.GetReplicationController(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(imageName) != 0 {
|
||||
controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image = imageName
|
||||
controller, err = client.UpdateReplicationController(controller)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s := labels.Set(controller.DesiredState.ReplicaSelector).AsSelector()
|
||||
|
||||
podList, err := client.ListPods(s)
|
||||
@ -168,7 +181,7 @@ func RunController(image, name string, replicas int, client client.Interface, po
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
Replicas: replicas,
|
||||
ReplicaSelector: map[string]string{
|
||||
"name": name,
|
||||
"replicationController": name,
|
||||
},
|
||||
PodTemplate: api.PodTemplate{
|
||||
DesiredState: api.PodState{
|
||||
@ -184,13 +197,10 @@ func RunController(image, name string, replicas int, client client.Interface, po
|
||||
},
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"name": name,
|
||||
"replicationController": name,
|
||||
},
|
||||
},
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"name": name,
|
||||
},
|
||||
}
|
||||
|
||||
controllerOut, err := client.CreateReplicationController(controller)
|
||||
|
@ -26,10 +26,11 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func validateAction(expectedAction, actualAction client.FakeAction, t *testing.T) {
|
||||
if expectedAction != actualAction {
|
||||
if !reflect.DeepEqual(expectedAction, actualAction) {
|
||||
t.Errorf("Unexpected Action: %#v, expected: %#v", actualAction, expectedAction)
|
||||
}
|
||||
}
|
||||
@ -43,7 +44,7 @@ func TestUpdateWithPods(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
Update("foo", &fakeClient, 0)
|
||||
Update("foo", &fakeClient, 0, "")
|
||||
if len(fakeClient.Actions) != 5 {
|
||||
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
|
||||
}
|
||||
@ -57,7 +58,7 @@ func TestUpdateWithPods(t *testing.T) {
|
||||
|
||||
func TestUpdateNoPods(t *testing.T) {
|
||||
fakeClient := client.Fake{}
|
||||
Update("foo", &fakeClient, 0)
|
||||
Update("foo", &fakeClient, 0, "")
|
||||
if len(fakeClient.Actions) != 2 {
|
||||
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
|
||||
}
|
||||
@ -65,6 +66,45 @@ func TestUpdateNoPods(t *testing.T) {
|
||||
validateAction(client.FakeAction{Action: "list-pods"}, fakeClient.Actions[1], t)
|
||||
}
|
||||
|
||||
func TestUpdateWithNewImage(t *testing.T) {
|
||||
fakeClient := client.Fake{
|
||||
Pods: api.PodList{
|
||||
Items: []api.Pod{
|
||||
{JSONBase: api.JSONBase{ID: "pod-1"}},
|
||||
{JSONBase: api.JSONBase{ID: "pod-2"}},
|
||||
},
|
||||
},
|
||||
Ctrl: api.ReplicationController{
|
||||
DesiredState: api.ReplicationControllerState{
|
||||
PodTemplate: api.PodTemplate{
|
||||
DesiredState: api.PodState{
|
||||
Manifest: api.ContainerManifest{
|
||||
Containers: []api.Container{
|
||||
{Image: "fooImage:1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Update("foo", &fakeClient, 0, "fooImage:2")
|
||||
if len(fakeClient.Actions) != 6 {
|
||||
t.Errorf("Unexpected action list %#v", fakeClient.Actions)
|
||||
}
|
||||
validateAction(client.FakeAction{Action: "get-controller", Value: "foo"}, fakeClient.Actions[0], t)
|
||||
|
||||
newCtrl := *runtime.CopyOrDie(fakeClient.Ctrl).(*api.ReplicationController)
|
||||
newCtrl.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image = "fooImage:2"
|
||||
validateAction(client.FakeAction{Action: "update-controller", Value: newCtrl}, fakeClient.Actions[1], t)
|
||||
|
||||
validateAction(client.FakeAction{Action: "list-pods"}, fakeClient.Actions[2], t)
|
||||
// Update deletes the pods, it relies on the replication controller to replace them.
|
||||
validateAction(client.FakeAction{Action: "delete-pod", Value: "pod-1"}, fakeClient.Actions[3], t)
|
||||
validateAction(client.FakeAction{Action: "delete-pod", Value: "pod-2"}, fakeClient.Actions[4], t)
|
||||
validateAction(client.FakeAction{Action: "list-pods"}, fakeClient.Actions[5], t)
|
||||
}
|
||||
|
||||
func TestRunController(t *testing.T) {
|
||||
fakeClient := client.Fake{}
|
||||
name := "name"
|
||||
|
@ -194,6 +194,24 @@ func DecodeInto(data []byte, obj interface{}) error {
|
||||
return conversionScheme.DecodeInto(data, obj)
|
||||
}
|
||||
|
||||
// Does a deep copy of an API object. Useful mostly for tests.
|
||||
// TODO(dbsmith): implement directly instead of via Encode/Decode
|
||||
func Copy(obj interface{}) (interface{}, error) {
|
||||
data, err := Encode(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Decode(data)
|
||||
}
|
||||
|
||||
func CopyOrDie(obj interface{}) interface{} {
|
||||
newObj, err := Copy(obj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
|
||||
// metaInsertion implements conversion.MetaInsertionFactory, which lets the conversion
|
||||
// package figure out how to encode our object's types and versions. These fields are
|
||||
// located in our JSONBase.
|
||||
|
Loading…
Reference in New Issue
Block a user