CORD-281 CORD-551 hide secret for switchq and pull images on deploy

Change-Id: Ie0a5f4b1f9804391b058b25663ba10fa73df4746
diff --git a/automation/state.go b/automation/state.go
index f305509..3769d2d 100644
--- a/automation/state.go
+++ b/automation/state.go
@@ -207,7 +207,7 @@
 		})
 
 		if err != nil {
-			log.Errorf("unable to provision '%s' (%s) : %s", node.ID, node.Hostname(), err)
+			log.Errorf("unable to provision '%s' (%s) : %s", node.ID(), node.Hostname(), err)
 		}
 
 	} else if options.ProvisionTTL > 0 &&
diff --git a/roles/maas/tasks/main.yml b/roles/maas/tasks/main.yml
index 540c843..83c43b1 100644
--- a/roles/maas/tasks/main.yml
+++ b/roles/maas/tasks/main.yml
@@ -320,16 +320,17 @@
     group: docker
     mode: 0755
 
-- name: Ensure MAAS API Key Secret
+- name: Ensure Automation Container Secrets
   become: yes
-  lineinfile:
-    dest: /etc/maas/secrets/automation.env
-    create: true
-    regexp: "^AUTOMATION_MAAS_API_KEY=.*$"
-    line: "AUTOMATION_MAAS_API_KEY={{ apikey.stdout }}"
+  template:
+    src: templates/{{ item }}.j2
+    dest: /etc/maas/secrets/{{ item }}
     owner: root
     group: docker
     mode: 0440
+  with_items:
+    - automation.env
+    - switchq.env
 
 - name: Custom Automation Compose Configurations
   become: yes
@@ -342,7 +343,28 @@
   with_items:
     - automation-compose.yml
 
-- name: Automation
+- name: Kill Automation Containers
+  become: yes
+  command: docker-compose -f /etc/maas/{{ item }} kill
+  with_items:
+    - automation-compose.yml
+  changed_when: true
+
+- name: Remove Automation Containers
+  become: yes
+  command: docker-compose -f /etc/maas/{{ item }} rm -f
+  with_items:
+    - automation-compose.yml
+  changed_when: true
+
+- name: Pull Latest Automation Images
+  become: yes
+  command: docker-compose -f /etc/maas/{{ item }} pull
+  with_items:
+    - automation-compose.yml
+  changed_when: true
+
+- name: Start Automation
   become: yes
   command: docker-compose -f /etc/maas/{{ item }} up -d
   with_items:
diff --git a/roles/maas/templates/automation-compose.yml.j2 b/roles/maas/templates/automation-compose.yml.j2
index 52467f2..78ddb3a 100644
--- a/roles/maas/templates/automation-compose.yml.j2
+++ b/roles/maas/templates/automation-compose.yml.j2
@@ -72,6 +72,8 @@
       - "lab.component=switchq"
     links:
       - provisioner
+    env_file:
+      - "/etc/maas/secrets/switchq.env"
     environment:
       - "SWITCHQ_SCRIPT=/etc/maas/ansible/do-switch"
       - "SWITCHQ_PROVISION_URL=http://provisioner:4243/provision/"
@@ -81,7 +83,6 @@
       - "SWITCHQ_LOG_LEVEL=debug"
       - "SWITCHQ_LOG_FORMAT=text"
       - "SWITCHQ_MAAS_URL=http://{{ mgmt_ip_address.stdout }}/MAAS"
-      - "SWITCHQ_MAAS_API_KEY={{ apikey.stdout }}"
     volumes:
       - "/etc/bind/maas:/switchq/dhcp"
     restart: unless-stopped
diff --git a/roles/maas/templates/automation.env.j2 b/roles/maas/templates/automation.env.j2
new file mode 100644
index 0000000..679cd8e
--- /dev/null
+++ b/roles/maas/templates/automation.env.j2
@@ -0,0 +1 @@
+AUTOMATION_MAAS_API_KEY={{ apikey.stdout }}
diff --git a/roles/maas/templates/switchq.env.j2 b/roles/maas/templates/switchq.env.j2
new file mode 100644
index 0000000..314e684
--- /dev/null
+++ b/roles/maas/templates/switchq.env.j2
@@ -0,0 +1 @@
+SWITCHQ_MAAS_API_KEY={{ apikey.stdout }}
diff --git a/switchq/switchq.go b/switchq/switchq.go
index deddf74..e946ff1 100644
--- a/switchq/switchq.go
+++ b/switchq/switchq.go
@@ -21,19 +21,21 @@
 	"github.com/gorilla/mux"
 	maas "github.com/juju/gomaasapi"
 	"github.com/kelseyhightower/envconfig"
+	"io/ioutil"
 	"net/http"
+	"regexp"
 	"sync"
 	"time"
 )
 
 type Config struct {
-	VendorsURL      string `default:"file:///switchq/vendors.json" envconfig:"vendors_url"`
-	AddressURL      string `default:"file:///switchq/dhcp_harvest.inc" envconfig:"address_url"`
-	PollInterval    string `default:"1m" envconfig:"poll_interval"`
-	ProvisionTTL    string `default:"1h" envconfig:"provision_ttl"`
-	ProvisionURL    string `default:"" envconfig:"provision_url"`
-	RoleSelectorURL string `default:"" envconfig:"role_selector_url"`
-	DefaultRole     string `default:"fabric-switch" envconfig:"default_role"`
+	VendorsURL      string `default:"file:///switchq/vendors.json" envconfig:"VENDORS_URL"`
+	AddressURL      string `default:"file:///switchq/dhcp_harvest.inc" envconfig:"ADDRESS_URL"`
+	PollInterval    string `default:"1m" envconfig:"POLL_INTERVAL"`
+	ProvisionTTL    string `default:"1h" envconfig:"PROVISION_TTL"`
+	ProvisionURL    string `default:"" envconfig:"PROVISION_URL"`
+	RoleSelectorURL string `default:"" envconfig:"ROLE_SELECTOR_URL"`
+	DefaultRole     string `default:"fabric-switch" envconfig:"DEFAULT_ROLE"`
 	Script          string `default:"do-ansible"`
 	LogLevel        string `default:"warning" envconfig:"LOG_LEVEL"`
 	LogFormat       string `default:"text" envconfig:"LOG_FORMAT"`
@@ -41,6 +43,8 @@
 	Port            int    `default:"4244"`
 	MaasURL         string `default:"http://localhost/MAAS" envconfig:"MAAS_URL"`
 	MaasKey         string `default:"" envconfig:"MAAS_API_KEY"`
+	ShowApiKey      bool   `default:"false" envconfig:"MAAS_SHOW_API_KEY"`
+	ApiKeyFile      string `default:"/secrets/maas_api_key" envconfig:"MAAS_API_KEY_FILE"`
 
 	vendors       Vendors
 	addressSource AddressSource
@@ -302,25 +306,33 @@
 	}
 	log.Level = level
 
+	re := regexp.MustCompile("[^:]")
+	pubKey := context.config.MaasKey
+	if !context.config.ShowApiKey {
+		pubKey = re.ReplaceAllString(context.config.MaasKey, "X")
+	}
+
 	log.Infof(`Configuration:
-		Vendors URL:       %s
-		Poll Interval:     %s
-		Address Source:    %s
-		Provision TTL:     %s
-		Provision URL:     %s
-		Role Selector URL: %s
-		Default Role:      %s
-		Script:            %s
-		API Listen IP:     %s
-		API Listen Port:   %d
-		MAAS URL:          %s
-		MAAS APIKEY:       %s
-		Log Level:         %s
-		Log Format:        %s`,
+		VENDORS_URL:       %s
+		POLL_INTERVAL:     %s
+		ADDRESS_URL:       %s
+		PROVISION_TTL:     %s
+		PROVISION_URL:     %s
+		ROLE_SELECTOR_URL: %s
+		DEFAULT_ROLE:      %s
+		SCRIPT:            %s
+		LISTEN:            %s
+		PORT:              %d
+		MAAS_URL:          %s
+		MAAS_SHOW_API_KEY  %t
+		MAAS_API_KEY:      %s
+		MAAS_API_KEY_FILE: %s
+		LOG_LEVEL:         %s
+		LOG_FORMAT:        %s`,
 		context.config.VendorsURL, context.config.PollInterval, context.config.AddressURL, context.config.ProvisionTTL,
 		context.config.ProvisionURL, context.config.RoleSelectorURL, context.config.DefaultRole, context.config.Script,
-		context.config.Listen, context.config.Port, context.config.MaasURL, context.config.MaasKey,
-		context.config.LogLevel, context.config.LogFormat)
+		context.config.Listen, context.config.Port, context.config.MaasURL, context.config.ShowApiKey, pubKey,
+		context.config.ApiKeyFile, context.config.LogLevel, context.config.LogFormat)
 
 	context.config.vendors, err = NewVendors(context.config.VendorsURL)
 	checkError(err, "Unable to create known vendors list from specified URL '%s' : %s", context.config.VendorsURL, err)
@@ -334,6 +346,24 @@
 	context.config.ttl, err = time.ParseDuration(context.config.ProvisionTTL)
 	checkError(err, "Unable to parse specified provision TTL value of '%s' : %s", context.config.ProvisionTTL, err)
 
+	// Attempt to load the API key from a file if it was not set via the environment
+	// and if the file exists
+	if context.config.MaasKey == "" {
+		log.Debugf("Attempting to read MAAS API key from file '%s', because it was not set via environment", context.config.ApiKeyFile)
+		keyBytes, err := ioutil.ReadFile(context.config.ApiKeyFile)
+		if err != nil {
+			log.Warnf("Failed to read MAAS API key from file '%s', was the file mounted as a volume? : %s ",
+				context.config.ApiKeyFile, err)
+		} else {
+			context.config.MaasKey = string(keyBytes)
+			if context.config.ShowApiKey {
+				pubKey = context.config.MaasKey
+			} else {
+				pubKey = re.ReplaceAllString(context.config.MaasKey, "X")
+			}
+		}
+	}
+
 	if len(context.config.MaasURL) > 0 {
 
 		// Attempt to connect to MAAS