Skip to content

Commit

Permalink
report and register via grpc (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
majst01 authored Jun 10, 2022
1 parent 90c0095 commit 3a88102
Show file tree
Hide file tree
Showing 24 changed files with 572 additions and 3,136 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ vendor
.idea
.vscode
.vagrant
metal-core
metal-hammer
metal-hammer-kernel.md5
metal-hammer.tar
Expand Down
13 changes: 2 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ MAINMODULE := .
COMMONDIR := $(or ${COMMONDIR},../builder)
CGO_ENABLED := 1

in-docker: clean-local-dirs generate-client gofmt test all;
in-docker: gofmt test all;

include $(COMMONDIR)/Makefile.inc

release:: generate-client gofmt test all ;
release:: gofmt test all ;

.PHONY: clean
clean::
Expand Down Expand Up @@ -67,15 +67,6 @@ ramdisk:
&& ${COMPRESSOR} ${COMPRESSOR_ARGS} ${INITRD} ${INITRD_COMPRESSED} \
&& rm -f ${INITRD}

clean-local-dirs:
rm -rf metal-core
mkdir metal-core

# 'swaggergenerate' generates swagger client with SWAGGERSPEC="swagger.json" SWAGGERTARGET="./".
generate-client: SWAGGERSPEC="metal-core.json"
generate-client: SWAGGERTARGET="metal-core"
generate-client: clean-local-dirs swaggergenerate

vagrant-destroy:
vagrant destroy -f

Expand Down
2 changes: 0 additions & 2 deletions REINSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ Triggering an OS reinstallation starts by calling the **metal-api** REST endpoin

**metal-api** marks the machine to get reinstalled by setting `allocation.Reinstall = true`. It then informs **metal-core** via NSQ about the desired reinstallation by sending the machine command `REINSTALL` event with the machine ID.

**metal-core** simply queries the IPMI details of the machine, set the boot order to PXE and power resets the machine.

**metal-hammer** reboots in PXE mode, brings all interfaces up, read the hardware details - and therewith creates a new password for the `metal` user - and registers the machine, just as usual.

It then fetches the machine data from **metal-api** and evaluates the `allocation.Reinstall` flag. If it's `false` it continues as usual, i.e. wiping all disks, etc. If it's `true`, which is the case in this scenario, it skips the usual process and first checks if there is an `allocation.BootInfo` struct given, which contains data of the currently given OS, i.e the current `imageID`, `primaryDisk`, `osPartition`, `initrd`, `cmdline`, `kernel` and `bootloaderID` parameters.
Expand Down
4 changes: 2 additions & 2 deletions cmd/bios.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// ConfigureBIOS ensures that UEFI boot is enabled and CSM-support is disabled.
// It then reboots the machine.
func (h *Hammer) ConfigureBIOS() error {
if h.Spec.DevMode || h.Hal.Board().VM {
if h.Hal.Board().VM {
return nil
}

Expand All @@ -37,7 +37,7 @@ func (h *Hammer) ConfigureBIOS() error {
// EnsureBootOrder ensures that the BIOS boot order is properly set,
// i.e. first boot from OS image and then PXE boot
func (h *Hammer) EnsureBootOrder(bootloaderID string) error {
if h.Spec.DevMode || h.Hal.Board().VM {
if h.Hal.Board().VM {
return nil
}

Expand Down
43 changes: 0 additions & 43 deletions cmd/event/event_test.go

This file was deleted.

85 changes: 0 additions & 85 deletions cmd/grpc.go

This file was deleted.

51 changes: 30 additions & 21 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (

"github.com/metal-stack/metal-hammer/cmd/utils"

"github.com/metal-stack/metal-go/api/models"
img "github.com/metal-stack/metal-hammer/cmd/image"
"github.com/metal-stack/metal-hammer/cmd/storage"
"github.com/metal-stack/metal-hammer/metal-core/models"
"github.com/metal-stack/metal-hammer/pkg/kernel"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)

// InstallerConfig contains configuration items which are
Expand All @@ -26,25 +26,23 @@ type InstallerConfig struct {
// Hostname of the machine
Hostname string `yaml:"hostname"`
// Networks all networks connected to this machine
Networks []*models.ModelsV1MachineNetwork `yaml:"networks"`
Networks []*models.V1MachineNetwork `yaml:"networks"`
// MachineUUID is the unique UUID for this machine, usually the board serial.
MachineUUID string `yaml:"machineuuid"`
// SSHPublicKey of the user
SSHPublicKey string `yaml:"sshpublickey"`
// Password is the password for the metal user.
Password string `yaml:"password"`
// Devmode passes mode of installation.
Devmode bool `yaml:"devmode"`
// Console specifies where the kernel should connect its console to.
Console string `yaml:"console"`
// Timestamp is the the timestamp of installer config creation.
Timestamp string `yaml:"timestamp"`
// Nics are the network interfaces of this machine including their neighbors.
Nics []*models.ModelsV1MachineNicExtended `yaml:"nics"`
Nics []*models.V1MachineNic `yaml:"nics"`
}

// Install a given image to the disk by using genuinetools/img
func (h *Hammer) Install(machine *models.ModelsV1MachineResponse, nics []*models.ModelsV1MachineNicExtended) (*kernel.Bootinfo, error) {
func (h *Hammer) Install(machine *models.V1MachineResponse) (*kernel.Bootinfo, error) {
s := storage.New(h.log, h.ChrootPrefix, *h.FilesystemLayout)
err := s.Run()
if err != nil {
Expand All @@ -63,7 +61,7 @@ func (h *Hammer) Install(machine *models.ModelsV1MachineResponse, nics []*models
return nil, err
}

info, err := h.install(h.ChrootPrefix, machine, nics)
info, err := h.install(h.ChrootPrefix, machine)
if err != nil {
return nil, err
}
Expand All @@ -82,10 +80,10 @@ func (h *Hammer) Install(machine *models.ModelsV1MachineResponse, nics []*models

// install will execute /install.sh in the pulled docker image which was extracted onto disk
// to finish installation e.g. install mbr, grub, write network and filesystem config
func (h *Hammer) install(prefix string, machine *models.ModelsV1MachineResponse, nics []*models.ModelsV1MachineNicExtended) (*kernel.Bootinfo, error) {
func (h *Hammer) install(prefix string, machine *models.V1MachineResponse) (*kernel.Bootinfo, error) {
h.log.Infow("install", "image", machine.Allocation.Image.URL)

err := h.writeInstallerConfig(machine, nics)
err := h.writeInstallerConfig(machine)
if err != nil {
return nil, fmt.Errorf("writing configuration install.yaml failed %w", err)
}
Expand Down Expand Up @@ -193,7 +191,7 @@ func (h *Hammer) writeLVMLocalConf() error {
return nil
}

func (h *Hammer) writeUserData(machine *models.ModelsV1MachineResponse) error {
func (h *Hammer) writeUserData(machine *models.V1MachineResponse) error {
configdir := path.Join(h.ChrootPrefix, "etc", "metal")
destination := path.Join(configdir, "userdata")

Expand All @@ -209,7 +207,7 @@ func (h *Hammer) writeUserData(machine *models.ModelsV1MachineResponse) error {
return nil
}

func (h *Hammer) writeInstallerConfig(machine *models.ModelsV1MachineResponse, nics []*models.ModelsV1MachineNicExtended) error {
func (h *Hammer) writeInstallerConfig(machine *models.V1MachineResponse) error {
h.log.Infow("write installation configuration")
configdir := path.Join(h.ChrootPrefix, "etc", "metal")
err := os.MkdirAll(configdir, 0755)
Expand All @@ -236,11 +234,10 @@ func (h *Hammer) writeInstallerConfig(machine *models.ModelsV1MachineResponse, n
SSHPublicKey: sshPubkeys,
Networks: alloc.Networks,
MachineUUID: h.Spec.MachineUUID,
Devmode: h.Spec.DevMode,
Password: h.Spec.ConsolePassword,
Console: console,
Timestamp: time.Now().Format(time.RFC3339),
Nics: nicsWithNeighbors(nics),
Nics: h.onlyNicsWithNeighbors(machine.Hardware.Nics),
}
yamlContent, err := yaml.Marshal(y)
if err != nil {
Expand All @@ -249,15 +246,27 @@ func (h *Hammer) writeInstallerConfig(machine *models.ModelsV1MachineResponse, n

return os.WriteFile(destination, yamlContent, 0600)
}

func nicsWithNeighbors(nics []*models.ModelsV1MachineNicExtended) []*models.ModelsV1MachineNicExtended {
result := []*models.ModelsV1MachineNicExtended{}
for _, nic := range nics {
for _, neigh := range nic.Neighbors {
if *neigh.Mac != "" {
result = append(result, nic)
func (h *Hammer) onlyNicsWithNeighbors(nics []*models.V1MachineNic) []*models.V1MachineNic {
noNeighbors := func(neighbors []*models.V1MachineNic) bool {
if len(neighbors) == 0 {
return true
}
for _, n := range neighbors {
if n.Mac == nil || *n.Mac == "" {
return true
}
}
return false
}

result := []*models.V1MachineNic{}
for i := range nics {
nic := nics[i]
if noNeighbors(nic.Neighbors) {
continue
}
result = append(result, nic)
}
h.log.Infow("onlyNicWithNeighbors add", "result", result)
return result
}
60 changes: 60 additions & 0 deletions cmd/install_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cmd

import (
"reflect"
"testing"

"github.com/metal-stack/metal-go/api/models"
"go.uber.org/zap/zaptest"
)

func TestHammer_onlyNicsWithNeighbors(t *testing.T) {

tests := []struct {
name string
nics []*models.V1MachineNic
want []*models.V1MachineNic
}{
{
name: "4 interfaces, two with neighbors",
nics: []*models.V1MachineNic{
{Name: ptr("eth0")},
{Name: ptr("eth1")},
{Name: ptr("eth2"), Mac: ptr("aa:bb"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp1"), Mac: ptr("cc:dd")}}},
{Name: ptr("eth3"), Mac: ptr("aa:bc"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp2"), Mac: ptr("cc:de")}}},
},
want: []*models.V1MachineNic{
{Name: ptr("eth2"), Mac: ptr("aa:bb"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp1"), Mac: ptr("cc:dd")}}},
{Name: ptr("eth3"), Mac: ptr("aa:bc"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp2"), Mac: ptr("cc:de")}}},
},
},
{
name: "4 interfaces, two with neighbors, one with empty Mac",
nics: []*models.V1MachineNic{
{Name: ptr("eth0")},
{Name: ptr("eth1"), Mac: ptr("aa:bb"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp1")}}},
{Name: ptr("eth2"), Mac: ptr("aa:bb"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp1"), Mac: ptr("cc:dd")}}},
{Name: ptr("eth3"), Mac: ptr("aa:bc"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp2"), Mac: ptr("cc:de")}}},
},
want: []*models.V1MachineNic{
{Name: ptr("eth2"), Mac: ptr("aa:bb"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp1"), Mac: ptr("cc:dd")}}},
{Name: ptr("eth3"), Mac: ptr("aa:bc"), Neighbors: []*models.V1MachineNic{{Name: ptr("swp2"), Mac: ptr("cc:de")}}},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
h := &Hammer{
log: zaptest.NewLogger(t).Sugar(),
}
if got := h.onlyNicsWithNeighbors(tt.nics); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Hammer.onlyNicsWithNeighbors() = %v, want %v", got, tt.want)
}
})
}
}

func ptr(s string) *string {
return &s
}
Loading

0 comments on commit 3a88102

Please sign in to comment.