asteris-llc/converge

View on GitHub
resource/lvm/lowlevel/query.go

Summary

Maintainability
A
0 mins
Test Coverage
// Copyright © 2016 Asteris, LLC
//
// 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.

package lowlevel

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
    "github.com/pkg/errors"
    "strings"
)

func (lvm *realLVM) Blkid(dev string) (string, error) {
    if ok, err := lvm.backend.Exists(dev); err != nil || !ok {
        return "", errors.Wrapf(err, "check for device")
    }

    blkid, rc, err := lvm.backend.ReadWithExitCode("blkid", []string{"-c", "/dev/null", "-o", "value", "-s", "TYPE", dev})
    if err != nil {
        return "", err
    }
    // excerpt from `man blkid`:
    // RETURN CODE
    // If  the  specified  device  or  device addressed by specified token (option -t) was found and it's possible to gather any information about the device, an exit code 0 is returned.
    // Note the option -s filters output tags, but it does not affect return code.
    // If the specified token was not found, or no (specified) devices could be identified, an exit code of 2 is returned.
    // For usage or other errors, an exit code of 4 is returned.
    //  If an ambivalent low-level probing result was detected, an exit code of 8 is returned.
    if rc != 2 && rc != 0 {
        return blkid, fmt.Errorf("blkid terminated with rc == %d, and output `%s`", rc, blkid)
    }
    return blkid, nil
}

func (lvm *realLVM) QueryDeviceMapperName(dmName string) (string, error) {
    out, err := lvm.backend.Read("dmsetup", []string{"info", "-C", "--noheadings", "-o", "name", dmName})
    if err != nil {
        return "", errors.Wrapf(err, "query devicemapper")
    }
    return fmt.Sprintf("/dev/mapper/%s", out), nil
}

func (lvm *realLVM) Query(prog string, out string, extras []string) ([]map[string]interface{}, error) {
    result := []map[string]interface{}{}
    args := []string{"--nameprefix", "--noheadings", "--unquoted", "--units", "b", "-o", out, "--separator", ";"}
    args = append(args, extras...)
    output, err := lvm.backend.Read(prog, args)
    if err != nil {
        return nil, errors.Wrapf(err, "querying %s", prog)
    }
    for _, line := range strings.Split(output, "\n") {
        values := map[string]interface{}{}
        for _, field := range strings.Split(line, ";") {
            parts := strings.Split(field, "=")
            if len(parts) == 1 {
                continue
            }
            values[parts[0]] = parts[1]
        }
        if len(values) > 0 {
            result = append(result, values)
        }
    }
    return result, nil
}

func (lvm *realLVM) parse(values interface{}, dest interface{}) error {
    return mapstructure.Decode(values, dest)
}