Created
October 11, 2020 21:37
-
-
Save Trumeet/2abb2788644a6df4a0f86297d6689807 to your computer and use it in GitHub Desktop.
EvictPowerSrv Linux version rewritten in C.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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