Skip to content

Commit

Permalink
feat: add ability to find disk by disk properties
Browse files Browse the repository at this point in the history
Fixes: #3323

Not exactly matching with udevd generated `by-<id>` symlinks, but should
provide sufficient amount of property selectors to be able to pick
specific disks for any kind of disk: sd card, hdd, ssd, nvme.

Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
  • Loading branch information
Unix4ever authored and talos-bot committed Mar 23, 2021
1 parent ac87647 commit 6ffabe5
Show file tree
Hide file tree
Showing 26 changed files with 1,098 additions and 105 deletions.
19 changes: 19 additions & 0 deletions api/storage/storage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ message Disk {
string model = 2;
// DeviceName indicates the disk name (e.g. `sda`).
string device_name = 3;
// Name as in `/sys/block/<dev>/device/name`.
string name = 4;
// Serial as in `/sys/block/<dev>/device/serial`.
string serial = 5;
// Modalias as in `/sys/block/<dev>/device/modalias`.
string modalias = 6;
// Uuid as in `/sys/block/<dev>/device/uuid`.
string uuid = 7;
// Wwid as in `/sys/block/<dev>/device/wwid`.
string wwid = 8;
enum DiskType {
UNKNOWN = 0;
SSD = 1;
HDD = 2;
NVME = 3;
SD = 4;
}
// Type is a type of the disk: nvme, ssd, hdd, sd card.
DiskType type = 9;
}

// DisksResponse represents the response of the `Disks` RPC.
Expand Down
5 changes: 3 additions & 2 deletions cmd/talosctl/cmd/mgmt/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
)

Expand All @@ -26,7 +27,7 @@ var validateCmd = &cobra.Command{
Long: ``,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
config, err := configloader.NewFromFile(validateConfigArg)
cfg, err := configloader.NewFromFile(validateConfigArg)
if err != nil {
return err
}
Expand All @@ -35,7 +36,7 @@ var validateCmd = &cobra.Command{
if err != nil {
return err
}
if err := config.Validate(mode); err != nil {
if err := cfg.Validate(mode, config.WithLocal()); err != nil {
return err
}

Expand Down
132 changes: 132 additions & 0 deletions cmd/talosctl/cmd/talos/disks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// 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 talos

import (
"context"
"crypto/tls"
"fmt"
"os"
"strings"
"text/tabwriter"

humanize "github.com/dustin/go-humanize"
"github.com/spf13/cobra"

"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/machinery/client"
)

var disksCmdFlags struct {
insecure bool
}

var disksCmd = &cobra.Command{
Use: "disks",
Short: "Get the list of disks from /sys/block on the machine",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
if disksCmdFlags.insecure {
ctx := context.Background()

c, err := client.New(ctx, client.WithTLSConfig(&tls.Config{
InsecureSkipVerify: true,
}), client.WithEndpoints(Nodes...))
if err != nil {
return err
}

return printDisks(ctx, c)
}

return WithClient(printDisks)
},
}

//nolint:gocyclo
func printDisks(ctx context.Context, c *client.Client) error {
response, err := c.Disks(ctx)
if err != nil {
if response == nil {
return fmt.Errorf("error getting disks: %w", err)
}

cli.Warning("%s", err)
}

w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
node := ""

labels := strings.Join(
[]string{
"DEV",
"MODEL",
"SERIAL",
"TYPE",
"UUID",
"WWID",
"MODALIAS",
"NAME",
"SIZE",
}, "\t")

getWithPlaceholder := func(in string) string {
if in == "" {
return "-"
}

return in
}

for i, message := range response.Messages {
if message.Metadata != nil && message.Metadata.Hostname != "" {
node = message.Metadata.Hostname
}

if len(message.Disks) == 0 {
continue
}

for j, disk := range message.Disks {
if i == 0 && j == 0 {
if node != "" {
fmt.Fprintln(w, "NODE\t"+labels)
} else {
fmt.Fprintln(w, labels)
}
}

args := []interface{}{}

if node != "" {
args = append(args, node)
}

args = append(args, []interface{}{
getWithPlaceholder(disk.DeviceName),
getWithPlaceholder(disk.Model),
getWithPlaceholder(disk.Serial),
disk.Type.String(),
getWithPlaceholder(disk.Uuid),
getWithPlaceholder(disk.Wwid),
getWithPlaceholder(disk.Modalias),
getWithPlaceholder(disk.Name),
humanize.Bytes(disk.Size),
}...)

pattern := strings.Repeat("%s\t", len(args))
pattern = strings.TrimSpace(pattern) + "\n"

fmt.Fprintf(w, pattern, args...)
}
}

return w.Flush()
}

func init() {
disksCmd.Flags().BoolVarP(&disksCmdFlags.insecure, "insecure", "i", false, "get disks using the insecure (encrypted with no auth) maintenance service")
addCommand(disksCmd)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ require (
github.com/stretchr/testify v1.7.0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // can't be bumped, requires new runc
github.com/talos-systems/crypto v0.2.1-0.20210202170911-39584f1b6e54
github.com/talos-systems/go-blockdevice v0.2.1-0.20210305142622-bb3ad73f6983
github.com/talos-systems/go-blockdevice v0.2.1-0.20210322192639-776b37d31de0
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0
github.com/talos-systems/go-loadbalancer v0.1.0
github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,8 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
Expand Down Expand Up @@ -974,8 +976,8 @@ github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/talos-systems/crypto v0.2.1-0.20210202170911-39584f1b6e54 h1:2IGs3f0qG7f33Fv37XuYzIMxLARl4dcpwahZXLmdT2A=
github.com/talos-systems/crypto v0.2.1-0.20210202170911-39584f1b6e54/go.mod h1:OXCK52Q0dzm88YRG4VdTBdidkPUtqrCxCyW7bUs4DAw=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210305142622-bb3ad73f6983 h1:tYxXpKNUNvrBKFE4itbU3lJVBws/XUmlYkuEI93kCAE=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210305142622-bb3ad73f6983/go.mod h1:Wt0/JMsa+WysYRDlNo6fu9rdn/re73uRnktFWyVUqjs=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210322192639-776b37d31de0 h1:ZOIwpHUR0i2e4VaCe8nwHZuBRjD25XUv+xImyPWHw50=
github.com/talos-systems/go-blockdevice v0.2.1-0.20210322192639-776b37d31de0/go.mod h1:qnn/zDc09I1DA2BUDDCOSA2D0P8pIDjN8pGiRoRaQig=
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0 h1:DI+BjK+fcrLBc70Fi50dZocQcaHosqsuWHrGHKp2NzE=
github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0/go.mod h1:kf+rZzTEmlDiYQ6ulslvRONnKLQH8x83TowltGMhO+k=
github.com/talos-systems/go-loadbalancer v0.1.0 h1:MQFONvSjoleU8RrKq1O1Z8CyTCJGd4SLqdAHDlR6o9s=
Expand Down
4 changes: 4 additions & 0 deletions hack/docgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ func collectFields(s *structType) (fields []*Field) {
log.Fatalf("field %q is missing a documentation", f.Names[0].Name)
}

if strings.Contains(f.Doc.Text(), "docgen:nodoc") {
continue
}

name := f.Names[0].Name

fieldType := formatFieldType(f.Type)
Expand Down
21 changes: 19 additions & 2 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ github_repo = "talos-systems/talos"
match_deps = "^github.com/(talos-systems/[a-zA-Z0-9-]+)$"

# previous release
previous = "v0.9.0-beta.0"
previous = "v0.9.0"

pre_release = true

Expand All @@ -24,8 +24,25 @@ preface = """\

[notes.optimize]
title = "Optmizations"
descriptions = """\
description = """\
* Talos `system` services now run without container images on initramfs from the single executable; this change reduces RAM usage, initramfs size and boot time..
"""

[notes.machineconfig]
title = "Install Disk Selector"
description = """\
Install section of the machine config now has `diskSelector` field that allows querying install disk using the list of qualifiers:
```yaml
...
install:
diskSelector:
size: >= 500GB
model: WDC*
...
```
`talosctl disks -n <node> -i` can be used to check allowed disk qualifiers when the node is running in the maintenance mode.
"""

[make_deps]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ import (
installer "github.com/talos-systems/talos/cmd/installer/pkg/install"
"github.com/talos-systems/talos/internal/app/machined/internal/install"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/disk"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/adv"
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub"
"github.com/talos-systems/talos/internal/app/machined/pkg/system"
storaged "github.com/talos-systems/talos/internal/app/storaged"
"github.com/talos-systems/talos/internal/pkg/configuration"
"github.com/talos-systems/talos/internal/pkg/containers"
taloscontainerd "github.com/talos-systems/talos/internal/pkg/containers/containerd"
Expand All @@ -62,6 +64,7 @@ import (
"github.com/talos-systems/talos/pkg/machinery/api/inspect"
"github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/api/resource"
"github.com/talos-systems/talos/pkg/machinery/api/storage"
"github.com/talos-systems/talos/pkg/machinery/config"
machinetype "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
"github.com/talos-systems/talos/pkg/machinery/constants"
Expand Down Expand Up @@ -106,6 +109,7 @@ func (s *Server) Register(obj *grpc.Server) {
cluster.RegisterClusterServiceServer(obj, s)
resource.RegisterResourceServiceServer(obj, &ResourceServer{server: s})
inspect.RegisterInspectServiceServer(obj, &InspectServer{server: s})
storage.RegisterStorageServiceServer(obj, &storaged.Server{})
}

// ApplyConfiguration implements machine.MachineService.
Expand Down Expand Up @@ -246,8 +250,13 @@ func (s *Server) Rollback(ctx context.Context, in *machine.RollbackRequest) (*ma
}
}()

disk := s.Controller.Runtime().State().Machine().Disk(disk.WithPartitionLabel(constants.BootPartitionLabel))
if disk == nil {
return fmt.Errorf("boot disk not found")
}

grub := &grub.Grub{
BootDisk: s.Controller.Runtime().Config().Machine().Install().Disk(),
BootDisk: disk.Device().Name(),
}

_, next, err := grub.Labels()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -740,10 +740,16 @@ func VerifyInstallation(seq runtime.Sequence, data interface{}) (runtime.TaskExe
var (
current string
next string
disk string
)

disk, err = r.Config().Machine().Install().Disk()
if err != nil {
return err
}

grub := &grub.Grub{
BootDisk: r.Config().Machine().Install().Disk(),
BootDisk: disk,
}

current, next, err = grub.Labels()
Expand Down Expand Up @@ -1630,8 +1636,15 @@ func Install(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc,
installerImage = images.DefaultInstallerImage
}

var disk string

disk, err = r.Config().Machine().Install().Disk()
if err != nil {
return err
}

err = install.RunInstallerContainer(
r.Config().Machine().Install().Disk(),
disk,
r.State().Platform().Name(),
installerImage,
r.Config().Machine().Registries(),
Expand Down
17 changes: 5 additions & 12 deletions internal/app/maintenance/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@ import (

// Server implements machine.MachineService, network.NetworkService, and storage.StorageService.
type Server struct {
storage.UnimplementedStorageServiceServer
machine.UnimplementedMachineServiceServer
network.UnimplementedNetworkServiceServer

runtime runtime.Runtime
logger *log.Logger
cfgCh chan []byte
server *grpc.Server
storaged storaged.Server
runtime runtime.Runtime
logger *log.Logger
cfgCh chan []byte
server *grpc.Server
}

// New initializes and returns a `Server`.
Expand All @@ -49,16 +47,11 @@ func New(r runtime.Runtime, logger *log.Logger, cfgCh chan []byte) *Server {
func (s *Server) Register(obj *grpc.Server) {
s.server = obj

storage.RegisterStorageServiceServer(obj, s)
storage.RegisterStorageServiceServer(obj, &storaged.Server{})
machine.RegisterMachineServiceServer(obj, s)
network.RegisterNetworkServiceServer(obj, s)
}

// Disks implements storage.StorageService.
func (s *Server) Disks(ctx context.Context, in *empty.Empty) (reply *storage.DisksResponse, err error) {
return s.storaged.Disks(ctx, in)
}

// ApplyConfiguration implements machine.MachineService.
func (s *Server) ApplyConfiguration(ctx context.Context, in *machine.ApplyConfigurationRequest) (reply *machine.ApplyConfigurationResponse, err error) {
if in.OnReboot {
Expand Down
1 change: 1 addition & 0 deletions internal/app/routerd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func Main() {
router.RegisterLocalBackend("time.TimeService", backend.NewLocal("timed", constants.TimeSocketPath))
router.RegisterLocalBackend("network.NetworkService", backend.NewLocal("networkd", constants.NetworkSocketPath))
router.RegisterLocalBackend("cluster.ClusterService", machinedBackend)
router.RegisterLocalBackend("storage.StorageService", machinedBackend)

err := factory.ListenAndServe(
router,
Expand Down
Loading

0 comments on commit 6ffabe5

Please sign in to comment.