mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Add SoftLayer DNS provider (#59)
Add SoftLayer DNS as a DomainServiceProvider. The SoftLayer API is a bit of a mess and treats MX and SRV records differently. This leads to some replication and custom handling issues to work around. In this patch I have to change the SRV test case to be _tcp instead of _protocol because softlayer requires a "known" protocol which AFAICT is tcp, udp or tls. I think this will be acceptable in most cases. Signed-off-by: Jamie Lennox <jamielennox@gmail.com>
This commit is contained in:
committed by
Tom Limoncelli
parent
e7535fe3cb
commit
7daa7a6467
232
vendor/github.com/softlayer/softlayer-go/session/rest.go
generated
vendored
Normal file
232
vendor/github.com/softlayer/softlayer-go/session/rest.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* 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 session
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/softlayer/softlayer-go/datatypes"
|
||||
"github.com/softlayer/softlayer-go/sl"
|
||||
)
|
||||
|
||||
type RestTransport struct{}
|
||||
|
||||
// DoRequest - Implementation of the TransportHandler interface for handling
|
||||
// calls to the REST endpoint.
|
||||
func (r *RestTransport) DoRequest(sess *Session, service string, method string, args []interface{}, options *sl.Options, pResult interface{}) error {
|
||||
restMethod := httpMethod(method, args)
|
||||
|
||||
// Parse any method parameters and determine the HTTP method
|
||||
var parameters []byte
|
||||
if len(args) > 0 {
|
||||
// parse the parameters
|
||||
parameters, _ = json.Marshal(
|
||||
map[string]interface{}{
|
||||
"parameters": args,
|
||||
})
|
||||
}
|
||||
|
||||
path := buildPath(service, method, options)
|
||||
|
||||
resp, code, err := makeHTTPRequest(
|
||||
sess,
|
||||
path,
|
||||
restMethod,
|
||||
bytes.NewBuffer(parameters),
|
||||
options)
|
||||
|
||||
if err != nil {
|
||||
return sl.Error{Wrapped: err}
|
||||
}
|
||||
|
||||
if code < 200 || code > 299 {
|
||||
e := sl.Error{StatusCode: code}
|
||||
|
||||
err = json.Unmarshal(resp, &e)
|
||||
|
||||
// If unparseable, wrap the json error
|
||||
if err != nil {
|
||||
e.Wrapped = err
|
||||
e.Message = err.Error()
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
// Some APIs that normally return a collection, omit the []'s when the API returns a single value
|
||||
returnType := reflect.TypeOf(pResult).String()
|
||||
if strings.Index(returnType, "[]") == 1 && strings.Index(string(resp), "[") != 0 {
|
||||
resp = []byte("[" + string(resp) + "]")
|
||||
}
|
||||
|
||||
// At this point, all that's left to do is parse the return value to the appropriate type, and return
|
||||
// any parse errors (or nil if successful)
|
||||
|
||||
err = nil
|
||||
switch pResult.(type) {
|
||||
case *[]uint8:
|
||||
// exclude quotes
|
||||
*pResult.(*[]uint8) = resp[1 : len(resp)-1]
|
||||
case *datatypes.Void:
|
||||
case *uint:
|
||||
var val uint64
|
||||
val, err = strconv.ParseUint(string(resp), 0, 64)
|
||||
if err == nil {
|
||||
*pResult.(*uint) = uint(val)
|
||||
}
|
||||
case *bool:
|
||||
*pResult.(*bool), err = strconv.ParseBool(string(resp))
|
||||
case *string:
|
||||
str := string(resp)
|
||||
strIdx := len(str) - 1
|
||||
if str == "null" {
|
||||
str = ""
|
||||
} else if str[0] == '"' && str[strIdx] == '"' {
|
||||
rawStr := rawString{str}
|
||||
err = json.Unmarshal([]byte(`{"val":`+str+`}`), &rawStr)
|
||||
if err == nil {
|
||||
str = rawStr.Val
|
||||
}
|
||||
}
|
||||
*pResult.(*string) = str
|
||||
default:
|
||||
// Must be a json representation of one of the many softlayer datatypes
|
||||
err = json.Unmarshal(resp, pResult)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = sl.Error{Message: err.Error(), Wrapped: err}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type rawString struct {
|
||||
Val string
|
||||
}
|
||||
|
||||
func buildPath(service string, method string, options *sl.Options) string {
|
||||
path := service
|
||||
|
||||
if options.Id != nil {
|
||||
path = path + "/" + strconv.Itoa(*options.Id)
|
||||
}
|
||||
|
||||
// omit the API method name if the method represents one of the basic REST methods
|
||||
if method != "getObject" && method != "deleteObject" && method != "createObject" &&
|
||||
method != "createObjects" && method != "editObject" && method != "editObjects" {
|
||||
path = path + "/" + method
|
||||
}
|
||||
|
||||
return path + ".json"
|
||||
}
|
||||
|
||||
func encodeQuery(opts *sl.Options) string {
|
||||
query := new(url.URL).Query()
|
||||
|
||||
if opts.Mask != "" {
|
||||
query.Add("objectMask", opts.Mask)
|
||||
}
|
||||
|
||||
if opts.Filter != "" {
|
||||
query.Add("objectFilter", opts.Filter)
|
||||
}
|
||||
|
||||
// resultLimit=<offset>,<limit>
|
||||
// If offset unspecified, default to 0
|
||||
if opts.Limit != nil {
|
||||
startOffset := 0
|
||||
if opts.Offset != nil {
|
||||
startOffset = *opts.Offset
|
||||
}
|
||||
|
||||
query.Add("resultLimit", fmt.Sprintf("%d,%d", startOffset, *opts.Limit))
|
||||
}
|
||||
|
||||
return query.Encode()
|
||||
}
|
||||
|
||||
func makeHTTPRequest(session *Session, path string, requestType string, requestBody *bytes.Buffer, options *sl.Options) ([]byte, int, error) {
|
||||
log := Logger
|
||||
client := http.DefaultClient
|
||||
client.Timeout = DefaultTimeout
|
||||
if session.Timeout != 0 {
|
||||
client.Timeout = session.Timeout
|
||||
}
|
||||
|
||||
var url string
|
||||
if session.Endpoint == "" {
|
||||
url = url + DefaultEndpoint
|
||||
} else {
|
||||
url = url + session.Endpoint
|
||||
}
|
||||
url = fmt.Sprintf("%s/%s", strings.TrimRight(url, "/"), path)
|
||||
req, err := http.NewRequest(requestType, url, requestBody)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if session.APIKey != "" {
|
||||
req.SetBasicAuth(session.UserName, session.APIKey)
|
||||
} else if session.AuthToken != "" {
|
||||
req.SetBasicAuth(fmt.Sprintf("%d", session.UserId), session.AuthToken)
|
||||
}
|
||||
|
||||
req.URL.RawQuery = encodeQuery(options)
|
||||
|
||||
if session.Debug {
|
||||
log.Println("[DEBUG] Request URL: ", requestType, req.URL)
|
||||
log.Println("[DEBUG] Parameters: ", requestBody.String())
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, 520, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
responseBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, resp.StatusCode, err
|
||||
}
|
||||
|
||||
if session.Debug {
|
||||
log.Println("[DEBUG] Response: ", string(responseBody))
|
||||
}
|
||||
return responseBody, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func httpMethod(name string, args []interface{}) string {
|
||||
if name == "deleteObject" {
|
||||
return "DELETE"
|
||||
} else if name == "editObject" || name == "editObjects" {
|
||||
return "PUT"
|
||||
} else if name == "createObject" || name == "createObjects" || len(args) > 0 {
|
||||
return "POST"
|
||||
}
|
||||
|
||||
return "GET"
|
||||
}
|
234
vendor/github.com/softlayer/softlayer-go/session/session.go
generated
vendored
Normal file
234
vendor/github.com/softlayer/softlayer-go/session/session.go
generated
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* 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 session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/user"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/softlayer/softlayer-go/config"
|
||||
"github.com/softlayer/softlayer-go/sl"
|
||||
)
|
||||
|
||||
// Logger is the logger used by the SoftLayer session package. Can be overridden by the user.
|
||||
var Logger *log.Logger
|
||||
|
||||
func init() {
|
||||
// initialize the logger used by the session package.
|
||||
Logger = log.New(os.Stderr, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
// DefaultEndpoint is the default endpoint for API calls, when no override
|
||||
// is provided.
|
||||
const DefaultEndpoint = "https://api.softlayer.com/rest/v3"
|
||||
|
||||
// TransportHandler
|
||||
type TransportHandler interface {
|
||||
// DoRequest is the protocol-specific handler for making API requests.
|
||||
//
|
||||
// sess is a reference to the current session object, where authentication and
|
||||
// endpoint information can be found.
|
||||
//
|
||||
// service and method are the SoftLayer service name and method name, exactly as they
|
||||
// are documented at http://sldn.softlayer.com/reference/softlayerapi (i.e., with the
|
||||
// 'SoftLayer_' prefix and properly cased.
|
||||
//
|
||||
// args is a slice of arguments required for the service method being invoked. The
|
||||
// types of each argument varies. See the method definition in the services package
|
||||
// for the expected type of each argument.
|
||||
//
|
||||
// options is an sl.Options struct, containing any mask, filter, or result limit values
|
||||
// to be applied.
|
||||
//
|
||||
// pResult is a pointer to a variable to be populated with the result of the API call.
|
||||
// DoRequest should ensure that the native API response (i.e., XML or JSON) is correctly
|
||||
// unmarshaled into the result structure.
|
||||
//
|
||||
// A sl.Error is returned, and can be (with a type assertion) inspected for details of
|
||||
// the error (http code, API error message, etc.), or simply handled as a generic error,
|
||||
// (in which case no type assertion would be necessary)
|
||||
DoRequest(
|
||||
sess *Session,
|
||||
service string,
|
||||
method string,
|
||||
args []interface{},
|
||||
options *sl.Options,
|
||||
pResult interface{}) error
|
||||
}
|
||||
|
||||
const DefaultTimeout = time.Second * 120
|
||||
|
||||
// Session stores the information required for communication with the SoftLayer
|
||||
// API
|
||||
type Session struct {
|
||||
// UserName is the name of the SoftLayer API user
|
||||
UserName string
|
||||
|
||||
// ApiKey is the secret for making API calls
|
||||
APIKey string
|
||||
|
||||
// Endpoint is the SoftLayer API endpoint to communicate with
|
||||
Endpoint string
|
||||
|
||||
// UserId is the user id for token-based authentication
|
||||
UserId int
|
||||
|
||||
// AuthToken is the token secret for token-based authentication
|
||||
AuthToken string
|
||||
|
||||
// Debug controls logging of request details (URI, parameters, etc.)
|
||||
Debug bool
|
||||
|
||||
// The handler whose DoRequest() function will be called for each API request.
|
||||
// Handles the request and any response parsing specific to the desired protocol
|
||||
// (e.g., REST). Set automatically for a new Session, based on the
|
||||
// provided Endpoint.
|
||||
TransportHandler TransportHandler
|
||||
|
||||
// Timeout specifies a time limit for http requests made by this
|
||||
// session. Requests that take longer that the specified timeout
|
||||
// will result in an error.
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// New creates and returns a pointer to a new session object. It takes up to
|
||||
// three parameters, all of which are optional. If specified, they will be
|
||||
// interpreted in the following sequence:
|
||||
//
|
||||
// 1. UserName
|
||||
// 2. Api Key
|
||||
// 3. Endpoint
|
||||
// 4. Timeout
|
||||
//
|
||||
// If one or more are omitted, New() will attempt to retrieve these values from
|
||||
// the environment, and the ~/.softlayer config file, in that order.
|
||||
func New(args ...interface{}) *Session {
|
||||
keys := map[string]int{"username": 0, "api_key": 1, "endpoint_url": 2, "timeout": 3}
|
||||
values := []string{"", "", "", ""}
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
values[i] = args[i].(string)
|
||||
}
|
||||
|
||||
// Default to the environment variables
|
||||
|
||||
// Prioritize SL_USERNAME
|
||||
envFallback("SL_USERNAME", &values[keys["username"]])
|
||||
envFallback("SOFTLAYER_USERNAME", &values[keys["username"]])
|
||||
|
||||
// Prioritize SL_API_KEY
|
||||
envFallback("SL_API_KEY", &values[keys["api_key"]])
|
||||
envFallback("SOFTLAYER_API_KEY", &values[keys["api_key"]])
|
||||
|
||||
// Prioritize SL_ENDPOINT_URL
|
||||
envFallback("SL_ENDPOINT_URL", &values[keys["endpoint_url"]])
|
||||
envFallback("SOFTLAYER_ENDPOINT_URL", &values[keys["endpoint_url"]])
|
||||
|
||||
envFallback("SL_TIMEOUT", &values[keys["timeout"]])
|
||||
envFallback("SOFTLAYER_TIMEOUT", &values[keys["timeout"]])
|
||||
|
||||
// Read ~/.softlayer for configuration
|
||||
var homeDir string
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
for _, name := range []string{"HOME", "USERPROFILE"} { // *nix, windows
|
||||
if dir := os.Getenv(name); dir != "" {
|
||||
homeDir = dir
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
homeDir = u.HomeDir
|
||||
}
|
||||
|
||||
if homeDir != "" {
|
||||
configPath := fmt.Sprintf("%s/.softlayer", homeDir)
|
||||
if _, err = os.Stat(configPath); !os.IsNotExist(err) {
|
||||
// config file exists
|
||||
file, err := config.LoadFile(configPath)
|
||||
if err != nil {
|
||||
log.Println(fmt.Sprintf("[WARN] session: Could not parse %s : %s", configPath, err))
|
||||
} else {
|
||||
for k, v := range keys {
|
||||
value, ok := file.Get("softlayer", k)
|
||||
if ok && values[v] == "" {
|
||||
values[v] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Println("[WARN] session: home dir could not be determined. Skipping read of ~/.softlayer.")
|
||||
}
|
||||
|
||||
endpointURL := values[keys["endpoint_url"]]
|
||||
if endpointURL == "" {
|
||||
endpointURL = DefaultEndpoint
|
||||
}
|
||||
|
||||
sess := &Session{
|
||||
UserName: values[keys["username"]],
|
||||
APIKey: values[keys["api_key"]],
|
||||
Endpoint: endpointURL,
|
||||
}
|
||||
|
||||
timeout := values[keys["timeout"]]
|
||||
if timeout != "" {
|
||||
timeoutDuration, err := time.ParseDuration(fmt.Sprintf("%ss", timeout))
|
||||
if err == nil {
|
||||
sess.Timeout = timeoutDuration
|
||||
}
|
||||
}
|
||||
|
||||
return sess
|
||||
}
|
||||
|
||||
// DoRequest hands off the processing to the assigned transport handler. It is
|
||||
// normally called internally by the service objects, but is exported so that it can
|
||||
// be invoked directly by client code in exceptional cases where direct control is
|
||||
// needed over one of the parameters.
|
||||
//
|
||||
// For a description of parameters, see TransportHandler.DoRequest in this package
|
||||
func (r *Session) DoRequest(service string, method string, args []interface{}, options *sl.Options, pResult interface{}) error {
|
||||
if r.TransportHandler == nil {
|
||||
r.TransportHandler = getDefaultTransport(r.Endpoint)
|
||||
}
|
||||
|
||||
return r.TransportHandler.DoRequest(r, service, method, args, options, pResult)
|
||||
}
|
||||
|
||||
func envFallback(keyName string, value *string) {
|
||||
if *value == "" {
|
||||
*value = os.Getenv(keyName)
|
||||
}
|
||||
}
|
||||
|
||||
func getDefaultTransport(endpointURL string) TransportHandler {
|
||||
var transportHandler TransportHandler
|
||||
|
||||
if strings.Contains(endpointURL, "/xmlrpc/") {
|
||||
transportHandler = &XmlRpcTransport{}
|
||||
} else {
|
||||
transportHandler = &RestTransport{}
|
||||
}
|
||||
|
||||
return transportHandler
|
||||
}
|
195
vendor/github.com/softlayer/softlayer-go/session/xmlrpc.go
generated
vendored
Normal file
195
vendor/github.com/softlayer/softlayer-go/session/xmlrpc.go
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Copyright 2016 IBM Corp.
|
||||
*
|
||||
* 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 session
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
|
||||
"github.com/renier/xmlrpc"
|
||||
"github.com/softlayer/softlayer-go/sl"
|
||||
)
|
||||
|
||||
// Debugging RoundTripper
|
||||
type debugRoundTripper struct{}
|
||||
|
||||
func (mrt debugRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
log := Logger
|
||||
log.Println("->>>Request:")
|
||||
dumpedReq, _ := httputil.DumpRequestOut(request, true)
|
||||
log.Println(string(dumpedReq))
|
||||
|
||||
response, err := http.DefaultTransport.RoundTrip(request)
|
||||
if err != nil {
|
||||
log.Println("Error:", err)
|
||||
return response, err
|
||||
}
|
||||
|
||||
log.Println("\n\n<<<-Response:")
|
||||
dumpedResp, _ := httputil.DumpResponse(response, true)
|
||||
log.Println(string(dumpedResp))
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
// XML-RPC Transport
|
||||
type XmlRpcTransport struct{}
|
||||
|
||||
func (x *XmlRpcTransport) DoRequest(
|
||||
sess *Session,
|
||||
service string,
|
||||
method string,
|
||||
args []interface{},
|
||||
options *sl.Options,
|
||||
pResult interface{},
|
||||
) error {
|
||||
|
||||
serviceUrl := fmt.Sprintf("%s/%s", strings.TrimRight(sess.Endpoint, "/"), service)
|
||||
|
||||
var roundTripper http.RoundTripper
|
||||
if sess.Debug {
|
||||
roundTripper = debugRoundTripper{}
|
||||
}
|
||||
|
||||
timeout := DefaultTimeout
|
||||
if sess.Timeout != 0 {
|
||||
timeout = sess.Timeout
|
||||
}
|
||||
|
||||
client, err := xmlrpc.NewClient(serviceUrl, roundTripper, timeout)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not create an xmlrpc client for %s: %s", service, err)
|
||||
}
|
||||
|
||||
authenticate := map[string]interface{}{}
|
||||
if sess.UserName != "" {
|
||||
authenticate["username"] = sess.UserName
|
||||
}
|
||||
|
||||
if sess.APIKey != "" {
|
||||
authenticate["apiKey"] = sess.APIKey
|
||||
}
|
||||
|
||||
if sess.UserId != 0 {
|
||||
authenticate["userId"] = sess.UserId
|
||||
authenticate["complexType"] = "PortalLoginToken"
|
||||
}
|
||||
|
||||
if sess.AuthToken != "" {
|
||||
authenticate["authToken"] = sess.AuthToken
|
||||
authenticate["complexType"] = "PortalLoginToken"
|
||||
}
|
||||
|
||||
headers := map[string]interface{}{}
|
||||
if len(authenticate) > 0 {
|
||||
headers["authenticate"] = authenticate
|
||||
}
|
||||
|
||||
if options.Id != nil {
|
||||
headers[fmt.Sprintf("%sInitParameters", service)] = map[string]int{
|
||||
"id": *options.Id,
|
||||
}
|
||||
}
|
||||
|
||||
mask := options.Mask
|
||||
if mask != "" {
|
||||
if !strings.HasPrefix(mask, "mask[") && !strings.Contains(mask, ";") && strings.Contains(mask, ",") {
|
||||
mask = fmt.Sprintf("mask[%s]", mask)
|
||||
headers["SoftLayer_ObjectMask"] = map[string]string{"mask": mask}
|
||||
} else {
|
||||
headers[fmt.Sprintf("%sObjectMask", service)] =
|
||||
map[string]interface{}{"mask": genXMLMask(mask)}
|
||||
}
|
||||
}
|
||||
|
||||
if options.Filter != "" {
|
||||
// FIXME: This json unmarshaling presents a performance problem,
|
||||
// since the filter builder marshals a data structure to json.
|
||||
// This then undoes that step to pass it to the xmlrpc request.
|
||||
// It would be better to get the umarshaled data structure
|
||||
// from the filter builder, but that will require changes to the
|
||||
// public API in Options.
|
||||
objFilter := map[string]interface{}{}
|
||||
err := json.Unmarshal([]byte(options.Filter), &objFilter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error encoding object filter: %s", err)
|
||||
}
|
||||
headers[fmt.Sprintf("%sObjectFilter", service)] = objFilter
|
||||
}
|
||||
|
||||
if options.Limit != nil {
|
||||
offset := 0
|
||||
if options.Offset != nil {
|
||||
offset = *options.Offset
|
||||
}
|
||||
|
||||
headers["resultLimit"] = map[string]int{
|
||||
"limit": *options.Limit,
|
||||
"offset": offset,
|
||||
}
|
||||
}
|
||||
|
||||
// Add incoming arguments to xmlrpc parameter array
|
||||
params := []interface{}{}
|
||||
|
||||
if len(headers) > 0 {
|
||||
params = append(params, map[string]interface{}{"headers": headers})
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
params = append(params, arg)
|
||||
}
|
||||
|
||||
err = client.Call(method, params, pResult)
|
||||
if xmlRpcError, ok := err.(*xmlrpc.XmlRpcError); ok {
|
||||
return sl.Error{
|
||||
StatusCode: xmlRpcError.HttpStatusCode,
|
||||
Exception: xmlRpcError.Code.(string),
|
||||
Message: xmlRpcError.Err,
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func genXMLMask(mask string) interface{} {
|
||||
objectMask := map[string]interface{}{}
|
||||
for _, item := range strings.Split(mask, ";") {
|
||||
if !strings.Contains(item, ".") {
|
||||
objectMask[item] = []string{}
|
||||
continue
|
||||
}
|
||||
|
||||
level := objectMask
|
||||
names := strings.Split(item, ".")
|
||||
totalNames := len(names)
|
||||
for i, name := range names {
|
||||
if i == totalNames-1 {
|
||||
level[name] = []string{}
|
||||
continue
|
||||
}
|
||||
|
||||
level[name] = map[string]interface{}{}
|
||||
level = level[name].(map[string]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
return objectMask
|
||||
}
|
Reference in New Issue
Block a user