Esempio n. 1
0
// CheckApply method for Hostname resource.
func (obj *HostnameRes) CheckApply(apply bool) (checkOK bool, err error) {
	conn, err := util.SystemBusPrivateUsable()
	if err != nil {
		return false, errwrap.Wrap(err, "Failed to connect to the private system bus")
	}
	defer conn.Close()

	hostnameObject := conn.Object(hostname1Iface, hostname1Path)

	checkOK = true
	if obj.PrettyHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.PrettyHostname, "PrettyHostname", "SetPrettyHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}
	if obj.StaticHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.StaticHostname, "StaticHostname", "SetStaticHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}
	if obj.TransientHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.TransientHostname, "Hostname", "SetHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}

	return checkOK, nil
}
Esempio n. 2
0
// NewBus returns a new bus connection.
func NewBus() *Conn {
	// if we share the bus with others, we will get each others messages!!
	bus, err := util.SystemBusPrivateUsable() // don't share the bus connection!
	if err != nil {
		return nil
	}
	return &Conn{
		conn: bus,
	}
}
Esempio n. 3
0
// CheckApply method for Hostname resource.
func (obj *HostnameRes) CheckApply(apply bool) (checkOK bool, err error) {
	log.Printf("%v[%v]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply)

	if obj.isStateOK { // cached state
		return true, nil
	}

	conn, err := util.SystemBusPrivateUsable()
	if err != nil {
		return false, errwrap.Wrap(err, "Failed to connect to the private system bus")
	}
	defer conn.Close()

	hostnameObject := conn.Object(hostname1Iface, hostname1Path)

	checkOK = true
	if obj.PrettyHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.PrettyHostname, "PrettyHostname", "SetPrettyHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}
	if obj.StaticHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.StaticHostname, "StaticHostname", "SetStaticHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}
	if obj.TransientHostname != "" {
		propertyCheckOK, err := updateHostnameProperty(hostnameObject, obj.TransientHostname, "Hostname", "SetHostname", apply)
		if err != nil {
			return false, err
		}
		checkOK = checkOK && propertyCheckOK
	}

	if apply || checkOK {
		obj.isStateOK = true
	}

	return checkOK, nil
}
Esempio n. 4
0
// Watch is the primary listener for this resource and it outputs events.
func (obj *SvcRes) Watch(processChan chan event.Event) error {
	if obj.IsWatching() {
		return nil
	}
	obj.SetWatching(true)
	defer obj.SetWatching(false)
	cuid := obj.converger.Register()
	defer cuid.Unregister()

	var startup bool
	Startup := func(block bool) <-chan time.Time {
		if block {
			return nil // blocks forever
			//return make(chan time.Time) // blocks forever
		}
		return time.After(time.Duration(500) * time.Millisecond) // 1/2 the resolution of converged timeout
	}

	// obj.Name: svc name
	if !systemdUtil.IsRunningSystemd() {
		return fmt.Errorf("Systemd is not running.")
	}

	conn, err := systemd.NewSystemdConnection() // needs root access
	if err != nil {
		return errwrap.Wrapf(err, "Failed to connect to systemd")
	}
	defer conn.Close()

	// if we share the bus with others, we will get each others messages!!
	bus, err := util.SystemBusPrivateUsable() // don't share the bus connection!
	if err != nil {
		return errwrap.Wrapf(err, "Failed to connect to bus")
	}

	// XXX: will this detect new units?
	bus.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
		"type='signal',interface='org.freedesktop.systemd1.Manager',member='Reloading'")
	buschan := make(chan *dbus.Signal, 10)
	bus.Signal(buschan)

	var svc = fmt.Sprintf("%s.service", obj.Name) // systemd name
	var send = false                              // send event?
	var exit = false
	var invalid = false              // does the svc exist or not?
	var previous bool                // previous invalid value
	set := conn.NewSubscriptionSet() // no error should be returned
	subChannel, subErrors := set.Subscribe()
	var activeSet = false

	for {
		// XXX: watch for an event for new units...
		// XXX: detect if startup enabled/disabled value changes...

		previous = invalid
		invalid = false

		// firstly, does svc even exist or not?
		loadstate, err := conn.GetUnitProperty(svc, "LoadState")
		if err != nil {
			log.Printf("Failed to get property: %v", err)
			invalid = true
		}

		if !invalid {
			var notFound = (loadstate.Value == dbus.MakeVariant("not-found"))
			if notFound { // XXX: in the loop we'll handle changes better...
				log.Printf("Failed to find svc: %s", svc)
				invalid = true // XXX: ?
			}
		}

		if previous != invalid { // if invalid changed, send signal
			send = true
			obj.StateOK(false) // dirty
		}

		if invalid {
			log.Printf("Waiting for: %s", svc) // waiting for svc to appear...
			if activeSet {
				activeSet = false
				set.Remove(svc) // no return value should ever occur
			}

			obj.SetState(ResStateWatching) // reset
			select {
			case <-buschan: // XXX: wait for new units event to unstick
				cuid.SetConverged(false)
				// loop so that we can see the changed invalid signal
				log.Printf("Svc[%s]->DaemonReload()", svc)

			case event := <-obj.Events():
				cuid.SetConverged(false)
				if exit, send = obj.ReadEvent(&event); exit {
					return nil // exit
				}

			case <-cuid.ConvergedTimer():
				cuid.SetConverged(true) // converged!
				continue

			case <-Startup(startup):
				cuid.SetConverged(false)
				send = true
				obj.StateOK(false) // dirty
			}
		} else {
			if !activeSet {
				activeSet = true
				set.Add(svc) // no return value should ever occur
			}

			log.Printf("Watching: %s", svc) // attempting to watch...
			obj.SetState(ResStateWatching)  // reset
			select {
			case event := <-subChannel:

				log.Printf("Svc event: %+v", event)
				// NOTE: the value returned is a map for some reason...
				if event[svc] != nil {
					// event[svc].ActiveState is not nil

					switch event[svc].ActiveState {
					case "active":
						log.Printf("Svc[%s]->Started", svc)
					case "inactive":
						log.Printf("Svc[%s]->Stopped", svc)
					case "reloading":
						log.Printf("Svc[%s]->Reloading", svc)
					default:
						log.Fatalf("Unknown svc state: %s", event[svc].ActiveState)
					}
				} else {
					// svc stopped (and ActiveState is nil...)
					log.Printf("Svc[%s]->Stopped", svc)
				}
				send = true
				obj.StateOK(false) // dirty

			case err := <-subErrors:
				cuid.SetConverged(false)
				return errwrap.Wrapf(err, "Unknown %s[%s] error", obj.Kind(), obj.GetName())

			case event := <-obj.Events():
				cuid.SetConverged(false)
				if exit, send = obj.ReadEvent(&event); exit {
					return nil // exit
				}

			case <-cuid.ConvergedTimer():
				cuid.SetConverged(true) // converged!
				continue

			case <-Startup(startup):
				cuid.SetConverged(false)
				send = true
				obj.StateOK(false) // dirty
			}
		}

		if send {
			startup = true // startup finished
			send = false
			if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
				return err // we exit or bubble up a NACK...
			}
		}
	}
}
Esempio n. 5
0
// Watch is the primary listener for this resource and it outputs events.
func (obj *HostnameRes) Watch(processChan chan event.Event) error {
	if obj.IsWatching() {
		return nil // TODO: should this be an error?
	}
	obj.SetWatching(true)
	defer obj.SetWatching(false)
	cuid := obj.converger.Register()
	defer cuid.Unregister()

	var startup bool
	Startup := func(block bool) <-chan time.Time {
		if block {
			return nil // blocks forever
			//return make(chan time.Time) // blocks forever
		}
		return time.After(time.Duration(500) * time.Millisecond) // 1/2 the resolution of converged timeout
	}

	// if we share the bus with others, we will get each others messages!!
	bus, err := util.SystemBusPrivateUsable() // don't share the bus connection!
	if err != nil {
		return errwrap.Wrap(err, "Failed to connect to bus")
	}
	defer bus.Close()
	callResult := bus.BusObject().Call(
		"org.freedesktop.DBus.AddMatch", 0,
		fmt.Sprintf("type='signal',path='%s',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'", hostname1Path))
	if callResult.Err != nil {
		return errwrap.Wrap(callResult.Err, "Failed to subscribe to DBus events for hostname1")
	}

	signals := make(chan *dbus.Signal, 10) // closed by dbus package
	bus.Signal(signals)

	var send = false // send event?
	var dirty = false

	for {
		obj.SetState(ResStateWatching) // reset
		select {
		case <-signals:
			cuid.SetConverged(false)
			send = true
			dirty = true

		case event := <-obj.Events():
			cuid.SetConverged(false)
			// we avoid sending events on unpause
			if exit, _ := obj.ReadEvent(&event); exit {
				return nil // exit
			}
			send = true
			dirty = true

		case <-cuid.ConvergedTimer():
			cuid.SetConverged(true) // converged!
			continue

		case <-Startup(startup):
			cuid.SetConverged(false)
			send = true
		}

		// do all our event sending all together to avoid duplicate msgs
		if send {
			startup = true // startup finished
			send = false
			if dirty {
				dirty = false
				obj.isStateOK = false // something made state dirty
			}
			// only do this on certain types of events
			if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
				return err // we exit or bubble up a NACK...
			}
		}
	}
}
Esempio n. 6
0
// Watch for state changes and sends a message to the bus if there is a change
func (obj *NspawnRes) Watch(processChan chan event.Event) error {
	if obj.IsWatching() {
		return nil
	}
	obj.SetWatching(true)
	defer obj.SetWatching(false)
	cuid := obj.converger.Register()
	defer cuid.Unregister()

	var startup bool
	Startup := func(block bool) <-chan time.Time {
		if block {
			return nil // blocks forever
		}
		// 1/2 the resolution of converged timeout
		return time.After(time.Duration(500) * time.Millisecond)
	}

	// this resource depends on systemd ensure that it's running
	if !systemdUtil.IsRunningSystemd() {
		return fmt.Errorf("Systemd is not running.")
	}

	// create a private message bus
	bus, err := util.SystemBusPrivateUsable()
	if err != nil {
		return errwrap.Wrapf(err, "Failed to connect to bus")
	}

	// add a match rule to match messages going through the message bus
	call := bus.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
		fmt.Sprintf("type='signal',interface='%s',eavesdrop='true'",
			dbusInterface))
	// <-call.Done
	if err := call.Err; err != nil {
		return err
	}
	buschan := make(chan *dbus.Signal, 10)
	bus.Signal(buschan)

	var send = false
	var exit = false
	var dirty = false

	for {
		obj.SetState(ResStateWatching)
		select {
		case event := <-buschan:
			// process org.freedesktop.machine1 events for this resource's name
			if event.Body[0] == obj.GetName() {
				log.Printf("%s[%s]: Event received: %v", obj.Kind(), obj.GetName(), event.Name)
				if event.Name == machineNew {
					log.Printf("%s[%s]: Machine started", obj.Kind(), obj.GetName())
				} else if event.Name == machineRemoved {
					log.Printf("%s[%s]: Machine stopped", obj.Kind(), obj.GetName())
				} else {
					return fmt.Errorf("Unknown event: %s", event.Name)
				}
				send = true
				dirty = true
			}

		case event := <-obj.Events():
			cuid.SetConverged(false)
			if exit, send = obj.ReadEvent(&event); exit {
				return nil // exit
			}

		case <-cuid.ConvergedTimer():
			cuid.SetConverged(true) // converged!
			continue

		case <-Startup(startup):
			cuid.SetConverged(false)
			send = true
			dirty = true
		}

		// do all our event sending all together to avoid duplicate msgs
		if send || !obj.isStateOK {
			startup = true // startup finished
			send = false
			// only invalid state on certain types of events
			if dirty {
				dirty = false
				obj.isStateOK = false // something made state dirty
			}
			if exit, err := obj.DoSend(processChan, ""); exit || err != nil {
				return err // we exit or bubble up a NACK...
			}
		}
	}
}