Merge pull request #414 from justinsb/ubuntu_initial_support

Initial (experimental) Ubuntu 16.04 support
This commit is contained in:
Justin Santa Barbara 2016-09-08 10:21:24 -04:00 committed by GitHub
commit 0b4a558864
9 changed files with 156 additions and 10 deletions

View File

@ -33,14 +33,19 @@ func init() {
cmd.Flags().BoolVar(&rollingupdateCluster.Force, "force", false, "Force rolling update, even if no changes")
cmd.Run = func(cmd *cobra.Command, args []string) {
err := rollingupdateCluster.Run()
err := rollingupdateCluster.Run(args)
if err != nil {
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()
if err != nil {
return err

19
docs/images.md Normal file
View File

@ -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

View File

@ -103,6 +103,12 @@ function download-release() {
done
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 )
}

View File

@ -127,6 +127,12 @@ function download-release() {
done
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 )
}

View File

@ -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
}

View File

@ -399,7 +399,7 @@ func (c *AWSCloud) ResolveImage(name string) (*ec2.Image, error) {
request.ImageIds = []*string{&name}
} else {
// Either <imagename> or <owner>/<imagename>
tokens := strings.Split(name, "/")
tokens := strings.SplitN(name, "/", 2)
if len(tokens) == 1 {
// self is a well-known value in the DescribeImages call
request.Owners = aws.StringSlice([]string{"self"})

View File

@ -11,7 +11,9 @@ import (
"os"
"os/exec"
"path"
"reflect"
"strings"
"sync"
)
type Package struct {
@ -21,6 +23,9 @@ type Package struct {
Source *string `json:"source"`
Hash *string `json:"hash"`
PreventStart *bool `json:"preventStart"`
// Healthy is true if the package installation did not fail
Healthy *bool `json:"healthy"`
}
const (
@ -29,16 +34,37 @@ const (
var _ fi.HasDependencies = &Package{}
// GetDependencies computes dependencies for the package task
func (p *Package) GetDependencies(tasks map[string]fi.Task) []fi.Task {
var deps []fi.Task
// UpdatePackages before we install any packages
for _, v := range tasks {
if _, ok := v.(*UpdatePackages); ok {
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
}
// 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 {
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)
}
}
// 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
}
@ -69,6 +101,7 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
}
installed := false
var healthy *bool
installedVersion := ""
for _, line := range strings.Split(string(output), "\n") {
if line == "" {
@ -86,6 +119,11 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
case "ii":
installed = true
installedVersion = version
healthy = fi.Bool(true)
case "iF":
installed = true
installedVersion = version
healthy = fi.Bool(false)
case "rc":
// removed
installed = false
@ -104,6 +142,7 @@ func (e *Package) Find(c *fi.Context) (*Package, error) {
return &Package{
Name: e.Name,
Version: fi.String(installedVersion),
Healthy: healthy,
}, nil
}
@ -115,8 +154,15 @@ func (s *Package) CheckChanges(a, e, changes *Package) error {
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 {
if changes.Version != nil {
packageManagerLock.Lock()
defer packageManagerLock.Unlock()
if a == nil || changes.Version != nil {
glog.Infof("Installing package %q", e.Name)
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))
}
}
} 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

View File

@ -12,6 +12,21 @@ import (
// FindOSTags infers tags from the current distro
// We will likely remove this when everything is containerized
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"))
if err == nil {
debianVersion := strings.TrimSpace(string(debianVersionBytes))
@ -21,8 +36,9 @@ func FindOSTags(rootfs string) ([]string, error) {
return nil, fmt.Errorf("unhandled debian version %q", debianVersion)
}
} 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")
}