From fc893330770c9bae12fb251ddcc3b7b20908895f Mon Sep 17 00:00:00 2001 From: Stefan de Konink Date: Thu, 7 Aug 2008 13:45:48 +0200 Subject: [PATCH] Initial combination of announce and domudns --- migrateoff.c | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 migrateoff.c diff --git a/migrateoff.c b/migrateoff.c new file mode 100644 index 0000000..222d6ee --- /dev/null +++ b/migrateoff.c @@ -0,0 +1,365 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define POLL 5 + +struct list_el { + unsigned short keep; + unsigned int domainid; + float cost; + char *targetdomain; + virDomainPtr thisDomain; + AvahiEntryGroup *group; +}; + +virConnectPtr conn = NULL; +typedef struct list_el domu; + +domu * domus = NULL; /* list of domains */ +unsigned int domu_count = 0; +static AvahiSimplePoll *simple_poll = NULL; + +static void resolve_callback( + AvahiServiceResolver *r, + AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void* userdata) { + + assert(r); + + /* Called whenever a service has been resolved successfully or timed out */ + + switch (event) { + case AVAHI_RESOLVER_FAILURE: + 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)))); + break; + + case AVAHI_RESOLVER_FOUND: { + char a[AVAHI_ADDRESS_STR_MAX], *t; + AvahiStringList *needle; + + fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); + + avahi_address_snprint(a, sizeof(a), address); + t = avahi_string_list_to_string(txt); + fprintf(stderr, + "\t%s:%u (%s)\n" + "\tTXT=%s\n" + "\tcookie is %u\n" + "\tis_local: %i\n" + "\tour_own: %i\n" + "\twide_area: %i\n" + "\tmulticast: %i\n" + "\tcached: %i\n", + host_name, port, a, + t, + avahi_string_list_get_service_cookie(txt), + !!(flags & AVAHI_LOOKUP_RESULT_LOCAL), + !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN), + !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA), + !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST), + !!(flags & AVAHI_LOOKUP_RESULT_CACHED)); + + avahi_free(t); + + for (i = 0; i < domu_count; i++) { + const char *thisName = virDomainGetName(domu[i].thisDomain); + unsigned int len = strlen(thisName); + + if (strlen(name) > len && name[len] == '.' && strncmp(thisName, name, len) == 0) { + if ((needle = avahi_string_list_find (txt, "cost")) != NULL) { + + float amount; + char *cost; + avahi_string_list_get_pair (needle, NULL, &cost, NULL); + amount = atof(cost); + + printf("%s: I'll run the VM for the competing cost of L$W %f\n", host_name, amount); + if (errno != ERANGE && amount < domu[i]->cost) { + domu[i]->cost = amount; + free(domu[i]->domain); + domu[i]->domain = strdup(&name[++len]); + } + + avahi_free(cost); + } + break; + } + } + } + } + + avahi_service_resolver_free(r); +} + +static void browse_callback( + AvahiServiceBrowser *b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) { + + assert(b); + AvahiClient *c = avahi_service_browser_get_client(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + + switch (event) { + case AVAHI_BROWSER_FAILURE: + + fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + avahi_simple_poll_quit(simple_poll); + return; + + case AVAHI_BROWSER_NEW: + fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + + /* We ignore the returned resolver object. In the callback + function we free it. If the server is terminated before + the callback function is called the server will free + the resolver for us. */ + + if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata))) + fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); + + break; + + case AVAHI_BROWSER_REMOVE: + fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain); + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); + break; + } +} + + +static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) { + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + /* The entry group has been established successfully */ + break; + + case AVAHI_ENTRY_GROUP_COLLISION : { + /* A service name collision with a remote service + * happened. */ + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + /* Some kind of failure happened while we were registering our services */ + avahi_simple_poll_quit(simple_poll); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + } +} + +void create_services(AvahiClient *c) { + conn = virConnectOpenReadOnly(NULL); + if (conn == NULL) + return; + int maxid = virConnectNumOfDomains(conn); + if (maxid > 1) { /* ignore dom0 */ + int *ids = (int *) malloc(sizeof(int) * maxid); + if ((maxid = virConnectListDomains(conn, &ids[0], maxid)) < 0) { + // error + } else { + int i; + unsigned int domu_count_new = (maxid - 1); + domu * domus_old = domus; + domus = (domu *) malloc(sizeof(domu) * domu_count_new); + for (i = 0; i < domu_count_new; i++) { + int j; + domus[i].group = NULL; + domus[i].domainid = ids[i+1]; + domus[i].keep = 0; + + for (j = 0; j < domu_count; j++) { + if (ids[i+1] == domus_old[j].domainid) { + domus[i].group = domus_old[j].group; + domus_old[j].keep = 1; + } + } + if (i > domu_count || domus[i].group == NULL) { + char txt[254]; + domus[i].thisDomain = virDomainLookupByID(conn, ids[i+1]); + snprintf(txt, 254, "memory=%lu", virDomainGetMaxMemory(domus[i].thisDomain)); + txt[253] = '\0' + domus[i].keep = 1; + domus[i].domain = NULL; + domus[i].cost = 100000.0f; + domus[i].group = avahi_entry_group_new(c, entry_group_callback, NULL); + avahi_entry_group_add_service(domus[i].group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, + virDomainGetName(domus[i].thisDomain), "_offer._tcp", NULL, NULL, 651, txt, NULL, NULL); + avahi_entry_group_commit(domus[i].group); + } + } + + for (i = 0; i < domu_count; i++) { + if (domus_old[i].keep == 0) { + if (domus_old[i].group) + avahi_entry_group_free(domus_old[i].group); + if (domus_old[i].domain) + free(domus_old[i].domain); + virDomainFree(domus[i].thisDomain); + } else if (domus_old[i].cost < 100000.0f) { + avahi_entry_group_free(domus_old[i].group); + domus_old[i].group = NULL; + printf("Migrate %s to %s\n", virDomainGetName(domus[i].thisDomain), domus[i].domain); + } + } + + free(domus_old); + domu_count = domu_count_new; + } + free(ids); + } + virConnectClose(conn); +} + + +static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) { + assert(c); + + /* Called whenever the client or server state changes */ + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + + /* The server has startup successfully and registered its host + * name on the network, so it's time to create our services */ + create_services(c); + break; + + case AVAHI_CLIENT_FAILURE: + + fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c))); + avahi_simple_poll_quit(simple_poll); + + break; + + case AVAHI_CLIENT_S_COLLISION: + + /* Let's drop our registered services. When the server is back + * in AVAHI_SERVER_RUNNING state we will register them + * again with the new host name. */ + + case AVAHI_CLIENT_S_REGISTERING: + + /* The server records are now being established. This + * might be caused by a host name change. We need to wait + * for our own records to register until the host name is + * properly esatblished. */ + +/* if (group) + avahi_entry_group_reset(group);*/ + + break; + + case AVAHI_CLIENT_CONNECTING: + ; + } +} + + + +static void modify_callback(AvahiTimeout *e, void *userdata) { + struct timeval tv; + AvahiClient *client = userdata; + +// fprintf(stderr, "Doing some weird modification\n"); + + /* If the server is currently running, we need to remove our + * service and create it anew */ + if (avahi_client_get_state(client) == AVAHI_CLIENT_S_RUNNING) { + /* And create them again with the new name */ + create_services(client); + + avahi_simple_poll_get(simple_poll)->timeout_update(e, avahi_elapse_time(&tv, 1000*POLL, 0)); + } + + +} +int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) { + AvahiClient *client = NULL; + AvahiServiceBrowser *sb = NULL; + int error; + int ret = 1; + struct timeval tv; + /* Allocate main loop object */ + if (!(simple_poll = avahi_simple_poll_new())) { + fprintf(stderr, "Failed to create simple poll object.\n"); + goto fail; + } + + /* Allocate a new client */ + client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error); + + /* Check wether creating the client object succeeded */ + if (!client) { + fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error)); + goto fail; + } + + /* Create the service browser */ + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_tender._tcp", NULL, 0, browse_callback, this))) { + fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); + goto fail; + } + + /* After POLL seconds we will update the list of VMs and hope we have some domains to migrate off to */ + avahi_simple_poll_get(simple_poll)->timeout_new( + avahi_simple_poll_get(simple_poll), + avahi_elapse_time(&tv, 1000*POLL, 0), + modify_callback, + client); + + /* Run the main loop */ + avahi_simple_poll_loop(simple_poll); + + ret = 0; + +fail: + + /* Cleanup things */ + + if (client) + avahi_client_free(client); + + if (simple_poll) + avahi_simple_poll_free(simple_poll); + + return ret; +} + -- 2.11.4.GIT