Skip to content

Commit

Permalink
Merge pull request #769 from Mirantis/ivan4th/disable-cloud-init-netc…
Browse files Browse the repository at this point in the history
…onf-for-persistent-rootfs

Disable cloud-init netconfig for persistent rootfs
  • Loading branch information
jellonek authored Sep 25, 2018
2 parents 7cdc1e4 + 09cad88 commit 219c0ea
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
meta-data:
instance-id: foo.default
local-hostname: foo
network-config: null
user-data: null
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@
- name: 'domain conn: virtlet-231700d5-c9a6-container1: iso image'
value:
meta-data: '{"instance-id":"testName_0.default","local-hostname":"testName_0"}'
network-config: |
version: 1
user-data: |
#cloud-config
- name: 'domain conn: virtlet-231700d5-c9a6-container1: Destroy'
Expand Down
2 changes: 1 addition & 1 deletion pkg/libvirttools/block_volumesource.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (v *blockVolume) Teardown() error {
func GetBlockVolumes(config *types.VMConfig, owner volumeOwner) ([]VMVolume, error) {
var vols []VMVolume
for _, dev := range config.VolumeDevices {
if dev.DevicePath == "/" {
if dev.IsRoot() {
continue
}
vols = append(vols, &blockVolume{
Expand Down
23 changes: 16 additions & 7 deletions pkg/libvirttools/cloudinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ func (g *CloudInitGenerator) generateUserData(volumeMap diskPathMap) ([]byte, er
}

func (g *CloudInitGenerator) generateNetworkConfiguration() ([]byte, error) {
if g.config.RootVolumeDevice() != nil {
// We don't use network config with persistent rootfs
// for now because with some cloud-init
// implementations it's applied only once
return nil, nil
}
// TODO: get rid of this switch. Use descriptor for cloud-init image types.
switch g.config.ParsedAnnotations.CDImageType {
case types.CloudInitImageTypeNoCloud:
Expand Down Expand Up @@ -464,11 +470,14 @@ func (g *CloudInitGenerator) GenerateImage(volumeMap diskPathMap) error {
return fmt.Errorf("unknown cloud-init config image type: %q", g.config.ParsedAnnotations.CDImageType)
}

if err := utils.WriteFiles(tmpDir, map[string][]byte{
userDataLocation: userData,
metaDataLocation: metaData,
networkConfigLocation: networkConfiguration,
}); err != nil {
fileMap := map[string][]byte{
userDataLocation: userData,
metaDataLocation: metaData,
}
if networkConfiguration != nil {
fileMap[networkConfigLocation] = networkConfiguration
}
if err := utils.WriteFiles(tmpDir, fileMap); err != nil {
return fmt.Errorf("can't write user-data: %v", err)
}

Expand Down Expand Up @@ -506,7 +515,7 @@ func isRegularFile(path string) bool {
func (g *CloudInitGenerator) generateSymlinkScript(volumeMap diskPathMap) string {
var symlinkLines []string
for _, dev := range g.config.VolumeDevices {
if dev.DevicePath == "/" {
if dev.IsRoot() {
// special case for the persistent rootfs
continue
}
Expand All @@ -527,7 +536,7 @@ func (g *CloudInitGenerator) generateSymlinkScript(volumeMap diskPathMap) string
func (g *CloudInitGenerator) fixMounts(volumeMap diskPathMap, mounts []interface{}) []interface{} {
devMap := make(map[string]string)
for _, dev := range g.config.VolumeDevices {
if dev.DevicePath == "/" {
if dev.IsRoot() {
// special case for the persistent rootfs
continue
}
Expand Down
136 changes: 112 additions & 24 deletions pkg/libvirttools/cloudinit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,24 @@ func TestCloudInitGenerator(t *testing.T) {
verifyMetaData: true,
verifyUserData: true,
},
{
name: "pod with persistent rootfs",
config: &types.VMConfig{
PodName: "foo",
PodNamespace: "default",
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeNoCloud},
VolumeDevices: []types.VMVolumeDevice{
{
DevicePath: "/",
HostPath: volDevs[0].HostPath,
},
},
},
verifyMetaData: true,
verifyUserData: true,
// make sure network config is null for the persistent rootfs case
verifyNetworkConfig: true,
},
{
name: "injecting mount script into user data script",
config: &types.VMConfig{
Expand Down Expand Up @@ -700,33 +718,103 @@ func TestCloudInitDiskDef(t *testing.T) {
}

func TestCloudInitGenerateImage(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "config-")
if err != nil {
t.Fatalf("Can't create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)

g := NewCloudInitGenerator(&types.VMConfig{
PodName: "foo",
PodNamespace: "default",
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeNoCloud},
}, tmpDir)
for _, tc := range []struct {
name string
vmConfig *types.VMConfig
expectedFiles map[string]interface{}
}{
{
name: "nocloud",
vmConfig: &types.VMConfig{
PodName: "foo",
PodNamespace: "default",
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeNoCloud},
},
expectedFiles: map[string]interface{}{
"meta-data": "{\"instance-id\":\"foo.default\",\"local-hostname\":\"foo\"}",
"network-config": "version: 1\n",
"user-data": "#cloud-config\n",
},
},
{
name: "nocloud with persistent rootfs",
vmConfig: &types.VMConfig{
PodName: "foo",
PodNamespace: "default",
VolumeDevices: []types.VMVolumeDevice{
{
DevicePath: "/",
HostPath: "/dev/loop0",
},
},
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeNoCloud},
},
expectedFiles: map[string]interface{}{
"meta-data": "{\"instance-id\":\"foo.default\",\"local-hostname\":\"foo\"}",
"user-data": "#cloud-config\n",
},
},
{
name: "configdrive",
vmConfig: &types.VMConfig{
PodName: "foo",
PodNamespace: "default",
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeConfigDrive},
},
expectedFiles: map[string]interface{}{
"openstack": map[string]interface{}{
"latest": map[string]interface{}{
"meta_data.json": "{\"hostname\":\"foo\",\"instance-id\":\"foo.default\",\"local-hostname\":\"foo\",\"uuid\":\"foo.default\"}",
"network_data.json": "{}",
"user_data": "#cloud-config\n",
},
},
},
},
{
name: "configdrive with persistent rootfs",
vmConfig: &types.VMConfig{
PodName: "foo",
PodNamespace: "default",
VolumeDevices: []types.VMVolumeDevice{
{
DevicePath: "/",
HostPath: "/dev/loop0",
},
},
ParsedAnnotations: &types.VirtletAnnotations{CDImageType: types.CloudInitImageTypeConfigDrive},
},
expectedFiles: map[string]interface{}{
"openstack": map[string]interface{}{
"latest": map[string]interface{}{
"meta_data.json": "{\"hostname\":\"foo\",\"instance-id\":\"foo.default\",\"local-hostname\":\"foo\",\"uuid\":\"foo.default\"}",
"user_data": "#cloud-config\n",
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "config-")
if err != nil {
t.Fatalf("Can't create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)

if err := g.GenerateImage(nil); err != nil {
t.Fatalf("GenerateImage(): %v", err)
}
g := NewCloudInitGenerator(tc.vmConfig, tmpDir)
if err := g.GenerateImage(nil); err != nil {
t.Fatalf("GenerateImage(): %v", err)
}

m, err := testutils.IsoToMap(g.IsoPath())
if err != nil {
t.Fatalf("IsoToMap(): %v", err)
}
m, err := testutils.IsoToMap(g.IsoPath())
if err != nil {
t.Fatalf("IsoToMap(): %v", err)
}

if !reflect.DeepEqual(m, map[string]interface{}{
"meta-data": "{\"instance-id\":\"foo.default\",\"local-hostname\":\"foo\"}",
"network-config": "version: 1\n",
"user-data": "#cloud-config\n",
}) {
t.Errorf("Bad iso content:\n%s", spew.Sdump(m))
if !reflect.DeepEqual(m, tc.expectedFiles) {
t.Errorf("Bad iso content:\n%s", spew.Sdump(m))
}
})
}
}

Expand Down
15 changes: 6 additions & 9 deletions pkg/libvirttools/root_volumesource.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,13 @@ var _ VMVolume = &rootVolume{}
// GetRootVolume returns volume source for root volume clone.
func GetRootVolume(config *types.VMConfig, owner volumeOwner) ([]VMVolume, error) {
var vol VMVolume
for _, dev := range config.VolumeDevices {
if dev.DevicePath == "/" {
vol = &persistentRootVolume{
volumeBase: volumeBase{config, owner},
dev: dev,
}
break
rootDev := config.RootVolumeDevice()
if rootDev != nil {
vol = &persistentRootVolume{
volumeBase: volumeBase{config, owner},
dev: *rootDev,
}
}
if vol == nil {
} else {
vol = &rootVolume{
volumeBase{config, owner},
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/metadata/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ type VMVolumeDevice struct {
HostPath string
}

// IsRoot returns true if this volume device should be used for a
// persistent root filesystem, that is, its DevicePath is "/"
func (d VMVolumeDevice) IsRoot() bool {
return d.DevicePath == "/"
}

// UUID returns an uuid that uniquely identifies the block device on
// the host.
func (dev VMVolumeDevice) UUID() string {
Expand Down Expand Up @@ -271,6 +277,18 @@ type VMConfig struct {
LogPath string
}

// RootVolumeDevice returns the volume device that should be used for
// a persistent root filesystem, that is, its DevicePath is "/"
func (c *VMConfig) RootVolumeDevice() *VMVolumeDevice {
for n, _ := range c.VolumeDevices {
dev := &c.VolumeDevices[n]
if dev.IsRoot() {
return dev
}
}
return nil
}

// LoadAnnotations parses pod annotations in the VM config an
// populates the ParsedAnnotations field.
func (c *VMConfig) LoadAnnotations() error {
Expand Down

0 comments on commit 219c0ea

Please sign in to comment.