mirror of https://github.com/kubernetes/kops.git
Merge pull request #414 from justinsb/ubuntu_initial_support
Initial (experimental) Ubuntu 16.04 support
This commit is contained in:
commit
0b4a558864
|
|
@ -33,14 +33,19 @@ func init() {
|
||||||
cmd.Flags().BoolVar(&rollingupdateCluster.Force, "force", false, "Force rolling update, even if no changes")
|
cmd.Flags().BoolVar(&rollingupdateCluster.Force, "force", false, "Force rolling update, even if no changes")
|
||||||
|
|
||||||
cmd.Run = func(cmd *cobra.Command, args []string) {
|
cmd.Run = func(cmd *cobra.Command, args []string) {
|
||||||
err := rollingupdateCluster.Run()
|
err := rollingupdateCluster.Run(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exitWithError(err)
|
exitWithError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RollingUpdateClusterCmd) Run() error {
|
func (c *RollingUpdateClusterCmd) Run(args []string) error {
|
||||||
|
err := rootCommand.ProcessArgs(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_, cluster, err := rootCommand.Cluster()
|
_, cluster, err := rootCommand.Cluster()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Images
|
||||||
|
|
||||||
|
Changing the image for an instance group
|
||||||
|
|
||||||
|
You can choose a different AMI for an instance group.
|
||||||
|
|
||||||
|
If you `kops edit ig nodes`, you should see an `image` member of the spec.
|
||||||
|
|
||||||
|
Various syntaxes are available:
|
||||||
|
|
||||||
|
* `ami-abcdef` specifies an AMI by id directly.
|
||||||
|
* `<owner>/<name>` specifies an AMI by its owner and Name properties
|
||||||
|
|
||||||
|
The ami spec is precise, but AMIs vary by region. So it is often more convenient to use the `<owner>/<name>`
|
||||||
|
specifier, if equivalent images have been copied to various regions with the same name.
|
||||||
|
|
||||||
|
For example, to use Ubuntu 16.04, you can specify:
|
||||||
|
|
||||||
|
`image: 099720109477/ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20160830`
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -103,6 +103,12 @@ function download-release() {
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Running release install script"
|
echo "Running release install script"
|
||||||
|
# We run in the background to work around https://github.com/docker/docker/issues/23793
|
||||||
|
run-nodeup &
|
||||||
|
}
|
||||||
|
|
||||||
|
function run-nodeup() {
|
||||||
|
sleep 1
|
||||||
( cd ${INSTALL_DIR}; ./nodeup --conf=/var/cache/kubernetes-install/kube_env.yaml --v=8 )
|
( cd ${INSTALL_DIR}; ./nodeup --conf=/var/cache/kubernetes-install/kube_env.yaml --v=8 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,12 @@ function download-release() {
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Running release install script"
|
echo "Running release install script"
|
||||||
|
# We run in the background to work around https://github.com/docker/docker/issues/23793
|
||||||
|
run-nodeup &
|
||||||
|
}
|
||||||
|
|
||||||
|
function run-nodeup() {
|
||||||
|
sleep 1
|
||||||
( cd ${INSTALL_DIR}; ./nodeup --conf=/var/cache/kubernetes-install/kube_env.yaml --v=8 )
|
( cd ${INSTALL_DIR}; ./nodeup --conf=/var/cache/kubernetes-install/kube_env.yaml --v=8 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"version": "1.11.2-0~xenial",
|
||||||
|
"source": "http://apt.dockerproject.org/repo/pool/main/d/docker-engine/docker-engine_1.11.2-0~xenial_amd64.deb",
|
||||||
|
"hash": "194bfa864f0424d1bbdc7d499ccfa0445ce09b9f",
|
||||||
|
|
||||||
|
"preventStart": true
|
||||||
|
}
|
||||||
|
|
@ -399,7 +399,7 @@ func (c *AWSCloud) ResolveImage(name string) (*ec2.Image, error) {
|
||||||
request.ImageIds = []*string{&name}
|
request.ImageIds = []*string{&name}
|
||||||
} else {
|
} else {
|
||||||
// Either <imagename> or <owner>/<imagename>
|
// Either <imagename> or <owner>/<imagename>
|
||||||
tokens := strings.Split(name, "/")
|
tokens := strings.SplitN(name, "/", 2)
|
||||||
if len(tokens) == 1 {
|
if len(tokens) == 1 {
|
||||||
// self is a well-known value in the DescribeImages call
|
// self is a well-known value in the DescribeImages call
|
||||||
request.Owners = aws.StringSlice([]string{"self"})
|
request.Owners = aws.StringSlice([]string{"self"})
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Package struct {
|
type Package struct {
|
||||||
|
|
@ -21,6 +23,9 @@ type Package struct {
|
||||||
Source *string `json:"source"`
|
Source *string `json:"source"`
|
||||||
Hash *string `json:"hash"`
|
Hash *string `json:"hash"`
|
||||||
PreventStart *bool `json:"preventStart"`
|
PreventStart *bool `json:"preventStart"`
|
||||||
|
|
||||||
|
// Healthy is true if the package installation did not fail
|
||||||
|
Healthy *bool `json:"healthy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -29,16 +34,37 @@ const (
|
||||||
|
|
||||||
var _ fi.HasDependencies = &Package{}
|
var _ fi.HasDependencies = &Package{}
|
||||||
|
|
||||||
|
// GetDependencies computes dependencies for the package task
|
||||||
func (p *Package) GetDependencies(tasks map[string]fi.Task) []fi.Task {
|
func (p *Package) GetDependencies(tasks map[string]fi.Task) []fi.Task {
|
||||||
var deps []fi.Task
|
var deps []fi.Task
|
||||||
|
|
||||||
|
// UpdatePackages before we install any packages
|
||||||
for _, v := range tasks {
|
for _, v := range tasks {
|
||||||
if _, ok := v.(*UpdatePackages); ok {
|
if _, ok := v.(*UpdatePackages); ok {
|
||||||
deps = append(deps, v)
|
deps = append(deps, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this package is a bare deb, install it after OS managed packages
|
||||||
|
if !p.isOSPackage() {
|
||||||
|
for _, v := range tasks {
|
||||||
|
if vp, ok := v.(*Package); ok {
|
||||||
|
if vp.isOSPackage() {
|
||||||
|
deps = append(deps, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isOSPackage returns true if this is an OS provided package (as opposed to a bare .deb, for example)
|
||||||
|
func (p *Package) isOSPackage() bool {
|
||||||
|
return fi.StringValue(p.Source) == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation, implementing the Stringer interface
|
||||||
func (p *Package) String() string {
|
func (p *Package) String() string {
|
||||||
return fmt.Sprintf("Package: %s", p.Name)
|
return fmt.Sprintf("Package: %s", p.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +77,12 @@ func NewPackage(name string, contents string, meta string) (fi.Task, error) {
|
||||||
return nil, fmt.Errorf("error parsing json for package %q: %v", name, err)
|
return nil, fmt.Errorf("error parsing json for package %q: %v", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default values: we want to install a package so that it is healthy
|
||||||
|
if p.Healthy == nil {
|
||||||
|
p.Healthy = fi.Bool(true)
|
||||||
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +101,7 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
installed := false
|
installed := false
|
||||||
|
var healthy *bool
|
||||||
installedVersion := ""
|
installedVersion := ""
|
||||||
for _, line := range strings.Split(string(output), "\n") {
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
if line == "" {
|
if line == "" {
|
||||||
|
|
@ -86,6 +119,11 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
|
||||||
case "ii":
|
case "ii":
|
||||||
installed = true
|
installed = true
|
||||||
installedVersion = version
|
installedVersion = version
|
||||||
|
healthy = fi.Bool(true)
|
||||||
|
case "iF":
|
||||||
|
installed = true
|
||||||
|
installedVersion = version
|
||||||
|
healthy = fi.Bool(false)
|
||||||
case "rc":
|
case "rc":
|
||||||
// removed
|
// removed
|
||||||
installed = false
|
installed = false
|
||||||
|
|
@ -104,6 +142,7 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
|
||||||
return &Package{
|
return &Package{
|
||||||
Name: e.Name,
|
Name: e.Name,
|
||||||
Version: fi.String(installedVersion),
|
Version: fi.String(installedVersion),
|
||||||
|
Healthy: healthy,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,8 +154,15 @@ func (s *Package) CheckChanges(a, e, changes *Package) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// packageManagerLock is a simple lock that prevents concurrent package manager operations
|
||||||
|
// It just avoids unnecessary failures from running e.g. concurrent apt-get installs
|
||||||
|
var packageManagerLock sync.Mutex
|
||||||
|
|
||||||
func (_ *Package) RenderLocal(t *local.LocalTarget, a, e, changes *Package) error {
|
func (_ *Package) RenderLocal(t *local.LocalTarget, a, e, changes *Package) error {
|
||||||
if changes.Version != nil {
|
packageManagerLock.Lock()
|
||||||
|
defer packageManagerLock.Unlock()
|
||||||
|
|
||||||
|
if a == nil || changes.Version != nil {
|
||||||
glog.Infof("Installing package %q", e.Name)
|
glog.Infof("Installing package %q", e.Name)
|
||||||
|
|
||||||
if e.Source != nil {
|
if e.Source != nil {
|
||||||
|
|
@ -156,6 +202,22 @@ func (_ *Package) RenderLocal(t *local.LocalTarget, a, e, changes *Package) erro
|
||||||
return fmt.Errorf("error installing package %q: %v: %s", e.Name, err, string(output))
|
return fmt.Errorf("error installing package %q: %v: %s", e.Name, err, string(output))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if changes.Healthy != nil {
|
||||||
|
args := []string{"dpkg", "--configure", "-a"}
|
||||||
|
glog.Infof("package is not healthy; runnning command %s", args)
|
||||||
|
cmd := exec.Command(args[0], args[1:]...)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error running `dpkg --configure -a`: %v: %s", err, string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
changes.Healthy = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(changes, &Package{}) {
|
||||||
|
glog.Warningf("cannot apply package changes for %q: %v", e.Name, changes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,21 @@ import (
|
||||||
// FindOSTags infers tags from the current distro
|
// FindOSTags infers tags from the current distro
|
||||||
// We will likely remove this when everything is containerized
|
// We will likely remove this when everything is containerized
|
||||||
func FindOSTags(rootfs string) ([]string, error) {
|
func FindOSTags(rootfs string) ([]string, error) {
|
||||||
|
// Ubuntu has /etc/lsb-release (and /etc/debian_version)
|
||||||
|
lsbRelease, err := ioutil.ReadFile(path.Join(rootfs, "etc/lsb-release"))
|
||||||
|
if err == nil {
|
||||||
|
for _, line := range strings.Split(string(lsbRelease), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "DISTRIB_CODENAME=xenial" {
|
||||||
|
return []string{"_xenial", "_debian_family", "_systemd"}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glog.Warningf("unhandled lsb-release info %q", string(lsbRelease))
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
glog.Warningf("error reading /etc/lsb-release: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debian has /etc/debian_version
|
||||||
debianVersionBytes, err := ioutil.ReadFile(path.Join(rootfs, "etc/debian_version"))
|
debianVersionBytes, err := ioutil.ReadFile(path.Join(rootfs, "etc/debian_version"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
debianVersion := strings.TrimSpace(string(debianVersionBytes))
|
debianVersion := strings.TrimSpace(string(debianVersionBytes))
|
||||||
|
|
@ -21,8 +36,9 @@ func FindOSTags(rootfs string) ([]string, error) {
|
||||||
return nil, fmt.Errorf("unhandled debian version %q", debianVersion)
|
return nil, fmt.Errorf("unhandled debian version %q", debianVersion)
|
||||||
}
|
}
|
||||||
} else if !os.IsNotExist(err) {
|
} else if !os.IsNotExist(err) {
|
||||||
glog.Infof("error reading /etc/debian_version: %v", err)
|
glog.Warningf("error reading /etc/debian_version: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("cannot identify distro")
|
return nil, fmt.Errorf("cannot identify distro")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue