...

Source file src/github.com/coreos/go-systemd/v22/machine1/dbus.go

Documentation: github.com/coreos/go-systemd/v22/machine1

     1  /*
     2  Copyright 2015 CoreOS Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Integration with the systemd machined API.  See http://www.freedesktop.org/wiki/Software/systemd/machined/
    18  package machine1
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"strconv"
    24  	"syscall"
    25  
    26  	"github.com/godbus/dbus/v5"
    27  
    28  	sd_dbus "github.com/coreos/go-systemd/v22/dbus"
    29  )
    30  
    31  const (
    32  	dbusInterface = "org.freedesktop.machine1.Manager"
    33  	dbusPath      = "/org/freedesktop/machine1"
    34  )
    35  
    36  // Conn is a connection to systemds dbus endpoint.
    37  type Conn struct {
    38  	conn   *dbus.Conn
    39  	object dbus.BusObject
    40  }
    41  
    42  // MachineStatus is a set of necessary info for each machine
    43  type MachineStatus struct {
    44  	Name    string          // The primary machine name as string
    45  	Class   string          // The machine class as string
    46  	Service string          // The machine service as string
    47  	JobPath dbus.ObjectPath // The job object path
    48  }
    49  
    50  // ImageStatus is a set of necessary info for each machine image
    51  type ImageStatus struct {
    52  	Name       string          // The primary image name as string
    53  	ImageType  string          // The image type as string
    54  	Readonly   bool            // whether it's readonly or not
    55  	CreateTime uint64          // time when it's created
    56  	ModifyTime uint64          // time when it's modified
    57  	DiskUsage  uint64          // used disk space
    58  	JobPath    dbus.ObjectPath // The job object path
    59  }
    60  
    61  // New() establishes a connection to the system bus and authenticates.
    62  func New() (*Conn, error) {
    63  	c := new(Conn)
    64  
    65  	if err := c.initConnection(); err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	return c, nil
    70  }
    71  
    72  func (c *Conn) initConnection() error {
    73  	var err error
    74  	c.conn, err = dbus.SystemBusPrivate()
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	// Only use EXTERNAL method, and hardcode the uid (not username)
    80  	// to avoid a username lookup (which requires a dynamically linked
    81  	// libc)
    82  	methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
    83  
    84  	err = c.conn.Auth(methods)
    85  	if err != nil {
    86  		c.conn.Close()
    87  		return err
    88  	}
    89  
    90  	err = c.conn.Hello()
    91  	if err != nil {
    92  		c.conn.Close()
    93  		return err
    94  	}
    95  
    96  	c.object = c.conn.Object("org.freedesktop.machine1", dbus.ObjectPath(dbusPath))
    97  
    98  	return nil
    99  }
   100  
   101  func (c *Conn) getPath(method string, args ...interface{}) (dbus.ObjectPath, error) {
   102  	result := c.object.Call(fmt.Sprintf("%s.%s", dbusInterface, method), 0, args...)
   103  	if result.Err != nil {
   104  		return "", result.Err
   105  	}
   106  
   107  	path, typeErr := result.Body[0].(dbus.ObjectPath)
   108  	if !typeErr {
   109  		return "", fmt.Errorf("unable to convert dbus response '%v' to dbus.ObjectPath", result.Body[0])
   110  	}
   111  
   112  	return path, nil
   113  }
   114  
   115  // Connected returns whether conn is connected
   116  func (c *Conn) Connected() bool {
   117  	return c.conn.Connected()
   118  }
   119  
   120  // CreateMachine creates a new virtual machine or container with systemd-machined, generating a scope unit for it
   121  func (c *Conn) CreateMachine(name string, id []byte, service string, class string, pid int, root_directory string, scope_properties []sd_dbus.Property) error {
   122  	return c.object.Call(dbusInterface+".CreateMachine", 0, name, id, service, class, uint32(pid), root_directory, scope_properties).Err
   123  }
   124  
   125  // CreateMachineWithNetwork creates the container with its network config with systemd-machined
   126  func (c *Conn) CreateMachineWithNetwork(name string, id []byte, service string, class string, pid int, root_directory string, ifindices []int, scope_properties []sd_dbus.Property) error {
   127  	return c.object.Call(dbusInterface+".CreateMachineWithNetwork", 0, name, id, service, class, uint32(pid), root_directory, ifindices, scope_properties).Err
   128  }
   129  
   130  // GetMachine gets a specific container with systemd-machined
   131  func (c *Conn) GetMachine(name string) (dbus.ObjectPath, error) {
   132  	return c.getPath("GetMachine", name)
   133  }
   134  
   135  // GetImage gets a specific image with systemd-machined
   136  func (c *Conn) GetImage(name string) (dbus.ObjectPath, error) {
   137  	return c.getPath("GetImage", name)
   138  }
   139  
   140  // GetMachineByPID gets a machine specified by a PID from systemd-machined
   141  func (c *Conn) GetMachineByPID(pid uint) (dbus.ObjectPath, error) {
   142  	return c.getPath("GetMachineByPID", pid)
   143  }
   144  
   145  // GetMachineAddresses gets a list of IP addresses
   146  func (c *Conn) GetMachineAddresses(name string) (dbus.ObjectPath, error) {
   147  	return c.getPath("GetMachineAddresses", name)
   148  }
   149  
   150  // DescribeMachine gets the properties of a machine
   151  func (c *Conn) DescribeMachine(name string) (machineProps map[string]interface{}, err error) {
   152  	var dbusProps map[string]dbus.Variant
   153  	path, pathErr := c.GetMachine(name)
   154  	if pathErr != nil {
   155  		return nil, pathErr
   156  	}
   157  	obj := c.conn.Object("org.freedesktop.machine1", path)
   158  	err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, "").Store(&dbusProps)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  	machineProps = make(map[string]interface{}, len(dbusProps))
   163  	for key, val := range dbusProps {
   164  		machineProps[key] = val.Value()
   165  	}
   166  	return
   167  }
   168  
   169  // KillMachine sends a signal to a machine
   170  func (c *Conn) KillMachine(name, who string, sig syscall.Signal) error {
   171  	return c.object.Call(dbusInterface+".KillMachine", 0, name, who, sig).Err
   172  }
   173  
   174  // TerminateMachine causes systemd-machined to terminate a machine, killing its processes
   175  func (c *Conn) TerminateMachine(name string) error {
   176  	return c.object.Call(dbusInterface+".TerminateMachine", 0, name).Err
   177  }
   178  
   179  // RegisterMachine registers the container with the systemd-machined
   180  func (c *Conn) RegisterMachine(name string, id []byte, service string, class string, pid int, root_directory string) error {
   181  	return c.object.Call(dbusInterface+".RegisterMachine", 0, name, id, service, class, uint32(pid), root_directory).Err
   182  }
   183  
   184  // RegisterMachineWithNetwork registers the container with its network with systemd-machined
   185  func (c *Conn) RegisterMachineWithNetwork(name string, id []byte, service string, class string, pid int, root_directory string, ifindices []int) error {
   186  	return c.object.Call(dbusInterface+".RegisterMachineWithNetwork", 0, name, id, service, class, uint32(pid), root_directory, ifindices).Err
   187  }
   188  
   189  func machineFromInterfaces(machine []interface{}) (*MachineStatus, error) {
   190  	if len(machine) < 4 {
   191  		return nil, fmt.Errorf("invalid number of machine fields: %d", len(machine))
   192  	}
   193  	name, ok := machine[0].(string)
   194  	if !ok {
   195  		return nil, fmt.Errorf("failed to typecast machine field 0 to string")
   196  	}
   197  	class, ok := machine[1].(string)
   198  	if !ok {
   199  		return nil, fmt.Errorf("failed to typecast class field 1 to string")
   200  	}
   201  	service, ok := machine[2].(string)
   202  	if !ok {
   203  		return nil, fmt.Errorf("failed to typecast service field 2 to string")
   204  	}
   205  	jobpath, ok := machine[3].(dbus.ObjectPath)
   206  	if !ok {
   207  		return nil, fmt.Errorf("failed to typecast jobpath field 3 to ObjectPath")
   208  	}
   209  
   210  	ret := MachineStatus{Name: name, Class: class, Service: service, JobPath: jobpath}
   211  	return &ret, nil
   212  }
   213  
   214  // ListMachines returns an array of all currently running machines.
   215  func (c *Conn) ListMachines() ([]MachineStatus, error) {
   216  	result := make([][]interface{}, 0)
   217  	if err := c.object.Call(dbusInterface+".ListMachines", 0).Store(&result); err != nil {
   218  		return nil, err
   219  	}
   220  
   221  	machs := []MachineStatus{}
   222  	for _, i := range result {
   223  		machine, err := machineFromInterfaces(i)
   224  		if err != nil {
   225  			return nil, err
   226  		}
   227  		machs = append(machs, *machine)
   228  	}
   229  
   230  	return machs, nil
   231  }
   232  
   233  func imageFromInterfaces(image []interface{}) (*ImageStatus, error) {
   234  	if len(image) < 7 {
   235  		return nil, fmt.Errorf("invalid number of image fields: %d", len(image))
   236  	}
   237  	name, ok := image[0].(string)
   238  	if !ok {
   239  		return nil, fmt.Errorf("failed to typecast image field 0 to string")
   240  	}
   241  	imagetype, ok := image[1].(string)
   242  	if !ok {
   243  		return nil, fmt.Errorf("failed to typecast imagetype field 1 to string")
   244  	}
   245  	readonly, ok := image[2].(bool)
   246  	if !ok {
   247  		return nil, fmt.Errorf("failed to typecast readonly field 2 to bool")
   248  	}
   249  	createtime, ok := image[3].(uint64)
   250  	if !ok {
   251  		return nil, fmt.Errorf("failed to typecast createtime field 3 to uint64")
   252  	}
   253  	modifytime, ok := image[4].(uint64)
   254  	if !ok {
   255  		return nil, fmt.Errorf("failed to typecast modifytime field 4 to uint64")
   256  	}
   257  	diskusage, ok := image[5].(uint64)
   258  	if !ok {
   259  		return nil, fmt.Errorf("failed to typecast diskusage field 5 to uint64")
   260  	}
   261  	jobpath, ok := image[6].(dbus.ObjectPath)
   262  	if !ok {
   263  		return nil, fmt.Errorf("failed to typecast jobpath field 6 to ObjectPath")
   264  	}
   265  
   266  	ret := ImageStatus{Name: name, ImageType: imagetype, Readonly: readonly, CreateTime: createtime, ModifyTime: modifytime, DiskUsage: diskusage, JobPath: jobpath}
   267  	return &ret, nil
   268  }
   269  
   270  // ListImages returns an array of all currently available images.
   271  func (c *Conn) ListImages() ([]ImageStatus, error) {
   272  	result := make([][]interface{}, 0)
   273  	if err := c.object.Call(dbusInterface+".ListImages", 0).Store(&result); err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	images := []ImageStatus{}
   278  	for _, i := range result {
   279  		image, err := imageFromInterfaces(i)
   280  		if err != nil {
   281  			return nil, err
   282  		}
   283  		images = append(images, *image)
   284  	}
   285  
   286  	return images, nil
   287  }
   288  

View as plain text