talos/pkg/provision/providers/qemu/controller.go
Andrey Smirnov 7f5ffdacb8 test: implement API for QEMU VM provisioner
Fixes #2515

This implements simple HTTP API which should cover same methods as IPMI
methods in Sidero.

Examples:

```
$ curl http://172.20.0.1:34791/status
{"PoweredOn":false}
```

```
$ curl -X POST http://172.20.0.1:34791/poweroff
```

API listens on bridge address, each VM has unique port which can be
found in cluster state as `apiport: NNNN`.

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
2020-09-15 15:05:55 -07:00

145 lines
2.5 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package qemu
import (
"sync"
"github.com/talos-systems/talos/pkg/provision/providers/vm"
)
// PowerState is current VM power state.
type PowerState string
// Virtual machine power state.
const (
PoweredOn PowerState = "on"
PoweredOff PowerState = "off"
)
// VMCommand is a translated VM command.
type VMCommand string
// Virtual machine commands.
const (
VMCommandStart VMCommand = "start"
VMCommandStop VMCommand = "stop"
)
// Controller supports IPMI-like machine control.
type Controller struct {
mu sync.Mutex
state PowerState
forcePXEBoot bool
commandsCh chan VMCommand
}
// NewController initializes controller in "powered on" state.
func NewController() *Controller {
return &Controller{
state: PoweredOn,
commandsCh: make(chan VMCommand),
}
}
// PowerOn implements vm.Controller interface.
func (c *Controller) PowerOn() error {
c.mu.Lock()
if c.state == PoweredOn {
c.mu.Unlock()
return nil
}
c.state = PoweredOn
c.mu.Unlock()
c.commandsCh <- VMCommandStart
return nil
}
// PowerOff implements vm.Controller interface.
func (c *Controller) PowerOff() error {
c.mu.Lock()
if c.state == PoweredOff {
c.mu.Unlock()
return nil
}
c.state = PoweredOff
c.mu.Unlock()
c.commandsCh <- VMCommandStop
return nil
}
// Reboot implements vm.Controller interface.
func (c *Controller) Reboot() error {
c.mu.Lock()
if c.state == PoweredOff {
c.mu.Unlock()
return nil
}
c.mu.Unlock()
c.commandsCh <- VMCommandStop
return nil
}
// PXEBootOnce implements vm.Controller interface.
func (c *Controller) PXEBootOnce() error {
c.mu.Lock()
defer c.mu.Unlock()
c.forcePXEBoot = true
return nil
}
// Status implements vm.Controller interface.
func (c *Controller) Status() vm.Status {
return vm.Status{
PoweredOn: c.PowerState() == PoweredOn,
}
}
// PowerState returns current power state.
func (c *Controller) PowerState() PowerState {
c.mu.Lock()
defer c.mu.Unlock()
return c.state
}
// ForcePXEBoot returns whether next boot should be PXE boot.
func (c *Controller) ForcePXEBoot() bool {
c.mu.Lock()
defer c.mu.Unlock()
if c.forcePXEBoot {
c.forcePXEBoot = false
return true
}
return false
}
// CommandsCh returns channel with commands.
func (c *Controller) CommandsCh() <-chan VMCommand {
return c.commandsCh
}