changeset 386:999f4f83a072

Configure GeoServer via REST-API. TODO: Configure layers.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 13 Aug 2018 13:41:08 +0200
parents 3cfab707f909
children 0f78b13f4a9a
files cmd/gemma/geoserver.go cmd/gemma/main.go config/config.go misc/encode.go
diffstat 4 files changed, 207 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/gemma/geoserver.go	Mon Aug 13 13:41:08 2018 +0200
@@ -0,0 +1,188 @@
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+
+	"gemma.intevation.de/gemma/config"
+	"gemma.intevation.de/gemma/misc"
+)
+
+const (
+	workspaceName  = "gemma"
+	datastoreName  = "gemma"
+	databaseScheme = "waterway"
+	databaseType   = "postgis"
+)
+
+const startupSQL = `SET SESSION AUTHORIZATION waterway_user;`
+
+func basicAuth(user, password string) func(req *http.Request) {
+	auth := "Basic " + misc.BasicAuth(user, password)
+	return func(req *http.Request) {
+		req.Header.Add("Authorization", auth)
+	}
+}
+
+func asJSON(req *http.Request) {
+	req.Header.Set("Content-Type", "application/json")
+}
+
+func ensureWorkspace() error {
+	var (
+		url      = config.GeoServerURL()
+		user     = config.GeoServerUser()
+		password = config.GeoServerPassword()
+		auth     = basicAuth(user, password)
+	)
+
+	// Probe  workspace.
+	req, err := http.NewRequest(
+		http.MethodGet,
+		url+"/rest/workspaces/"+workspaceName+".json",
+		nil)
+	if err != nil {
+		return err
+	}
+	auth(req)
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return err
+	}
+
+	if resp.StatusCode != http.StatusNotFound {
+		log.Println("info: workspace " + workspaceName + " already exists.")
+		return nil
+	}
+
+	// Create workspace
+	const createJSON = `{"workspace":{"name":"` + workspaceName + `"}}`
+
+	req, err = http.NewRequest(
+		http.MethodPost,
+		url+"/rest/workspaces",
+		bytes.NewReader([]byte(createJSON)))
+	if err != nil {
+		return err
+	}
+	auth(req)
+	asJSON(req)
+	if resp, err = http.DefaultClient.Do(req); err != nil {
+		return err
+	}
+
+	if resp.StatusCode != http.StatusCreated {
+		err = fmt.Errorf("Status code '%s' (%d)",
+			http.StatusText(resp.StatusCode),
+			resp.StatusCode)
+	}
+
+	return err
+}
+
+func ensureDataStore() error {
+	var (
+		url      = config.GeoServerURL()
+		user     = config.GeoServerUser()
+		password = config.GeoServerPassword()
+		auth     = basicAuth(user, password)
+	)
+
+	// Probe  workspace.
+	req, err := http.NewRequest(
+		http.MethodGet,
+		url+"/rest/workspaces/"+workspaceName+"/datastores/"+datastoreName+".json",
+		nil)
+	if err != nil {
+		return err
+	}
+	auth(req)
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return err
+	}
+
+	if resp.StatusCode != http.StatusNotFound {
+		log.Println("info: datastore " + datastoreName + " already exists.")
+		return nil
+	}
+
+	type entry struct {
+		Key   interface{} `json:"@key"`
+		Value interface{} `json:"$"`
+	}
+
+	// Create datastore.
+	ds := map[string]interface{}{
+		"dataStore": map[string]interface{}{
+			"name": datastoreName,
+			"connectionParameters": map[string]interface{}{
+				"entry": []entry{
+					{"host", config.DBHost()},
+					{"port", config.DBPort()},
+					{"schema", databaseScheme},
+					{"user", config.SysAdmin()},
+					{"passwd", config.SysAdminPassword()},
+					{"dbtype", databaseType},
+					{"Session startup SQL", startupSQL},
+				},
+			},
+		},
+	}
+	var out bytes.Buffer
+	enc := json.NewEncoder(&out)
+	if err := enc.Encode(&ds); err != nil {
+		return err
+	}
+
+	req, err = http.NewRequest(
+		http.MethodPost,
+		url+"/rest/workspaces/"+workspaceName+"/datastores",
+		bytes.NewReader(out.Bytes()))
+	if err != nil {
+		return err
+	}
+	auth(req)
+	asJSON(req)
+	resp, err = http.DefaultClient.Do(req)
+	if err != nil {
+		return err
+	}
+
+	if resp.StatusCode != http.StatusCreated {
+		err = fmt.Errorf("Status code '%s' (%d)",
+			http.StatusText(resp.StatusCode),
+			resp.StatusCode)
+	}
+
+	return err
+}
+
+func prepareGeoServer() error {
+
+	var (
+		url = config.GeoServerURL()
+		//tables   = config.GeoServerTables()
+	)
+
+	//if url == "" || len(tables) == 0 {
+	if url == "" {
+		log.Println("info: No tables to publish on GeoServer")
+		return nil
+	}
+
+	if err := ensureWorkspace(); err != nil {
+		return err
+	}
+
+	if err := ensureDataStore(); err != nil {
+		return err
+	}
+
+	// TODO: Create layers.
+
+	return nil
+}
--- a/cmd/gemma/main.go	Mon Aug 13 11:17:56 2018 +0200
+++ b/cmd/gemma/main.go	Mon Aug 13 13:41:08 2018 +0200
@@ -37,6 +37,13 @@
 
 	prepareConnectionPool()
 
+	// Do GeoServer setup in background.
+	go func() {
+		if err := prepareGeoServer(); err != nil {
+			log.Printf("warn: preparing GeoServer: %v\n", err)
+		}
+	}()
+
 	m := mux.NewRouter()
 	controllers.BindRoutes(m)
 
--- a/config/config.go	Mon Aug 13 11:17:56 2018 +0200
+++ b/config/config.go	Mon Aug 13 13:41:08 2018 +0200
@@ -25,6 +25,9 @@
 func ServiceUser() string     { return viper.GetString("service-user") }
 func ServicePassword() string { return viper.GetString("service-password") }
 
+func SysAdmin() string         { return viper.GetString("sys-admin") }
+func SysAdminPassword() string { return viper.GetString("sys-admin-password") }
+
 func MailHost() string     { return viper.GetString("mail-host") }
 func MailPort() uint       { return uint(viper.GetInt32("mail-port")) }
 func MailUser() string     { return viper.GetString("mail-user") }
@@ -96,6 +99,9 @@
 	str("service-user", "postgres", "user to do service tasks")
 	str("service-password", "", "password of user to do service tasks")
 
+	str("sys-admin", "postgres", "user to do admin tasks")
+	str("sys-admin-password", "", "password of user to do admin tasks")
+
 	str("mail-host", "localhost", "server to send mail with")
 	ui("mail-port", 465, "port of server to send mail with")
 	str("mail-user", "gemma", "user to send mail with")
--- a/misc/encode.go	Mon Aug 13 11:17:56 2018 +0200
+++ b/misc/encode.go	Mon Aug 13 13:41:08 2018 +0200
@@ -1,6 +1,7 @@
 package misc
 
 import (
+	"encoding/base64"
 	"encoding/binary"
 	"io"
 )
@@ -68,3 +69,8 @@
 		w.Err = binary.Write(w.Writer, binary.BigEndian, []byte(s))
 	}
 }
+
+func BasicAuth(user, password string) string {
+	auth := user + ":" + password
+	return base64.StdEncoding.EncodeToString([]byte(auth))
+}