diff --git a/cmd/qemu/events/lifecycle.go b/cmd/qemu/events/lifecycle.go new file mode 100644 index 0000000..b83afc3 --- /dev/null +++ b/cmd/qemu/events/lifecycle.go @@ -0,0 +1,179 @@ +package events + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + "time" + + "deevirt.fr/compute/pkg/amqp" + clientv3 "go.etcd.io/etcd/client/v3" + "libvirt.org/go/libvirt" +) + +func Lifecyle(c *libvirt.Connect, d *libvirt.Domain, e *libvirt.DomainEventLifecycle) { + var detail, event string + domainID, _ := d.GetUUIDString() + + // Read Etcd URI + config, err := Config() + if err != nil { + log.Fatalf("Fail to read file: %v", err) + } + + etcd, err := clientv3.New(clientv3.Config{ + Endpoints: strings.Split(config.Section("etcd").Key("uri").String(), ","), + DialTimeout: 5 * time.Second, + }) + if err != nil { + log.Fatalf("Error connexion to etcd: %v", err) + } + defer etcd.Close() + + ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) + + switch e.Event { + case libvirt.DOMAIN_EVENT_DEFINED: + event = "defined" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/host/"+MachineID()+"/qemu/"+domainID, "") + + switch libvirt.DomainEventDefinedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_DEFINED_ADDED: + detail = "added" + case libvirt.DOMAIN_EVENT_DEFINED_UPDATED: + detail = "updated" + case libvirt.DOMAIN_EVENT_DEFINED_RENAMED: + detail = "renamed" + case libvirt.DOMAIN_EVENT_DEFINED_FROM_SNAPSHOT: + detail = "snapshot" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_UNDEFINED: + event = "undefined" + etcd.Delete(ctx, "/cluster/"+ClusterID()+"/host/"+MachineID()+"/qemu/"+domainID) + + switch libvirt.DomainEventUndefinedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_UNDEFINED_REMOVED: + detail = "removed" + case libvirt.DOMAIN_EVENT_UNDEFINED_RENAMED: + detail = "renamed" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_STARTED: + event = "started" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/domain/"+domainID+"/state", "2") + + switch libvirt.DomainEventStartedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_STARTED_BOOTED: + detail = "booted" + case libvirt.DOMAIN_EVENT_STARTED_MIGRATED: + detail = "migrated" + case libvirt.DOMAIN_EVENT_STARTED_RESTORED: + detail = "restored" + case libvirt.DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: + detail = "snapshot" + case libvirt.DOMAIN_EVENT_STARTED_WAKEUP: + detail = "wakeup" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_SUSPENDED: + event = "suspended" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/domain/"+domainID+"/state", "3") + + switch libvirt.DomainEventSuspendedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_SUSPENDED_PAUSED: + detail = "paused" + case libvirt.DOMAIN_EVENT_SUSPENDED_MIGRATED: + detail = "migrated" + case libvirt.DOMAIN_EVENT_SUSPENDED_IOERROR: + detail = "I/O error" + case libvirt.DOMAIN_EVENT_SUSPENDED_WATCHDOG: + detail = "watchdog" + case libvirt.DOMAIN_EVENT_SUSPENDED_RESTORED: + detail = "restored" + case libvirt.DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: + detail = "snapshot" + case libvirt.DOMAIN_EVENT_SUSPENDED_API_ERROR: + detail = "api error" + case libvirt.DOMAIN_EVENT_SUSPENDED_POSTCOPY: + detail = "postcopy" + case libvirt.DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: + detail = "postcopy failed" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_RESUMED: + event = "resumed" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/domain/"+domainID+"/state", "4") + + switch libvirt.DomainEventResumedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_RESUMED_UNPAUSED: + detail = "unpaused" + case libvirt.DOMAIN_EVENT_RESUMED_MIGRATED: + detail = "migrated" + case libvirt.DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: + detail = "snapshot" + case libvirt.DOMAIN_EVENT_RESUMED_POSTCOPY: + detail = "postcopy" + case libvirt.DOMAIN_EVENT_RESUMED_POSTCOPY_FAILED: + detail = "postcopy failed" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_STOPPED: + event = "stopped" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/domain/"+domainID+"/state", "5") + + switch libvirt.DomainEventStoppedDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_STOPPED_SHUTDOWN: + detail = "shutdown" + case libvirt.DOMAIN_EVENT_STOPPED_DESTROYED: + detail = "destroyed" + case libvirt.DOMAIN_EVENT_STOPPED_CRASHED: + detail = "crashed" + case libvirt.DOMAIN_EVENT_STOPPED_MIGRATED: + detail = "migrated" + case libvirt.DOMAIN_EVENT_STOPPED_SAVED: + detail = "saved" + case libvirt.DOMAIN_EVENT_STOPPED_FAILED: + detail = "failed" + case libvirt.DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT: + detail = "snapshot" + default: + detail = "unknown" + } + + case libvirt.DOMAIN_EVENT_SHUTDOWN: + event = "shutdown" + etcd.Put(ctx, "/cluster/"+ClusterID()+"/domain/"+domainID+"/state", "6") + + switch libvirt.DomainEventShutdownDetailType(e.Detail) { + case libvirt.DOMAIN_EVENT_SHUTDOWN_FINISHED: + detail = "finished" + case libvirt.DOMAIN_EVENT_SHUTDOWN_GUEST: + detail = "guest" + case libvirt.DOMAIN_EVENT_SHUTDOWN_HOST: + detail = "host" + default: + detail = "unknown" + } + + default: + event = "unknown" + } + + // AMQP + amqp.Publisher([]byte(strconv.FormatInt(int64(e.Event), 10))) + + fmt.Printf("Domain event=%q detail=%q\n", event, detail) +} diff --git a/cmd/qemu/events/server.go b/cmd/qemu/events/server.go new file mode 100644 index 0000000..5da0519 --- /dev/null +++ b/cmd/qemu/events/server.go @@ -0,0 +1,74 @@ +package events + +import ( + "encoding/hex" + "fmt" + "log" + "os" + + "github.com/denisbrodbeck/machineid" + "gopkg.in/ini.v1" + "libvirt.org/go/libvirt" +) + +func Config() (*ini.File, error) { + return ini.Load("/etc/deevirt/config.ini") +} + +var ClusterID = func() string { + config, _ := Config() + return config.Section("").Key("id").String() +} + +var MachineID = func() string { + id, err := machineid.ID() + if err != nil { + log.Fatal(err) + } + u, _ := hex.DecodeString(id) + return fmt.Sprintf("%x-%x-%x-%x-%x\n", u[:4], u[4:6], u[6:8], u[8:10], u[10:]) +} + +func agentLifecycle(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventAgentLifecycle) { + println(event.State) + println(event.Reason) + +} + +func graphics(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventGraphics) { + println(event.String()) +} + +func reboot(c *libvirt.Connect, d *libvirt.Domain) { + +} + +func watchdog(c *libvirt.Connect, d *libvirt.Domain, event *libvirt.DomainEventWatchdog) { + println(event.String()) +} + +func Server() { + err := libvirt.EventRegisterDefaultImpl() + if err != nil { + log.Fatalf("Échec d'EventRegisterDefaultImpl: %v", err) + os.Exit(0) + } + + conn, err := libvirt.NewConnect("qemu:///system") + if err != nil { + log.Println("Connexion Error") + } + defer conn.Close() + + conn.SetKeepAlive(5, 3) + + conn.DomainEventAgentLifecycleRegister(nil, agentLifecycle) + conn.DomainEventGraphicsRegister(nil, graphics) + conn.DomainEventLifecycleRegister(nil, Lifecyle) + conn.DomainEventRebootRegister(nil, reboot) + conn.DomainEventWatchdogRegister(nil, watchdog) + + for { + libvirt.EventRunDefaultImpl() + } +}