changeset 869:42df1cabf410

Merged package movement from geo-style back to default.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sat, 29 Sep 2018 22:35:53 +0200
parents 848c44e01060 (current diff) aa8f30c1ed27 (diff)
children 52fe3e20f750
files cmd/gemma/geoserver.go
diffstat 3 files changed, 340 insertions(+), 337 deletions(-) [+]
line wrap: on
line diff
--- a/cmd/gemma/geoserver.go	Sat Sep 29 22:24:31 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"log"
-	"net/http"
-	"strings"
-
-	"gemma.intevation.de/gemma/pkg/config"
-	"gemma.intevation.de/gemma/pkg/models"
-)
-
-const (
-	workspaceName  = "gemma"
-	datastoreName  = "gemma"
-	databaseScheme = "waterway"
-	databaseType   = "postgis"
-)
-
-const (
-	startupSQL = `SELECT public.setrole('${user,'||encode('waterway_user', 'hex')||'}')`
-	closeupSQL = `RESET ROLE`
-)
-
-func basicAuth(user, password string) func(req *http.Request) {
-	return func(req *http.Request) {
-		req.SetBasicAuth(user, password)
-	}
-}
-
-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
-
-	log.Println("info: creating workspace " + workspaceName)
-
-	const createJSON = `{"workspace":{"name":"` + workspaceName + `"}}`
-
-	req, err = http.NewRequest(
-		http.MethodPost,
-		url+"/rest/workspaces",
-		strings.NewReader(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 datastore.
-	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
-	}
-
-	// Create datastore.
-	log.Println("info: creating datastore " + datastoreName)
-
-	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()},
-					{"database", config.DBName()},
-					{"schema", databaseScheme},
-					{"user", config.DBUser()},
-					{"passwd", config.DBPassword()},
-					{"dbtype", databaseType},
-					{"Session startup SQL", startupSQL},
-					{"Session close-up SQL", closeupSQL},
-				},
-			},
-		},
-	}
-	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 ensureFeatures() error {
-	var (
-		url      = config.GeoServerURL()
-		user     = config.GeoServerUser()
-		password = config.GeoServerPassword()
-		auth     = basicAuth(user, password)
-	)
-
-	tables := models.InternalServices.Filter(models.IntWFS)
-	if len(tables) == 0 {
-		log.Println("info: no tables to publish")
-		return nil
-	}
-
-	log.Printf("info: number of tables to publish %d\n", len(tables))
-
-	var features struct {
-		FeatureTypes struct {
-			FeatureType []struct {
-				Name string `json:"name"`
-			} `json:"featureType"`
-		} `json:"featureTypes"`
-	}
-
-	hasFeature := func(name string) bool {
-		for _, ft := range features.FeatureTypes.FeatureType {
-			if ft.Name == name {
-				return true
-			}
-		}
-		return false
-	}
-
-	// Fetch all featuretypes.
-	req, err := http.NewRequest(
-		http.MethodGet,
-		url+"/rest/workspaces/"+workspaceName+
-			"/datastores/"+datastoreName+
-			"/featuretypes.json",
-		nil)
-	if err != nil {
-		return err
-	}
-	auth(req)
-	resp, err := http.DefaultClient.Do(req)
-	if err != nil {
-		return err
-	}
-
-	err = json.NewDecoder(resp.Body).Decode(&features)
-	resp.Body.Close()
-	if err != nil {
-		// XXX: Quirk in the JSON return by GeoServer:
-		// If there are no features in the datastore
-		// featureType deserializes to an empty string ""
-		// instead of an empty array *palmface*.
-		// So assume there no features.
-		hasFeature = func(string) bool { return false }
-	}
-
-	for i := range tables {
-		table := tables[i].Name
-
-		if hasFeature(table) {
-			log.Printf("info: featuretype %s already exists.\n", table)
-			continue
-		}
-
-		// Create featuretype.
-		log.Printf("info: creating featuretype %s.\n", table)
-
-		// Create featuretype
-		ft := map[string]interface{}{
-			"featureType": map[string]interface{}{
-				"name":       table,
-				"nativeName": table,
-				"title":      table,
-			},
-		}
-
-		var out bytes.Buffer
-		enc := json.NewEncoder(&out)
-		if err := enc.Encode(&ft); err != nil {
-			return err
-		}
-
-		req, err := http.NewRequest(
-			http.MethodPost,
-			url+"/rest/workspaces/"+workspaceName+
-				"/datastores/"+datastoreName+
-				"/featuretypes",
-			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 {
-			return fmt.Errorf("Status code '%s' (%d)",
-				http.StatusText(resp.StatusCode),
-				resp.StatusCode)
-		}
-	}
-
-	return nil
-}
-
-func prepareGeoServer() error {
-
-	if config.DBUser() == "" {
-		log.Println("info: Need metamorphic db user to configure GeoServer")
-		return nil
-	}
-
-	if config.GeoServerURL() == "" {
-		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: Styles
-
-	return ensureFeatures()
-}
--- a/cmd/gemma/main.go	Sat Sep 29 22:24:31 2018 +0200
+++ b/cmd/gemma/main.go	Sat Sep 29 22:35:53 2018 +0200
@@ -4,14 +4,11 @@
 	"context"
 	"fmt"
 	"log"
-	"net"
 	"net/http"
-	"net/url"
 	"os"
 	"os/signal"
 	"path/filepath"
 	"syscall"
-	"time"
 
 	"github.com/gorilla/mux"
 	"github.com/rs/cors"
@@ -20,6 +17,7 @@
 	"gemma.intevation.de/gemma/pkg/auth"
 	"gemma.intevation.de/gemma/pkg/config"
 	"gemma.intevation.de/gemma/pkg/controllers"
+	"gemma.intevation.de/gemma/pkg/geoserver"
 )
 
 func prepareSessionStore() {
@@ -41,30 +39,7 @@
 	prepareSessionStore()
 
 	// Do GeoServer setup in background.
-	go func() {
-		log.Println("Configure GeoServer...")
-		const maxTries = 10
-		const sleep = time.Second * 5
-
-		for try := 1; try <= maxTries; try++ {
-			err := prepareGeoServer()
-			if err == nil {
-				break
-			}
-			if try < maxTries {
-				if uerr, ok := err.(*url.Error); ok {
-					if oerr, ok := uerr.Err.(*net.OpError); ok && oerr.Op == "dial" {
-						log.Printf("Failed attempt %d of %d to configure GeoServer. "+
-							"Will try again in %s...\n", try, maxTries, sleep)
-						time.Sleep(sleep)
-						continue
-					}
-				}
-			}
-			log.Printf("warn: configure GeoServer failed: %v\n", err)
-			break
-		}
-	}()
+	go geoserver.ConfigureBoot()
 
 	m := mux.NewRouter()
 	controllers.BindRoutes(m)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/geoserver/boot.go	Sat Sep 29 22:35:53 2018 +0200
@@ -0,0 +1,338 @@
+package geoserver
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+
+	"gemma.intevation.de/gemma/pkg/config"
+	"gemma.intevation.de/gemma/pkg/models"
+)
+
+const (
+	workspaceName  = "gemma"
+	datastoreName  = "gemma"
+	databaseScheme = "waterway"
+	databaseType   = "postgis"
+)
+
+const (
+	startupSQL = `SELECT public.setrole('${user,'||encode('waterway_user', 'hex')||'}')`
+	closeupSQL = `RESET ROLE`
+)
+
+func basicAuth(user, password string) func(req *http.Request) {
+	return func(req *http.Request) {
+		req.SetBasicAuth(user, password)
+	}
+}
+
+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
+
+	log.Println("info: creating workspace " + workspaceName)
+
+	const createJSON = `{"workspace":{"name":"` + workspaceName + `"}}`
+
+	req, err = http.NewRequest(
+		http.MethodPost,
+		url+"/rest/workspaces",
+		strings.NewReader(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 datastore.
+	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
+	}
+
+	// Create datastore.
+	log.Println("info: creating datastore " + datastoreName)
+
+	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()},
+					{"database", config.DBName()},
+					{"schema", databaseScheme},
+					{"user", config.DBUser()},
+					{"passwd", config.DBPassword()},
+					{"dbtype", databaseType},
+					{"Session startup SQL", startupSQL},
+					{"Session close-up SQL", closeupSQL},
+				},
+			},
+		},
+	}
+	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 ensureFeatures() error {
+	var (
+		url      = config.GeoServerURL()
+		user     = config.GeoServerUser()
+		password = config.GeoServerPassword()
+		auth     = basicAuth(user, password)
+	)
+
+	tables := models.InternalServices.Filter(models.IntWFS)
+	if len(tables) == 0 {
+		log.Println("info: no tables to publish")
+		return nil
+	}
+
+	log.Printf("info: number of tables to publish %d\n", len(tables))
+
+	var features struct {
+		FeatureTypes struct {
+			FeatureType []struct {
+				Name string `json:"name"`
+			} `json:"featureType"`
+		} `json:"featureTypes"`
+	}
+
+	hasFeature := func(name string) bool {
+		for _, ft := range features.FeatureTypes.FeatureType {
+			if ft.Name == name {
+				return true
+			}
+		}
+		return false
+	}
+
+	// Fetch all featuretypes.
+	req, err := http.NewRequest(
+		http.MethodGet,
+		url+"/rest/workspaces/"+workspaceName+
+			"/datastores/"+datastoreName+
+			"/featuretypes.json",
+		nil)
+	if err != nil {
+		return err
+	}
+	auth(req)
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return err
+	}
+
+	err = json.NewDecoder(resp.Body).Decode(&features)
+	resp.Body.Close()
+	if err != nil {
+		// XXX: Quirk in the JSON return by GeoServer:
+		// If there are no features in the datastore
+		// featureType deserializes to an empty string ""
+		// instead of an empty array *palmface*.
+		// So assume there no features.
+		hasFeature = func(string) bool { return false }
+	}
+
+	for i := range tables {
+		table := tables[i].Name
+
+		if hasFeature(table) {
+			log.Printf("info: featuretype %s already exists.\n", table)
+			continue
+		}
+
+		// Create featuretype.
+		log.Printf("info: creating featuretype %s.\n", table)
+
+		// Create featuretype
+		ft := map[string]interface{}{
+			"featureType": map[string]interface{}{
+				"name":       table,
+				"nativeName": table,
+				"title":      table,
+			},
+		}
+
+		var out bytes.Buffer
+		enc := json.NewEncoder(&out)
+		if err := enc.Encode(&ft); err != nil {
+			return err
+		}
+
+		req, err := http.NewRequest(
+			http.MethodPost,
+			url+"/rest/workspaces/"+workspaceName+
+				"/datastores/"+datastoreName+
+				"/featuretypes",
+			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 {
+			return fmt.Errorf("Status code '%s' (%d)",
+				http.StatusText(resp.StatusCode),
+				resp.StatusCode)
+		}
+	}
+
+	return nil
+}
+
+func prepareGeoServer() error {
+
+	if config.DBUser() == "" {
+		log.Println("info: Need metamorphic db user to configure GeoServer")
+		return nil
+	}
+
+	if config.GeoServerURL() == "" {
+		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: Styles
+
+	return ensureFeatures()
+}
+
+func ConfigureBoot() {
+	log.Println("Configure GeoServer...")
+	const maxTries = 10
+	const sleep = time.Second * 5
+
+	for try := 1; try <= maxTries; try++ {
+		err := prepareGeoServer()
+		if err == nil {
+			break
+		}
+		if try < maxTries {
+			if uerr, ok := err.(*url.Error); ok {
+				if oerr, ok := uerr.Err.(*net.OpError); ok && oerr.Op == "dial" {
+					log.Printf("Failed attempt %d of %d to configure GeoServer. "+
+						"Will try again in %s...\n", try, maxTries, sleep)
+					time.Sleep(sleep)
+					continue
+				}
+			}
+		}
+		log.Printf("warn: configure GeoServer failed: %v\n", err)
+		break
+	}
+}