package main import ( "fmt" "dim/query" "dim/types" ) // PoolCreate will create a new pool. func PoolCreate(c *Context, req Request, res *Response) error { name := "" options := struct { Layer3Domain string `json:"layer3domain"` VLAN uint `json:"vlan"` Owner string `json:"owner"` Attributes types.FieldMap `json:"attributes"` }{ Attributes: types.NewFieldMap(map[string]interface{}{}), } if err := req.ParseAtLeast(1, &name, &options); err != nil { res.AddMessage(LevelError, "could not parse options: %s", err) return nil } if name == "" { res.AddMessage(LevelError, "name is empty") return nil } if options.VLAN > 0 { options.Attributes.Set("vlan", options.VLAN) } attrs, err := options.Attributes.MarshalJSON() if err != nil { res.AddMessage(LevelError, "could not encode attributes to json: %s", err) return nil } l3id := 0 err = c.tx.QueryRow(`select id from layer3domains where name = $1`, options.Layer3Domain).Scan(&l3id) if err != nil { res.AddMessage(LevelError, "could not resolve layer3domain") return fmt.Errorf("could not resolve layer3domain '%s': %#v", options.Layer3Domain, err) } _, err = c.tx.Exec(`insert into pools(name, created_by, modified_by, attributes, layer3domain_id) values ($1, $2, $2, $3, $4)`, name, c.username, attrs, l3id) if err != nil { res.AddMessage(LevelError, "could not create new pool") return fmt.Errorf("could not create new pool '%s': %#v", name, err) } res.AddMessage(LevelInfo, "created pool '%s'", name) return nil } // PoolDelete deletes a pool. func PoolDelete(c *Context, req Request, res *Response) error { name := "" options := struct { Force bool `json:"force"` DeleteSubnets bool `json:"delete_subnets"` }{} if err := req.ParseAtLeast(1, &name, &options); err != nil { res.AddMessage(LevelError, "could not parse options: %s", err) return nil } if name == "" { res.AddMessage(LevelError, "name is empty") return nil } id := 0 l3id := 0 err := c.tx.QueryRow(`select id, layer3domain_id from pools where name = $1 for update`, name). Scan(&id, &l3id) if err != nil { res.AddMessage(LevelError, "could not fetch pool information") // TODO implement sql.ErrNotFound return fmt.Errorf("could not find pool '%s': %#v", name, err) } if options.Force && options.DeleteSubnets { // TODO what else needs to be deleted? _, err := c.tx.Exec(`delete from containers where id = $1 and layer3domain_id = $2`, id, l3id) if err != nil { res.AddMessage(LevelError, "could not delete subnets") return fmt.Errorf("could not delete subnets for pool '%s': %#v", name, err) } } if _, err := c.tx.Exec(`delete from pools where id = $1 and layer3domain_id = $2`, id, l3id); err != nil { res.AddMessage(LevelError, "could not delete pool") return fmt.Errorf("could not delete pool '%s': %#v", name, err) } res.AddMessage(LevelInfo, "deleted pool '%s'", name) return nil } // PoolList lists all pools with the requested fields. func PoolList(c *Context, req Request, res *Response) error { options := struct { Attributes types.FieldList }{ Attributes: types.NewFieldList("name", "vlan", "subnets"), } if err := req.ParseAtLeast(0, &options); err != nil { res.AddMessage(LevelError, "could not parse options") return nil } fieldMap := 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", "subnets": "(jsonb_agg(c.network::text) filter (where c.network is not null))::text", } selClause := query.FieldListToSelect("p", options.Attributes, fieldMap) from := "pools p" groupBy := "p.name, p.modified_by, p.modified_at, p.created_by, p.created_at, p.attributes" if options.Attributes.Contains("layer3domain") { from += " join layer3domains l on p.layer3domain_id = l.id" groupBy += ",l.name" } if options.Attributes.Contains("subnets") { from += " left join containers c on p.id = c.pool_id and p.layer3domain_id = c.layer3domain_id" } qry := fmt.Sprintf("select %s from %s group by %s order by p.name", selClause, from, groupBy) rows, err := c.tx.Query(qry) if err != nil { res.AddMessage(LevelError, "could not fetch pools") return fmt.Errorf("could not fetch pools: %#v - query: %s", err, qry) } defer rows.Close() res.Result, err = query.RowsToMap(rows) if err != nil { res.Result = nil res.AddMessage(LevelError, "could not parse pools") return fmt.Errorf("could not generate pool list: %#v", err) } return nil } func PoolGetAttr(c *Context, req Request, res *Response) error { return nil } func PoolSetAttr(c *Context, req Request, res *Response) error { return nil }