Updates with respect to migration
[handlervirt.git] / migrateoff.c
bloba66893b5142760b9f5d95275f1fe4595645c216a
1 #include <time.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <assert.h>
6 #include <errno.h>
8 #include <avahi-client/client.h>
9 #include <avahi-client/publish.h>
10 #include <avahi-client/lookup.h>
12 #include <avahi-common/alternative.h>
13 #include <avahi-common/simple-watch.h>
14 #include <avahi-common/malloc.h>
15 #include <avahi-common/error.h>
16 #include <avahi-common/timeval.h>
18 #include <libvirt/libvirt.h>
20 #define POLL 5
22 struct list_el {
23 unsigned short keep;
24 unsigned int domainid;
25 float cost;
26 char *targetdomain;
27 virDomainPtr thisDomain; /* TODO: GAAT DIT GOED? */
28 AvahiEntryGroup *group;
31 virConnectPtr conn = NULL;
32 typedef struct list_el domu;
34 domu * domus = NULL; /* list of domains */
35 unsigned int domu_count = 0;
36 static AvahiSimplePoll *simple_poll = NULL;
38 static void resolve_callback(
39 AvahiServiceResolver *r,
40 AVAHI_GCC_UNUSED AvahiIfIndex interface,
41 AVAHI_GCC_UNUSED AvahiProtocol protocol,
42 AvahiResolverEvent event,
43 const char *name,
44 const char *type,
45 const char *domain,
46 const char *host_name,
47 const AvahiAddress *address,
48 uint16_t port,
49 AvahiStringList *txt,
50 AvahiLookupResultFlags flags,
51 void* userdata) {
53 assert(r);
55 /* Called whenever a service has been resolved successfully or timed out */
57 switch (event) {
58 case AVAHI_RESOLVER_FAILURE:
59 fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
60 break;
62 case AVAHI_RESOLVER_FOUND: {
63 char a[AVAHI_ADDRESS_STR_MAX], *t;
64 AvahiStringList *needle;
66 fprintf(stderr, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
68 avahi_address_snprint(a, sizeof(a), address);
69 t = avahi_string_list_to_string(txt);
70 fprintf(stderr,
71 "\t%s:%u (%s)\n"
72 "\tTXT=%s\n"
73 "\tcookie is %u\n"
74 "\tis_local: %i\n"
75 "\tour_own: %i\n"
76 "\twide_area: %i\n"
77 "\tmulticast: %i\n"
78 "\tcached: %i\n",
79 host_name, port, a,
81 avahi_string_list_get_service_cookie(txt),
82 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
83 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
84 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
85 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
86 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
88 avahi_free(t);
90 int i;
91 for (i = 0; i < domu_count; i++) {
92 const char *thisName = virDomainGetName(domus[i].thisDomain);
93 unsigned int len = strlen(thisName);
95 if (strlen(name) > len && name[len] == '.' && strncmp(thisName, name, len) == 0) {
96 if ((needle = avahi_string_list_find (txt, "cost")) != NULL) {
98 float amount;
99 char *cost;
100 avahi_string_list_get_pair (needle, NULL, &cost, NULL);
101 amount = atof(cost);
103 printf("%s: I'll run %s for the competing cost of L$W %f\n", host_name, thisName, amount);
104 if (errno != ERANGE && amount < domus[i].cost) {
105 domus[i].cost = amount;
106 if (domus[i].targetdomain)
107 free(domus[i].targetdomain);
108 domus[i].targetdomain = strdup(&name[++len]);
111 avahi_free(cost);
113 break;
118 avahi_service_resolver_free(r);
121 static void browse_callback(
122 AvahiServiceBrowser *b,
123 AvahiIfIndex interface,
124 AvahiProtocol protocol,
125 AvahiBrowserEvent event,
126 const char *name,
127 const char *type,
128 const char *domain,
129 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
130 void* userdata) {
132 assert(b);
133 AvahiClient *c = avahi_service_browser_get_client(b);
135 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
137 switch (event) {
138 case AVAHI_BROWSER_FAILURE:
140 fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
141 avahi_simple_poll_quit(simple_poll);
142 return;
144 case AVAHI_BROWSER_NEW:
145 fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
147 /* We ignore the returned resolver object. In the callback
148 function we free it. If the server is terminated before
149 the callback function is called the server will free
150 the resolver for us. */
152 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
153 fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
155 break;
157 case AVAHI_BROWSER_REMOVE:
158 fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
159 break;
161 case AVAHI_BROWSER_ALL_FOR_NOW:
162 case AVAHI_BROWSER_CACHE_EXHAUSTED:
163 fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
164 break;
169 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
170 switch (state) {
171 case AVAHI_ENTRY_GROUP_ESTABLISHED :
172 /* The entry group has been established successfully */
173 break;
175 case AVAHI_ENTRY_GROUP_COLLISION : {
176 /* A service name collision with a remote service
177 * happened. */
178 break;
181 case AVAHI_ENTRY_GROUP_FAILURE :
182 /* Some kind of failure happened while we were registering our services */
183 avahi_simple_poll_quit(simple_poll);
184 break;
186 case AVAHI_ENTRY_GROUP_UNCOMMITED:
187 case AVAHI_ENTRY_GROUP_REGISTERING:
192 void create_services(AvahiClient *c) {
193 conn = virConnectOpen(NULL);
194 if (conn == NULL)
195 return;
196 int maxid = virConnectNumOfDomains(conn);
197 if (maxid > 1) { /* ignore dom0 */
198 int *ids = (int *) malloc(sizeof(int) * maxid);
199 if ((maxid = virConnectListDomains(conn, &ids[0], maxid)) < 0) {
200 // error
201 } else {
202 int i;
203 unsigned int domu_count_new = (maxid - 1);
204 domu * domus_old = domus;
205 domus = (domu *) malloc(sizeof(domu) * domu_count_new);
206 for (i = 0; i < domu_count_new; i++) {
207 int j;
208 domus[i].thisDomain = NULL;
209 domus[i].targetdomain = NULL;
210 domus[i].group = NULL;
211 domus[i].domainid = ids[i+1];
212 domus[i].keep = 0;
213 domus[i].cost = 100000.0f;
215 for (j = 0; j < domu_count; j++) {
216 if (ids[i+1] == domus_old[j].domainid) {
217 domus[i].group = domus_old[j].group;
218 domus_old[j].keep = 1;
221 if (i > domu_count || domus[i].group == NULL) {
222 char txt[254];
223 domus[i].thisDomain = virDomainLookupByID(conn, ids[i+1]);
224 snprintf(txt, 254, "memory=%lu", virDomainGetMaxMemory(domus[i].thisDomain));
225 txt[253] = '\0';
226 domus[i].keep = 1;
227 domus[i].group = avahi_entry_group_new(c, entry_group_callback, NULL);
228 avahi_entry_group_add_service(domus[i].group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,
229 virDomainGetName(domus[i].thisDomain), "_offer._tcp", NULL, NULL, 651, txt, NULL, NULL);
230 avahi_entry_group_commit(domus[i].group);
234 for (i = 0; i < domu_count; i++) {
235 if (domus_old[i].keep == 0) {
236 if (domus_old[i].group)
237 avahi_entry_group_free(domus_old[i].group);
238 if (domus_old[i].targetdomain)
239 free(domus_old[i].targetdomain);
240 virDomainFree(domus[i].thisDomain);
241 } else if (domus_old[i].thisDomain && domus_old[i].cost < 100000.0f) {
242 virConnectPtr dconn;
243 virDomainPtr ddomain;
244 char uri[128];
245 avahi_entry_group_free(domus_old[i].group);
246 snprintf(uri, 126, "xen://%s/", domus_old[i].targetdomain);
247 uri[127] = '\0';
248 dconn = virConnectOpen(uri);
249 domus_old[i].group = NULL;
250 if ((ddomain = virDomainMigrate(domus_old[i].thisDomain, dconn, VIR_MIGRATE_LIVE, NULL, NULL, 0)) == NULL)
251 printf("Migration failed!");
252 else {
253 printf("Migrated %s to %s\n", virDomainGetName(domus_old[i].thisDomain), domus_old[i].targetdomain);
254 virDomainFree(ddomain);
255 virConnectClose(conn);
260 free(domus_old);
261 domu_count = domu_count_new;
263 free(ids);
265 virConnectClose(conn);
269 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
270 assert(c);
272 /* Called whenever the client or server state changes */
274 switch (state) {
275 case AVAHI_CLIENT_S_RUNNING:
277 /* The server has startup successfully and registered its host
278 * name on the network, so it's time to create our services */
279 create_services(c);
280 break;
282 case AVAHI_CLIENT_FAILURE:
284 fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
285 avahi_simple_poll_quit(simple_poll);
287 break;
289 case AVAHI_CLIENT_S_COLLISION:
291 /* Let's drop our registered services. When the server is back
292 * in AVAHI_SERVER_RUNNING state we will register them
293 * again with the new host name. */
295 case AVAHI_CLIENT_S_REGISTERING:
297 /* The server records are now being established. This
298 * might be caused by a host name change. We need to wait
299 * for our own records to register until the host name is
300 * properly esatblished. */
302 /* if (group)
303 avahi_entry_group_reset(group);*/
305 break;
307 case AVAHI_CLIENT_CONNECTING:
314 static void modify_callback(AvahiTimeout *e, void *userdata) {
315 struct timeval tv;
316 AvahiClient *client = userdata;
318 // fprintf(stderr, "Doing some weird modification\n");
320 /* If the server is currently running, we need to remove our
321 * service and create it anew */
322 if (avahi_client_get_state(client) == AVAHI_CLIENT_S_RUNNING) {
323 /* And create them again with the new name */
324 create_services(client);
326 avahi_simple_poll_get(simple_poll)->timeout_update(e, avahi_elapse_time(&tv, 1000*POLL, 0));
331 int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
332 AvahiClient *client = NULL;
333 AvahiServiceBrowser *sb = NULL;
334 int error;
335 int ret = 1;
336 struct timeval tv;
337 /* Allocate main loop object */
338 if (!(simple_poll = avahi_simple_poll_new())) {
339 fprintf(stderr, "Failed to create simple poll object.\n");
340 goto fail;
343 /* Allocate a new client */
344 client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error);
346 /* Check wether creating the client object succeeded */
347 if (!client) {
348 fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
349 goto fail;
352 /* Create the service browser */
353 if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_tender._tcp", NULL, 0, browse_callback, NULL))) {
354 fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
355 goto fail;
358 /* After POLL seconds we will update the list of VMs and hope we have some domains to migrate off to */
359 avahi_simple_poll_get(simple_poll)->timeout_new(
360 avahi_simple_poll_get(simple_poll),
361 avahi_elapse_time(&tv, 1000*POLL, 0),
362 modify_callback,
363 client);
365 /* Run the main loop */
366 avahi_simple_poll_loop(simple_poll);
368 ret = 0;
370 fail:
372 /* Cleanup things */
374 if (client)
375 avahi_client_free(client);
377 if (simple_poll)
378 avahi_simple_poll_free(simple_poll);
380 return ret;