diff --git a/pool.go b/pool.go index ce6c1ef..dc8c7ae 100644 --- a/pool.go +++ b/pool.go @@ -1,6 +1,8 @@ package main import ( + "database/sql" + "encoding/json" "fmt" "dim/query" @@ -141,9 +143,93 @@ func PoolList(c *Context, req Request, res *Response) error { } func PoolGetAttr(c *Context, req Request, res *Response) error { + name := "" + if err := req.ParseAtLeast(1, &name); err != nil { + res.AddMessage(LevelError, "could not parse name: %s", err) + return nil + } + if name == "" { + res.AddMessage(LevelError, "empty name was provided") + return nil + } + + result := json.RawMessage{} + selClause := query.FieldsToJSON("p", map[string]string{ + "name": "p.name", + "modified_by": "p.modified_by", + "modified_at": "p.modified_at", + "created_by": "p.created_by", + "created_at": "p.created_at", + "layer3domain": "l.name", + }) + queryStr := fmt.Sprintf(`select %s from pools p join layer3domains l + on p.layer3domain_id = l.id + where p.name = $1`, selClause) + err := c.tx.QueryRow(queryStr, name).Scan(&result) + if err != nil { + res.AddMessage(LevelError, "could not return result") + return fmt.Errorf("could not get pool '%s': %s - query: %s", name, err, queryStr) + } + res.Result = result return nil } func PoolSetAttr(c *Context, req Request, res *Response) error { + name := "" + attrs := types.FieldMap{} + if err := req.ParseAtLeast(2, &name, &attrs); err != nil { + res.AddMessage(LevelError, "could not parse options: %s", err) + return nil + } + if name == "" { + res.AddMessage(LevelError, "empty name was provided") + return nil + } + if attrs.Size() == 0 { + res.AddMessage(LevelError, "no key/value pairs provided to update") + return nil + } + + // TODO this is ugly. Can we have better API somehow? + fieldMap := map[string]string{ + "name": "", + "modified_by": "", + "modified_at": "", + "created_by": "", + "created_at": "", + "layer3domain_id": "", + } + if attrs.Contains("subnets") { + res.AddMessage(LevelError, "can not set subnets as attributes") + return nil + } + if attrs.Contains("layer3domain") { + l3name := attrs.Fields()["layer3domain"] + attrs.Delete("layer3domain") + l3id := 0 + err := c.tx.QueryRow(`select id from layer3domains where name = $1`, l3name).Scan(&l3id) + if err != nil { + if err == sql.ErrNoRows { + res.AddMessage(LevelError, "layer3domain '%s' does not exist", l3name) + return nil + } + res.AddMessage(LevelError, "could not get layer3domain") + return fmt.Errorf("could not fetch layer3domain id for name '%s': %#v", l3name, err) + } + attrs.Set("layer3domain_id", l3id) + } + setClause, args, err := query.FieldMapToUpdate(attrs, fieldMap) + if err != nil { + res.AddMessage(LevelError, "could not encode requested attributes: %s", err) + return nil + } + queryStr := fmt.Sprintf("update pools p set %s where name = $%d", setClause, len(args)+1) + args = append(args, name) // don't forget to add the where clause parameter + c.Logf(LevelInfo, "query: %s - args: %#v", queryStr, args) + if _, err := c.tx.Exec(queryStr, args...); err != nil { + res.AddMessage(LevelError, "could not set attributes") + c.Logf(LevelError, "could not set attributes on layer3domain '%s': %s - query: `%s` - args: `%#v`", name, err, queryStr, args) + return nil + } return nil } diff --git a/types/fields.go b/types/fields.go index 81a8e12..0a4232a 100644 --- a/types/fields.go +++ b/types/fields.go @@ -94,11 +94,20 @@ func (fm *FieldMap) UnmarshalJSON(raw []byte) error { return nil } +func (fm FieldMap) Contains(key string) bool { + _, found := fm.fields[key] + return found +} + // Set adds a key to the field map. func (fm FieldMap) Set(key string, val interface{}) { fm.fields[key] = val } +func (fm FieldMap) Delete(key string) { + delete(fm.fields, key) +} + // Fields returns all key/value pairs. func (fm FieldMap) Fields() map[string]interface{} { return fm.fields