mirror of
https://github.com/cristicalin/synology-csi.git
synced 2026-05-08 05:52:38 +00:00
Initial commit
This commit is contained in:
208
pkg/dsm/webapi/dsmwebapi.go
Normal file
208
pkg/dsm/webapi/dsmwebapi.go
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2021 Synology Inc.
|
||||
*/
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"github.com/SynologyOpenSource/synology-csi/pkg/logger"
|
||||
)
|
||||
|
||||
type DSM struct {
|
||||
Ip string
|
||||
Port int
|
||||
Username string
|
||||
Password string
|
||||
Sid string
|
||||
Https bool
|
||||
}
|
||||
|
||||
type errData struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type dsmApiResp struct {
|
||||
Success bool `json:"success"`
|
||||
Err errData `json:"error"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
StatusCode int
|
||||
ErrorCode int
|
||||
Success bool
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func (dsm *DSM) sendRequest(data string, apiTemplate interface{}, params url.Values, cgiPath string) (Response, error) {
|
||||
resp, err := dsm.sendRequestWithoutConnectionCheck(data, apiTemplate, params, cgiPath)
|
||||
if err != nil && resp.ErrorCode == 119 { // WEBAPI_ERR_SID_NOT_FOUND
|
||||
// Re-login
|
||||
if err := dsm.Login(); err != nil {
|
||||
return Response{}, fmt.Errorf("Failed to re-login to DSM: [%s]. err: %v", dsm.Ip, err)
|
||||
}
|
||||
log.Info("Re-login succeeded.")
|
||||
return dsm.sendRequestWithoutConnectionCheck(data, apiTemplate, params, cgiPath);
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (dsm *DSM) sendRequestWithoutConnectionCheck(data string, apiTemplate interface{}, params url.Values, cgiPath string) (Response, error) {
|
||||
client := &http.Client{}
|
||||
var req *http.Request
|
||||
var err error
|
||||
var cgiUrl string
|
||||
|
||||
// Ex: http://10.12.12.14:5000/webapi/auth.cgi
|
||||
if dsm.Https {
|
||||
// TODO: input CA certificate and fill in tls config
|
||||
// Skip Verify when https
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
client = &http.Client{Transport: tr}
|
||||
cgiUrl = fmt.Sprintf("https://%s:%d/%s", dsm.Ip, dsm.Port, cgiPath)
|
||||
} else {
|
||||
cgiUrl = fmt.Sprintf("http://%s:%d/%s", dsm.Ip, dsm.Port, cgiPath)
|
||||
}
|
||||
|
||||
baseUrl, err := url.Parse(cgiUrl)
|
||||
if err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
|
||||
baseUrl.RawQuery = params.Encode()
|
||||
|
||||
if logger.WebapiDebug {
|
||||
log.Debugln(baseUrl.RawQuery)
|
||||
}
|
||||
|
||||
if data != "" {
|
||||
req, err = http.NewRequest("POST", baseUrl.String(), nil)
|
||||
} else {
|
||||
req, err = http.NewRequest("GET", baseUrl.String(), nil)
|
||||
}
|
||||
|
||||
if dsm.Sid != "" {
|
||||
cookie := http.Cookie{Name: "id", Value: dsm.Sid}
|
||||
req.AddCookie(&cookie)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// For debug print text body
|
||||
var bodyText []byte
|
||||
if logger.WebapiDebug {
|
||||
bodyText, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
s := string(bodyText)
|
||||
log.Debugln(s)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 302 {
|
||||
return Response{}, fmt.Errorf("Bad response status code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Strip data json data from response
|
||||
type envelop struct {
|
||||
dsmApiResp
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
e := envelop{}
|
||||
var outResp Response
|
||||
|
||||
if logger.WebapiDebug {
|
||||
if err := json.Unmarshal(bodyText, &e); err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
} else {
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
|
||||
if err := decoder.Decode(&e); err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
}
|
||||
outResp.Success = e.Success
|
||||
outResp.ErrorCode = e.Err.Code
|
||||
outResp.StatusCode = resp.StatusCode
|
||||
|
||||
if !e.Success {
|
||||
return outResp, fmt.Errorf("DSM Api error. Error code:%d", outResp.ErrorCode)
|
||||
}
|
||||
|
||||
if e.Data != nil {
|
||||
if err := json.Unmarshal(e.Data, apiTemplate); err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
}
|
||||
|
||||
outResp.Data = apiTemplate
|
||||
|
||||
if err != nil {
|
||||
return Response{}, err
|
||||
}
|
||||
|
||||
return outResp, nil
|
||||
}
|
||||
|
||||
// Login by given user name and password
|
||||
func (dsm *DSM) Login() error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.API.Auth")
|
||||
params.Add("method", "login")
|
||||
params.Add("version", "3")
|
||||
params.Add("account", dsm.Username)
|
||||
params.Add("passwd", dsm.Password)
|
||||
params.Add("format", "sid")
|
||||
|
||||
type LoginResp struct {
|
||||
Sid string `json:"sid"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequestWithoutConnectionCheck("", &LoginResp{}, params, "webapi/auth.cgi")
|
||||
if err != nil {
|
||||
r, _ := regexp.Compile("passwd=.*&")
|
||||
temp := r.ReplaceAllString(err.Error(), "")
|
||||
|
||||
return fmt.Errorf("%s", temp)
|
||||
}
|
||||
|
||||
loginResp, ok := resp.Data.(*LoginResp)
|
||||
if !ok {
|
||||
return fmt.Errorf("Failed to assert response to %T", &LoginResp{})
|
||||
}
|
||||
dsm.Sid = loginResp.Sid
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout on current IP and reset the synoToken
|
||||
func (dsm *DSM) Logout() error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.API.Auth")
|
||||
params.Add("method", "logout")
|
||||
params.Add("version", "1")
|
||||
|
||||
_, err := dsm.sendRequestWithoutConnectionCheck("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dsm.Sid = ""
|
||||
|
||||
return nil
|
||||
}
|
||||
500
pkg/dsm/webapi/iscsi.go
Normal file
500
pkg/dsm/webapi/iscsi.go
Normal file
@@ -0,0 +1,500 @@
|
||||
// Copyright 2021 Synology Inc.
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/SynologyOpenSource/synology-csi/pkg/logger"
|
||||
"github.com/SynologyOpenSource/synology-csi/pkg/utils"
|
||||
)
|
||||
|
||||
type LunInfo struct {
|
||||
Name string `json:"name"`
|
||||
Uuid string `json:"uuid"`
|
||||
LunType int `json:"type"`
|
||||
Location string `json:"location"`
|
||||
Size uint64 `json:"size"`
|
||||
Used uint64 `json:"allocated_size"`
|
||||
Status string `json:"status"`
|
||||
FlashcacheStatus string `json:"flashcache_status"`
|
||||
IsActionLocked bool `json:"is_action_locked"`
|
||||
}
|
||||
|
||||
type MappedLun struct {
|
||||
LunUuid string `json:"lun_uuid"`
|
||||
MappingIndex int `json:"mapping_index"`
|
||||
}
|
||||
|
||||
type ConncetedSession struct {
|
||||
Iqn string `json:"iqn"`
|
||||
Ip string `json:"ip"`
|
||||
}
|
||||
|
||||
type NetworkPortal struct {
|
||||
ControllerId int `json:"controller_id"`
|
||||
InterfaceName string `json:"interface_name"`
|
||||
}
|
||||
|
||||
type TargetInfo struct {
|
||||
Name string `json:"name"`
|
||||
Iqn string `json:"iqn"`
|
||||
Status string `json:"status"`
|
||||
MaxSessions int `json:"max_sessions"`
|
||||
MappedLuns []MappedLun `json:"mapped_luns"`
|
||||
ConnectedSessions []ConncetedSession `json:"connected_sessions"`
|
||||
NetworkPortals []NetworkPortal `json:"network_portals"`
|
||||
TargetId int `json:"target_id"`
|
||||
}
|
||||
|
||||
type SnapshotInfo struct {
|
||||
Name string `json:"name"`
|
||||
Uuid string `json:"uuid"`
|
||||
ParentUuid string `json:"parent_uuid"`
|
||||
Status string `json:"status"`
|
||||
TotalSize int64 `json:"total_size"`
|
||||
CreateTime int64 `json:"create_time"`
|
||||
}
|
||||
|
||||
type LunDevAttrib struct {
|
||||
DevAttrib string `json:"dev_attrib"`
|
||||
Enable int `json:"enable"`
|
||||
}
|
||||
|
||||
type LunCreateSpec struct {
|
||||
Name string
|
||||
Location string
|
||||
Size int64
|
||||
Type string
|
||||
DevAttribs []LunDevAttrib
|
||||
}
|
||||
|
||||
type LunUpdateSpec struct {
|
||||
Uuid string
|
||||
NewSize uint64
|
||||
}
|
||||
|
||||
type LunCloneSpec struct {
|
||||
Name string
|
||||
SrcLunUuid string
|
||||
Location string
|
||||
}
|
||||
|
||||
type TargetCreateSpec struct {
|
||||
Name string
|
||||
Iqn string
|
||||
}
|
||||
|
||||
type SnapshotCreateSpec struct {
|
||||
Name string
|
||||
LunUuid string
|
||||
Description string
|
||||
TakenBy string
|
||||
IsLocked bool
|
||||
}
|
||||
|
||||
type SnapshotCloneSpec struct {
|
||||
Name string
|
||||
SrcLunUuid string
|
||||
SrcSnapshotUuid string
|
||||
}
|
||||
|
||||
func errCodeMapping(errCode int, oriErr error) error {
|
||||
switch errCode {
|
||||
case 18990002: // Out of free space
|
||||
return utils.OutOfFreeSpaceError("")
|
||||
case 18990538: // Duplicated LUN name
|
||||
return utils.AlreadyExistError("")
|
||||
case 18990541:
|
||||
return utils.LunReachMaxCountError("")
|
||||
case 18990542:
|
||||
return utils.TargetReachMaxCountError("")
|
||||
case 18990744: // Duplicated Target name
|
||||
return utils.AlreadyExistError("")
|
||||
case 18990532:
|
||||
return utils.NoSuchSnapshotError("")
|
||||
case 18990500:
|
||||
return utils.BadLunTypeError("")
|
||||
case 18990543:
|
||||
return utils.SnapshotReachMaxCountError("")
|
||||
}
|
||||
|
||||
if errCode > 18990000 {
|
||||
return utils.IscsiDefaultError("")
|
||||
}
|
||||
return oriErr
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunList() ([]LunInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "list")
|
||||
params.Add("version", "1")
|
||||
params.Add("types", "[\"BLOCK\", \"FILE\", \"THIN\", \"ADV\", \"SINK\", \"CINDER\", \"CINDER_BLUN\", \"CINDER_BLUN_THICK\", \"BLUN\", \"BLUN_THICK\", \"BLUN_SINK\", \"BLUN_THICK_SINK\"]")
|
||||
params.Add("additional", "[\"allocated_size\",\"status\",\"flashcache_status\", \"is_action_locked\"]")
|
||||
|
||||
type LunInfos struct {
|
||||
Luns []LunInfo `json:"luns"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &LunInfos{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lunInfos, ok := resp.Data.(*LunInfos)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &LunInfos{})
|
||||
}
|
||||
return lunInfos.Luns, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunCreate(spec LunCreateSpec) (string, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "create")
|
||||
params.Add("version", "1")
|
||||
params.Add("name", strconv.Quote(spec.Name))
|
||||
params.Add("size", strconv.FormatInt(int64(spec.Size), 10))
|
||||
params.Add("type", spec.Type)
|
||||
params.Add("location", spec.Location)
|
||||
|
||||
js, err := json.Marshal(spec.DevAttribs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
params.Add("dev_attribs", string(js))
|
||||
|
||||
type LunCreateResp struct {
|
||||
Uuid string `json:"uuid"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &LunCreateResp{}, params, "webapi/entry.cgi")
|
||||
err = errCodeMapping(resp.ErrorCode, err)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
lunResp, ok := resp.Data.(*LunCreateResp)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Failed to assert response to %T", &LunCreateResp{})
|
||||
}
|
||||
|
||||
return lunResp.Uuid, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunUpdate(spec LunUpdateSpec) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "set")
|
||||
params.Add("version", "1")
|
||||
params.Add("uuid", strconv.Quote(spec.Uuid))
|
||||
params.Add("new_size", strconv.FormatInt(int64(spec.NewSize), 10))
|
||||
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunGet(uuid string) (LunInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "get")
|
||||
params.Add("version", "1")
|
||||
params.Add("uuid", strconv.Quote(uuid))
|
||||
params.Add("additional", "[\"allocated_size\",\"status\",\"flashcache_status\", \"is_action_locked\"]")
|
||||
|
||||
type Info struct {
|
||||
Lun LunInfo `json:"lun"`
|
||||
}
|
||||
info := Info{}
|
||||
|
||||
_, err := dsm.sendRequest("", &info, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return LunInfo{}, err
|
||||
}
|
||||
|
||||
return info.Lun, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunClone(spec LunCloneSpec) (string, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "clone")
|
||||
params.Add("version", "1")
|
||||
params.Add("src_lun_uuid", strconv.Quote(spec.SrcLunUuid))
|
||||
params.Add("dst_lun_name", strconv.Quote(spec.Name))
|
||||
params.Add("dst_location", strconv.Quote(spec.Location))
|
||||
|
||||
type LunCloneResp struct {
|
||||
Uuid string `json:"dst_lun_uuid"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &LunCloneResp{}, params, "webapi/entry.cgi")
|
||||
err = errCodeMapping(resp.ErrorCode, err)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cloneLunResp, ok := resp.Data.(*LunCloneResp)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Failed to assert response to %T", &LunCloneResp{})
|
||||
}
|
||||
|
||||
return cloneLunResp.Uuid, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) TargetList() ([]TargetInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.Target")
|
||||
params.Add("method", "list")
|
||||
params.Add("version", "1")
|
||||
params.Add("additional", "[\"mapped_lun\", \"connected_sessions\"]")
|
||||
|
||||
type TargetInfos struct {
|
||||
Targets []TargetInfo `json:"targets"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &TargetInfos{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trgInfos, ok := resp.Data.(*TargetInfos)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &TargetInfos{})
|
||||
}
|
||||
return trgInfos.Targets, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) TargetGet(targetId string) (TargetInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.Target")
|
||||
params.Add("method", "get")
|
||||
params.Add("version", "1")
|
||||
params.Add("target_id", strconv.Quote(targetId))
|
||||
params.Add("additional", "[\"mapped_lun\", \"connected_sessions\"]")
|
||||
|
||||
type Info struct {
|
||||
Target TargetInfo `json:"target"`
|
||||
}
|
||||
info := Info{}
|
||||
|
||||
_, err := dsm.sendRequest("", &info, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return TargetInfo{}, err
|
||||
}
|
||||
|
||||
return info.Target, nil
|
||||
}
|
||||
|
||||
// Enable muti session
|
||||
func (dsm *DSM) TargetSet(targetId string, maxSession int) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.Target")
|
||||
params.Add("method", "set")
|
||||
params.Add("version", "1")
|
||||
params.Add("target_id", strconv.Quote(targetId))
|
||||
params.Add("max_sessions", strconv.Itoa(maxSession))
|
||||
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) TargetCreate(spec TargetCreateSpec) (string, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.Target")
|
||||
params.Add("method", "create")
|
||||
params.Add("version", "1")
|
||||
params.Add("name", spec.Name)
|
||||
params.Add("auth_type", "0")
|
||||
params.Add("iqn", spec.Iqn)
|
||||
|
||||
type TrgCreateResp struct {
|
||||
TargetId int `json:"target_id"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &TrgCreateResp{}, params, "webapi/entry.cgi")
|
||||
err = errCodeMapping(resp.ErrorCode, err)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
trgResp, ok := resp.Data.(*TrgCreateResp)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Failed to assert response to %T", &TrgCreateResp{})
|
||||
}
|
||||
|
||||
return strconv.Itoa(trgResp.TargetId), nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunMapTarget(targetIds []string, lunUuid string) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "map_target")
|
||||
params.Add("version", "1")
|
||||
params.Add("uuid", strconv.Quote(lunUuid))
|
||||
params.Add("target_ids", fmt.Sprintf("[%s]", strings.Join(targetIds, ",")))
|
||||
|
||||
if logger.WebapiDebug {
|
||||
log.Debugln(params)
|
||||
}
|
||||
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) LunDelete(lunUuid string) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "delete")
|
||||
params.Add("version", "1")
|
||||
params.Add("uuid", strconv.Quote(lunUuid))
|
||||
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) TargetDelete(targetName string) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.Target")
|
||||
params.Add("method", "delete")
|
||||
params.Add("version", "1")
|
||||
params.Add("target_id", strconv.Quote(targetName))
|
||||
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) SnapshotCreate(spec SnapshotCreateSpec) (string, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "take_snapshot")
|
||||
params.Add("version", "1")
|
||||
params.Add("src_lun_uuid", strconv.Quote(spec.LunUuid))
|
||||
params.Add("snapshot_name", strconv.Quote(spec.Name))
|
||||
params.Add("description", strconv.Quote(spec.Description))
|
||||
params.Add("taken_by", strconv.Quote(spec.TakenBy))
|
||||
params.Add("is_locked", strconv.FormatBool(spec.IsLocked))
|
||||
params.Add("is_app_consistent", strconv.FormatBool(false))
|
||||
|
||||
type SnapshotCreateResp struct {
|
||||
Uuid string `json:"snapshot_uuid"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &SnapshotCreateResp{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return "", errCodeMapping(resp.ErrorCode, err)
|
||||
}
|
||||
|
||||
snapshotResp, ok := resp.Data.(*SnapshotCreateResp)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Failed to assert response to %T", &SnapshotCreateResp{})
|
||||
}
|
||||
|
||||
return snapshotResp.Uuid, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) SnapshotDelete(snapshotUuid string) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "delete_snapshot")
|
||||
params.Add("version", "1")
|
||||
params.Add("snapshot_uuid", strconv.Quote(snapshotUuid))
|
||||
|
||||
resp, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return errCodeMapping(resp.ErrorCode, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) SnapshotGet(snapshotUuid string) (SnapshotInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "get_snapshot")
|
||||
params.Add("version", "1")
|
||||
params.Add("snapshot_uuid", strconv.Quote(snapshotUuid))
|
||||
|
||||
type Info struct {
|
||||
Snapshot SnapshotInfo `json:"snapshot"`
|
||||
}
|
||||
info := Info{}
|
||||
|
||||
resp, err := dsm.sendRequest("", &info, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return SnapshotInfo{}, errCodeMapping(resp.ErrorCode, err)
|
||||
}
|
||||
|
||||
return info.Snapshot, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) SnapshotList(lunUuid string) ([]SnapshotInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "list_snapshot")
|
||||
params.Add("version", "1")
|
||||
params.Add("src_lun_uuid", strconv.Quote(lunUuid))
|
||||
|
||||
type Infos struct {
|
||||
Snapshots []SnapshotInfo `json:"snapshots"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &Infos{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, errCodeMapping(resp.ErrorCode, err)
|
||||
}
|
||||
|
||||
infos, ok := resp.Data.(*Infos)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &Infos{})
|
||||
}
|
||||
|
||||
return infos.Snapshots, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) SnapshotClone(spec SnapshotCloneSpec) (string, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.ISCSI.LUN")
|
||||
params.Add("method", "clone_snapshot")
|
||||
params.Add("version", "1")
|
||||
params.Add("src_lun_uuid", strconv.Quote(spec.SrcLunUuid))
|
||||
params.Add("snapshot_uuid", strconv.Quote(spec.SrcSnapshotUuid))
|
||||
params.Add("cloned_lun_name", strconv.Quote(spec.Name))
|
||||
|
||||
type SnapshotCloneResp struct {
|
||||
Uuid string `json:"cloned_lun_uuid"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &SnapshotCloneResp{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return "", errCodeMapping(resp.ErrorCode, err)
|
||||
}
|
||||
|
||||
snapshotCloneResp, ok := resp.Data.(*SnapshotCloneResp)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Failed to assert response to %T", &SnapshotCloneResp{})
|
||||
}
|
||||
|
||||
return snapshotCloneResp.Uuid, nil
|
||||
}
|
||||
87
pkg/dsm/webapi/share.go
Normal file
87
pkg/dsm/webapi/share.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2021 Synology Inc.
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ShareInfo struct {
|
||||
Name string `json:"name"`
|
||||
VolPath string `json:"vol_path"`
|
||||
Desc string `json:"desc"`
|
||||
EnableShareCow bool `json:"enable_share_cow"`
|
||||
EnableRecycleBin bool `json:"enable_recycle_bin"`
|
||||
RecycleBinAdminOnly bool `json:"recycle_bin_admin_only"`
|
||||
Encryption int `json:"encryption"`
|
||||
}
|
||||
|
||||
type ShareCreateSpec struct {
|
||||
Name string `json:"name"`
|
||||
ShareInfo ShareInfo `json:"shareinfo"`
|
||||
}
|
||||
|
||||
func (dsm *DSM) ShareList() ([]ShareInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.Share")
|
||||
params.Add("method", "list")
|
||||
params.Add("version", "1")
|
||||
params.Add("additional", "[\"encryption\"]")
|
||||
|
||||
type ShareInfos struct {
|
||||
Shares []ShareInfo `json:"shares"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &ShareInfos{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infos, ok := resp.Data.(*ShareInfos)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &ShareInfos{})
|
||||
}
|
||||
|
||||
return infos.Shares, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) ShareCreate(spec ShareCreateSpec) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.Share")
|
||||
params.Add("method", "create")
|
||||
params.Add("version", "1")
|
||||
params.Add("name", strconv.Quote(spec.Name))
|
||||
|
||||
js, err := json.Marshal(spec.ShareInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Add("shareinfo", string(js))
|
||||
|
||||
// response : {"data":{"name":"Share-2"},"success":true}
|
||||
_, err = dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) ShareDelete(shareName string) error {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.Share")
|
||||
params.Add("method", "delete")
|
||||
params.Add("version", "1")
|
||||
params.Add("name", strconv.Quote(shareName))
|
||||
|
||||
// response : {"success":true}
|
||||
_, err := dsm.sendRequest("", &struct{}{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
67
pkg/dsm/webapi/storage.go
Normal file
67
pkg/dsm/webapi/storage.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2021 Synology Inc.
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type VolInfo struct {
|
||||
Name string `json:"display_name"`
|
||||
Path string `json:"volume_path"`
|
||||
Status string `json:"status"`
|
||||
FsType string `json:"fs_type"`
|
||||
Size string `json:"size_total_byte"`
|
||||
Free string `json:"size_free_byte"`
|
||||
Container string `json:"container"`
|
||||
Location string `json:"location"`
|
||||
}
|
||||
|
||||
func (dsm *DSM) VolumeList() ([]VolInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.Storage.Volume")
|
||||
params.Add("method", "list")
|
||||
params.Add("version", "1")
|
||||
params.Add("offset", "0")
|
||||
params.Add("limit", "-1")
|
||||
params.Add("location", "all")
|
||||
|
||||
type VolInfos struct {
|
||||
Vols []VolInfo `json:"volumes"`
|
||||
}
|
||||
|
||||
resp, err := dsm.sendRequest("", &VolInfos{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
volInfos, ok := resp.Data.(*VolInfos)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &VolInfos{})
|
||||
}
|
||||
|
||||
return volInfos.Vols, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) VolumeGet(name string) (VolInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.Storage.Volume")
|
||||
params.Add("method", "get")
|
||||
params.Add("version", "1")
|
||||
params.Add("volume_path", strconv.Quote(name))
|
||||
|
||||
type Info struct {
|
||||
Volume VolInfo `json:"volume"`
|
||||
}
|
||||
info := Info{}
|
||||
|
||||
_, err := dsm.sendRequest("", &info, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return VolInfo{}, err
|
||||
}
|
||||
|
||||
return info.Volume, nil
|
||||
}
|
||||
|
||||
57
pkg/dsm/webapi/systeminfo.go
Normal file
57
pkg/dsm/webapi/systeminfo.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 Synology Inc.
|
||||
|
||||
package webapi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type DsmInfo struct {
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
type DsmSysInfo struct {
|
||||
Model string `json:"model"`
|
||||
FirmwareVer string `json:"firmware_ver"`
|
||||
Serial string `json:"serial"`
|
||||
}
|
||||
|
||||
func (dsm *DSM) DsmInfoGet() (*DsmInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.System")
|
||||
params.Add("method", "info")
|
||||
params.Add("version", "1")
|
||||
params.Add("type", "network")
|
||||
|
||||
resp, err := dsm.sendRequest("", &DsmInfo{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dsmInfo, ok := resp.Data.(*DsmInfo)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &DsmInfo{})
|
||||
}
|
||||
|
||||
return dsmInfo, nil
|
||||
}
|
||||
|
||||
func (dsm *DSM) DsmSystemInfoGet() (*DsmSysInfo, error) {
|
||||
params := url.Values{}
|
||||
params.Add("api", "SYNO.Core.System")
|
||||
params.Add("method", "info")
|
||||
params.Add("version", "1")
|
||||
|
||||
resp, err := dsm.sendRequest("", &DsmSysInfo{}, params, "webapi/entry.cgi")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dsmInfo, ok := resp.Data.(*DsmSysInfo)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Failed to assert response to %T", &DsmSysInfo{})
|
||||
}
|
||||
|
||||
return dsmInfo, nil
|
||||
}
|
||||
1
pkg/dsm/webapi/utils.go
Normal file
1
pkg/dsm/webapi/utils.go
Normal file
@@ -0,0 +1 @@
|
||||
package webapi
|
||||
Reference in New Issue
Block a user