From f47bf2514f09072ca54670380ca9ea92164d6508 Mon Sep 17 00:00:00 2001 From: Joseph Vazhappilly Date: Tue, 12 Nov 2019 15:32:44 +0530 Subject: [PATCH] Add CRUD support for availability zone --- client/client.go | 2 + client/zone.go | 117 ++++++++++++++++++++ osdsctl/cli/cli.go | 1 + osdsctl/cli/zone.go | 163 +++++++++++++++++++++++++++ pkg/api/controllers/pool.go | 22 ---- pkg/api/controllers/zone.go | 212 ++++++++++++++++++++++++++++++++++++ pkg/api/routers/router.go | 3 +- pkg/db/db.go | 12 ++ pkg/db/drivers/etcd/etcd.go | 136 +++++++++++++++++++++++ pkg/model/zone.go | 55 ++++++++++ pkg/utils/urls/urls.go | 4 + testutils/db/fake.go | 29 +++++ 12 files changed, 733 insertions(+), 23 deletions(-) create mode 100644 client/zone.go create mode 100644 osdsctl/cli/zone.go create mode 100644 pkg/api/controllers/zone.go create mode 100644 pkg/model/zone.go diff --git a/client/client.go b/client/client.go index db47e41f9..425c35039 100755 --- a/client/client.go +++ b/client/client.go @@ -42,6 +42,7 @@ type Client struct { *VersionMgr *ReplicationMgr *FileShareMgr + *ZoneMgr cfg *Config } @@ -98,6 +99,7 @@ func NewClient(c *Config) (*Client, error) { VersionMgr: NewVersionMgr(r, c.Endpoint, t), ReplicationMgr: NewReplicationMgr(r, c.Endpoint, t), FileShareMgr: NewFileShareMgr(r, c.Endpoint, t), + ZoneMgr: NewZoneMgr(r, c.Endpoint, t), }, nil } diff --git a/client/zone.go b/client/zone.go new file mode 100644 index 000000000..d21cb5b70 --- /dev/null +++ b/client/zone.go @@ -0,0 +1,117 @@ +// Copyright 2019 The OpenSDS Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package client + +import ( + "strings" + + "github.com/opensds/opensds/pkg/model" + "github.com/opensds/opensds/pkg/utils/urls" +) + +// ZoneBuilder contains request body of handling a zone request. +// Currently it's assigned as the pointer of ZoneSpec struct, but it +// could be discussed if it's better to define an interface. +type ZoneBuilder *model.ZoneSpec + +// NewZoneMgr +func NewZoneMgr(r Receiver, edp string, tenantId string) *ZoneMgr { + return &ZoneMgr{ + Receiver: r, + Endpoint: edp, + TenantId: tenantId, + } +} + +// ZoneMgr +type ZoneMgr struct { + Receiver + Endpoint string + TenantId string +} + +// CreateZone +func (p *ZoneMgr) CreateZone(body ZoneBuilder) (*model.ZoneSpec, error) { + var res model.ZoneSpec + url := strings.Join([]string{ + p.Endpoint, + urls.GenerateZoneURL(urls.Client, p.TenantId)}, "/") + + if err := p.Recv(url, "POST", body, &res); err != nil { + return nil, err + } + + return &res, nil +} + +// GetZone +func (p *ZoneMgr) GetZone(zoneID string) (*model.ZoneSpec, error) { + var res model.ZoneSpec + url := strings.Join([]string{ + p.Endpoint, + urls.GenerateZoneURL(urls.Client, p.TenantId, zoneID)}, "/") + + if err := p.Recv(url, "GET", nil, &res); err != nil { + return nil, err + } + + return &res, nil +} + +// UpdateZone ... +func (p *ZoneMgr) UpdateZone(zoneID string, body ZoneBuilder) (*model.ZoneSpec, error) { + var res model.ZoneSpec + url := strings.Join([]string{ + p.Endpoint, + urls.GenerateZoneURL(urls.Client, p.TenantId, zoneID)}, "/") + + if err := p.Recv(url, "PUT", body, &res); err != nil { + return nil, err + } + + return &res, nil +} + +// ListZones +func (p *ZoneMgr) ListZones(args ...interface{}) ([]*model.ZoneSpec, error) { + var res []*model.ZoneSpec + + url := strings.Join([]string{ + p.Endpoint, + urls.GenerateZoneURL(urls.Client, p.TenantId)}, "/") + + param, err := processListParam(args) + if err != nil { + return nil, err + } + + if param != "" { + url += "?" + param + } + if err := p.Recv(url, "GET", nil, &res); err != nil { + return nil, err + } + + return res, nil +} + +// DeleteZone +func (p *ZoneMgr) DeleteZone(zoneID string) error { + url := strings.Join([]string{ + p.Endpoint, + urls.GenerateZoneURL(urls.Client, p.TenantId, zoneID)}, "/") + + return p.Recv(url, "DELETE", nil, nil) +} diff --git a/osdsctl/cli/cli.go b/osdsctl/cli/cli.go index 814ab905c..6168aed19 100644 --- a/osdsctl/cli/cli.go +++ b/osdsctl/cli/cli.go @@ -49,6 +49,7 @@ func init() { rootCommand.AddCommand(poolCommand) rootCommand.AddCommand(profileCommand) rootCommand.AddCommand(fileShareCommand) + rootCommand.AddCommand(zoneCommand) flags := rootCommand.PersistentFlags() flags.BoolVar(&Debug, "debug", false, "shows debugging output.") } diff --git a/osdsctl/cli/zone.go b/osdsctl/cli/zone.go new file mode 100644 index 000000000..ffbdb03f2 --- /dev/null +++ b/osdsctl/cli/zone.go @@ -0,0 +1,163 @@ +// Copyright 2019 The OpenSDS Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +This module implements a entry into the OpenSDS service. +*/ + +package cli + +import ( + "encoding/json" + "os" + + "github.com/opensds/opensds/pkg/model" + "github.com/spf13/cobra" +) + +var zoneCommand = &cobra.Command{ + Use: "zone", + Short: "manage OpenSDS Availability Zone resources", + Run: zoneAction, +} + +var zoneCreateCommand = &cobra.Command{ + Use: "create ", + Short: "create a new availability zone resource", + Run: zoneCreateAction, +} + +var zoneShowCommand = &cobra.Command{ + Use: "show ", + Short: "show information of specified availability zone", + Run: zoneShowAction, +} + +var zoneListCommand = &cobra.Command{ + Use: "list", + Short: "get all availability zone resources", + Run: zoneListAction, +} + +var zoneDeleteCommand = &cobra.Command{ + Use: "delete ", + Short: "delete a specified availability zone resource", + Run: zoneDeleteAction, +} + +var zoneUpdateCommand = &cobra.Command{ + Use: "update ", + Short: "update a specified zone resource", + Run: zoneUpdateAction, +} + +var ( + zoneLimit string + zoneOffset string + zoneSortDir string + zoneSortKey string + zoneId string + zoneName string + zoneDescription string +) + +func init() { + zoneListCommand.Flags().StringVarP(&zoneLimit, "limit", "", "50", "the number of ertries displayed per page") + zoneListCommand.Flags().StringVarP(&zoneOffset, "offset", "", "0", "all requested data offsets") + zoneListCommand.Flags().StringVarP(&zoneSortDir, "sortDir", "", "desc", "the sort direction of all requested data. supports asc or desc(default)") + zoneListCommand.Flags().StringVarP(&zoneSortKey, "sortKey", "", "id", "the sort key of all requested data. supports id(default), name, description") + zoneListCommand.Flags().StringVarP(&zoneId, "id", "", "", "list availability zone by id") + zoneListCommand.Flags().StringVarP(&zoneName, "name", "", "", "list availability zone by name") + zoneListCommand.Flags().StringVarP(&zoneDescription, "description", "", "", "list availability zone by description") + + zoneCommand.AddCommand(zoneCreateCommand) + zoneCommand.AddCommand(zoneShowCommand) + zoneCommand.AddCommand(zoneListCommand) + zoneCommand.AddCommand(zoneDeleteCommand) + zoneCommand.AddCommand(zoneUpdateCommand) +} + +func zoneAction(cmd *cobra.Command, args []string) { + cmd.Usage() + os.Exit(1) +} + +var zoneFormatters = FormatterList{} + +func zoneCreateAction(cmd *cobra.Command, args []string) { + ArgsNumCheck(cmd, args, 1) + az := &model.ZoneSpec{} + if err := json.Unmarshal([]byte(args[0]), az); err != nil { + Errorln(err) + cmd.Usage() + os.Exit(1) + } + + resp, err := client.CreateZone(az) + if err != nil { + Fatalln(HttpErrStrip(err)) + } + keys := KeyList{"Id", "CreatedAt", "UpdatedAt", "Name", "Description"} + PrintDict(resp, keys, zoneFormatters) +} + +func zoneShowAction(cmd *cobra.Command, args []string) { + ArgsNumCheck(cmd, args, 1) + resp, err := client.GetZone(args[0]) + if err != nil { + Fatalln(HttpErrStrip(err)) + } + keys := KeyList{"Id", "CreatedAt", "UpdatedAt", "Name", "Description"} + PrintDict(resp, keys, zoneFormatters) +} + +func zoneListAction(cmd *cobra.Command, args []string) { + ArgsNumCheck(cmd, args, 0) + var opts = map[string]string{"limit": zoneLimit, "offset": zoneOffset, "sortDir": zoneSortDir, + "sortKey": zoneSortKey, "Id": zoneId, + "Name": zoneName, "Description": zoneDescription} + + resp, err := client.ListZones(opts) + if err != nil { + Fatalln(HttpErrStrip(err)) + } + keys := KeyList{"Id", "CreatedAt", "UpdatedAt", "Name", "Description"} + PrintList(resp, keys, FormatterList{}) +} + +func zoneDeleteAction(cmd *cobra.Command, args []string) { + ArgsNumCheck(cmd, args, 1) + err := client.DeleteZone(args[0]) + if err != nil { + Fatalln(HttpErrStrip(err)) + } +} + +func zoneUpdateAction(cmd *cobra.Command, args []string) { + ArgsNumCheck(cmd, args, 2) + az := &model.ZoneSpec{} + + if err := json.Unmarshal([]byte(args[1]), az); err != nil { + Errorln(err) + cmd.Usage() + os.Exit(1) + } + + resp, err := client.UpdateZone(args[0], az) + if err != nil { + Fatalln(HttpErrStrip(err)) + } + keys := KeyList{"Id", "UpdatedAt", "Name", "Description"} + PrintDict(resp, keys, FormatterList{}) +} \ No newline at end of file diff --git a/pkg/api/controllers/pool.go b/pkg/api/controllers/pool.go index e764f0cbf..73b1922d4 100755 --- a/pkg/api/controllers/pool.go +++ b/pkg/api/controllers/pool.go @@ -33,28 +33,6 @@ type PoolPortal struct { BasePortal } -func (p *PoolPortal) ListAvailabilityZones() { - if !policy.Authorize(p.Ctx, "availability_zone:list") { - return - } - azs, err := db.C.ListAvailabilityZones(c.GetContext(p.Ctx)) - if err != nil { - errMsg := fmt.Sprintf("get AvailabilityZones for pools failed: %s", err.Error()) - p.ErrorHandle(model.ErrorInternalServer, errMsg) - return - } - - body, err := json.Marshal(azs) - if err != nil { - errMsg := fmt.Sprintf("marshal AvailabilityZones failed: %s", err.Error()) - p.ErrorHandle(model.ErrorInternalServer, errMsg) - return - } - - p.SuccessHandle(StatusOK, body) - return -} - func (p *PoolPortal) ListPools() { if !policy.Authorize(p.Ctx, "pool:list") { return diff --git a/pkg/api/controllers/zone.go b/pkg/api/controllers/zone.go new file mode 100644 index 000000000..aa5391908 --- /dev/null +++ b/pkg/api/controllers/zone.go @@ -0,0 +1,212 @@ +// Copyright 2019 The OpenSDS Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +This module implements a entry into the OpenSDS northbound service. + +*/ + +package controllers + +import ( + "encoding/json" + "fmt" + // "strings" + + // log "github.com/golang/glog" + "github.com/opensds/opensds/pkg/api/policy" + c "github.com/opensds/opensds/pkg/context" + "github.com/opensds/opensds/pkg/db" + "github.com/opensds/opensds/pkg/model" + // "github.com/opensds/opensds/pkg/utils/constants" +) + +type ZonePortal struct { + BasePortal +} + +func (p *ZonePortal) ListAvailabilityZones() { + if !policy.Authorize(p.Ctx, "availability_zone:list") { + return + } + azs, err := db.C.ListZones(c.GetContext(p.Ctx)) + if err != nil { + errMsg := fmt.Sprintf("get AvailabilityZones failed: %s", err.Error()) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + body, err := json.Marshal(azs) + if err != nil { + errMsg := fmt.Sprintf("marshal AvailabilityZones failed: %s", err.Error()) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, body) + return +} + +func (p *ZonePortal) CreateZone() { + if !policy.Authorize(p.Ctx, "zone:create") { + return + } + + var zone = model.ZoneSpec{ + BaseModel: &model.BaseModel{}, + } + + // Unmarshal the request body + if err := json.NewDecoder(p.Ctx.Request.Body).Decode(&zone); err != nil { + errMsg := fmt.Sprintf("parse zone request body failed: %v", err) + p.ErrorHandle(model.ErrorBadRequest, errMsg) + return + } + + // Call db api module to handle create zone request. + result, err := db.C.CreateZone(c.GetContext(p.Ctx), &zone) + if err != nil { + errMsg := fmt.Sprintf("create zone failed: %v", err) + p.ErrorHandle(model.ErrorBadRequest, errMsg) + return + } + + // Marshal the result. + body, err := json.Marshal(result) + if err != nil { + errMsg := fmt.Sprintf("marshal zone created result failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, body) + return +} + +func (p *ZonePortal) ListZones() { + if !policy.Authorize(p.Ctx, "zone:list") { + return + } + + m, err := p.GetParameters() + if err != nil { + errMsg := fmt.Sprintf("list zones failed: %v", err) + p.ErrorHandle(model.ErrorBadRequest, errMsg) + return + } + + result, err := db.C.ListZonesWithFilter(c.GetContext(p.Ctx), m) + if err != nil { + errMsg := fmt.Sprintf("list zones failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + // Marshal the result. + body, err := json.Marshal(result) + if err != nil { + errMsg := fmt.Sprintf("marshal zones listed result failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, body) + return +} + +func (p *ZonePortal) GetZone() { + if !policy.Authorize(p.Ctx, "zone:get") { + return + } + id := p.Ctx.Input.Param(":zoneId") + + result, err := db.C.GetZone(c.GetContext(p.Ctx), id) + if err != nil { + errMsg := fmt.Sprintf("zone %s not found: %v", id, err) + p.ErrorHandle(model.ErrorNotFound, errMsg) + return + } + + // Marshal the result. + body, err := json.Marshal(result) + if err != nil { + errMsg := fmt.Sprintf("marshal zone got result failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, body) + return +} + +func (p *ZonePortal) UpdateZone() { + + if !policy.Authorize(p.Ctx, "zone:update") { + return + } + + var zone = model.ZoneSpec{ + BaseModel: &model.BaseModel{}, + } + id := p.Ctx.Input.Param(":zoneId") + + if err := json.NewDecoder(p.Ctx.Request.Body).Decode(&zone); err != nil { + errMsg := fmt.Sprintf("parse zone request body failed: %v", err) + p.ErrorHandle(model.ErrorBadRequest, errMsg) + return + } + + result, err := db.C.UpdateZone(c.GetContext(p.Ctx), id, &zone) + if err != nil { + errMsg := fmt.Sprintf("update zones failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + // Marshal the result. + body, err := json.Marshal(result) + if err != nil { + errMsg := fmt.Sprintf("marshal zone updated result failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, body) + return +} + +func (p *ZonePortal) DeleteZone() { + + if !policy.Authorize(p.Ctx, "zone:delete") { + return + } + id := p.Ctx.Input.Param(":zoneId") + ctx := c.GetContext(p.Ctx) + zone, err := db.C.GetZone(ctx, id) + if err != nil { + errMsg := fmt.Sprintf("zone %s not found: %v", id, err) + p.ErrorHandle(model.ErrorNotFound, errMsg) + return + } + + err = db.C.DeleteZone(ctx, zone.Id) + if err != nil { + errMsg := fmt.Sprintf("delete zones failed: %v", err) + p.ErrorHandle(model.ErrorInternalServer, errMsg) + return + } + + p.SuccessHandle(StatusOK, nil) + return +} diff --git a/pkg/api/routers/router.go b/pkg/api/routers/router.go index d4a79177e..66f214886 100755 --- a/pkg/api/routers/router.go +++ b/pkg/api/routers/router.go @@ -60,7 +60,8 @@ func init() { // ListPools and GetPool are used for checking the status of backend pool, admin only beego.NSRouter("/:tenantId/pools", &controllers.PoolPortal{}, "get:ListPools"), beego.NSRouter("/:tenantId/pools/:poolId", &controllers.PoolPortal{}, "get:GetPool"), - beego.NSRouter("/:tenantId/availabilityZones", &controllers.PoolPortal{}, "get:ListAvailabilityZones"), + beego.NSRouter("/:tenantId/availabilityZones", &controllers.ZonePortal{}, "get:ListAvailabilityZones;post:CreateZone"), + beego.NSRouter("/:tenantId/availabilityZones/:zoneId", &controllers.ZonePortal{}, "get:GetZone;put:UpdateZone;delete:DeleteZone"), ) beego.AddNamespace(ns) diff --git a/pkg/db/db.go b/pkg/db/db.go index 29b80f647..62f154841 100755 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -125,6 +125,18 @@ type Client interface { DeletePool(ctx *c.Context, polID string) error + GetZone(ctx *c.Context, zoneID string) (*model.ZoneSpec, error) + + CreateZone(ctx *c.Context, zone *model.ZoneSpec) (*model.ZoneSpec, error) + + ListZones(ctx *c.Context) ([]*model.ZoneSpec, error) + + ListZonesWithFilter(ctx *c.Context, m map[string][]string) ([]*model.ZoneSpec, error) + + UpdateZone(ctx *c.Context, zoneID string, zone *model.ZoneSpec) (*model.ZoneSpec, error) + + DeleteZone(ctx *c.Context, zoneID string) error + CreateProfile(ctx *c.Context, prf *model.ProfileSpec) (*model.ProfileSpec, error) GetProfile(ctx *c.Context, prfID string) (*model.ProfileSpec, error) diff --git a/pkg/db/drivers/etcd/etcd.go b/pkg/db/drivers/etcd/etcd.go index 1a4833e62..11c68cef0 100644 --- a/pkg/db/drivers/etcd/etcd.go +++ b/pkg/db/drivers/etcd/etcd.go @@ -1359,6 +1359,142 @@ func (c *Client) ListAvailabilityZones(ctx *c.Context) ([]string, error) { return azs, nil } +// GetZone +func (c *Client) GetZone(ctx *c.Context, zoneID string) (*model.ZoneSpec, error) { + dbReq := &Request{ + Url: urls.GenerateZoneURL(urls.Etcd, "", zoneID), + } + dbRes := c.Get(dbReq) + if dbRes.Status != "Success" { + log.Error("When get zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + + var z = &model.ZoneSpec{} + if err := json.Unmarshal([]byte(dbRes.Message[0]), z); err != nil { + log.Error("When parsing zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + return z, nil +} + +// CreateZone +func (c *Client) CreateZone(ctx *c.Context, zone *model.ZoneSpec) (*model.ZoneSpec, error) { + if zone.Id == "" { + zone.Id = uuid.NewV4().String() + } + if zone.CreatedAt == "" { + zone.CreatedAt = time.Now().Format(constants.TimeFormat) + } + + // zone name must be unique. + // if _, err := c.getZoneByName(ctx, zone.Name); err == nil { + // return nil, fmt.Errorf("the zone name '%s' already exists", zone.Name) + // } + + zoneBody, err := json.Marshal(zone) + if err != nil { + return nil, err + } + + dbReq := &Request{ + Url: urls.GenerateZoneURL(urls.Etcd, "", zone.Id), + Content: string(zoneBody), + } + dbRes := c.Create(dbReq) + if dbRes.Status != "Success" { + log.Error("When create zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + + return zone, nil +} + +// UpdateZone +func (c *Client) UpdateZone(ctx *c.Context, zoneID string, input *model.ZoneSpec) (*model.ZoneSpec, error) { + z, err := c.GetZone(ctx, zoneID) + if err != nil { + return nil, err + } + if name := input.Name; name != "" { + z.Name = name + } + if desc := input.Description; desc != "" { + z.Description = desc + } + z.UpdatedAt = time.Now().Format(constants.TimeFormat) + + zBody, err := json.Marshal(z) + if err != nil { + return nil, err + } + + dbReq := &Request{ + Url: urls.GenerateZoneURL(urls.Etcd, "", zoneID), + NewContent: string(zBody), + } + dbRes := c.Update(dbReq) + if dbRes.Status != "Success" { + log.Error("When update zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + return z, nil +} + +// DeleteZone +func (c *Client) DeleteZone(ctx *c.Context, zoneID string) error { + dbReq := &Request{ + Url: urls.GenerateZoneURL(urls.Etcd, "", zoneID), + } + dbRes := c.Delete(dbReq) + if dbRes.Status != "Success" { + log.Error("When delete profile in db:", dbRes.Error) + return errors.New(dbRes.Error) + } + return nil +} + +//ListZonesWithFilter +func (c *Client) ListZonesWithFilter(ctx *c.Context, m map[string][]string) ([]*model.ZoneSpec, error) { + zones, err := c.ListZones(ctx) + if err != nil { + log.Error("List zones failed: ", err.Error()) + return nil, err + } + + // z := c.SelectZones(m, zones) + // p := c.ParameterFilter(m, len(z), []string{"ID", "NAME", "STATUS", "AVAILABILITYZONE", "DOCKID", "DESCRIPTION"}) + // return c.SortZones(z, p)[p.beginIdx:p.endIdx], nil + + return zones, nil +} + +//ListZones +func (c *Client) ListZones(ctx *c.Context) ([]*model.ZoneSpec, error) { + dbReq := &Request{ + Url: urls.GenerateZoneURL(urls.Etcd, ""), + } + dbRes := c.List(dbReq) + if dbRes.Status != "Success" { + log.Error("Failed to get zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + var azs = []*model.ZoneSpec{} + if len(dbRes.Message) == 0 { + return azs, nil + } + for _, msg := range dbRes.Message { + var az = &model.ZoneSpec{} + if err := json.Unmarshal([]byte(msg), az); err != nil { + log.Error("When parsing zone in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + azs = append(azs, az) + } + + return azs, nil +} + // ListPools func (c *Client) ListPools(ctx *c.Context) ([]*model.StoragePoolSpec, error) { dbReq := &Request{ diff --git a/pkg/model/zone.go b/pkg/model/zone.go new file mode 100644 index 000000000..6c87e034b --- /dev/null +++ b/pkg/model/zone.go @@ -0,0 +1,55 @@ +// Copyright 2019 The OpenSDS Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* +This module implements the common data structure. + +*/ + +package model + +import ( + "encoding/json" + + "github.com/golang/glog" +) + +// An OpenSDS zone is identified by a unique name and ID. +type ZoneSpec struct { + *BaseModel + + // The name of the zone. + Name string `json:"name,omitempty"` + + // The description of the zone. + // +optional + Description string `json:"description,omitempty"` +} + +func NewZoneFromJson(s string) *ZoneSpec { + p := &ZoneSpec{} + err := json.Unmarshal([]byte(s), p) + if err != nil { + glog.Errorf("Unmarshal json to ZoneSpec failed, %v", err) + } + return p +} + +func (p *ZoneSpec) ToJson() string { + b, err := json.Marshal(p) + if err != nil { + glog.Errorf("ZoneSpec convert to json failed, %v", err) + } + return string(b) +} diff --git a/pkg/utils/urls/urls.go b/pkg/utils/urls/urls.go index 4af0942a7..ad7a1695c 100644 --- a/pkg/utils/urls/urls.go +++ b/pkg/utils/urls/urls.go @@ -45,6 +45,10 @@ func GeneratePoolURL(urlType int, tenantId string, in ...string) string { return generateURL("pools", urlType, tenantId, in...) } +func GenerateZoneURL(urlType int, tenantId string, in ...string) string { + return generateURL("availabilityZones", urlType, tenantId, in...) +} + func GenerateProfileURL(urlType int, tenantId string, in ...string) string { return generateURL("profiles", urlType, tenantId, in...) } diff --git a/testutils/db/fake.go b/testutils/db/fake.go index fffedaf2c..546dcee70 100755 --- a/testutils/db/fake.go +++ b/testutils/db/fake.go @@ -230,6 +230,35 @@ func (fc *FakeDbClient) ListAvailabilityZones(ctx *c.Context) ([]string, error) return azs, nil } +// GetZone +func (fc *FakeDbClient) GetZone(ctx *c.Context, zoneID string) (*model.ZoneSpec, error) { + return nil, nil +} + +// CreateZone +func (fc *FakeDbClient) CreateZone(ctx *c.Context, zone *model.ZoneSpec) (*model.ZoneSpec, error) { + return nil, nil +} + +// UpdateZone +func (fc *FakeDbClient) UpdateZone(ctx *c.Context, zoneID string, zone *model.ZoneSpec) (*model.ZoneSpec, error) { + return nil, nil +} + +// DeleteZone +func (fc *FakeDbClient) DeleteZone(ctx *c.Context, zoneID string) error { + return nil +} + +// ListZonesWithFilter +func (fc *FakeDbClient) ListZonesWithFilter(ctx *c.Context, m map[string][]string) ([]*model.ZoneSpec, error) { + return nil, nil +} + +func (fc *FakeDbClient) ListZones(ctx *c.Context) ([]*model.ZoneSpec, error) { + return nil, nil +} + // UpdateDock func (fc *FakeDbClient) UpdateDock(ctx *c.Context, dckID, name, desp string) (*model.DockSpec, error) { return nil, nil