From 59ae9d00060da5329d7ca538974498292bbe1d91 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Tue, 26 Jun 2018 10:18:29 -0300
Subject: [PATCH 1/7] fence_gce: add support for stackdriver logging

Add --logging option to enable sending logs to google stackdriver
---
 agents/gce/fence_gce.py           | 65 +++++++++++++++++++++++++++++++++++++--
 tests/data/metadata/fence_gce.xml |  5 +++
 2 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/fence/agents/gce/fence_gce.py b/fence/agents/gce/fence_gce.py
index 3abb5207..3af5bfc8 100644
--- a/fence/agents/gce/fence_gce.py
+++ b/fence/agents/gce/fence_gce.py
@@ -1,12 +1,19 @@
 #!@PYTHON@ -tt
 
 import atexit
+import logging
+import platform
 import sys
+import time
 sys.path.append("@FENCEAGENTSLIBDIR@")
 
 import googleapiclient.discovery
 from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
 
+
+LOGGER = logging
+
+
 def translate_status(instance_status):
 	"Returns on | off | unknown."
 	if instance_status == "RUNNING":
@@ -27,6 +34,7 @@ def get_nodes_list(conn, options):
 
 	return result
 
+
 def get_power_status(conn, options):
 	try:
 		instance = conn.instances().get(
@@ -38,18 +46,37 @@ def get_power_status(conn, options):
 		fail_usage("Failed: get_power_status: {}".format(str(err)))
 
 
+def wait_for_operation(conn, project, zone, operation):
+	while True:
+		result = conn.zoneOperations().get(
+			project=project,
+			zone=zone,
+			operation=operation['name']).execute()
+		if result['status'] == 'DONE':
+			if 'error' in result:
+				raise Exception(result['error'])
+			return
+		time.sleep(1)
+
+
 def set_power_status(conn, options):
 	try:
 		if options["--action"] == "off":
-			conn.instances().stop(
+			LOGGER.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"]))
+			operation = conn.instances().stop(
 					project=options["--project"],
 					zone=options["--zone"],
 					instance=options["--plug"]).execute()
+			wait_for_operation(conn, options["--project"], options["--zone"], operation)
+			LOGGER.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"]))
 		elif options["--action"] == "on":
-			conn.instances().start(
+			LOGGER.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"]))
+			operation = conn.instances().start(
 					project=options["--project"],
 					zone=options["--zone"],
 					instance=options["--plug"]).execute()
+			wait_for_operation(conn, options["--project"], options["--zone"], operation)
+			LOGGER.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"]))
 	except Exception as err:
 		fail_usage("Failed: set_power_status: {}".format(str(err)))
 
@@ -71,11 +98,24 @@ def define_new_opts():
 		"required" : "1",
 		"order" : 3
 	}
+	all_opt["logging"] = {
+		"getopt" : ":",
+		"longopt" : "logging",
+		"help" : "--logging=[bool]               Logging, true/false",
+		"shortdesc" : "Stackdriver-logging support.",
+		"longdesc" : "If enabled (set to true), IP failover logs will be posted to stackdriver logging.",
+		"required" : "0",
+		"default" : "false",
+		"order" : 4
+	}
 
 def main():
 	conn = None
+	global LOGGER
+
+	hostname = platform.node()
 
-	device_opt = ["port", "no_password", "zone", "project"]
+	device_opt = ["port", "no_password", "zone", "project", "logging"]
 
 	atexit.register(atexit_handler)
 
@@ -97,6 +137,25 @@ def main():
 
 	run_delay(options)
 
+	# Prepare logging
+	logging_env = options.get('--logging')
+	if logging_env:
+		logging_env = logging_env.lower()
+		if any(x in logging_env for x in ['yes', 'true', 'enabled']):
+			try:
+				import google.cloud.logging.handlers
+				client = google.cloud.logging.Client()
+				handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
+				formatter = logging.Formatter('gcp:stonish "%(message)s"')
+				LOGGER = logging.getLogger(hostname)
+				handler.setFormatter(formatter)
+				LOGGER.addHandler(handler)
+				LOGGER.setLevel(logging.INFO)
+			except ImportError:
+				LOGGER.error('Couldn\'t import google.cloud.logging, '
+					'disabling Stackdriver-logging support')
+
+	# Prepare cli
 	try:
 		credentials = None
 		if tuple(googleapiclient.__version__) < tuple("1.6.0"):
diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
index 2a147f21..805ecc6b 100644
--- a/tests/data/metadata/fence_gce.xml
+++ b/tests/data/metadata/fence_gce.xml
@@ -30,6 +30,11 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui
 		<content type="string"  />
 		<shortdesc lang="en">Project ID.</shortdesc>
 	</parameter>
+	<parameter name="logging" unique="0" required="0">
+		<getopt mixed="--logging=[bool]" />
+		<content type="string" default="false"  />
+		<shortdesc lang="en">Stackdriver-logging support.</shortdesc>
+	</parameter>
 	<parameter name="quiet" unique="0" required="0">
 		<getopt mixed="-q, --quiet" />
 		<content type="boolean"  />
-- 
2.16.4

