mirror of
https://github.com/rancher/os.git
synced 2025-09-03 15:54:24 +00:00
OS upgrade and list
This commit is contained in:
@@ -1,14 +1,16 @@
|
|||||||
package control
|
package control
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
dockerClient "github.com/fsouza/go-dockerclient"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/rancherio/os/cmd/power"
|
"github.com/rancherio/os/cmd/power"
|
||||||
@@ -16,11 +18,10 @@ import (
|
|||||||
"github.com/rancherio/os/docker"
|
"github.com/rancherio/os/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var osChannels map[string]string
|
type Images struct {
|
||||||
|
Current string `yaml:"current,omitempty"`
|
||||||
const (
|
Available []string `yaml:"available,omitempty"`
|
||||||
osVersionsFile = "/var/lib/rancher/versions"
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func osSubcommands() []cli.Command {
|
func osSubcommands() []cli.Command {
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
@@ -37,10 +38,6 @@ func osSubcommands() []cli.Command {
|
|||||||
Name: "image, i",
|
Name: "image, i",
|
||||||
Usage: "upgrade to a certain image",
|
Usage: "upgrade to a certain image",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
|
||||||
Name: "channel, c",
|
|
||||||
Usage: "upgrade to the latest in a specific channel",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,80 +45,102 @@ func osSubcommands() []cli.Command {
|
|||||||
Usage: "list the current available versions",
|
Usage: "list the current available versions",
|
||||||
Action: osMetaDataGet,
|
Action: osMetaDataGet,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "rollback",
|
|
||||||
Usage: "rollback to the previous version",
|
|
||||||
Action: osRollback,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func osRollback(c *cli.Context) {
|
func getImages() (*Images, error) {
|
||||||
file, err := os.Open(osVersionsFile)
|
upgradeUrl, err := getUpgradeUrl()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileReader := bufio.NewScanner(file)
|
var body []byte
|
||||||
line := " "
|
|
||||||
for line[len(line)-1:] != "*" {
|
if strings.HasPrefix(upgradeUrl, "/") {
|
||||||
if !fileReader.Scan() {
|
body, err = ioutil.ReadFile(upgradeUrl)
|
||||||
log.Error("Current version not indicated in " + osVersionsFile)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
u, err := url.Parse(upgradeUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
line = fileReader.Text()
|
|
||||||
}
|
|
||||||
if !fileReader.Scan() {
|
|
||||||
log.Error("already at earliest version, please choose a version specifically using upgrade --image")
|
|
||||||
}
|
|
||||||
line = fileReader.Text()
|
|
||||||
//TODO: process string if required
|
|
||||||
|
|
||||||
startUpgradeContainer(line, false)
|
q := u.Query()
|
||||||
|
q.Set("current", config.VERSION)
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
upgradeUrl = u.String()
|
||||||
|
|
||||||
|
resp, err := http.Get(upgradeUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err = ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseBody(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func osMetaDataGet(c *cli.Context) {
|
func osMetaDataGet(c *cli.Context) {
|
||||||
osChannel, ok := getChannelUrl("meta")
|
images, err := getImages()
|
||||||
if !ok {
|
|
||||||
log.Fatal("unrecognized channel meta")
|
|
||||||
}
|
|
||||||
resp, err := http.Get(osChannel)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
client, err := docker.NewSystemClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Print(parseBody(body, osChannel))
|
|
||||||
|
for _, image := range images.Available {
|
||||||
|
_, err := client.InspectImage(image)
|
||||||
|
if err == dockerClient.ErrNoSuchImage {
|
||||||
|
fmt.Println(image, " remote")
|
||||||
|
} else {
|
||||||
|
fmt.Println(image, " local")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLatestImage() (string, error) {
|
||||||
|
images, err := getImages()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return images.Current, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func osUpgrade(c *cli.Context) {
|
func osUpgrade(c *cli.Context) {
|
||||||
channel := c.String("channel")
|
|
||||||
|
|
||||||
image := c.String("image")
|
image := c.String("image")
|
||||||
|
|
||||||
if image == "" {
|
if image == "" {
|
||||||
var err error
|
var err error
|
||||||
image, err = getLatestImage(channel)
|
image, err = getLatestImage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if image == "" {
|
||||||
|
log.Fatal("Failed to find latest image")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
startUpgradeContainer(image, c.Bool("stage"))
|
startUpgradeContainer(image, c.Bool("stage"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func startUpgradeContainer(image string, stage bool) {
|
func startUpgradeContainer(image string, stage bool) {
|
||||||
container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &config.ContainerConfig{
|
container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &config.ContainerConfig{
|
||||||
Cmd: "--name=upgrade " +
|
Cmd: "--name=os-upgrade " +
|
||||||
|
"--rm " +
|
||||||
"--privileged " +
|
"--privileged " +
|
||||||
"--net=host " +
|
"--net=host " +
|
||||||
"--ipc=host " +
|
image + " " +
|
||||||
"--pid=host " +
|
"-t rancher-upgrade " +
|
||||||
"-v=/var:/var " +
|
"-r " + config.VERSION,
|
||||||
"--volumes-from=system-volumes " +
|
|
||||||
image,
|
|
||||||
}).Stage()
|
}).Stage()
|
||||||
|
|
||||||
if container.Err != nil {
|
if container.Err != nil {
|
||||||
@@ -137,62 +156,21 @@ func startUpgradeContainer(image string, stage bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLatestImage(channel string) (string, error) {
|
func parseBody(body []byte) (*Images, error) {
|
||||||
data, err := getConfigData()
|
update := &Images{}
|
||||||
|
err := yaml.Unmarshal(body, update)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return update, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUpgradeUrl() (string, error) {
|
||||||
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pivot string
|
return cfg.Upgrade.Url, nil
|
||||||
|
|
||||||
if pivot == "" {
|
|
||||||
val := getOrSetVal("os_upgrade_channel", data, nil)
|
|
||||||
|
|
||||||
if val == nil {
|
|
||||||
return "", errors.New("os_upgrade_channel is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch currentChannel := val.(type) {
|
|
||||||
case string:
|
|
||||||
pivot = currentChannel
|
|
||||||
default:
|
|
||||||
return "", errors.New("invalid format of rancherctl config get os_upgrade_channel")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pivot = channel
|
|
||||||
}
|
|
||||||
osChannel, ok := getChannelUrl(pivot)
|
|
||||||
if !ok {
|
|
||||||
return "", errors.New("unrecognized channel " + pivot)
|
|
||||||
}
|
|
||||||
resp, err := http.Get(osChannel)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return parseBody(body, osChannel), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBody(body []byte, channel string) string {
|
|
||||||
// just going to assume that the response is the image name
|
|
||||||
// can change it later based on server response design
|
|
||||||
return string(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getChannelUrl(channel string) (string, bool) {
|
|
||||||
if osChannels == nil {
|
|
||||||
osChannels = map[string]string{
|
|
||||||
"stable": "",
|
|
||||||
"alpha": "",
|
|
||||||
"beta": "",
|
|
||||||
"meta": "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
channel, ok := osChannels[channel]
|
|
||||||
return channel, ok
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user