fix: verify installation definition
This fixes the possibility of panicing on a nil pointer by running the verification steps earlier. Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
parent
1c7e86ce5c
commit
6940aaf233
@ -63,7 +63,10 @@ var installCmd = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
i, err := installer.NewInstaller(cmdline, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err = i.Install(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -98,7 +98,11 @@ func (b *BareMetal) Initialize(data *userdata.UserData) (err error) {
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
// No previous installation was found, attempt an install
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
var i *installer.Installer
|
||||
i, err = installer.NewInstaller(cmdline, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
}
|
||||
|
@ -96,7 +96,10 @@ func (i *ISO) Initialize(data *userdata.UserData) (err error) {
|
||||
cmdline.Append(constants.KernelParamPlatform, "bare-metal")
|
||||
cmdline.Append(constants.KernelParamUserData, endpoint)
|
||||
|
||||
inst := installer.NewInstaller(cmdline, data)
|
||||
inst, err := installer.NewInstaller(cmdline, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = inst.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
}
|
||||
|
@ -59,7 +59,11 @@ func (p *Packet) Initialize(data *userdata.UserData) (err error) {
|
||||
mountpoints, err = owned.MountPointsFromLabels()
|
||||
if err != nil {
|
||||
// No previous installation was found, attempt an install
|
||||
i := installer.NewInstaller(cmdline, data)
|
||||
var i *installer.Installer
|
||||
i, err = installer.NewInstaller(cmdline, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = i.Install(); err != nil {
|
||||
return errors.Wrap(err, "failed to install")
|
||||
}
|
||||
|
@ -20,28 +20,9 @@ import (
|
||||
"github.com/talos-systems/talos/internal/pkg/mount/manager/owned"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"github.com/talos-systems/talos/pkg/version"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultSizeBootDevice is the default size of the boot partition.
|
||||
// TODO(andrewrynhard): We should inspect the sizes of the artifacts and dynamically set the boot partition's size.
|
||||
DefaultSizeBootDevice = 512 * 1000 * 1000
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultURLBase is the base URL for all default artifacts.
|
||||
// TODO(andrewrynhard): We need to setup infrastructure for publishing artifacts and not depend on GitHub.
|
||||
DefaultURLBase = "https://github.com/talos-systems/talos/releases/download/" + version.Tag
|
||||
|
||||
// DefaultKernelURL is the URL to the kernel.
|
||||
DefaultKernelURL = DefaultURLBase + "/vmlinuz"
|
||||
|
||||
// DefaultInitramfsURL is the URL to the initramfs.
|
||||
DefaultInitramfsURL = DefaultURLBase + "/initramfs.xz"
|
||||
)
|
||||
|
||||
// Installer represents the installer logic. It serves as the entrypoint to all
|
||||
// installation methods.
|
||||
type Installer struct {
|
||||
@ -51,15 +32,18 @@ type Installer struct {
|
||||
}
|
||||
|
||||
// NewInstaller initializes and returns an Installer.
|
||||
func NewInstaller(cmdline *kernel.Cmdline, data *userdata.UserData) *Installer {
|
||||
i := &Installer{
|
||||
func NewInstaller(cmdline *kernel.Cmdline, data *userdata.UserData) (i *Installer, err error) {
|
||||
i = &Installer{
|
||||
cmdline: cmdline,
|
||||
data: data,
|
||||
}
|
||||
|
||||
i.manifest = manifest.NewManifest(data)
|
||||
i.manifest, err = manifest.NewManifest(data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create installation manifest")
|
||||
}
|
||||
|
||||
return i
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// Install fetches the necessary data locations and copies or extracts
|
||||
@ -70,16 +54,6 @@ func (i *Installer) Install() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify that the target device(s) can satisify the requested options.
|
||||
|
||||
if err = VerifyBootDevice(i.data); err != nil {
|
||||
return errors.Wrap(err, "failed to prepare boot device")
|
||||
}
|
||||
|
||||
if err = VerifyDataDevice(i.data); err != nil {
|
||||
return errors.Wrap(err, "failed to prepare data device")
|
||||
}
|
||||
|
||||
if i.data.Install.Wipe {
|
||||
if err = wipe(i.manifest); err != nil {
|
||||
return errors.Wrap(err, "failed to wipe device(s)")
|
||||
|
@ -2,106 +2,13 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package installer
|
||||
package installer_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
import "testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type validateSuite struct {
|
||||
suite.Suite
|
||||
func TestEmpty(t *testing.T) {
|
||||
// added for accurate coverage estimation
|
||||
//
|
||||
// please remove it once any unit-test is added
|
||||
// for this package
|
||||
}
|
||||
|
||||
func TestValidateSuite(t *testing.T) {
|
||||
suite.Run(t, new(validateSuite))
|
||||
}
|
||||
|
||||
func (suite *validateSuite) TestVerifyDevice() {
|
||||
// Start off with success and then remove bits
|
||||
data := &userdata.UserData{}
|
||||
err := yaml.Unmarshal([]byte(testConfig), data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(VerifyBootDevice(data))
|
||||
suite.Require().NoError(VerifyDataDevice(data))
|
||||
|
||||
// No impact because we can infer all data from the data device and
|
||||
// defaults.
|
||||
data.Install.Boot = nil
|
||||
suite.Require().NoError(VerifyBootDevice(data))
|
||||
data.Install.Ephemeral = &userdata.InstallDevice{
|
||||
Device: "/dev/sda",
|
||||
}
|
||||
suite.Require().NoError(VerifyDataDevice(data))
|
||||
}
|
||||
|
||||
// TODO we should move this to a well defined location
|
||||
// Copied from userdata_test.go
|
||||
const testConfig = `version: "1"
|
||||
security:
|
||||
os:
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
identity:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
kubernetes:
|
||||
ca:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
sa:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
frontproxy:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
etcd:
|
||||
crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||
key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0=
|
||||
networking:
|
||||
os: {}
|
||||
kubernetes: {}
|
||||
services:
|
||||
init:
|
||||
cni: flannel
|
||||
kubeadm:
|
||||
certificateKey: 'test'
|
||||
configuration: |
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
kind: InitConfiguration
|
||||
localAPIEndpoint:
|
||||
bindPort: 6443
|
||||
bootstrapTokens:
|
||||
- token: '1qbsj9.3oz5hsk6grdfp98b'
|
||||
ttl: 0s
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta1
|
||||
kind: ClusterConfiguration
|
||||
clusterName: test
|
||||
kubernetesVersion: v1.16.0-alpha.3
|
||||
---
|
||||
apiVersion: kubeproxy.config.k8s.io/v1alpha1
|
||||
kind: KubeProxyConfiguration
|
||||
mode: ipvs
|
||||
ipvs:
|
||||
scheduler: lc
|
||||
trustd:
|
||||
username: 'test'
|
||||
password: 'test'
|
||||
endpoints: [ "1.2.3.4" ]
|
||||
certSANs: []
|
||||
install:
|
||||
wipe: true
|
||||
force: true
|
||||
boot:
|
||||
device: /dev/sda
|
||||
size: 1024000000
|
||||
ephemeral:
|
||||
device: /dev/sda
|
||||
size: 1024000000
|
||||
`
|
||||
|
@ -25,6 +25,25 @@ import (
|
||||
"github.com/talos-systems/talos/pkg/blockdevice/table/gpt/partition"
|
||||
"github.com/talos-systems/talos/pkg/constants"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"github.com/talos-systems/talos/pkg/version"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultSizeBootDevice is the default size of the boot partition.
|
||||
// TODO(andrewrynhard): We should inspect the sizes of the artifacts and dynamically set the boot partition's size.
|
||||
DefaultSizeBootDevice = 512 * 1000 * 1000
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultURLBase is the base URL for all default artifacts.
|
||||
// TODO(andrewrynhard): We need to setup infrastructure for publishing artifacts and not depend on GitHub.
|
||||
DefaultURLBase = "https://github.com/talos-systems/talos/releases/download/" + version.Tag
|
||||
|
||||
// DefaultKernelURL is the URL to the kernel.
|
||||
DefaultKernelURL = DefaultURLBase + "/vmlinuz"
|
||||
|
||||
// DefaultInitramfsURL is the URL to the initramfs.
|
||||
DefaultInitramfsURL = DefaultURLBase + "/initramfs.xz"
|
||||
)
|
||||
|
||||
// Manifest represents the instructions for preparing all block devices
|
||||
@ -54,11 +73,21 @@ type Asset struct {
|
||||
}
|
||||
|
||||
// NewManifest initializes and returns a Manifest.
|
||||
func NewManifest(data *userdata.UserData) (manifest *Manifest) {
|
||||
func NewManifest(data *userdata.UserData) (manifest *Manifest, err error) {
|
||||
manifest = &Manifest{
|
||||
Targets: map[string][]*Target{},
|
||||
}
|
||||
|
||||
// Verify that the target device(s) can satisify the requested options.
|
||||
|
||||
if err = VerifyDataDevice(data); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prepare ephemeral partition")
|
||||
}
|
||||
|
||||
if err = VerifyBootDevice(data); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prepare boot partition")
|
||||
}
|
||||
|
||||
// Initialize any slices we need. Note that a boot paritition is not
|
||||
// required.
|
||||
|
||||
@ -121,7 +150,7 @@ func NewManifest(data *userdata.UserData) (manifest *Manifest) {
|
||||
}
|
||||
}
|
||||
|
||||
return manifest
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
// ExecuteManifest partitions and formats all disks in a manifest.
|
||||
|
@ -32,7 +32,8 @@ func (suite *manifestSuite) TestNewManifest() {
|
||||
err := yaml.Unmarshal([]byte(testConfig), data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
manifests := NewManifest(data)
|
||||
manifests, err := NewManifest(data)
|
||||
suite.Require().NoError(err)
|
||||
assert.Equal(suite.T(), 2, len(manifests.Targets["/dev/sda"]))
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package installer
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
@ -13,13 +13,17 @@ import (
|
||||
|
||||
// VerifyDataDevice verifies the supplied data device options.
|
||||
func VerifyDataDevice(data *userdata.UserData) (err error) {
|
||||
// Ensure that an installation is specified
|
||||
if data.Install == nil {
|
||||
return errors.New("missing installation definition")
|
||||
}
|
||||
// Set data device to root device if not specified
|
||||
if data.Install.Ephemeral == nil {
|
||||
data.Install.Ephemeral = &userdata.InstallDevice{}
|
||||
return errors.New("missing definition")
|
||||
}
|
||||
|
||||
if data.Install.Ephemeral.Device == "" {
|
||||
return errors.New("an ephemeral device is required")
|
||||
return errors.New("missing disk")
|
||||
}
|
||||
|
||||
if !data.Install.Force {
|
||||
@ -33,6 +37,10 @@ func VerifyDataDevice(data *userdata.UserData) (err error) {
|
||||
|
||||
// VerifyBootDevice verifies the supplied boot device options.
|
||||
func VerifyBootDevice(data *userdata.UserData) (err error) {
|
||||
if data.Install == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if data.Install.Boot == nil {
|
||||
return nil
|
||||
}
|
40
internal/pkg/installer/manifest/verify_test.go
Normal file
40
internal/pkg/installer/manifest/verify_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/talos-systems/talos/pkg/userdata"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type validateSuite struct {
|
||||
suite.Suite
|
||||
}
|
||||
|
||||
func TestValidateSuite(t *testing.T) {
|
||||
suite.Run(t, new(validateSuite))
|
||||
}
|
||||
|
||||
func (suite *validateSuite) TestVerifyDevice() {
|
||||
// Start off with success and then remove bits
|
||||
data := &userdata.UserData{}
|
||||
err := yaml.Unmarshal([]byte(testConfig), data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(VerifyBootDevice(data))
|
||||
suite.Require().NoError(VerifyDataDevice(data))
|
||||
|
||||
// No impact because we can infer all data from the data device and
|
||||
// defaults.
|
||||
data.Install.Boot = nil
|
||||
suite.Require().NoError(VerifyBootDevice(data))
|
||||
data.Install.Ephemeral = &userdata.InstallDevice{
|
||||
Device: "/dev/sda",
|
||||
}
|
||||
suite.Require().NoError(VerifyDataDevice(data))
|
||||
}
|
Loading…
Reference in New Issue
Block a user