1
0
mirror of https://github.com/rancher/os.git synced 2025-08-29 19:44:22 +00:00

Add ipxe support

This commit is contained in:
Darren Shepherd 2021-10-13 16:00:29 -07:00
parent b4cc0014b2
commit 0e46d19194
16 changed files with 287 additions and 126 deletions

View File

@ -4,7 +4,7 @@ RUN zypper ref
ARG DAPPER_HOST_ARCH ARG DAPPER_HOST_ARCH
ENV ARCH $DAPPER_HOST_ARCH ENV ARCH $DAPPER_HOST_ARCH
RUN zypper in -y bash git gcc docker vim less file curl wget ca-certificates make mkisofs go1.16 RUN zypper in -y bash git gcc docker vim less file curl wget ca-certificates make mkisofs go1.16 qemu-tools
RUN go get golang.org/x/tools/cmd/goimports RUN go get golang.org/x/tools/cmd/goimports
RUN if [ "${ARCH}" == "amd64" ]; then \ RUN if [ "${ARCH}" == "amd64" ]; then \
curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.40.1; \ curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.40.1; \

View File

@ -68,6 +68,10 @@ ami:
run: run:
./scripts/run ./scripts/run
.PHONY: run
pxe:
./scripts/run pxe
all-amis: \ all-amis: \
ami-us-west-1 \ ami-us-west-1 \
ami-us-west-2 ami-us-west-2

View File

@ -2,18 +2,36 @@ package main
import ( import (
"flag" "flag"
"os"
"github.com/rancher/os/pkg/config"
"github.com/rancher/os/pkg/install" "github.com/rancher/os/pkg/install"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"sigs.k8s.io/yaml"
) )
var ( var (
output = flag.Bool("automatic", false, "Check for and run automatic installation") output = flag.Bool("automatic", false, "Check for and run automatic installation")
printConfig = flag.Bool("print-config", false, "Print effective configuration and exit")
configFile = flag.String("config-file", "", "Config file to use, local file or http/tftp URL")
) )
func main() { func main() {
flag.Parse() flag.Parse()
if err := install.Run(*output); err != nil { if *printConfig {
cfg, err := config.ReadConfig(*configFile)
if err != nil {
logrus.Fatal(err)
}
data, err := yaml.Marshal(cfg)
if err != nil {
logrus.Fatal(err)
}
os.Stdout.Write(data)
return
}
if err := install.Run(*output, *configFile); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
} }

View File

@ -0,0 +1 @@
/usr/lib/systemd/system/ros-installer.service

View File

@ -0,0 +1,17 @@
[Unit]
Description=RancherOS Automatic Installation
Documentation=https://github.com/rancher/os
Wants=network-online.target
After=network-online.target
Before=getty-pre.target serial-getty@ttyS0.service
[Install]
WantedBy=multi-user.target
[Service]
Type=oneshot
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
TimeoutStartSec=0
StandardOutput=journal+console
ExecStart=/usr/sbin/ros-installer -automatic

3
go.mod
View File

@ -4,12 +4,13 @@ go 1.16
require ( require (
github.com/mattn/go-isatty v0.0.10 github.com/mattn/go-isatty v0.0.10
github.com/pin/tftp v2.1.0+incompatible // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rancher/wrangler v0.8.3 github.com/rancher/wrangler v0.8.3
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/stretchr/testify v1.4.0
github.com/tredoe/osutil v1.0.5 github.com/tredoe/osutil v1.0.5
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
gopkg.in/pin/tftp.v2 v2.1.0
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )

4
go.sum
View File

@ -244,6 +244,8 @@ github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pin/tftp v2.1.0+incompatible h1:Yng4J7jv6lOc6IF4XoB5mnd3P7ZrF60XQq+my3FAMus=
github.com/pin/tftp v2.1.0+incompatible/go.mod h1:xVpZOMCXTy+A5QMjEVN0Glwa1sUvaJhFXbr/aAxuxGY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -473,6 +475,8 @@ gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/pin/tftp.v2 v2.1.0 h1:QbLeBeg/UoYf1dkjJS5nLj/x9t8gFQRG06fq5PEOWDw=
gopkg.in/pin/tftp.v2 v2.1.0/go.mod h1:OptUw+bblWIH7jYabWNBP0CAH4/sBtD2N0oBeXcRG98=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

View File

@ -1,6 +1,6 @@
package config package config
type Rancher struct { type RancherOS struct {
Install Install `json:"install,omitempty"` Install Install `json:"install,omitempty"`
} }
@ -15,31 +15,22 @@ type Install struct {
NoFormat bool `json:"noFormat,omitempty"` NoFormat bool `json:"noFormat,omitempty"`
Debug bool `json:"debug,omitempty"` Debug bool `json:"debug,omitempty"`
TTY string `json:"tty,omitempty"` TTY string `json:"tty,omitempty"`
ServerURL string `json:"serverUrl,omitempty"`
Token string `json:"token,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
} }
type Config struct { type Config struct {
SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"`
Rancher Rancher `json:"rancher,omitempty"` RancherOS RancherOS `json:"rancheros,omitempty"`
} }
type YipConfig struct { type YipConfig struct {
Stages map[string][]Stage `json:"stages,omitempty"` Stages map[string][]Stage `json:"stages,omitempty"`
Rancherd Rancherd `json:"rancherd,omitempty"`
} }
type Stage struct { type Stage struct {
Users map[string]User `json:"users,omitempty"` Users map[string]User `json:"users,omitempty"`
} }
type Rancherd struct {
Server string `json:"server,omitempty"`
Role string `json:"role,omitempty"`
Token string `json:"token,omitempty"`
}
type User struct { type User struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
PasswordHash string `json:"passwd,omitempty"` PasswordHash string `json:"passwd,omitempty"`

View File

@ -3,6 +3,7 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"regexp" "regexp"
"strings" "strings"
@ -10,18 +11,20 @@ import (
values "github.com/rancher/wrangler/pkg/data" values "github.com/rancher/wrangler/pkg/data"
"github.com/rancher/wrangler/pkg/data/convert" "github.com/rancher/wrangler/pkg/data/convert"
schemas2 "github.com/rancher/wrangler/pkg/schemas" schemas2 "github.com/rancher/wrangler/pkg/schemas"
"sigs.k8s.io/yaml"
) )
var ( var (
defaultMappers = schemas2.Mappers{
NewToMap(),
NewToSlice(),
NewToBool(),
&FuzzyNames{},
}
schemas = schemas2.EmptySchemas().Init(func(s *schemas2.Schemas) *schemas2.Schemas { schemas = schemas2.EmptySchemas().Init(func(s *schemas2.Schemas) *schemas2.Schemas {
s.DefaultMapper = func() schemas2.Mapper { s.AddMapper("config", defaultMappers)
return schemas2.Mappers{ s.AddMapper("rancherOS", defaultMappers)
NewToMap(), s.AddMapper("install", defaultMappers)
NewToSlice(),
NewToBool(),
&FuzzyNames{},
}
}
return s return s
}).MustImport(Config{}) }).MustImport(Config{})
schema = schemas.Schema("config") schema = schemas.Schema("config")
@ -40,7 +43,7 @@ func mapToEnv(prefix string, data map[string]interface{}) []string {
var result []string var result []string
for k, v := range data { for k, v := range data {
keyName := strings.ToUpper(prefix + convert.ToYAMLKey(k)) keyName := strings.ToUpper(prefix + convert.ToYAMLKey(k))
keyName = strings.ReplaceAll(keyName, "RANCHER_", "COS_") keyName = strings.ReplaceAll(keyName, "RANCHEROS_", "COS_")
if data, ok := v.(map[string]interface{}); ok { if data, ok := v.(map[string]interface{}); ok {
subResult := mapToEnv(keyName+"_", data) subResult := mapToEnv(keyName+"_", data)
result = append(result, subResult...) result = append(result, subResult...)
@ -51,14 +54,86 @@ func mapToEnv(prefix string, data map[string]interface{}) []string {
return result return result
} }
func ReadConfig() (Config, error) { func readFile(path string) (result map[string]interface{}, _ error) {
result := Config{} result = map[string]interface{}{}
defer func() {
if v, ok := result["install"]; ok {
values.PutValue(result, v, "rancheros", "install")
}
}()
data, err := readCmdline() switch {
if err != nil { case strings.HasPrefix(path, "http://"):
return result, err fallthrough
case strings.HasPrefix(path, "https://"):
resp, err := http.Get(path)
if err != nil {
return nil, err
}
defer resp.Body.Close()
buffer, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read %s: %w", path, err)
}
return result, yaml.Unmarshal(buffer, &result)
case strings.HasPrefix(path, "tftp://"):
return tftpGet(path)
} }
if err := schema.Mapper.ToInternal(data); err != nil {
f, err := ioutil.ReadFile(path)
if os.IsNotExist(err) {
return nil, nil
} else if err != nil {
return nil, err
}
data := map[string]interface{}{}
if err := yaml.Unmarshal(f, &data); err != nil {
return nil, err
}
return data, nil
}
type reader func() (map[string]interface{}, error)
func merge(readers ...reader) (map[string]interface{}, error) {
d := map[string]interface{}{}
for _, r := range readers {
newData, err := r()
if err != nil {
return nil, err
}
if err := schema.Mapper.ToInternal(newData); err != nil {
return nil, err
}
d = values.MergeMapsConcatSlice(d, newData)
}
return d, nil
}
func readConfigMap(cfg string) (map[string]interface{}, error) {
var (
err error
data map[string]interface{}
)
return merge(func() (map[string]interface{}, error) {
data, err = merge(readCmdline,
func() (map[string]interface{}, error) {
return readFile(cfg)
},
)
return data, err
}, func() (map[string]interface{}, error) {
return readFile(convert.ToString(values.GetValueN(data, "rancheros", "install", "configUrl")))
})
}
func ReadConfig(cfg string) (result Config, err error) {
data, err := readConfigMap(cfg)
if err != nil {
return result, err return result, err
} }
@ -72,7 +147,11 @@ func readCmdline() (map[string]interface{}, error) {
return nil, nil return nil, nil
} }
bytes, err := ioutil.ReadFile("/proc/cmdline") procCmdLine := os.Getenv("PROC_CMDLINE")
if procCmdLine == "" {
procCmdLine = "/proc/cmdline"
}
bytes, err := ioutil.ReadFile(procCmdLine)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil, nil return nil, nil
} else if err != nil { } else if err != nil {

View File

@ -30,7 +30,9 @@ func (f *FuzzyNames) addName(name, toName string) {
} }
func (f *FuzzyNames) ModifySchema(schema *schemas2.Schema, schemas *schemas2.Schemas) error { func (f *FuzzyNames) ModifySchema(schema *schemas2.Schema, schemas *schemas2.Schemas) error {
f.names = map[string]string{} if f.names == nil {
f.names = map[string]string{}
}
for name := range schema.ResourceFields { for name := range schema.ResourceFields {
if strings.HasSuffix(name, "s") && len(name) > 1 { if strings.HasSuffix(name, "s") && len(name) > 1 {

41
pkg/config/tftpget.go Normal file
View File

@ -0,0 +1,41 @@
package config
import (
"bytes"
"fmt"
"net"
"net/url"
"gopkg.in/pin/tftp.v2"
"sigs.k8s.io/yaml"
)
func tftpGet(tftpURL string) (map[string]interface{}, error) {
u, err := url.Parse(tftpURL)
if err != nil {
return nil, err
}
host, _, err := net.SplitHostPort(u.Host)
if err != nil {
host = u.Host + ":69"
}
fmt.Printf("Downloading config from host %s, file %s\n", host, u.Path)
client, err := tftp.NewClient(host)
if err != nil {
return nil, err
}
writerTo, err := client.Receive(u.Path, "octet")
if err != nil {
return nil, err
}
buf := &bytes.Buffer{}
if _, err := writerTo.WriteTo(buf); err != nil {
return nil, err
}
result := map[string]interface{}{}
return result, yaml.Unmarshal(buf.Bytes(), &result)
}

View File

@ -6,10 +6,10 @@ import (
) )
func PrintInstall(cfg Config) ([]byte, error) { func PrintInstall(cfg Config) ([]byte, error) {
if cfg.Rancher.Install.Password != "" { if cfg.RancherOS.Install.Password != "" {
cfg.Rancher.Install.Password = "******" cfg.RancherOS.Install.Password = "******"
} }
data, err := convert.EncodeToMap(cfg.Rancher.Install) data, err := convert.EncodeToMap(cfg.RancherOS.Install)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -10,10 +10,6 @@ import (
) )
func Ask(cfg *config.Config) error { func Ask(cfg *config.Config) error {
if cfg.Rancher.Install.Silent {
return nil
}
if err := AskInstallDevice(cfg); err != nil { if err := AskInstallDevice(cfg); err != nil {
return err return err
} }
@ -22,7 +18,7 @@ func Ask(cfg *config.Config) error {
return err return err
} }
if cfg.Rancher.Install.ConfigURL == "" { if cfg.RancherOS.Install.ConfigURL == "" {
if err := AskGithub(cfg); err != nil { if err := AskGithub(cfg); err != nil {
return err return err
} }
@ -30,17 +26,13 @@ func Ask(cfg *config.Config) error {
if err := AskPassword(cfg); err != nil { if err := AskPassword(cfg); err != nil {
return err return err
} }
if err := AskServerAgent(cfg); err != nil {
return err
}
} }
return nil return nil
} }
func AskInstallDevice(cfg *config.Config) error { func AskInstallDevice(cfg *config.Config) error {
if cfg.Rancher.Install.Device != "" { if cfg.RancherOS.Install.Device != "" {
return nil return nil
} }
@ -54,69 +46,22 @@ func AskInstallDevice(cfg *config.Config) error {
return err return err
} }
cfg.Rancher.Install.Device = "/dev/" + fields[i] cfg.RancherOS.Install.Device = "/dev/" + fields[i]
return nil return nil
} }
func AskToken(cfg *config.Config, server bool) error { func isServer(cfg *config.Config) (bool, bool, error) {
var ( opts := []string{"server", "agent", "none"}
token string
err error
)
if cfg.Rancher.Install.Token != "" {
return nil
}
msg := "Token or cluster secret"
if server {
msg += " (optional)"
}
if server {
token, err = questions.PromptOptional(msg+": ", "")
} else {
token, err = questions.Prompt(msg+": ", "")
}
cfg.Rancher.Install.Token = token
return err
}
func isServer(cfg *config.Config) (bool, error) {
opts := []string{"server", "agent"}
i, err := questions.PromptFormattedOptions("Run as server or agent?", 0, opts...) i, err := questions.PromptFormattedOptions("Run as server or agent?", 0, opts...)
if err != nil { if err != nil {
return false, err return false, false, err
} }
return i == 0, nil return i == 0, i == 1, nil
}
func AskServerAgent(cfg *config.Config) error {
if cfg.Rancher.Install.ServerURL != "" {
return nil
}
server, err := isServer(cfg)
if err != nil {
return err
}
if server {
return AskToken(cfg, true)
}
url, err := questions.Prompt("URL of server: ", "")
if err != nil {
return err
}
cfg.Rancher.Install.ServerURL = url
return AskToken(cfg, false)
} }
func AskPassword(cfg *config.Config) error { func AskPassword(cfg *config.Config) error {
if cfg.Rancher.Install.Silent || cfg.Rancher.Install.Password != "" { if cfg.RancherOS.Install.Silent || cfg.RancherOS.Install.Password != "" {
return nil return nil
} }
@ -140,12 +85,12 @@ func AskPassword(cfg *config.Config) error {
} }
} }
cfg.Rancher.Install.Password = pass cfg.RancherOS.Install.Password = pass
return nil return nil
} }
func AskGithub(cfg *config.Config) error { func AskGithub(cfg *config.Config) error {
if len(cfg.SSHAuthorizedKeys) > 0 || cfg.Rancher.Install.Password != "" { if len(cfg.SSHAuthorizedKeys) > 0 || cfg.RancherOS.Install.Password != "" || cfg.RancherOS.Install.Silent {
return nil return nil
} }
@ -167,7 +112,7 @@ func AskGithub(cfg *config.Config) error {
} }
func AskConfigURL(cfg *config.Config) error { func AskConfigURL(cfg *config.Config) error {
if cfg.Rancher.Install.ConfigURL != "" { if cfg.RancherOS.Install.ConfigURL != "" || cfg.RancherOS.Install.Silent {
return nil return nil
} }
@ -185,6 +130,6 @@ func AskConfigURL(cfg *config.Config) error {
return err return err
} }
cfg.Rancher.Install.ConfigURL = str cfg.RancherOS.Install.ConfigURL = str
return nil return nil
} }

View File

@ -1,6 +1,7 @@
package install package install
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -10,16 +11,16 @@ import (
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
func Run(automatic bool) error { func Run(automatic bool, configFile string) error {
cfg, err := config.ReadConfig() cfg, err := config.ReadConfig(configFile)
if err != nil { if err != nil {
return err return err
} }
if automatic && !cfg.Rancher.Install.Automatic { if automatic && !cfg.RancherOS.Install.Automatic {
return nil return nil
} else if automatic { } else if automatic {
cfg.Rancher.Install.Silent = true cfg.RancherOS.Install.Silent = true
} }
err = Ask(&cfg) err = Ask(&cfg)
@ -44,7 +45,7 @@ func runInstall(cfg config.Config, output string) error {
return err return err
} }
if !cfg.Rancher.Install.Silent { if !cfg.RancherOS.Install.Silent {
val, err := questions.PromptBool("\nConfiguration\n"+"-------------\n\n"+ val, err := questions.PromptBool("\nConfiguration\n"+"-------------\n\n"+
string(installBytes)+ string(installBytes)+
"\nYour disk will be formatted and installed with the above configuration.\nContinue?", false) "\nYour disk will be formatted and installed with the above configuration.\nContinue?", false)
@ -53,30 +54,20 @@ func runInstall(cfg config.Config, output string) error {
} }
} }
if cfg.Rancher.Install.ConfigURL == "" { if cfg.RancherOS.Install.ConfigURL == "" && !cfg.RancherOS.Install.Silent {
yip := config.YipConfig{ yip := config.YipConfig{}
Rancherd: config.Rancherd{ if cfg.RancherOS.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 {
Server: cfg.Rancher.Install.ServerURL,
Token: cfg.Rancher.Install.Token,
},
}
if cfg.Rancher.Install.ServerURL == "" {
yip.Rancherd.Role = "cluster-init"
} else {
yip.Rancherd.Role = "agent"
}
if cfg.Rancher.Install.Password != "" || len(cfg.SSHAuthorizedKeys) > 0 {
yip.Stages = map[string][]config.Stage{ yip.Stages = map[string][]config.Stage{
"network": {{ "network": {{
Users: map[string]config.User{ Users: map[string]config.User{
"root": { "root": {
Name: "root", Name: "root",
PasswordHash: cfg.Rancher.Install.Password, PasswordHash: cfg.RancherOS.Install.Password,
SSHAuthorizedKeys: cfg.SSHAuthorizedKeys, SSHAuthorizedKeys: cfg.SSHAuthorizedKeys,
}, },
}}, }},
}} }}
cfg.Rancher.Install.Password = "" cfg.RancherOS.Install.Password = ""
} }
data, err := yaml.Marshal(yip) data, err := yaml.Marshal(yip)
@ -87,7 +78,7 @@ func runInstall(cfg config.Config, output string) error {
if err := ioutil.WriteFile(output+".yip", data, 0600); err != nil { if err := ioutil.WriteFile(output+".yip", data, 0600); err != nil {
return err return err
} }
cfg.Rancher.Install.ConfigURL = output + ".yip" cfg.RancherOS.Install.ConfigURL = output + ".yip"
} }
ev, err := config.ToEnv(cfg) ev, err := config.ToEnv(cfg)
@ -95,6 +86,8 @@ func runInstall(cfg config.Config, output string) error {
return err return err
} }
printEnv(cfg)
cmd := exec.Command("cos-installer") cmd := exec.Command("cos-installer")
cmd.Env = append(os.Environ(), ev...) cmd.Env = append(os.Environ(), ev...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@ -102,3 +95,19 @@ func runInstall(cfg config.Config, output string) error {
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() return cmd.Run()
} }
func printEnv(cfg config.Config) {
if cfg.RancherOS.Install.Password != "" {
cfg.RancherOS.Install.Password = "<removed>"
}
ev2, err := config.ToEnv(cfg)
if err != nil {
return
}
fmt.Println("Install environment:")
for _, ev := range ev2 {
fmt.Println(ev)
}
}

View File

@ -32,6 +32,30 @@ isoinfo -x /rootfs.squashfs -R -i build/output.iso > build/output.squashfs
isoinfo -x /boot/kernel.xz -R -i build/output.iso > build/output-kernel isoinfo -x /boot/kernel.xz -R -i build/output.iso > build/output-kernel
isoinfo -x /boot/rootfs.xz -R -i build/output.iso > build/output-initrd isoinfo -x /boot/rootfs.xz -R -i build/output.iso > build/output-initrd
RELEASE_URL=${RELEASE_URL:-https://github.com/rancher/os/releases/download}
INSTALL_CFG=${RELEASE_URL}/${VERSION}/example-cloud-init
PXE_ASSET_VERSION="\${version}-\${arch}"
if [ "${TAG}" = "dev" ]; then
RELEASE_URL=tftp://10.0.2.2
INSTALL_CFG=
VERSION=${TAG}
PXE_ASSET_VERSION=${TAG}
fi
cat > build/output.ipxe << EOF
#!ipxe
set arch ${ARCH}
set version ${VERSION}
set url ${RELEASE_URL}/\${version}
set kernel rancheros-${PXE_ASSET_VERSION}-kernel
set initrd rancheros-${PXE_ASSET_VERSION}-initrd
set rootfs rancheros-${PXE_ASSET_VERSION}.squashfs
kernel \${url}/\${kernel} initrd=\${initrd} ip=dhcp rd.cos.disable root=live:\${url}/\${rootfs} rancheros.install.automatic=true rancheros.install.config_url=\${config} console=tty1 console=ttyS0
initrd \${url}/\${initrd}
boot
EOF
mkdir -p dist/artifacts mkdir -p dist/artifacts
for i in build/output*; do for i in build/output*; do
mv -f $i dist/artifacts/rancheros-${TAG}${i##build/output} mv -f $i dist/artifacts/rancheros-${TAG}${i##build/output}

View File

@ -11,10 +11,34 @@ fi
touch meta-data touch meta-data
touch user-data touch user-data
rm -f seed.iso rm -f seed.iso
genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data mkisofs -output seed.iso -volid cidata -joliet -rock user-data meta-data
BOOT=
if [ "$1" = "pxe" ]; then
shift 1
if [ ! -e ipxe.cfg ]; then
if [ ! -e ../dist/artifacts/rancheros-dev.ipxe ]; then
make -C .. package
fi
if [ -e ../dist/artifacts/rancheros-dev.ipxe ]; then
cp ../dist/artifacts/rancheros-dev.ipxe ipxe.cfg
fi
fi
BOOT="-boot cn"
if [ ! -e dev ]; then
ln -s ../dist/artifacts dev
fi
fi
if [ "$1" == "" ] && [ ! -e output.iso ]; then
make -C .. build iso
fi
#-bios /usr/share/qemu/OVMF.fd \ #-bios /usr/share/qemu/OVMF.fd \
qemu-system-x86_64 \ qemu-system-x86_64 \
$BOOT \
-enable-kvm \ -enable-kvm \
-m ${MEMORY:=4096} \ -m ${MEMORY:=4096} \
-machine accel=${ACCEL:="kvm"} \ -machine accel=${ACCEL:="kvm"} \
@ -23,6 +47,7 @@ qemu-system-x86_64 \
-serial mon:stdio \ -serial mon:stdio \
-rtc base=utc,clock=rt \ -rtc base=utc,clock=rt \
-chardev socket,path=qga.sock,server,nowait,id=qga0 \ -chardev socket,path=qga.sock,server,nowait,id=qga0 \
-nic user,tftp=./,bootfile=/ipxe.cfg \
-device virtio-serial \ -device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \ -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
-drive if=virtio,media=disk,file=disk.img \ -drive if=virtio,media=disk,file=disk.img \