/
volume.go
142 lines (120 loc) · 4 KB
/
volume.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package storage
import (
"github.com/juju/cmd"
"github.com/juju/errors"
"github.com/juju/names"
"github.com/juju/juju/apiserver/params"
jujucmd "github.com/juju/juju/cmd"
"github.com/juju/juju/cmd/envcmd"
)
const volumeCmdDoc = `
"juju storage volume" is used to manage storage volumes in
the Juju environment.
`
const volumeCmdPurpose = "manage storage volumes"
// NewVolumeSuperCommand creates the storage volume super subcommand and
// registers the subcommands that it supports.
func NewVolumeSuperCommand() cmd.Command {
poolcmd := Command{
SuperCommand: *jujucmd.NewSubSuperCommand(cmd.SuperCommandParams{
Name: "volume",
Doc: volumeCmdDoc,
UsagePrefix: "juju storage",
Purpose: volumeCmdPurpose,
})}
poolcmd.Register(envcmd.Wrap(&VolumeListCommand{}))
return &poolcmd
}
// VolumeCommandBase is a helper base structure for volume commands.
type VolumeCommandBase struct {
StorageCommandBase
}
// VolumeInfo defines the serialization behaviour for storage volume.
type VolumeInfo struct {
// from params.Volume. This is provider-supplied unique volume id.
VolumeId string `yaml:"id" json:"id"`
// from params.Volume
HardwareId string `yaml:"hardwareid" json:"hardwareid"`
// from params.Volume
Size uint64 `yaml:"size" json:"size"`
// from params.Volume
Persistent bool `yaml:"persistent" json:"persistent"`
// from params.VolumeAttachments
DeviceName string `yaml:"device,omitempty" json:"device,omitempty"`
// from params.VolumeAttachments
ReadOnly bool `yaml:"read-only" json:"read-only"`
// from params.Volume. This is juju volume id.
Volume string `yaml:"volume,omitempty" json:"volume,omitempty"`
}
// convertToVolumeInfo returns map of maps with volume info
// keyed first on machine_id and then on volume_id.
func convertToVolumeInfo(all []params.VolumeItem) (map[string]map[string]map[string]VolumeInfo, error) {
result := map[string]map[string]map[string]VolumeInfo{}
for _, one := range all {
if err := convertVolumeItem(one, result); err != nil {
return nil, errors.Trace(err)
}
}
return result, nil
}
func convertVolumeItem(item params.VolumeItem, all map[string]map[string]map[string]VolumeInfo) error {
if len(item.Attachments) != 0 {
// add info for volume attachments
return convertVolumeAttachments(item, all)
}
unattached, unit, storage := createInfo(item.Volume)
addOneToAll("unattached", unit, storage, unattached, all)
return nil
}
var idFromTag = func(s string) (string, error) {
tag, err := names.ParseTag(s)
if err != nil {
return "", errors.Annotatef(err, "invalid tag %v", tag)
}
return tag.Id(), nil
}
func convertVolumeAttachments(item params.VolumeItem, all map[string]map[string]map[string]VolumeInfo) error {
for _, one := range item.Attachments {
machine, err := idFromTag(one.MachineTag)
if err != nil {
return errors.Trace(err)
}
info, unit, storage := createInfo(item.Volume)
info.DeviceName = one.Info.DeviceName
info.ReadOnly = one.Info.ReadOnly
addOneToAll(machine, unit, storage, info, all)
}
return nil
}
func addOneToAll(machineId, unitId, storageId string, item VolumeInfo, all map[string]map[string]map[string]VolumeInfo) {
machineVolumes, ok := all[machineId]
if !ok {
machineVolumes = map[string]map[string]VolumeInfo{}
all[machineId] = machineVolumes
}
unitVolumes, ok := machineVolumes[unitId]
if !ok {
unitVolumes = map[string]VolumeInfo{}
machineVolumes[unitId] = unitVolumes
}
unitVolumes[storageId] = item
}
func createInfo(volume params.VolumeInstance) (info VolumeInfo, unit, storage string) {
info.VolumeId = volume.VolumeId
info.HardwareId = volume.HardwareId
info.Size = volume.Size
info.Persistent = volume.Persistent
if v, err := idFromTag(volume.VolumeTag); err == nil {
info.Volume = v
}
var err error
if storage, err = idFromTag(volume.StorageTag); err != nil {
storage = "unassigned"
}
if unit, err = idFromTag(volume.UnitTag); err != nil {
unit = "unattached"
}
return
}