From 1f710f715666e535ce9b0fd48cac3ec089dbf71a Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Wed, 3 Nov 2021 14:30:53 -0400 Subject: [PATCH] providers/nutanix: add Nutanix platform Add Nutanix AHV platform support(https://github.com/coreos/fedora-coreos-tracker/issues/1007) which is similar to Openstack. --- internal/platform/platform.go | 5 ++ internal/providers/nutanix/nutanix.go | 90 +++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 internal/providers/nutanix/nutanix.go diff --git a/internal/platform/platform.go b/internal/platform/platform.go index 63939fb62..bd393e6a3 100644 --- a/internal/platform/platform.go +++ b/internal/platform/platform.go @@ -30,6 +30,7 @@ import ( "github.com/coreos/ignition/v2/internal/providers/gcp" "github.com/coreos/ignition/v2/internal/providers/ibmcloud" "github.com/coreos/ignition/v2/internal/providers/noop" + "github.com/coreos/ignition/v2/internal/providers/nutanix" "github.com/coreos/ignition/v2/internal/providers/openstack" "github.com/coreos/ignition/v2/internal/providers/packet" "github.com/coreos/ignition/v2/internal/providers/powervs" @@ -144,6 +145,10 @@ func init() { name: "metal", fetch: noop.FetchConfig, }) + configs.Register(Config{ + name: "nutanix", + fetch: nutanix.FetchConfig, + }) configs.Register(Config{ name: "openstack", fetch: openstack.FetchConfig, diff --git a/internal/providers/nutanix/nutanix.go b/internal/providers/nutanix/nutanix.go new file mode 100644 index 000000000..c46beab4b --- /dev/null +++ b/internal/providers/nutanix/nutanix.go @@ -0,0 +1,90 @@ +// Copyright 2021 Red Hat. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The Nutanix AHV (https://www.nutanix.com/products/ahv) provider fetches +// configuration from the userdata available in the config-drive. It is similar +// to Openstack and uses the same APIs. + +package nutanix + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "time" + + "github.com/coreos/ignition/v2/config/v3_4_experimental/types" + "github.com/coreos/ignition/v2/internal/distro" + "github.com/coreos/ignition/v2/internal/log" + "github.com/coreos/ignition/v2/internal/providers/util" + "github.com/coreos/ignition/v2/internal/resource" + ut "github.com/coreos/ignition/v2/internal/util" + + "github.com/coreos/vcontext/report" +) + +const ( + configDriveUserdataPath = "/openstack/latest/user_data" +) + +func FetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) { + data, err := fetchConfigFromDevice(f.Logger, filepath.Join(distro.DiskByLabelDir(), "config-2")) + if err != nil { + return types.Config{}, report.Report{}, err + } + + return util.ParseConfig(f.Logger, data) +} + +func fileExists(path string) bool { + _, err := os.Stat(path) + return (err == nil) +} + +func fetchConfigFromDevice(logger *log.Logger, path string) ([]byte, error) { + // The config drive is always attached, even if there's no user-data passed + for !fileExists(path) { + logger.Debug("config drive (%q) not found. Waiting...", path) + time.Sleep(time.Second) + } + + logger.Debug("creating temporary mount point") + mnt, err := ioutil.TempDir("", "ignition-configdrive") + if err != nil { + return nil, fmt.Errorf("failed to create temp directory: %v", err) + } + defer os.Remove(mnt) + + cmd := exec.Command(distro.MountCmd(), "-o", "ro", "-t", "auto", path, mnt) + if _, err := logger.LogCmd(cmd, "mounting config drive"); err != nil { + return nil, err + } + defer func() { + _ = logger.LogOp( + func() error { + return ut.UmountPath(mnt) + }, + "unmounting %q at %q", path, mnt, + ) + }() + + mntConfigDriveUserdataPath := filepath.Join(mnt, configDriveUserdataPath) + if !fileExists(mntConfigDriveUserdataPath) { + return nil, nil + } + + return ioutil.ReadFile(mntConfigDriveUserdataPath) +}