Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to set hostname via DHCP during install #726

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/console/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ const (
persistentSizeNote = "Note: persistent partition stores data like system package and container images, not the VM data. \nYou can specify a size like 200Gi or 153600Mi. \nLeave it blank to use the default value."

authorizedFile = "/home/rancher/.ssh/authorized_keys"

defaultHostname = "rancher"
)
131 changes: 80 additions & 51 deletions pkg/console/install_panels.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ func addDiskPanel(c *Console) error {
if installModeOnly {
return showNext(c, passwordConfirmPanel, passwordPanel)
}
return showHostnamePage(c)
return showNetworkPage(c)
}

diskConfirm := func(_ *gocui.Gui, _ *gocui.View) error {
Expand Down Expand Up @@ -840,7 +840,7 @@ func addAskCreatePanel(c *Console) error {
return showRolePage(c)
}
if alreadyInstalled {
return showHostnamePage(c)
return showNetworkPage(c)
}
return showDiskPage(c)
},
Expand Down Expand Up @@ -898,7 +898,7 @@ func addAskRolePanel(c *Console) error {
c.config.Install.Role = selected
askRoleV.Close()
if alreadyInstalled {
return showHostnamePage(c)
return showNetworkPage(c)
}
return showDiskPage(c)
},
Expand Down Expand Up @@ -1199,20 +1199,18 @@ func addHostnamePanel(c *Console) error {
return c.setContentByName(hostnameValidatorPanel, message)
}

getNextPagePanel := func() []string {
return []string{dnsServersPanel}
}

next := func() error {
c.CloseElements(hostnamePanel, hostnameValidatorPanel)
return showNetworkPage(c)
return showNext(c, getNextPagePanel()...)
}

prev := func(_ *gocui.Gui, _ *gocui.View) error {
c.CloseElements(hostnamePanel, hostnameValidatorPanel)
if alreadyInstalled {
if c.config.Install.Mode == config.ModeJoin {
return showNext(c, askRolePanel)
}
return showNext(c, askCreatePanel)
}
return showDiskPage(c)
return showNetworkPage(c)
}

validate := func() (string, error) {
Expand All @@ -1234,6 +1232,10 @@ func addHostnamePanel(c *Console) error {

hostnameV.PreShow = func() error {
c.Gui.Cursor = true
// On the first run through the interactive installer, the hostname is
// not yet set in the harvester config, but we might have been given
// a new hostname via DHCP...
checkDHCPHostname(c.config, false)
hostnameV.Value = c.config.Hostname
return c.setContentByName(titlePanel, hostnameTitle)
}
Expand Down Expand Up @@ -1391,10 +1393,6 @@ func addNetworkPanel(c *Console) error {
return "", nil
}

getNextPagePanel := func() []string {
return []string{dnsServersPanel}
}

gotoNextPage := func(fromPanel string) error {
if err := networkValidatorV.Show(); err != nil {
return err
Expand All @@ -1421,7 +1419,7 @@ func addNetworkPanel(c *Console) error {
spinner.Stop(false, "")
g.Update(func(_ *gocui.Gui) error {
closeThisPage()
return showNext(c, getNextPagePanel()...)
return showHostnamePage(c)
})
}
}(c.Gui)
Expand All @@ -1430,7 +1428,13 @@ func addNetworkPanel(c *Console) error {

gotoPrevPage := func(_ *gocui.Gui, _ *gocui.View) error {
closeThisPage()
return showHostnamePage(c)
if alreadyInstalled {
if c.config.Install.Mode == config.ModeJoin {
return showNext(c, askRolePanel)
}
return showNext(c, askCreatePanel)
}
return showDiskPage(c)
}
// askInterfaceV
askInterfaceV.PreShow = func() error {
Expand Down Expand Up @@ -2016,6 +2020,8 @@ func addInstallPanel(c *Console) error {
if alreadyInstalled && c.config.Automatic == true && c.config.ManagementInterface.Method == "dhcp" {
configureInstallModeDHCP(c)
}

// Need to merge remote config first
logrus.Info("Local config: ", c.config)
if c.config.Install.ConfigURL != "" {
printToPanel(c.Gui, fmt.Sprintf("Fetching %s...", c.config.Install.ConfigURL), installPanel)
Expand All @@ -2031,28 +2037,50 @@ func addInstallPanel(c *Console) error {
return
}
logrus.Info("Local config (merged): ", c.config)
}

if needToGetVIPFromDHCP(c.config.VipMode, c.config.Vip, c.config.VipHwAddr) {
printToPanel(c.Gui, "Configuring network...", installPanel)
if _, err := applyNetworks(c.config.ManagementInterface, c.config.Hostname); err != nil {
printToPanel(c.Gui, fmt.Sprintf("can't apply networks: %s", err), installPanel)
return
}
mgmtName := getManagementInterfaceName(c.config.ManagementInterface)
vip, err := getVipThroughDHCP(mgmtName)
if err != nil {
printToPanel(c.Gui, fmt.Sprintf("fail to get vip: %s", err), installPanel)
return
}
c.config.Vip = vip.ipv4Addr
c.config.VipHwAddr = vip.hwAddr
// case insensitive for network method and vip mode
c.config.ManagementInterface.Method = strings.ToLower(c.config.ManagementInterface.Method)
c.config.VipMode = strings.ToLower(c.config.VipMode)

// lookup MAC Address to populate device names where needed
// lookup device name to populate MAC Address
// This needs to happen early, before a possible call to
// applyNetworks() in the DHCP case.
for i := range c.config.ManagementInterface.Interfaces {
if err := c.config.ManagementInterface.Interfaces[i].FindNetworkInterfaceNameAndHwAddr(); err != nil {
logrus.Error(err)
printToPanel(c.Gui, err.Error(), installPanel)
return
}
}

if c.config.Automatic && c.config.Install.ManagementInterface.Method == config.NetworkMethodDHCP {
// Only need to do this for automatic installs, as manual installs will
// have already run applyNetworks()
printToPanel(c.Gui, "Configuring network...", installPanel)
if output, err := applyNetworks(c.config.ManagementInterface, c.config.Hostname); err != nil {
printToPanel(c.Gui, fmt.Sprintf("Can't apply networks: %s\n%s", err, string(output)), installPanel)
return
}
}
c.config.VipMode = strings.ToLower(c.config.VipMode)

if c.config.Hostname == "" {
c.config.Hostname = generateHostName()
if needToGetVIPFromDHCP(c.config.VipMode, c.config.Vip, c.config.VipHwAddr) {
mgmtName := getManagementInterfaceName(c.config.ManagementInterface)
vip, err := getVipThroughDHCP(mgmtName)
if err != nil {
printToPanel(c.Gui, fmt.Sprintf("fail to get vip: %s", err), installPanel)
return
}
c.config.Vip = vip.ipv4Addr
c.config.VipHwAddr = vip.hwAddr
}

// If no hostname was provided in the config, this function will
// default the hostname to either what's supplied by the DHCP sever,
// or a randomly generated name.
checkDHCPHostname(c.config, true)

if c.config.TTY == "" {
c.config.TTY = getFirstConsoleTTY()
}
Expand All @@ -2065,19 +2093,6 @@ func addInstallPanel(c *Console) error {
c.config.ServerURL = formatted
}

// lookup MAC Address to populate device names where needed
// lookup device name to populate MAC Address
tmpInterfaces := []config.NetworkInterface{}
for _, iface := range c.config.ManagementInterface.Interfaces {
if err := iface.FindNetworkInterfaceNameAndHwAddr(); err != nil {
logrus.Error(err)
printToPanel(c.Gui, err.Error(), installPanel)
return
}
tmpInterfaces = append(tmpInterfaces, iface)
}
c.config.ManagementInterface.Interfaces = tmpInterfaces

if !alreadyInstalled {
// Have to handle preflight warnings here because we can't check
// the NIC speed until we've got the correct set of interfaces.
Expand Down Expand Up @@ -2111,9 +2126,6 @@ func addInstallPanel(c *Console) error {
c.config.DataDisk = ""
}

// case insensitive for network method and vip mode
c.config.ManagementInterface.Method = strings.ToLower(c.config.ManagementInterface.Method)

if err := validateConfig(ConfigValidator{}, c.config); err != nil {
printToPanel(c.Gui, err.Error(), installPanel)
return
Expand Down Expand Up @@ -2434,7 +2446,7 @@ func addDNSServersPanel(c *Console) error {
}
gotoPrevPage := func(_ *gocui.Gui, _ *gocui.View) error {
closeThisPage()
return showNetworkPage(c)
return showHostnamePage(c)
}
gotoNextPage := func() error {
closeThisPage()
Expand Down Expand Up @@ -2560,6 +2572,23 @@ func configureInstallModeDHCP(c *Console) {

}

func checkDHCPHostname(c *config.HarvesterConfig, generate bool) {
if c.Hostname == "" {
hostname, err := os.Hostname()
if err != nil {
logrus.Errorf("error fetching hostname from underlying OS: %v", err)
}

if hostname != defaultHostname && hostname != "" {
c.Hostname = hostname
} else {
if generate {
c.Hostname = generateHostName()
}
}
}
}

func mergeCloudInit(c *config.HarvesterConfig) error {
cloudConfig, err := config.ReadUserDataConfig()
if err != nil {
Expand Down
29 changes: 28 additions & 1 deletion pkg/console/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ func applyNetworks(network config.Network, hostname string) ([]byte, error) {
return nil, err
}

// If called without a hostname set, we enable setting hostname via the
// DHCP server, in case the DHCP server is configured to give us a
// hostname we can use by default.
//
// If we move the network interface page of the installer so it's before
// the hostname page, this function will activate once the management
// NIC is configured, and if the DHCP server is configured correctly,
// the system hostname will be set to the one provided by the server.
// Later, on the hostname page, we can default the hostname field to
// the current system hostname.

dhclientSetHostname := "no"
if hostname == "" {
dhclientSetHostname = "yes"
}
output, err := exec.Command("sed", "-i",
fmt.Sprintf(`s/^DHCLIENT_SET_HOSTNAME=.*/DHCLIENT_SET_HOSTNAME="%s"/`, dhclientSetHostname),
"/etc/sysconfig/network/dhcp").CombinedOutput()
if err != nil {
logrus.Error(err, string(output))
return output, err
}

conf := &yipSchema.YipConfig{
Name: "Network Configuration",
Stages: map[string][]yipSchema.Stage{
Expand All @@ -33,7 +56,7 @@ func applyNetworks(network config.Network, hostname string) ([]byte, error) {
},
},
}
_, err := config.UpdateManagementInterfaceConfig(&conf.Stages["live"][1], network, true)
_, err = config.UpdateManagementInterfaceConfig(&conf.Stages["live"][1], network, true)
if err != nil {
return nil, err
}
Expand All @@ -56,6 +79,10 @@ func applyNetworks(network config.Network, hostname string) ([]byte, error) {
cmd := exec.Command("/usr/bin/yip", "-s", "live", tempFile.Name())
cmd.Env = os.Environ()
bytes, err = cmd.CombinedOutput()
if err != nil {
logrus.Error(err, string(bytes))
return bytes, err
}
// Restore Down NIC to up
if err := upAllLinks(); err != nil {
logrus.Errorf("failed to bring all link up: %s", err.Error())
Expand Down
Loading