Skip to content

Instantly share code, notes, and snippets.

@Trumeet
Created October 11, 2020 21:37
Show Gist options
  • Save Trumeet/2abb2788644a6df4a0f86297d6689807 to your computer and use it in GitHub Desktop.
Save Trumeet/2abb2788644a6df4a0f86297d6689807 to your computer and use it in GitHub Desktop.
EvictPowerSrv Linux version rewritten in C.
/*
* Shutdown the system properly when Azure evicts your Spot instance.
*
* Compile:
* Requires libcurl 4 and json-c 5 headers.
* cc -Wall -Werror -lcurl -ljson-c main.c
*
* Running:
* Requires `shutdown` command and the rights to execute it.
* Requires libcurl.so.4, libjson-c.so.5, and glibc.
*
* Daemon:
* Write yourself a systemd (or whatever service manager you are using) to run the program in background.
*
* License:
* GPL v2 only.
*/
#include <string.h>
#include <curl/curl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <json-c/json.h>
#define WAIT_ERR 5
#define WAIT_NONEED 3
// #define DEBUG 1
size_t cb(void *data, size_t size, size_t nmemb, void *ptr)
{
size_t realsize = size * nmemb;
#ifdef DEBUG
printf("cb(%lu)\n", realsize);
#endif
char *str = (char*)data;
json_object *obj = json_tokener_parse(str);
if (obj == NULL)
{
fprintf(stderr, "Cannot parse JSON");
return 0;
}
json_object *events = json_object_object_get(obj, "Events");
if (events == NULL)
{
free(obj);
fprintf(stderr, "Cannot obtain Events info");
return 0;
}
int shutdown = 0;
for (int i = 0; i < json_object_array_length(events); i ++)
{
json_object *current = json_object_array_get_idx(events, i);
if (current == NULL)
{
fprintf(stderr, "Cannot get the event information of %u", i);
free(events);
free(obj);
return 0;
}
json_object *type = json_object_object_get(current, "EventType");
if (type == NULL)
{
fprintf(stderr, "Cannot get the EventType");
free(current);
free(events);
free(obj);
return 0;
}
if (!strcmp(json_object_get_string(type), "Preempt"))
{
printf("The system is being preempted. Shutting down immediatedly.\n");
shutdown = 1;
}
free(type);
free(current);
if (shutdown)
break;
}
free(events);
free(obj);
if (shutdown)
{
// TODO: There should be a better way to do so.
if (system("shutdown now"))
{
fprintf(stderr, "Could not shutdown.\n");
return 0;
}
}
return realsize;
}
int main(int argc, char *argv[])
{
CURL *curl = curl_easy_init();
if (!curl)
{
fprintf(stderr, "Cannot create curl instance.\n");
return 1;
}
// Set CURL opts.
curl_easy_setopt(curl, CURLOPT_URL, "http://169.254.169.254/metadata/scheduledevents?api-version=2019-08-01");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Metadata: true");
#ifdef DEBUG
printf("Headers: %p\n", headers);
#endif
if (!headers)
{
fprintf(stderr, "Cannot create headers\n");
return 2;
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);
// Begin loop
while(1)
{
#ifdef DEBUG
printf("Requesting...\n");
#endif
CURLcode res = curl_easy_perform(curl);
if (res)
{
fprintf(stderr, "Cannot request scheduled events: %d\n", res);
sleep(WAIT_ERR);
continue;
}
#ifdef DEBUG
printf("No need to do anything.\n");
#endif
sleep(WAIT_NONEED);
}
// TODO: Do we need to clean up?
#ifdef DEBUG
printf("Cleaning up\n");
#endif
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment