mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
Merge branch 'master' into feature/tb-support-ctyun-crm-account
This commit is contained in:
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/aliyun"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/aliyun/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -85,12 +90,27 @@ func newClient(options *BaseOptions) (*aliyun.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := aliyun.NewAliyunClient(
|
||||
aliyun.NewAliyunClientConfig(
|
||||
options.CloudEnv,
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+20
-1
@@ -16,8 +16,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -87,13 +91,28 @@ func newClient(options *BaseOptions) (*apsara.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := apsara.NewApsaraClient(
|
||||
apsara.NewApsaraClientConfig(
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
options.Endpoint,
|
||||
options.SApsaraEndpoints,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,11 +16,16 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/aws"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/aws/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -87,13 +92,28 @@ func newClient(options *BaseOptions) (*aws.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := aws.NewAwsClient(
|
||||
aws.NewAwsClientConfig(
|
||||
options.AccessUrl,
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
options.AccountId,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/azure"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/azure/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/printutils"
|
||||
@@ -100,6 +105,16 @@ func newClient(options *BaseOptions) (*azure.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing Cloud Environment")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := azure.NewAzureClient(
|
||||
azure.NewAzureClientConfig(
|
||||
options.CloudEnv,
|
||||
@@ -108,7 +123,12 @@ func newClient(options *BaseOptions) (*azure.SRegion, error) {
|
||||
options.ApplicationKey,
|
||||
).
|
||||
SubscriptionId(options.SubscriptionID).
|
||||
Debug(options.Debug),
|
||||
Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/cloudpods"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/cloudpods/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -88,12 +93,27 @@ func newClient(options *BaseOptions) (*cloudpods.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing access secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := cloudpods.NewCloudpodsClient(
|
||||
cloudpods.NewCloudpodsClientConfig(
|
||||
options.AuthURL,
|
||||
options.AccessKey,
|
||||
options.AccessSecret,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+20
-1
@@ -16,8 +16,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -87,10 +91,25 @@ func newClient(options *BaseOptions) (*ctyun.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := ctyun.NewSCtyunClient(
|
||||
ctyun.NewSCtyunClientConfig(
|
||||
options.AccessKey, options.Secret, &options.SCtyunExtraOptions,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/ecloud"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/ecloud/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -84,10 +89,25 @@ func newClient(options *Options) (*ecloud.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing access secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := ecloud.NewEcloudClient(
|
||||
ecloud.NewEcloudClientConfig(
|
||||
ecloud.NewRamRoleSigner(options.AccessKey, options.AccessSecret),
|
||||
).SetDebug(options.Debug),
|
||||
).SetDebug(options.Debug).
|
||||
SetCloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/esxi"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/esxi/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -88,13 +93,28 @@ func newClient(options *BaseOptions) (*esxi.SESXiClient, error) {
|
||||
return nil, fmt.Errorf("Missing password")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
return esxi.NewESXiClient2(
|
||||
esxi.NewESXiClientConfig(
|
||||
options.Host,
|
||||
options.Port,
|
||||
options.Account,
|
||||
options.Password,
|
||||
),
|
||||
).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+21
-1
@@ -16,13 +16,18 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/google"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/google/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
@@ -112,13 +117,28 @@ func newClient(options *BaseOptions) (*google.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing ProjectID")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := google.NewGoogleClient(
|
||||
google.NewGoogleClientConfig(
|
||||
options.ProjectID,
|
||||
options.ClientEmail,
|
||||
options.PrivateKeyID,
|
||||
options.PrivateKey,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+20
-1
@@ -16,8 +16,12 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
@@ -87,13 +91,28 @@ func newClient(options *BaseOptions) (*huawei.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := huawei.NewHuaweiClient(
|
||||
huawei.NewHuaweiClientConfig(
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
options.ProjectId,
|
||||
&options.SHCSOEndpoints,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/huawei/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -86,13 +91,28 @@ func newClient(options *BaseOptions) (*huawei.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := huawei.NewHuaweiClient(
|
||||
huawei.NewHuaweiClientConfig(
|
||||
options.CloudEnv,
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
options.ProjectId,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+20
-1
@@ -16,13 +16,17 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/jdcloud"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/jdcloud/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -89,7 +93,22 @@ func newClient(options *Options) (*jdcloud.SRegion, error) {
|
||||
if regionId == "" {
|
||||
regionId = jdcloud.JDCLOUD_DEFAULT_REGION
|
||||
}
|
||||
region := jdcloud.NewRegion(regionId, options.AccessKey, options.AccessSecret, nil, options.Debug)
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cfcg := &cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
}
|
||||
|
||||
region := jdcloud.NewRegion(regionId, options.AccessKey, options.AccessSecret, cfcg, options.Debug)
|
||||
if region == nil {
|
||||
return nil, fmt.Errorf("no such region %s", regionId)
|
||||
}
|
||||
|
||||
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/openstack"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/openstack/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -93,6 +98,16 @@ func newClient(options *BaseOptions) (*openstack.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing Password")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := openstack.NewOpenStackClient(
|
||||
openstack.NewOpenstackClientConfig(
|
||||
options.AuthURL,
|
||||
@@ -103,7 +118,12 @@ func newClient(options *BaseOptions) (*openstack.SRegion, error) {
|
||||
).
|
||||
EndpointType(options.EndpointType).
|
||||
DomainName(options.DomainName).
|
||||
Debug(options.Debug),
|
||||
Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+22
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/qcloud"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/qcloud/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -85,11 +90,27 @@ func newClient(options *BaseOptions) (*qcloud.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing SecretID")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
if cli, err := qcloud.NewQcloudClient(
|
||||
qcloud.NewQcloudClientConfig(
|
||||
options.SecretID,
|
||||
options.SecretKey,
|
||||
).AppId(options.AppID).Debug(options.Debug),
|
||||
).AppId(options.AppID).
|
||||
Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
} else if region := cli.GetRegion(options.RegionId); region == nil {
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
_ "yunion.io/x/onecloud/cmd/rbdcli/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
type BaseOptions struct {
|
||||
Help bool `help:"Show help"`
|
||||
Debug bool `help:"debug mode"`
|
||||
MonHost string `help:"Ceph Mon Host" default:"$MON_HOST"`
|
||||
Pool string `help:"Ceph pool" default:"$CEPH_POOL" metavar:"CEPH_POOL"`
|
||||
Key string `help:"Secret" default:"$CEPH_KEY" metavar:"CEPH_KEY"`
|
||||
SUBCOMMAND string `help:"rbdcli subcommand" subcommand:"true"`
|
||||
}
|
||||
|
||||
func getSubcommandParser() (*structarg.ArgumentParser, error) {
|
||||
parse, e := structarg.NewArgumentParser(&BaseOptions{},
|
||||
"rbdcli",
|
||||
"Command-line interface to rbd API.",
|
||||
`See "rbdcli help COMMAND" for help on a specific command.`)
|
||||
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
subcmd := parse.GetSubcommand()
|
||||
if subcmd == nil {
|
||||
return nil, fmt.Errorf("No subcommand argument.")
|
||||
}
|
||||
type HelpOptions struct {
|
||||
SUBCOMMAND string `help:"sub-command name"`
|
||||
}
|
||||
shellutils.R(&HelpOptions{}, "help", "Show help of a subcommand", func(args *HelpOptions) error {
|
||||
helpstr, e := subcmd.SubHelpString(args.SUBCOMMAND)
|
||||
if e != nil {
|
||||
return e
|
||||
} else {
|
||||
fmt.Print(helpstr)
|
||||
return nil
|
||||
}
|
||||
})
|
||||
for _, v := range shellutils.CommandTable {
|
||||
_, e := subcmd.AddSubParser(v.Options, v.Command, v.Desc, v.Callback)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
return parse, nil
|
||||
}
|
||||
|
||||
func showErrorAndExit(e error) {
|
||||
fmt.Fprintf(os.Stderr, "%s", e)
|
||||
fmt.Fprintln(os.Stderr)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func newPool(opts *BaseOptions) (*rbdutils.SPool, error) {
|
||||
cli, err := rbdutils.NewCluster(opts.MonHost, opts.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool, err := cli.GetPool(opts.Pool)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetPool(%s)", opts.Pool)
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
parser, e := getSubcommandParser()
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
e = parser.ParseArgs(os.Args[1:], false)
|
||||
options := parser.Options().(*BaseOptions)
|
||||
|
||||
if options.Help {
|
||||
fmt.Print(parser.HelpString())
|
||||
return
|
||||
}
|
||||
subcmd := parser.GetSubcommand()
|
||||
subparser := subcmd.GetSubParser()
|
||||
if e != nil {
|
||||
if subparser != nil {
|
||||
fmt.Print(subparser.Usage())
|
||||
} else {
|
||||
fmt.Print(parser.Usage())
|
||||
}
|
||||
showErrorAndExit(e)
|
||||
return
|
||||
}
|
||||
suboptions := subparser.Options()
|
||||
if options.SUBCOMMAND == "help" {
|
||||
e = subcmd.Invoke(suboptions)
|
||||
} else {
|
||||
var pool *rbdutils.SPool
|
||||
pool, e = newPool(options)
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
e = subcmd.Invoke(pool, suboptions)
|
||||
}
|
||||
if e != nil {
|
||||
showErrorAndExit(e)
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type ClusterStatOption struct {
|
||||
}
|
||||
|
||||
shellutils.R(&ClusterStatOption{}, "cluster-stat", "Show Cluster State", func(cli *rbdutils.SPool, args *ClusterStatOption) error {
|
||||
cluster := cli.GetCluster()
|
||||
stat, err := cluster.GetClusterStats()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetClusterStats")
|
||||
}
|
||||
printObject(stat)
|
||||
return nil
|
||||
})
|
||||
|
||||
type CmdOptions struct {
|
||||
CMD string
|
||||
}
|
||||
|
||||
shellutils.R(&CmdOptions{}, "run", "Run Cluster command", func(cli *rbdutils.SPool, args *CmdOptions) error {
|
||||
ret, err := cli.GetCluster().MonCommand([]byte(args.CMD))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "MonCommand")
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 shell
|
||||
|
||||
import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type PoolListOptions struct {
|
||||
}
|
||||
shellutils.R(&PoolListOptions{}, "pool-list", "List pools", func(cli *rbdutils.SPool, args *PoolListOptions) error {
|
||||
cluster := cli.GetCluster()
|
||||
pools, err := cluster.ListPools()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "ListPools")
|
||||
}
|
||||
printObject(jsonutils.Marshal(map[string][]string{"pools": pools}))
|
||||
return nil
|
||||
})
|
||||
|
||||
type PoolDeleteOptions struct {
|
||||
POOL string
|
||||
}
|
||||
|
||||
shellutils.R(&PoolDeleteOptions{}, "pool-delete", "Delete Cluster pool", func(cli *rbdutils.SPool, args *PoolDeleteOptions) error {
|
||||
return cli.GetCluster().DeletePool(args.POOL)
|
||||
})
|
||||
|
||||
type ImageListOptions struct {
|
||||
}
|
||||
|
||||
shellutils.R(&ImageListOptions{}, "image-list", "List Pool images", func(cli *rbdutils.SPool, args *ImageListOptions) error {
|
||||
images, err := cli.ListImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(jsonutils.Marshal(map[string][]string{"images": images}))
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 shell
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/util/printutils"
|
||||
|
||||
func printList(data interface{}, total, offset, limit int, columns []string) {
|
||||
printutils.PrintInterfaceList(data, total, offset, limit, columns)
|
||||
}
|
||||
|
||||
func printObject(obj interface{}) {
|
||||
printutils.PrintInterfaceObject(obj)
|
||||
}
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/ucloud"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/ucloud/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -86,11 +91,26 @@ func newClient(options *BaseOptions) (*ucloud.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing secret")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := ucloud.NewUcloudClient(
|
||||
ucloud.NewUcloudClientConfig(
|
||||
options.AccessKey,
|
||||
options.Secret,
|
||||
).ProjectId(options.ProjectId).Debug(options.Debug),
|
||||
).ProjectId(options.ProjectId).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+21
-1
@@ -16,10 +16,15 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/http/httpproxy"
|
||||
|
||||
"yunion.io/x/structarg"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/zstack"
|
||||
_ "yunion.io/x/onecloud/pkg/multicloud/zstack/shell"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
@@ -89,12 +94,27 @@ func newClient(options *BaseOptions) (*zstack.SRegion, error) {
|
||||
return nil, fmt.Errorf("Missing Password")
|
||||
}
|
||||
|
||||
cfg := &httpproxy.Config{
|
||||
HTTPProxy: os.Getenv("HTTP_PROXY"),
|
||||
HTTPSProxy: os.Getenv("HTTPS_PROXY"),
|
||||
NoProxy: os.Getenv("NO_PROXY"),
|
||||
}
|
||||
cfgProxyFunc := cfg.ProxyFunc()
|
||||
proxyFunc := func(req *http.Request) (*url.URL, error) {
|
||||
return cfgProxyFunc(req.URL)
|
||||
}
|
||||
|
||||
cli, err := zstack.NewZStackClient(
|
||||
zstack.NewZstackClientConfig(
|
||||
options.AuthURL,
|
||||
options.Username,
|
||||
options.Password,
|
||||
).Debug(options.Debug),
|
||||
).Debug(options.Debug).
|
||||
CloudproviderConfig(
|
||||
cloudprovider.ProviderConfig{
|
||||
ProxyFunc: proxyFunc,
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -36,7 +36,6 @@ require (
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/c-bata/go-prompt v0.2.1
|
||||
github.com/ceph/go-ceph v0.0.0-20181217221554-e32f9f0f2e94
|
||||
github.com/cheggaaa/pb/v3 v3.0.8
|
||||
github.com/coredns/coredns v1.3.0
|
||||
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a // indirect
|
||||
@@ -60,7 +59,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.2 // indirect
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/gofrs/uuid v3.2.0+incompatible // indirect
|
||||
github.com/gofrs/uuid v4.1.0+incompatible // indirect
|
||||
github.com/golang-plus/errors v1.0.0
|
||||
github.com/golang-plus/testing v1.0.0 // indirect
|
||||
github.com/golang-plus/uuid v1.0.0
|
||||
@@ -152,7 +151,7 @@ require (
|
||||
k8s.io/client-go v0.19.3
|
||||
k8s.io/cluster-bootstrap v0.19.3
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656
|
||||
yunion.io/x/jsonutils v0.0.0-20210709075951-798a67800349
|
||||
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a
|
||||
yunion.io/x/log v0.0.0-20201210064738-43181789dc74
|
||||
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
|
||||
yunion.io/x/pkg v0.0.0-20210918114143-ce839f862c5f
|
||||
@@ -160,5 +159,3 @@ require (
|
||||
yunion.io/x/sqlchemy v0.0.0-20210918113031-c1c107f37ada
|
||||
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce
|
||||
)
|
||||
|
||||
replace github.com/ceph/go-ceph v0.0.0-20181217221554-e32f9f0f2e94 => github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859
|
||||
|
||||
@@ -266,8 +266,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk=
|
||||
github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
@@ -632,8 +632,6 @@ github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0s
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859 h1:wu596gn6sV3j5wy+GDfiG8nwtzIDpalJihfmC/TjoYc=
|
||||
github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859/go.mod h1:8XuBae5AzsgotLArJSewMruYVaQs8AlfsK5jBCG8T9Y=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5 h1:Gqga3zA9tdAcfqobUGjSoCob5L3f8Dt5EuOp3ihNZko=
|
||||
@@ -932,8 +930,8 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 h1:0zlZD5uhZoIHgLVAWCz2aHaYk2ZrNsACCYD7R6EIBII=
|
||||
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
|
||||
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
|
||||
yunion.io/x/jsonutils v0.0.0-20210709075951-798a67800349 h1:ESeezAb9LM2Dcy28DDrD2nI+h22qEf4MyAPXwuDO4uM=
|
||||
yunion.io/x/jsonutils v0.0.0-20210709075951-798a67800349/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
|
||||
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a h1:X/ucfLNcYsCfc4GFEX7R7GNWiDPr3vopLdnE4PuU46U=
|
||||
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
|
||||
yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE=
|
||||
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
|
||||
yunion.io/x/log v0.0.0-20201210064738-43181789dc74 h1:7D+sQ/XaUTUEm+NCrKXOhXBKlzEd0RyS2qZ4vBGjx2o=
|
||||
|
||||
@@ -80,8 +80,9 @@ type GuestnetworkJsonDesc struct {
|
||||
Virtual bool `json:"virtual"`
|
||||
Ip string `json:"ip"`
|
||||
Gateway string `json:"gateway"`
|
||||
DNS string `json:"dns"`
|
||||
Dns string `json:"dns"`
|
||||
Domain string `json:"domain"`
|
||||
Ntp string `json:"ntp"`
|
||||
Routes jsonutils.JSONObject `json:"routes"`
|
||||
Ifname string `json:"ifname"`
|
||||
Masklen int8 `json:"masklen"`
|
||||
|
||||
@@ -56,7 +56,11 @@ type InterVpcNetworkSyncstatusInput struct {
|
||||
}
|
||||
|
||||
type InterVpcNetworkAddVpcInput struct {
|
||||
VpcId string
|
||||
// 待加入的vpc id
|
||||
// vpc和当前vpc互联所必须是同一平台,且运营平台一致,例如aws中国区不能和aws国际区运营平台不一致
|
||||
// 可以通过 /vpcs?usable_for_inter_vpc_network_id=<当前vpc互联id> 过滤可以加入的vpc列表
|
||||
// required: true
|
||||
VpcId string `json:"vpc_id"`
|
||||
}
|
||||
|
||||
type InterVpcNetworkRemoveVpcInput struct {
|
||||
|
||||
@@ -99,6 +99,8 @@ type NetworkListInput struct {
|
||||
GuestDns []string `json:"guest_dns"`
|
||||
// allow multiple dhcp, seperated by ","
|
||||
GuestDhcp []string `json:"guest_dhcp"`
|
||||
// NTP
|
||||
GuestNtp []string `json:"guest_ntp"`
|
||||
|
||||
GuestDomain []string `json:"guest_domain"`
|
||||
|
||||
@@ -172,13 +174,17 @@ type NetworkCreateInput struct {
|
||||
GuestGateway string `json:"guest_gateway"`
|
||||
|
||||
// description: guest dns
|
||||
// example: 114.114.114.114
|
||||
// example: 114.114.114.114,8.8.8.8
|
||||
GuestDns string `json:"guest_dns"`
|
||||
|
||||
// description: guest dhcp
|
||||
// example: 192.168.222.1,192.168.222.4
|
||||
GuestDHCP string `json:"guest_dhcp"`
|
||||
|
||||
// description: guest ntp
|
||||
// example: cn.pool.ntp.org,0.cn.pool.ntp.org
|
||||
GuestNtp string `json:"guest_ntp"`
|
||||
|
||||
// swagger:ignore
|
||||
WireId string `json:"wire_id"`
|
||||
|
||||
@@ -349,6 +355,8 @@ type NetworkUpdateInput struct {
|
||||
GuestDns string `json:"guest_dns"`
|
||||
// allow multiple dhcp, seperated by ","
|
||||
GuestDhcp string `json:"guest_dhcp"`
|
||||
// NTP
|
||||
GuestNtp string `json:"guest_ntp"`
|
||||
|
||||
GuestDomain string `json:"guest_domain"`
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultDNSServers = "223.5.5.5,223.6.6.6"
|
||||
)
|
||||
|
||||
const (
|
||||
// # DEFAULT_BANDWIDTH = options.default_bandwidth
|
||||
MAX_BANDWIDTH = 100000
|
||||
|
||||
@@ -28,7 +28,8 @@ const (
|
||||
|
||||
type VpcPeeringConnectionDetails struct {
|
||||
apis.EnabledStatusInfrasResourceBaseDetails
|
||||
VpcName string
|
||||
VpcResourceInfo
|
||||
|
||||
PeerVpcName string
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ type VpcListInput struct {
|
||||
DnsZoneFilterListBase
|
||||
|
||||
InterVpcNetworkFilterListBase
|
||||
// 过滤可以加入指定vpc互联的vpc
|
||||
UsableForInterVpcNetworkId string `json:"usable_for_inter_vpc_network_id"`
|
||||
|
||||
UsableResourceListInput
|
||||
UsableVpcResourceListInput
|
||||
|
||||
@@ -18,7 +18,11 @@ import (
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
const VPC_OVN_ENCAP_COST = 58
|
||||
// IP: 20
|
||||
// UDP: 8
|
||||
// GENEVE HDR: 8 + 4x
|
||||
// total: 36 + 4x
|
||||
const VPC_OVN_ENCAP_COST = 60
|
||||
|
||||
const (
|
||||
VPC_EXTERNAL_ACCESS_MODE_DISTGW = "distgw" // distgw only
|
||||
|
||||
+24
-1
@@ -19,6 +19,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
@@ -77,13 +78,35 @@ func GetNicDHCPConfig(
|
||||
routes = append(routes, []string{route[0], route[1]})
|
||||
}
|
||||
|
||||
parseIPs := func(ips string) []net.IP {
|
||||
ret := make([]net.IP, 0)
|
||||
iplist := strings.Split(ips, ",")
|
||||
for _, ip := range iplist {
|
||||
ret = append(ret, net.ParseIP(ip))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
parseDomains := func(domains string) []net.IP {
|
||||
ret := make([]net.IP, 0)
|
||||
domainlist := strings.Split(domains, ",")
|
||||
for _, domain := range domainlist {
|
||||
addrs, _ := net.LookupHost(domain)
|
||||
for _, addr := range addrs {
|
||||
ret = append(ret, net.ParseIP(addr))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
conf := &dhcp.ResponseConfig{
|
||||
ServerIP: net.ParseIP(serverIP),
|
||||
ClientIP: net.ParseIP(ipAddr.String()),
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
SubnetMask: subnetMask,
|
||||
BroadcastAddr: net.ParseIP(ipAddr.BroadcastAddr(n.MaskLen).String()),
|
||||
DNSServer: net.ParseIP(n.Dns),
|
||||
DNSServers: parseIPs(n.Dns),
|
||||
NTPServers: parseDomains(n.Ntp),
|
||||
Domain: n.Domain,
|
||||
OsName: "Linux",
|
||||
Hostname: hostName,
|
||||
|
||||
@@ -185,7 +185,7 @@ func ValueToJSONObject(out reflect.Value) jsonutils.JSONObject {
|
||||
if obj, ok := isJSONObject(out); ok {
|
||||
return obj
|
||||
}
|
||||
return jsonutils.Marshal(out.Interface())
|
||||
return jsonutils.MarshalAll(out.Interface())
|
||||
}
|
||||
|
||||
func ValueToJSONDict(out reflect.Value) *jsonutils.JSONDict {
|
||||
@@ -207,8 +207,36 @@ func ValueToError(out reflect.Value) error {
|
||||
func mergeInputOutputData(data *jsonutils.JSONDict, resVal reflect.Value) *jsonutils.JSONDict {
|
||||
retJson := ValueToJSONDict(resVal)
|
||||
// preserve the input info not returned by caller
|
||||
data.Update(retJson)
|
||||
return data
|
||||
output := data.Copy()
|
||||
jsonMap, _ := retJson.GetMap()
|
||||
for k, v := range jsonMap {
|
||||
if output.Contains(k) {
|
||||
if v == jsonutils.JSONNull {
|
||||
output.Remove(k)
|
||||
} else {
|
||||
switch v.(type) {
|
||||
case *jsonutils.JSONString:
|
||||
if v.IsZero() {
|
||||
output.Remove(k)
|
||||
} else {
|
||||
output.Set(k, v)
|
||||
}
|
||||
default:
|
||||
output.Set(k, v)
|
||||
}
|
||||
}
|
||||
} else if v != jsonutils.JSONNull {
|
||||
switch v.(type) {
|
||||
case *jsonutils.JSONString:
|
||||
if !v.IsZero() {
|
||||
output.Add(v, k)
|
||||
}
|
||||
default:
|
||||
output.Add(v, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
func ValidateCreateData(funcName string, manager IModelManager, ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
|
||||
|
||||
@@ -40,7 +40,7 @@ func Test_valueToJSONObject(t *testing.T) {
|
||||
{
|
||||
name: "struct2json",
|
||||
args: &api.ServerRebuildRootInput{Image: "image"},
|
||||
want: jsonutils.Marshal(api.ServerRebuildRootInput{Image: "image"}),
|
||||
want: jsonutils.MarshalAll(api.ServerRebuildRootInput{Image: "image"}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -114,7 +114,7 @@ const (
|
||||
type CommonOptions struct {
|
||||
AuthURL string `help:"Keystone auth URL" alias:"auth-uri"`
|
||||
AdminUser string `help:"Admin username"`
|
||||
AdminDomain string `help:"Admin user domain" default:"default"`
|
||||
AdminDomain string `help:"Admin user domain" default:"Default"`
|
||||
AdminPassword string `help:"Admin password" alias:"admin-passwd"`
|
||||
AdminProject string `help:"Admin project" default:"system" alias:"admin-tenant-name"`
|
||||
AdminProjectDomain string `help:"Domain of Admin project" default:"default"`
|
||||
|
||||
@@ -31,6 +31,7 @@ type SNic struct {
|
||||
Mtu int64 `json:"mtu"`
|
||||
Mac string `json:"mac"`
|
||||
Dns string `json:"dns"`
|
||||
Ntp string `json:"ntp"`
|
||||
MaskLen int8 `json:"masklen"`
|
||||
Net string `json:"net"`
|
||||
Gateway string `json:"gateway"`
|
||||
@@ -65,6 +66,7 @@ type SServerNic struct {
|
||||
BandWidth int `json:"bw"`
|
||||
Mtu int `json:"mtu,omitempty"`
|
||||
Dns string `json:"dns"`
|
||||
Ntp string `json:"ntp"`
|
||||
Net string `json:"net"`
|
||||
Interface string `json:"interface"`
|
||||
Gateway string `json:"gateway"`
|
||||
@@ -95,6 +97,7 @@ func (n SServerNic) ToNic() SNic {
|
||||
NetId: n.NetId,
|
||||
Mac: n.Mac,
|
||||
Dns: n.Dns,
|
||||
Ntp: n.Ntp,
|
||||
MaskLen: int8(n.Masklen),
|
||||
Net: n.Net,
|
||||
Gateway: n.Gateway,
|
||||
|
||||
@@ -1477,6 +1477,7 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To
|
||||
CDNDomainManager,
|
||||
NetworkInterfaceManager,
|
||||
KubeClusterManager,
|
||||
InterVpcNetworkManager,
|
||||
CloudproviderRegionManager,
|
||||
CloudregionManager,
|
||||
CloudproviderQuotaManager,
|
||||
|
||||
@@ -260,6 +260,7 @@ func syncRegionVPCs(ctx context.Context, userCred mcclient.TokenCredential, sync
|
||||
}
|
||||
db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, userCred)
|
||||
// logclient.AddActionLog(provider, getAction(task.Params), notes, task.UserCred, true)
|
||||
globalVpcIds := []string{}
|
||||
for j := 0; j < len(localVpcs); j += 1 {
|
||||
func() {
|
||||
// lock vpc
|
||||
@@ -271,7 +272,12 @@ func syncRegionVPCs(ctx context.Context, userCred mcclient.TokenCredential, sync
|
||||
}
|
||||
|
||||
syncVpcWires(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange)
|
||||
if localRegion.GetDriver().IsSecurityGroupBelongVpc() || localRegion.GetDriver().IsSupportClassicSecurityGroup() || j == 0 { //有vpc属性的每次都同步,支持classic的vpc也同步,否则仅同步一次
|
||||
if localRegion.GetDriver().IsSecurityGroupBelongVpc() ||
|
||||
(localRegion.GetDriver().IsSecurityGroupBelongGlobalVpc() && !utils.IsInStringArray(localVpcs[j].GlobalvpcId, globalVpcIds)) ||
|
||||
localRegion.GetDriver().IsSupportClassicSecurityGroup() || j == 0 { //有vpc属性的每次都同步,支持classic的vpc也同步,否则仅同步一次
|
||||
if len(localVpcs[j].GlobalvpcId) > 0 {
|
||||
globalVpcIds = append(globalVpcIds, localVpcs[j].GlobalvpcId)
|
||||
}
|
||||
syncVpcSecGroup(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange)
|
||||
}
|
||||
syncVpcNatgateways(ctx, userCred, syncResults, provider, &localVpcs[j], remoteVpcs[j], syncRange)
|
||||
@@ -1464,18 +1470,15 @@ func syncKubeClusters(ctx context.Context, userCred mcclient.TokenCredential, sy
|
||||
return
|
||||
}
|
||||
|
||||
err = syncKubeClusterNodePools(ctx, userCred, syncResults, &localClusters[i], remoteClusters[i])
|
||||
if err != nil {
|
||||
if err := syncKubeClusterNodePools(ctx, userCred, syncResults, &localClusters[i], remoteClusters[i]); err != nil {
|
||||
log.Errorf("syncKubeClusterNodePools for %s error: %v", localClusters[i].Name, err)
|
||||
}
|
||||
|
||||
err = syncKubeClusterNodes(ctx, userCred, syncResults, &localClusters[i], remoteClusters[i])
|
||||
if err != nil {
|
||||
if err := syncKubeClusterNodes(ctx, userCred, syncResults, &localClusters[i], remoteClusters[i]); err != nil {
|
||||
log.Errorf("syncKubeClusterNodes for %s error: %v", localClusters[i].Name, err)
|
||||
}
|
||||
|
||||
err = localClusters[i].Import(ctx, userCred, remoteClusters[i])
|
||||
if err != nil {
|
||||
if err := localClusters[i].ImportOrUpdate(ctx, userCred, remoteClusters[i]); err != nil {
|
||||
log.Errorf("Import cluster %s error: %v", localClusters[i].Name, err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -563,8 +563,9 @@ func (self *SGuestnetwork) getJsonDesc() *api.GuestnetworkJsonDesc {
|
||||
desc.Ip = self.IpAddr
|
||||
}
|
||||
desc.Gateway = net.GuestGateway
|
||||
desc.DNS = net.GetDNS()
|
||||
desc.Dns = net.GetDNS()
|
||||
desc.Domain = net.GetDomain()
|
||||
desc.Ntp = net.GetNTP()
|
||||
|
||||
routes := net.GetRoutes()
|
||||
if routes != nil && len(routes) > 0 {
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -111,6 +112,25 @@ func (manager *SInterVpcNetworkManager) ListItemFilter(
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (manager *SInterVpcNetworkManager) ListItemExportKeys(ctx context.Context,
|
||||
q *sqlchemy.SQuery,
|
||||
userCred mcclient.TokenCredential,
|
||||
keys stringutils2.SSortedStrings,
|
||||
) (*sqlchemy.SQuery, error) {
|
||||
var err error
|
||||
q, err = manager.SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys")
|
||||
}
|
||||
if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
|
||||
q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (manager *SInterVpcNetworkManager) ValidateCreateData(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
@@ -141,10 +161,12 @@ func (manager *SInterVpcNetworkManager) FetchCustomizeColumns(
|
||||
) []api.InterVpcNetworkDetails {
|
||||
rows := make([]api.InterVpcNetworkDetails, len(objs))
|
||||
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
vpcNetworkIds := make([]string, len(objs))
|
||||
for i := range rows {
|
||||
rows[i] = api.InterVpcNetworkDetails{
|
||||
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
|
||||
ManagedResourceInfo: manRows[i],
|
||||
}
|
||||
vpcNetwork := objs[i].(*SInterVpcNetwork)
|
||||
vpcNetworkIds[i] = vpcNetwork.Id
|
||||
@@ -264,13 +286,9 @@ func (self *SInterVpcNetwork) PerformAddvpc(ctx context.Context, userCred mcclie
|
||||
if len(input.VpcId) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("vpc_id")
|
||||
}
|
||||
// get vpc
|
||||
_vpc, err := VpcManager.FetchByIdOrName(userCred, input.VpcId)
|
||||
_vpc, err := validators.ValidateModel(userCred, VpcManager, &input.VpcId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2("vpc", input.VpcId)
|
||||
}
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
return nil, err
|
||||
}
|
||||
vpc := _vpc.(*SVpc)
|
||||
|
||||
|
||||
@@ -200,39 +200,51 @@ func (self *SKubeCluster) syncRemoveCloudKubeCluster(ctx context.Context, userCr
|
||||
return self.RealDelete(ctx, userCred)
|
||||
}
|
||||
|
||||
func (self *SKubeCluster) Import(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudKubeCluster) error {
|
||||
func (self *SKubeCluster) ImportOrUpdate(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudKubeCluster) error {
|
||||
if len(self.ExternalClusterId) == 0 {
|
||||
config, err := ext.GetKubeConfig(false, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetKubeConfig")
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"name": self.Name,
|
||||
"mode": "import",
|
||||
"provider": "external",
|
||||
"resource_type": "unknown",
|
||||
"import_data": map[string]interface{}{
|
||||
"kubeconfig": config.Config,
|
||||
},
|
||||
}
|
||||
s := auth.GetAdminSession(ctx, options.Options.Region, "")
|
||||
resp, err := k8s.KubeClusters.Create(s, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Create")
|
||||
}
|
||||
id, err := resp.GetString("id")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "resp.GetId")
|
||||
}
|
||||
_, err = db.Update(self, func() error {
|
||||
self.ExternalClusterId = id
|
||||
return nil
|
||||
})
|
||||
return self.doRemoteImport(ctx, userCred, ext)
|
||||
}
|
||||
return self.doRemoteUpdate(ctx, userCred, ext)
|
||||
}
|
||||
|
||||
func (self *SKubeCluster) doRemoteImport(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudKubeCluster) error {
|
||||
config, err := ext.GetKubeConfig(false, 0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "GetKubeConfig")
|
||||
}
|
||||
|
||||
params := map[string]interface{}{
|
||||
"name": self.Name,
|
||||
"mode": "import",
|
||||
"external_cluster_id": self.GetId(),
|
||||
"resource_type": "guest",
|
||||
"import_data": map[string]interface{}{
|
||||
"kubeconfig": config.Config,
|
||||
},
|
||||
}
|
||||
s := auth.GetAdminSession(ctx, options.Options.Region, "")
|
||||
resp, err := k8s.KubeClusters.Create(s, jsonutils.Marshal(params))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Create")
|
||||
}
|
||||
id, err := resp.GetString("id")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "resp.GetId")
|
||||
}
|
||||
if _, err := db.Update(self, func() error {
|
||||
self.ExternalClusterId = id
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrapf(err, "db.Update")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKubeCluster) doRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudKubeCluster) error {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SKubeCluster) SyncAllWithCloudKubeCluster(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudKubeCluster, provider *SCloudprovider) error {
|
||||
err := self.SyncWithCloudKubeCluster(ctx, userCred, ext, provider)
|
||||
if err != nil {
|
||||
|
||||
@@ -977,6 +977,10 @@ func (lbbg *SLoadbalancerBackendGroup) syncRemoveCloudLoadbalancerBackendgroup(c
|
||||
lockman.LockObject(ctx, lbbg)
|
||||
defer lockman.ReleaseObject(ctx, lbbg)
|
||||
|
||||
if lbbg.GetProviderName() == api.CLOUD_PROVIDER_GOOGLE {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := lbbg.ValidateDeleteCondition(ctx, nil)
|
||||
if err != nil { // cannot delete
|
||||
err = lbbg.SetStatus(userCred, api.LB_STATUS_UNKNOWN, "sync to delete")
|
||||
|
||||
@@ -1134,7 +1134,8 @@ func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(userCred mc
|
||||
lblis.BackendGroupId = lb.BackendGroupId
|
||||
} else if group, err := db.FetchByExternalIdAndManagerId(LoadbalancerBackendGroupManager, groupId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
||||
sq := LoadbalancerManager.Query().SubQuery()
|
||||
return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("loadbalancer_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), lb.ManagerId))
|
||||
q = q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("loadbalancer_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), lb.ManagerId))
|
||||
return q.IsFalse("pending_deleted")
|
||||
}); err == nil {
|
||||
lblis.BackendGroupId = group.GetId()
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ func (self *SNetInterface) networkToJson(ipAddr string, network *SNetwork, desc
|
||||
}
|
||||
desc.Add(jsonutils.NewString(network.GetDNS()), "dns")
|
||||
desc.Add(jsonutils.NewString(network.GetDomain()), "domain")
|
||||
desc.Add(jsonutils.NewString(network.GetNTP()), "ntp")
|
||||
|
||||
routes := network.GetRoutes()
|
||||
if routes != nil && len(routes) > 0 {
|
||||
|
||||
@@ -111,10 +111,12 @@ type SNetwork struct {
|
||||
GuestIpMask int8 `nullable:"false" list:"user" update:"user" create:"required"`
|
||||
// 网关地址
|
||||
GuestGateway string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
// DNS
|
||||
GuestDns string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
// DNS, allow multiple dns, seperated by ","
|
||||
GuestDns string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
// allow multiple dhcp, seperated by ","
|
||||
GuestDhcp string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
// allow mutiple ntp, seperated by ","
|
||||
GuestNtp string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
|
||||
|
||||
GuestDomain string `width:"128" charset:"ascii" nullable:"true" get:"user" update:"user"`
|
||||
|
||||
@@ -382,10 +384,15 @@ func (self *SNetwork) getFreeIP(addrTable map[string]bool, recentUsedAddrTable m
|
||||
return candidate, nil
|
||||
}
|
||||
}
|
||||
// If network's alloc_policy is not none, then use network's alloc_policy
|
||||
if len(self.AllocPolicy) > 0 && api.IPAllocationDirection(self.AllocPolicy) != api.IPAllocationNone {
|
||||
allocDir = api.IPAllocationDirection(self.AllocPolicy)
|
||||
}
|
||||
if len(allocDir) == 0 || allocDir == api.IPAllocationStepdown {
|
||||
// if alloc_dir is not speicified, and network's alloc_policy is not either, use default
|
||||
if len(allocDir) == 0 {
|
||||
allocDir = api.IPAllocationDirection(options.Options.DefaultIPAllocationDirection)
|
||||
}
|
||||
if allocDir == api.IPAllocationStepdown {
|
||||
ip, _ := netutils.NewIPV4Addr(self.GuestIpEnd)
|
||||
for iprange.Contains(ip) {
|
||||
if !isIpUsed(ip.String(), addrTable, recentUsedAddrTable) {
|
||||
@@ -457,7 +464,42 @@ func (self *SNetwork) GetDNS() string {
|
||||
if len(self.GuestDns) > 0 {
|
||||
return self.GuestDns
|
||||
} else {
|
||||
return options.Options.DNSServer
|
||||
zoneName := ""
|
||||
wire, _ := self.GetWire()
|
||||
if wire != nil {
|
||||
zone, _ := wire.GetZone()
|
||||
if zone != nil {
|
||||
zoneName = zone.Name
|
||||
}
|
||||
}
|
||||
srvs, _ := auth.GetDNSServers(options.Options.Region, zoneName)
|
||||
if len(srvs) > 0 {
|
||||
return strings.Join(srvs, ",")
|
||||
}
|
||||
if len(options.Options.DNSServer) > 0 {
|
||||
return options.Options.DNSServer
|
||||
}
|
||||
return api.DefaultDNSServers
|
||||
}
|
||||
}
|
||||
|
||||
func (self *SNetwork) GetNTP() string {
|
||||
if len(self.GuestNtp) > 0 {
|
||||
return self.GuestNtp
|
||||
} else {
|
||||
zoneName := ""
|
||||
wire, _ := self.GetWire()
|
||||
if wire != nil {
|
||||
zone, _ := wire.GetZone()
|
||||
if zone != nil {
|
||||
zoneName = zone.Name
|
||||
}
|
||||
}
|
||||
srvs, _ := auth.GetNTPServers(options.Options.Region, zoneName)
|
||||
if len(srvs) > 0 {
|
||||
return strings.Join(srvs, ",")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1532,25 +1574,34 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred
|
||||
}
|
||||
}
|
||||
|
||||
if len(input.GuestDns) == 0 {
|
||||
input.GuestDns = options.Options.DNSServer
|
||||
}
|
||||
// do not set default dns
|
||||
// if len(input.GuestDns) == 0 {
|
||||
// input.GuestDns = options.Options.DNSServer
|
||||
// }
|
||||
|
||||
for key, ipStr := range map[string]string{
|
||||
"guest_gateway": input.GuestGateway,
|
||||
"guest_dns": input.GuestDns,
|
||||
"guest_dhcp": input.GuestDHCP,
|
||||
"guest_ntp": input.GuestNtp,
|
||||
} {
|
||||
if ipStr == "" {
|
||||
continue
|
||||
}
|
||||
if key == "guest_dhcp" {
|
||||
if key == "guest_dhcp" || key == "guest_dns" {
|
||||
ipList := strings.Split(ipStr, ",")
|
||||
for _, ipstr := range ipList {
|
||||
if !regutils.MatchIPAddr(ipstr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipstr)
|
||||
}
|
||||
}
|
||||
} else if key == "guest_ntp" {
|
||||
ipList := strings.Split(ipStr, ",")
|
||||
for _, ipstr := range ipList {
|
||||
if !regutils.MatchDomainName(ipstr) && !regutils.MatchIPAddr(ipstr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid domain name or IP address %s", key, ipstr)
|
||||
}
|
||||
}
|
||||
} else if !regutils.MatchIPAddr(ipStr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipStr)
|
||||
}
|
||||
@@ -1737,17 +1788,25 @@ func (self *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient.
|
||||
"guest_gateway": input.GuestGateway,
|
||||
"guest_dns": input.GuestDns,
|
||||
"guest_dhcp": input.GuestDhcp,
|
||||
"guest_ntp": input.GuestNtp,
|
||||
} {
|
||||
if ipStr == "" {
|
||||
continue
|
||||
}
|
||||
if key == "guest_dhcp" {
|
||||
if key == "guest_dhcp" || key == "guest_dns" {
|
||||
ipList := strings.Split(ipStr, ",")
|
||||
for _, ipstr := range ipList {
|
||||
if !regutils.MatchIPAddr(ipstr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipstr)
|
||||
}
|
||||
}
|
||||
} else if key == "guest_ntp" {
|
||||
ipList := strings.Split(ipStr, ",")
|
||||
for _, ipstr := range ipList {
|
||||
if !regutils.MatchDomainName(ipstr) && !regutils.MatchIPAddr(ipstr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid domain name or IP address %s", key, ipstr)
|
||||
}
|
||||
}
|
||||
} else if !regutils.MatchIPAddr(ipStr) {
|
||||
return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipStr)
|
||||
}
|
||||
@@ -1772,13 +1831,19 @@ func (self *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient.
|
||||
}
|
||||
|
||||
func (self *SNetwork) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.NetworkUpdateInput) (api.NetworkUpdateInput, error) {
|
||||
if !self.isManaged() && !self.isOneCloudVpcNetwork() {
|
||||
var err error
|
||||
input, err = self.validateUpdateData(ctx, userCred, query, input)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "validateUpdateData")
|
||||
if !self.isManaged() {
|
||||
if !self.isOneCloudVpcNetwork() {
|
||||
// classic network
|
||||
} else {
|
||||
// vpc network
|
||||
input.GuestIpStart = ""
|
||||
input.GuestIpEnd = ""
|
||||
input.GuestIpMask = nil
|
||||
input.GuestGateway = ""
|
||||
input.GuestDhcp = ""
|
||||
}
|
||||
} else {
|
||||
// managed network
|
||||
input.GuestIpStart = ""
|
||||
input.GuestIpEnd = ""
|
||||
input.GuestIpMask = nil
|
||||
@@ -1786,9 +1851,14 @@ func (self *SNetwork) ValidateUpdateData(ctx context.Context, userCred mcclient.
|
||||
input.GuestDns = ""
|
||||
input.GuestDomain = ""
|
||||
input.GuestDhcp = ""
|
||||
input.GuestNtp = ""
|
||||
}
|
||||
var err error
|
||||
input, err = self.validateUpdateData(ctx, userCred, query, input)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "validateUpdateData")
|
||||
}
|
||||
|
||||
var err error
|
||||
input.SharableVirtualResourceBaseUpdateInput, err = self.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
|
||||
if err != nil {
|
||||
return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
|
||||
@@ -2162,6 +2232,9 @@ func (manager *SNetworkManager) ListItemFilter(
|
||||
if len(input.GuestDhcp) > 0 {
|
||||
q = q.In("guest_dhcp", input.GuestDhcp)
|
||||
}
|
||||
if len(input.GuestNtp) > 0 {
|
||||
q = q.In("guest_ntp", input.GuestNtp)
|
||||
}
|
||||
if len(input.GuestDomain) > 0 {
|
||||
q = q.In("guest_domain", input.GuestDomain)
|
||||
}
|
||||
@@ -2534,6 +2607,7 @@ func (self *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenC
|
||||
network.GuestGateway = self.GuestGateway
|
||||
network.GuestDns = self.GuestDns
|
||||
network.GuestDhcp = self.GuestDhcp
|
||||
network.GuestNtp = self.GuestNtp
|
||||
network.GuestDomain = self.GuestDomain
|
||||
network.VlanId = self.VlanId
|
||||
network.WireId = self.WireId
|
||||
@@ -2688,6 +2762,7 @@ func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, use
|
||||
newNetwork.GuestIpMask = int8(input.Mask)
|
||||
newNetwork.GuestDns = nm.GuestDns
|
||||
newNetwork.GuestDhcp = nm.GuestDhcp
|
||||
newNetwork.GuestNtp = nm.GuestNtp
|
||||
newNetwork.WireId = nm.WireId
|
||||
newNetwork.ServerType = input.ServerType
|
||||
newNetwork.IsPublic = nm.IsPublic
|
||||
|
||||
@@ -1936,6 +1936,21 @@ func (vpcPC *SVpcPeeringConnection) purge(ctx context.Context, userCred mcclient
|
||||
return vpcPC.RealDelete(ctx, userCred)
|
||||
}
|
||||
|
||||
func (manager *SInterVpcNetworkManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
|
||||
networks := []SInterVpcNetwork{}
|
||||
err := fetchByManagerId(manager, providerId, &networks)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "fetchByManagerId")
|
||||
}
|
||||
for i := range networks {
|
||||
err := networks[i].RealDelete(ctx, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "inter vpc network delete")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SWafRuleGroupCacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
|
||||
caches := []SWafRuleGroupCache{}
|
||||
err := fetchByManagerId(manager, providerId, &caches)
|
||||
|
||||
@@ -253,20 +253,21 @@ func (manager *SVpcPeeringConnectionManager) FetchCustomizeColumns(
|
||||
) []api.VpcPeeringConnectionDetails {
|
||||
rows := make([]api.VpcPeeringConnectionDetails, len(objs))
|
||||
stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
vpcIds := make([]string, len(objs))
|
||||
vpcObjs := make([]interface{}, len(objs))
|
||||
peerVpcIds := make([]string, len(objs))
|
||||
for i := range rows {
|
||||
rows[i] = api.VpcPeeringConnectionDetails{
|
||||
EnabledStatusInfrasResourceBaseDetails: stdRows[i],
|
||||
}
|
||||
vpcPC := objs[i].(*SVpcPeeringConnection)
|
||||
vpcIds[i] = vpcPC.VpcId
|
||||
vpcObj := &SVpcResourceBase{VpcId: vpcPC.VpcId}
|
||||
vpcObjs[i] = vpcObj
|
||||
peerVpcIds[i] = vpcPC.PeerVpcId
|
||||
}
|
||||
|
||||
vpcMap, err := db.FetchIdNameMap2(VpcManager, vpcIds)
|
||||
if err != nil {
|
||||
return rows
|
||||
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, vpcObjs, fields, isList)
|
||||
for i := range rows {
|
||||
rows[i].VpcResourceInfo = vpcRows[i]
|
||||
}
|
||||
peerVpcMap, err := db.FetchIdNameMap2(VpcManager, peerVpcIds)
|
||||
if err != nil {
|
||||
@@ -274,7 +275,6 @@ func (manager *SVpcPeeringConnectionManager) FetchCustomizeColumns(
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
rows[i].VpcName, _ = vpcMap[vpcIds[i]]
|
||||
rows[i].PeerVpcName, _ = peerVpcMap[peerVpcIds[i]]
|
||||
}
|
||||
return rows
|
||||
@@ -341,6 +341,7 @@ func (manager *SVpcPeeringConnectionManager) ListItemExportKeys(ctx context.Cont
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys")
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1103,6 +1103,30 @@ func (manager *SVpcManager) ListItemFilter(
|
||||
q = q.In("id", sq.SubQuery())
|
||||
}
|
||||
|
||||
if len(query.UsableForInterVpcNetworkId) > 0 {
|
||||
_interVpc, err := validators.ValidateModel(userCred, InterVpcNetworkManager, &query.UsableForInterVpcNetworkId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
interVpc := _interVpc.(*SInterVpcNetwork)
|
||||
sq := InterVpcNetworkVpcManager.Query("vpc_id").Equals("inter_vpc_network_id", interVpc.GetId())
|
||||
q = q.NotIn("id", sq.SubQuery())
|
||||
account := interVpc.GetCloudaccount()
|
||||
if account == nil {
|
||||
return nil, httperrors.NewNotSupportedError("not supported for inter vpc network %s", interVpc.Name)
|
||||
}
|
||||
vpcs := VpcManager.Query().SubQuery()
|
||||
managers := CloudproviderManager.Query().SubQuery()
|
||||
accounts := CloudaccountManager.Query().SubQuery()
|
||||
vpcSQ := vpcs.Query(vpcs.Field("id")).Join(managers, sqlchemy.Equals(vpcs.Field("manager_id"), managers.Field("id"))).Join(accounts, sqlchemy.Equals(managers.Field("cloudaccount_id"), accounts.Field("id"))).Filter(
|
||||
sqlchemy.AND(
|
||||
sqlchemy.Equals(accounts.Field("provider"), account.Provider),
|
||||
sqlchemy.Equals(accounts.Field("access_url"), account.AccessUrl),
|
||||
),
|
||||
)
|
||||
q = q.In("id", vpcSQ.SubQuery())
|
||||
}
|
||||
|
||||
if len(query.InterVpcNetworkId) > 0 {
|
||||
vpcNetwork, err := InterVpcNetworkManager.FetchByIdOrName(userCred, query.InterVpcNetworkId)
|
||||
if err != nil {
|
||||
|
||||
@@ -177,6 +177,8 @@ type ComputeOptions struct {
|
||||
|
||||
GlobalMacPrefix string `help:"Global prefix of MAC address, default to 00:22" default:"00:22"`
|
||||
|
||||
DefaultIPAllocationDirection string `help:"default IP allocation direction" default:"stepdown"`
|
||||
|
||||
esxi.EsxiOptions
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -916,6 +917,52 @@ func (self *SKVMRegionDriver) ValidateEipChargeType(chargeType string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type eipNetwork struct {
|
||||
owner mcclient.TokenCredential
|
||||
freeCnt int
|
||||
net *models.SNetwork
|
||||
}
|
||||
|
||||
func (en eipNetwork) isOwnerProject() bool {
|
||||
return en.owner.GetProjectId() == en.net.ProjectId
|
||||
}
|
||||
|
||||
func (en eipNetwork) isOwnerProjectDomain() bool {
|
||||
return en.owner.GetProjectDomainId() == en.net.DomainId
|
||||
}
|
||||
|
||||
type eipNetworks []eipNetwork
|
||||
|
||||
func (a eipNetworks) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func (a eipNetworks) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
func (a eipNetworks) Less(i, j int) bool {
|
||||
if a[i].isOwnerProject() && !a[j].isOwnerProject() {
|
||||
return true
|
||||
} else if !a[i].isOwnerProject() && a[j].isOwnerProject() {
|
||||
return false
|
||||
}
|
||||
if a[i].isOwnerProjectDomain() && !a[j].isOwnerProjectDomain() {
|
||||
return true
|
||||
} else if !a[i].isOwnerProjectDomain() && a[j].isOwnerProjectDomain() {
|
||||
return false
|
||||
}
|
||||
if a[i].freeCnt > a[j].freeCnt {
|
||||
return true
|
||||
} else if a[i].freeCnt < a[j].freeCnt {
|
||||
return false
|
||||
}
|
||||
if a[i].net.Id < a[j].net.Id {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (self *SKVMRegionDriver) ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, input *api.SElasticipCreateInput) error {
|
||||
if err := self.ValidateEipChargeType(input.ChargeType); err != nil {
|
||||
return err
|
||||
@@ -939,18 +986,21 @@ func (self *SKVMRegionDriver) ValidateCreateEipData(ctx context.Context, userCre
|
||||
if err := db.FetchModelObjects(models.NetworkManager, q, &nets); err != nil {
|
||||
return err
|
||||
}
|
||||
eipNets := make([]eipNetwork, 0)
|
||||
for i := range nets {
|
||||
net := &nets[i]
|
||||
cnt, _ := net.GetFreeAddressCount()
|
||||
if cnt > 0 {
|
||||
network = net
|
||||
input.NetworkId = net.Id
|
||||
break
|
||||
eipNets = append(eipNets, eipNetwork{net: net, freeCnt: cnt, owner: userCred})
|
||||
}
|
||||
}
|
||||
if network == nil {
|
||||
if len(eipNets) == 0 {
|
||||
return httperrors.NewNotFoundError("no available eip network")
|
||||
}
|
||||
// prefer networks with identical project, domain, more free address, Id
|
||||
sort.Sort(eipNetworks(eipNets))
|
||||
network = eipNets[0].net
|
||||
input.NetworkId = network.Id
|
||||
}
|
||||
if network.ServerType != api.NETWORK_TYPE_EIP {
|
||||
return httperrors.NewInputParameterError("bad network type %q, want %q", network.ServerType, api.NETWORK_TYPE_EIP)
|
||||
|
||||
@@ -135,8 +135,19 @@ func (s *SGuestDHCPServer) getGuestConfig(guestDesc, guestNic jsonutils.JSONObje
|
||||
conf.Routes = route
|
||||
|
||||
if len(nicdesc.Dns) > 0 {
|
||||
conf.DNSServer = net.ParseIP(nicdesc.Dns)
|
||||
conf.DNSServers = make([]net.IP, 0)
|
||||
for _, dns := range strings.Split(nicdesc.Dns, ",") {
|
||||
conf.DNSServers = append(conf.DNSServers, net.ParseIP(dns))
|
||||
}
|
||||
}
|
||||
|
||||
if len(nicdesc.Ntp) > 0 {
|
||||
conf.NTPServers = make([]net.IP, 0)
|
||||
for _, ntp := range strings.Split(nicdesc.Ntp, ",") {
|
||||
conf.NTPServers = append(conf.NTPServers, net.ParseIP(ntp))
|
||||
}
|
||||
}
|
||||
|
||||
conf.OsName, _ = guestDesc.GetString("os_name")
|
||||
conf.LeaseTime = time.Duration(options.HostOptions.DhcpLeaseTime) * time.Second
|
||||
conf.RenewalTime = time.Duration(options.HostOptions.DhcpRenewalTime) * time.Second
|
||||
|
||||
@@ -1696,7 +1696,7 @@ func (h *SHostInfo) OnCatalogChanged(catalog mcclient.KeystoneServiceCatalogV3)
|
||||
}
|
||||
if options.HostOptions.ManageNtpConfiguration {
|
||||
ntpd := system_service.GetService("ntpd")
|
||||
urls, _ := catalog.GetServiceURLs("ntp", options.HostOptions.Region, "", defaultEndpointType)
|
||||
urls, _ := catalog.GetServiceURLs("ntp", options.HostOptions.Region, h.Zone, defaultEndpointType)
|
||||
if len(urls) > 0 {
|
||||
log.Infof("Get Ntp urls: %v", urls)
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,9 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
@@ -28,6 +30,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/apis/identity"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/syncman"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -231,6 +234,31 @@ func (a *authManager) GetServiceURLs(service, region, zone, endpointType string)
|
||||
return a.adminCredential.GetServiceURLs(service, region, zone, endpointType)
|
||||
}
|
||||
|
||||
func (a *authManager) getServiceIPs(service, region, zone, endpointType string, needResolve bool) ([]string, error) {
|
||||
urls, err := a.GetServiceURLs(service, region, zone, endpointType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetServiceURLs")
|
||||
}
|
||||
ret := stringutils2.NewSortedStrings(nil)
|
||||
for _, url := range urls {
|
||||
slashIdx := strings.Index(url, "://")
|
||||
if slashIdx >= 0 {
|
||||
url = url[slashIdx+3:]
|
||||
}
|
||||
if needResolve {
|
||||
addrs, err := net.LookupHost(url)
|
||||
if err != nil {
|
||||
log.Errorf("Lookup host %s fail: %s", url, err)
|
||||
} else {
|
||||
ret = ret.Append(addrs...)
|
||||
}
|
||||
} else {
|
||||
ret = ret.Append(url)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (a *authManager) getTokenString() string {
|
||||
return a.adminCredential.GetTokenString()
|
||||
}
|
||||
@@ -273,6 +301,14 @@ func GetServiceURLs(service, region, zone, endpointType string) ([]string, error
|
||||
return manager.GetServiceURLs(service, region, zone, endpointType)
|
||||
}
|
||||
|
||||
func GetDNSServers(region, zone string) ([]string, error) {
|
||||
return manager.getServiceIPs("dns", region, zone, identity.EndpointInterfacePublic, false)
|
||||
}
|
||||
|
||||
func GetNTPServers(region, zone string) ([]string, error) {
|
||||
return manager.getServiceIPs("ntp", region, zone, identity.EndpointInterfacePublic, true)
|
||||
}
|
||||
|
||||
func GetTokenString() string {
|
||||
return manager.getTokenString()
|
||||
}
|
||||
|
||||
@@ -52,7 +52,11 @@ func (this *ReservedIPManager) DoBatchReleaseReservedIps(s *mcclient.ClientSessi
|
||||
}
|
||||
|
||||
// filter ip and network pairs.
|
||||
ipFilterOps := jsonutils.NewDict()
|
||||
originFilter, _ := params.Get("query")
|
||||
if originFilter == nil {
|
||||
originFilter = jsonutils.NewDict()
|
||||
}
|
||||
ipFilterOps := originFilter.(*jsonutils.JSONDict)
|
||||
arr := jsonutils.NewArray()
|
||||
filterCondition := "ip_addr.in(" + strings.Join(ips, ",") + ")"
|
||||
arr.Add(jsonutils.NewString(filterCondition))
|
||||
|
||||
@@ -204,9 +204,12 @@ func (o K8SClusterCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
}
|
||||
|
||||
type KubeClusterImportOptions struct {
|
||||
NAME string `help:"Name of cluster"`
|
||||
KUBECONFIG string `help:"Cluster kubeconfig file path"`
|
||||
Distro string `help:"Kubernetes distribution, e.g. openshift"`
|
||||
NAME string `help:"Name of cluster"`
|
||||
KUBECONFIG string `help:"Cluster kubeconfig file path"`
|
||||
Distro string `help:"Kubernetes distribution, e.g. openshift"`
|
||||
Provider string `help:"Provider type" choices:"external|aliyun|qcloud|azure"`
|
||||
ResourceType string `help:"Node resource type" choices:"unknown|guest"`
|
||||
CloudKubeCluster string `help:"Cloud kube cluster id or name"`
|
||||
}
|
||||
|
||||
func (o KubeClusterImportOptions) Params() (jsonutils.JSONObject, error) {
|
||||
@@ -217,8 +220,14 @@ func (o KubeClusterImportOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(o.NAME), "name")
|
||||
params.Add(jsonutils.NewString("import"), "mode")
|
||||
params.Add(jsonutils.NewString("external"), "provider")
|
||||
params.Add(jsonutils.NewString("unknown"), "resource_type")
|
||||
params.Add(jsonutils.NewString(o.Provider), "provider")
|
||||
if o.ResourceType == "" {
|
||||
o.ResourceType = "unknown"
|
||||
}
|
||||
params.Add(jsonutils.NewString(o.ResourceType), "resource_type")
|
||||
if o.CloudKubeCluster != "" {
|
||||
params.Add(jsonutils.NewString(o.CloudKubeCluster), "external_cluster_id")
|
||||
}
|
||||
|
||||
importData := jsonutils.NewDict()
|
||||
importData.Add(jsonutils.NewString(string(kubeconfig)), "kubeconfig")
|
||||
|
||||
@@ -66,6 +66,7 @@ type NetworkUpdateOptions struct {
|
||||
Dns string `help:"IP of DNS server"`
|
||||
Domain string `help:"Domain"`
|
||||
Dhcp string `help:"DHCP server IP"`
|
||||
Ntp string `help:"Ntp server domain names"`
|
||||
VlanId int64 `help:"Vlan ID" default:"1"`
|
||||
ExternalId string `help:"External ID"`
|
||||
AllocPolicy string `help:"Address allocation policy" choices:"none|stepdown|stepup|random"`
|
||||
@@ -113,6 +114,13 @@ func (opts *NetworkUpdateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
params.Add(jsonutils.NewString(opts.Dhcp), "guest_dhcp")
|
||||
}
|
||||
}
|
||||
if len(opts.Ntp) > 0 {
|
||||
if opts.Ntp == "none" {
|
||||
params.Add(jsonutils.NewString(""), "guest_ntp")
|
||||
} else {
|
||||
params.Add(jsonutils.NewString(opts.Ntp), "guest_ntp")
|
||||
}
|
||||
}
|
||||
if opts.VlanId > 0 {
|
||||
params.Add(jsonutils.NewInt(opts.VlanId), "vlan_id")
|
||||
}
|
||||
|
||||
@@ -23,13 +23,14 @@ import (
|
||||
type VpcListOptions struct {
|
||||
BaseListOptions
|
||||
|
||||
Usable *bool `help:"Filter usable vpcs"`
|
||||
Region string `help:"ID or Name of region" json:"-"`
|
||||
Globalvpc string `help:"Filter by globalvpc"`
|
||||
DnsZoneId string `help:"Filter by DnsZone"`
|
||||
InterVpcNetworkId string `help:"Filter by InterVpcNetwork"`
|
||||
ExternalAccessMode string `help:"Filter by external access mode" choices:"distgw|eip|eip-distgw"`
|
||||
ZoneId string `help:"Filter by zone which has networks"`
|
||||
Usable *bool `help:"Filter usable vpcs"`
|
||||
Region string `help:"ID or Name of region" json:"-"`
|
||||
Globalvpc string `help:"Filter by globalvpc"`
|
||||
DnsZoneId string `help:"Filter by DnsZone"`
|
||||
InterVpcNetworkId string `help:"Filter by InterVpcNetwork"`
|
||||
ExternalAccessMode string `help:"Filter by external access mode" choices:"distgw|eip|eip-distgw"`
|
||||
ZoneId string `help:"Filter by zone which has networks"`
|
||||
UsableForInterVpcNetworkId string `help:"Filter usable vpcs for inter vpc network"`
|
||||
}
|
||||
|
||||
func (opts *VpcListOptions) GetContextId() string {
|
||||
|
||||
@@ -67,7 +67,20 @@ func (self *SLoadbalancer) IsEmulated() bool {
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetSysTags() map[string]string {
|
||||
return nil
|
||||
frs, err := self.GetForwardingRules()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ips := []string{}
|
||||
for i := range frs {
|
||||
if len(frs[i].IPAddress) > 0 {
|
||||
ips = append(ips, frs[i].IPAddress)
|
||||
}
|
||||
}
|
||||
data := map[string]string{}
|
||||
data["FrontendIPs"] = strings.Join(ips, ",")
|
||||
return data
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetTags() (map[string]string, error) {
|
||||
@@ -139,6 +152,29 @@ func (self *SLoadbalancer) GetNetworkIds() []string {
|
||||
}
|
||||
|
||||
func (self *SLoadbalancer) GetVpcId() string {
|
||||
networkIds := self.GetNetworkIds()
|
||||
if len(networkIds) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(networkIds) >= 1 {
|
||||
network, err := self.region.GetNetwork(networkIds[0])
|
||||
if err == nil && network != nil {
|
||||
wire := network.GetIWire()
|
||||
if wire == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
vpc := wire.GetIVpc()
|
||||
if vpc == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return vpc.GetGlobalId()
|
||||
}
|
||||
|
||||
log.Debugf("GetVpcId %s", err)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -659,11 +659,10 @@ func (self *SLoadbalancer) GetInstanceGroups() ([]SInstanceGroup, error) {
|
||||
if fs, ok := zonesFilter[zoneId]; ok {
|
||||
f := fmt.Sprintf(`(selfLink="%s")`, ig)
|
||||
if !utils.IsInStringArray(f, fs) {
|
||||
fs = append(fs, f)
|
||||
zonesFilter[zoneId] = append(fs, f)
|
||||
}
|
||||
} else {
|
||||
fs = []string{fmt.Sprintf(`(selfLink="%s")`, ig)}
|
||||
zonesFilter[zoneId] = fs
|
||||
zonesFilter[zoneId] = []string{fmt.Sprintf(`(selfLink="%s")`, ig)}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +232,10 @@ func (self *SLoadbalancerListener) GetStickySessionCookie() string {
|
||||
}
|
||||
|
||||
func (self *SLoadbalancerListener) GetStickySessionCookieTimeout() int {
|
||||
if len(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
sec, err := strconv.Atoi(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds)
|
||||
if err != nil {
|
||||
log.Debugf("GetStickySessionCookieTimeout %s", err)
|
||||
|
||||
@@ -32,6 +32,7 @@ const (
|
||||
OptClasslessRouteWin OptionCode = 249
|
||||
)
|
||||
|
||||
// http://www.networksorcery.com/enp/rfc/rfc2132.txt
|
||||
type ResponseConfig struct {
|
||||
OsName string
|
||||
ServerIP net.IP // OptServerIdentifier 54
|
||||
@@ -43,8 +44,9 @@ type ResponseConfig struct {
|
||||
BroadcastAddr net.IP // OptBroadcastAddr 28
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServer net.IP // OptDNSServers
|
||||
DNSServers []net.IP // OptDNSServers
|
||||
Routes [][]string // TODO: 249 for windows, 121 for linux
|
||||
NTPServers []net.IP // OptNTPServers 42
|
||||
|
||||
// TFTP config
|
||||
BootServer string
|
||||
@@ -64,6 +66,14 @@ func GetOptIP(ip net.IP) []byte {
|
||||
return []byte(ip.To4())
|
||||
}
|
||||
|
||||
func GetOptIPs(ips []net.IP) []byte {
|
||||
buf := make([]byte, 0)
|
||||
for _, ip := range ips {
|
||||
buf = append(buf, []byte(ip.To4())...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func GetOptTime(d time.Duration) []byte {
|
||||
timeBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(timeBytes, uint32(d/time.Second))
|
||||
@@ -138,8 +148,11 @@ func makeDHCPReplyPacket(req Packet, conf *ResponseConfig, msgType MessageType)
|
||||
if conf.Hostname != "" {
|
||||
opts = append(opts, Option{OptionHostName, []byte(conf.GetHostname())})
|
||||
}
|
||||
if conf.DNSServer != nil {
|
||||
opts = append(opts, Option{OptionDomainNameServer, GetOptIP(conf.DNSServer)})
|
||||
if len(conf.DNSServers) > 0 {
|
||||
opts = append(opts, Option{OptionDomainNameServer, GetOptIPs(conf.DNSServers)})
|
||||
}
|
||||
if len(conf.NTPServers) > 0 {
|
||||
opts = append(opts, Option{OptionNetworkTimeProtocolServers, GetOptIPs(conf.NTPServers)})
|
||||
}
|
||||
resp := ReplyPacket(req, msgType, conf.ServerIP, conf.ClientIP, conf.LeaseTime, opts)
|
||||
if conf.BootServer != "" {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 rbdutils // import "yunion.io/x/onecloud/pkg/util/rbdutils"
|
||||
@@ -1,154 +0,0 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 rbdutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ceph/go-ceph/rados"
|
||||
"github.com/ceph/go-ceph/rbd"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type SCluster struct {
|
||||
conn *rados.Conn
|
||||
}
|
||||
|
||||
func (self *SCluster) withCluster(doFunc func(*rados.Conn) (interface{}, error)) (interface{}, error) {
|
||||
defer self.conn.Shutdown()
|
||||
return doFunc(self.conn)
|
||||
}
|
||||
|
||||
type SPool struct {
|
||||
name string
|
||||
cluster *SCluster
|
||||
}
|
||||
|
||||
func (self *SPool) withIOContext(doFunc func(*rados.IOContext) (interface{}, error)) (interface{}, error) {
|
||||
return self.cluster.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
ioctx, err := conn.OpenIOContext(self.name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "OpenIOContext(%s)", self.name)
|
||||
}
|
||||
return doFunc(ioctx)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *SPool) GetCluster() *SCluster {
|
||||
return self.cluster
|
||||
}
|
||||
|
||||
func NewCluster(monHost, key string) (*SCluster, error) {
|
||||
conn, err := rados.NewConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range map[string]string{"mon_host": monHost, "key": key} {
|
||||
if len(v) > 0 {
|
||||
err = conn.SetConfigOption(k, v)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "SetConfigOption %s %s", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range map[string]int64{
|
||||
"rados_osd_op_timeout": 20 * 60,
|
||||
"rados_mon_op_timeout": 5,
|
||||
"client_mount_timeout": 2 * 60,
|
||||
} {
|
||||
err = conn.SetConfigOption(k, fmt.Sprintf("%d", v))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "SetConfigOption %s %d", k, v)
|
||||
}
|
||||
}
|
||||
err = conn.Connect()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "conn.Connect")
|
||||
}
|
||||
|
||||
return &SCluster{conn: conn}, nil
|
||||
}
|
||||
|
||||
func (self *SCluster) GetPool(name string) (*SPool, error) {
|
||||
return &SPool{name: name, cluster: self}, nil
|
||||
}
|
||||
|
||||
func (self *SCluster) ListPools() ([]string, error) {
|
||||
pools, err := self.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
return conn.ListPools()
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "ListPools")
|
||||
}
|
||||
return pools.([]string), nil
|
||||
}
|
||||
|
||||
func (self *SCluster) GetClusterStats() (rados.ClusterStat, error) {
|
||||
stat, err := self.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
return conn.GetClusterStats()
|
||||
})
|
||||
if err != nil {
|
||||
return rados.ClusterStat{}, errors.Wrapf(err, "GetClusterStats")
|
||||
}
|
||||
return stat.(rados.ClusterStat), nil
|
||||
}
|
||||
|
||||
func (self *SCluster) GetFSID() (string, error) {
|
||||
fsid, err := self.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
return conn.GetFSID()
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "GetFSID")
|
||||
}
|
||||
return fsid.(string), nil
|
||||
}
|
||||
|
||||
func (self *SCluster) DeletePool(pool string) error {
|
||||
_, err := self.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
return nil, conn.DeletePool(pool)
|
||||
})
|
||||
return errors.Wrapf(err, "DeletePool")
|
||||
}
|
||||
|
||||
type cmdOutput struct {
|
||||
Buffer string
|
||||
Info string
|
||||
}
|
||||
|
||||
func (self *SCluster) MonCommand(args []byte) (cmdOutput, error) {
|
||||
result := cmdOutput{}
|
||||
_, err := self.withCluster(func(conn *rados.Conn) (interface{}, error) {
|
||||
buffer, info, err := conn.MonCommand(args)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "MonCommand")
|
||||
}
|
||||
result.Buffer = string(buffer)
|
||||
result.Info = info
|
||||
return nil, nil
|
||||
})
|
||||
return result, errors.Wrapf(err, "DeletePool")
|
||||
}
|
||||
|
||||
func (self *SPool) ListImages() ([]string, error) {
|
||||
images, err := self.withIOContext(func(ioctx *rados.IOContext) (interface{}, error) {
|
||||
return rbd.GetImageNames(ioctx)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetImageNames")
|
||||
}
|
||||
return images.([]string), nil
|
||||
}
|
||||
@@ -27,7 +27,9 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
apis "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
agentmodels "yunion.io/x/onecloud/pkg/vpcagent/models"
|
||||
"yunion.io/x/onecloud/pkg/vpcagent/options"
|
||||
"yunion.io/x/onecloud/pkg/vpcagent/ovn/mac"
|
||||
"yunion.io/x/onecloud/pkg/vpcagent/ovnutil"
|
||||
)
|
||||
@@ -264,7 +266,7 @@ func (keeper *OVNNorthboundKeeper) ClaimVpc(ctx context.Context, vpc *agentmodel
|
||||
return keeper.cli.Must(ctx, "ClaimVpc", args)
|
||||
}
|
||||
|
||||
func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *agentmodels.Network, mtu int) error {
|
||||
func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *agentmodels.Network, opts *options.Options) error {
|
||||
var (
|
||||
rpMac = mac.HashSubnetRouterPortMac(network.Id)
|
||||
dhcpMac = mac.HashSubnetDhcpMac(network.Id)
|
||||
@@ -296,6 +298,7 @@ func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *ag
|
||||
mdIp, "0.0.0.0",
|
||||
"0.0.0.0/0", network.GuestGateway,
|
||||
}
|
||||
mtu := opts.OvnUnderlayMtu
|
||||
mtu -= apis.VPC_OVN_ENCAP_COST
|
||||
const (
|
||||
leaseTime = 86400 * 365 * 3
|
||||
@@ -318,10 +321,38 @@ func (keeper *OVNNorthboundKeeper) ClaimNetwork(ctx context.Context, network *ag
|
||||
externalKeyOcRef: network.Id,
|
||||
},
|
||||
}
|
||||
if network.GuestDns != "" {
|
||||
dhcpopts.Options["dns_server"] = "{" + network.GuestDns + "}"
|
||||
} else {
|
||||
dhcpopts.Options["dns_server"] = "{223.5.5.5,223.6.6.6}"
|
||||
{
|
||||
dnsSrvs := ""
|
||||
if network.GuestDns != "" {
|
||||
dnsSrvs = network.GuestDns
|
||||
} else {
|
||||
dns, err := auth.GetDNSServers(opts.Region, "")
|
||||
if err != nil {
|
||||
log.Errorf("auth.GetDNSServers fail %s", err)
|
||||
} else {
|
||||
dnsSrvs = strings.Join(dns, ",")
|
||||
}
|
||||
}
|
||||
if len(dnsSrvs) == 0 {
|
||||
dnsSrvs = apis.DefaultDNSServers
|
||||
}
|
||||
dhcpopts.Options["dns_server"] = "{" + dnsSrvs + "}"
|
||||
}
|
||||
{
|
||||
ntpSrvs := ""
|
||||
if network.GuestNtp != "" {
|
||||
ntpSrvs = network.GuestNtp
|
||||
} else {
|
||||
ntp, err := auth.GetNTPServers(opts.Region, "")
|
||||
if err != nil {
|
||||
log.Errorf("auth.GetNTPServers fail %s", err)
|
||||
} else {
|
||||
ntpSrvs = strings.Join(ntp, ",")
|
||||
}
|
||||
}
|
||||
if len(ntpSrvs) > 0 {
|
||||
dhcpopts.Options["ntp_server"] = "{" + ntpSrvs + "}"
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -124,7 +124,7 @@ func (w *Worker) run(ctx context.Context, mss *agentmodels.ModelSets) (err error
|
||||
ovndb.ClaimVpcEipgw(ctx, vpc)
|
||||
}
|
||||
for _, network := range vpc.Networks {
|
||||
ovndb.ClaimNetwork(ctx, network, w.opts.OvnUnderlayMtu)
|
||||
ovndb.ClaimNetwork(ctx, network, w.opts)
|
||||
for _, guestnetwork := range network.Guestnetworks {
|
||||
if guestnetwork.Guest == nil {
|
||||
continue
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Noah Watkins
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-328
@@ -1,328 +0,0 @@
|
||||
package rados
|
||||
|
||||
// #cgo LDFLAGS: -lrados
|
||||
// #include <stdlib.h>
|
||||
// #include <rados/librados.h>
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
import "bytes"
|
||||
import "fmt"
|
||||
|
||||
// ClusterStat represents Ceph cluster statistics.
|
||||
type ClusterStat struct {
|
||||
Kb uint64
|
||||
Kb_used uint64
|
||||
Kb_avail uint64
|
||||
Num_objects uint64
|
||||
}
|
||||
|
||||
// Conn is a connection handle to a Ceph cluster.
|
||||
type Conn struct {
|
||||
cluster C.rados_t
|
||||
connected bool
|
||||
}
|
||||
|
||||
// PingMonitor sends a ping to a monitor and returns the reply.
|
||||
func (c *Conn) PingMonitor(id string) (string, error) {
|
||||
c_id := C.CString(id)
|
||||
defer C.free(unsafe.Pointer(c_id))
|
||||
|
||||
var strlen C.size_t
|
||||
var strout *C.char
|
||||
|
||||
ret := C.rados_ping_monitor(c.cluster, c_id, &strout, &strlen)
|
||||
defer C.rados_buffer_free(strout)
|
||||
|
||||
if ret == 0 {
|
||||
reply := C.GoStringN(strout, (C.int)(strlen))
|
||||
return reply, nil
|
||||
} else {
|
||||
return "", RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Connect establishes a connection to a RADOS cluster. It returns an error,
|
||||
// if any.
|
||||
func (c *Conn) Connect() error {
|
||||
ret := C.rados_connect(c.cluster)
|
||||
if ret != 0 {
|
||||
return RadosError(int(ret))
|
||||
}
|
||||
c.connected = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown disconnects from the cluster.
|
||||
func (c *Conn) Shutdown() {
|
||||
if err := c.ensure_connected(); err != nil {
|
||||
return
|
||||
}
|
||||
C.rados_shutdown(c.cluster)
|
||||
}
|
||||
|
||||
// ReadConfigFile configures the connection using a Ceph configuration file.
|
||||
func (c *Conn) ReadConfigFile(path string) error {
|
||||
c_path := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(c_path))
|
||||
ret := C.rados_conf_read_file(c.cluster, c_path)
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// ReadDefaultConfigFile configures the connection using a Ceph configuration
|
||||
// file located at default locations.
|
||||
func (c *Conn) ReadDefaultConfigFile() error {
|
||||
ret := C.rados_conf_read_file(c.cluster, nil)
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) OpenIOContext(pool string) (*IOContext, error) {
|
||||
c_pool := C.CString(pool)
|
||||
defer C.free(unsafe.Pointer(c_pool))
|
||||
ioctx := &IOContext{}
|
||||
ret := C.rados_ioctx_create(c.cluster, c_pool, &ioctx.ioctx)
|
||||
if ret == 0 {
|
||||
return ioctx, nil
|
||||
} else {
|
||||
return nil, RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// ListPools returns the names of all existing pools.
|
||||
func (c *Conn) ListPools() (names []string, err error) {
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
ret := int(C.rados_pool_list(c.cluster,
|
||||
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
|
||||
if ret < 0 {
|
||||
return nil, RadosError(int(ret))
|
||||
}
|
||||
|
||||
if ret > len(buf) {
|
||||
buf = make([]byte, ret)
|
||||
continue
|
||||
}
|
||||
|
||||
tmp := bytes.SplitAfter(buf[:ret-1], []byte{0})
|
||||
for _, s := range tmp {
|
||||
if len(s) > 0 {
|
||||
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
return names, nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetConfigOption sets the value of the configuration option identified by
|
||||
// the given name.
|
||||
func (c *Conn) SetConfigOption(option, value string) error {
|
||||
c_opt, c_val := C.CString(option), C.CString(value)
|
||||
defer C.free(unsafe.Pointer(c_opt))
|
||||
defer C.free(unsafe.Pointer(c_val))
|
||||
ret := C.rados_conf_set(c.cluster, c_opt, c_val)
|
||||
if ret < 0 {
|
||||
return RadosError(int(ret))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetConfigOption returns the value of the Ceph configuration option
|
||||
// identified by the given name.
|
||||
func (c *Conn) GetConfigOption(name string) (value string, err error) {
|
||||
buf := make([]byte, 4096)
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
ret := int(C.rados_conf_get(c.cluster, c_name,
|
||||
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
|
||||
// FIXME: ret may be -ENAMETOOLONG if the buffer is not large enough. We
|
||||
// can handle this case, but we need a reliable way to test for
|
||||
// -ENAMETOOLONG constant. Will the syscall/Errno stuff in Go help?
|
||||
if ret == 0 {
|
||||
value = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
|
||||
return value, nil
|
||||
} else {
|
||||
return "", RadosError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForLatestOSDMap blocks the caller until the latest OSD map has been
|
||||
// retrieved.
|
||||
func (c *Conn) WaitForLatestOSDMap() error {
|
||||
ret := C.rados_wait_for_latest_osdmap(c.cluster)
|
||||
if ret < 0 {
|
||||
return RadosError(int(ret))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) ensure_connected() error {
|
||||
if c.connected {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(1)
|
||||
}
|
||||
}
|
||||
|
||||
// GetClusterStat returns statistics about the cluster associated with the
|
||||
// connection.
|
||||
func (c *Conn) GetClusterStats() (stat ClusterStat, err error) {
|
||||
if err := c.ensure_connected(); err != nil {
|
||||
return ClusterStat{}, err
|
||||
}
|
||||
c_stat := C.struct_rados_cluster_stat_t{}
|
||||
ret := C.rados_cluster_stat(c.cluster, &c_stat)
|
||||
if ret < 0 {
|
||||
return ClusterStat{}, RadosError(int(ret))
|
||||
} else {
|
||||
return ClusterStat{
|
||||
Kb: uint64(c_stat.kb),
|
||||
Kb_used: uint64(c_stat.kb_used),
|
||||
Kb_avail: uint64(c_stat.kb_avail),
|
||||
Num_objects: uint64(c_stat.num_objects),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseCmdLineArgs configures the connection from command line arguments.
|
||||
func (c *Conn) ParseCmdLineArgs(args []string) error {
|
||||
// add an empty element 0 -- Ceph treats the array as the actual contents
|
||||
// of argv and skips the first element (the executable name)
|
||||
argc := C.int(len(args) + 1)
|
||||
argv := make([]*C.char, argc)
|
||||
|
||||
// make the first element a string just in case it is ever examined
|
||||
argv[0] = C.CString("placeholder")
|
||||
defer C.free(unsafe.Pointer(argv[0]))
|
||||
|
||||
for i, arg := range args {
|
||||
argv[i+1] = C.CString(arg)
|
||||
defer C.free(unsafe.Pointer(argv[i+1]))
|
||||
}
|
||||
|
||||
ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0])
|
||||
if ret < 0 {
|
||||
return RadosError(int(ret))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDefaultConfigEnv configures the connection from the default Ceph
|
||||
// environment variable(s).
|
||||
func (c *Conn) ParseDefaultConfigEnv() error {
|
||||
ret := C.rados_conf_parse_env(c.cluster, nil)
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// GetFSID returns the fsid of the cluster as a hexadecimal string. The fsid
|
||||
// is a unique identifier of an entire Ceph cluster.
|
||||
func (c *Conn) GetFSID() (fsid string, err error) {
|
||||
buf := make([]byte, 37)
|
||||
ret := int(C.rados_cluster_fsid(c.cluster,
|
||||
(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
|
||||
// FIXME: the success case isn't documented correctly in librados.h
|
||||
if ret == 36 {
|
||||
fsid = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
|
||||
return fsid, nil
|
||||
} else {
|
||||
return "", RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// GetInstanceID returns a globally unique identifier for the cluster
|
||||
// connection instance.
|
||||
func (c *Conn) GetInstanceID() uint64 {
|
||||
// FIXME: are there any error cases for this?
|
||||
return uint64(C.rados_get_instance_id(c.cluster))
|
||||
}
|
||||
|
||||
// MakePool creates a new pool with default settings.
|
||||
func (c *Conn) MakePool(name string) error {
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
ret := int(C.rados_pool_create(c.cluster, c_name))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
// DeletePool deletes a pool and all the data inside the pool.
|
||||
func (c *Conn) DeletePool(name string) error {
|
||||
if err := c.ensure_connected(); err != nil {
|
||||
fmt.Println("NOT CONNECTED WHOOPS")
|
||||
return err
|
||||
}
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
ret := int(C.rados_pool_delete(c.cluster, c_name))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RadosError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
// MonCommand sends a command to one of the monitors
|
||||
func (c *Conn) MonCommand(args []byte) (buffer []byte, info string, err error) {
|
||||
return c.monCommand(args, nil)
|
||||
}
|
||||
|
||||
// MonCommand sends a command to one of the monitors, with an input buffer
|
||||
func (c *Conn) MonCommandWithInputBuffer(args, inputBuffer []byte) (buffer []byte, info string, err error) {
|
||||
return c.monCommand(args, inputBuffer)
|
||||
}
|
||||
|
||||
func (c *Conn) monCommand(args, inputBuffer []byte) (buffer []byte, info string, err error) {
|
||||
argv := C.CString(string(args))
|
||||
defer C.free(unsafe.Pointer(argv))
|
||||
|
||||
var (
|
||||
outs, outbuf *C.char
|
||||
outslen, outbuflen C.size_t
|
||||
)
|
||||
inbuf := C.CString(string(inputBuffer))
|
||||
inbufLen := len(inputBuffer)
|
||||
defer C.free(unsafe.Pointer(inbuf))
|
||||
|
||||
ret := C.rados_mon_command(c.cluster,
|
||||
&argv, 1,
|
||||
inbuf, // bulk input (e.g. crush map)
|
||||
C.size_t(inbufLen), // length inbuf
|
||||
&outbuf, // buffer
|
||||
&outbuflen, // buffer length
|
||||
&outs, // status string
|
||||
&outslen)
|
||||
|
||||
if outslen > 0 {
|
||||
info = C.GoStringN(outs, C.int(outslen))
|
||||
C.free(unsafe.Pointer(outs))
|
||||
}
|
||||
if outbuflen > 0 {
|
||||
buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
|
||||
C.free(unsafe.Pointer(outbuf))
|
||||
}
|
||||
if ret != 0 {
|
||||
err = RadosError(int(ret))
|
||||
return nil, info, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
/*
|
||||
Set of wrappers around librados API.
|
||||
*/
|
||||
package rados
|
||||
-890
@@ -1,890 +0,0 @@
|
||||
package rados
|
||||
|
||||
// #cgo LDFLAGS: -lrados
|
||||
// #include <errno.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <rados/librados.h>
|
||||
//
|
||||
// char* nextChunk(char **idx) {
|
||||
// char *copy;
|
||||
// copy = strdup(*idx);
|
||||
// *idx += strlen(*idx) + 1;
|
||||
// return copy;
|
||||
// }
|
||||
//
|
||||
// #if __APPLE__
|
||||
// #define ceph_time_t __darwin_time_t
|
||||
// #define ceph_suseconds_t __darwin_suseconds_t
|
||||
// #elif __GLIBC__
|
||||
// #define ceph_time_t __time_t
|
||||
// #define ceph_suseconds_t __suseconds_t
|
||||
// #else
|
||||
// #define ceph_time_t time_t
|
||||
// #define ceph_suseconds_t suseconds_t
|
||||
// #endif
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// PoolStat represents Ceph pool statistics.
|
||||
type PoolStat struct {
|
||||
// space used in bytes
|
||||
Num_bytes uint64
|
||||
// space used in KB
|
||||
Num_kb uint64
|
||||
// number of objects in the pool
|
||||
Num_objects uint64
|
||||
// number of clones of objects
|
||||
Num_object_clones uint64
|
||||
// num_objects * num_replicas
|
||||
Num_object_copies uint64
|
||||
Num_objects_missing_on_primary uint64
|
||||
// number of objects found on no OSDs
|
||||
Num_objects_unfound uint64
|
||||
// number of objects replicated fewer times than they should be
|
||||
// (but found on at least one OSD)
|
||||
Num_objects_degraded uint64
|
||||
Num_rd uint64
|
||||
Num_rd_kb uint64
|
||||
Num_wr uint64
|
||||
Num_wr_kb uint64
|
||||
}
|
||||
|
||||
// ObjectStat represents an object stat information
|
||||
type ObjectStat struct {
|
||||
// current length in bytes
|
||||
Size uint64
|
||||
// last modification time
|
||||
ModTime time.Time
|
||||
}
|
||||
|
||||
// LockInfo represents information on a current Ceph lock
|
||||
type LockInfo struct {
|
||||
NumLockers int
|
||||
Exclusive bool
|
||||
Tag string
|
||||
Clients []string
|
||||
Cookies []string
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
// IOContext represents a context for performing I/O within a pool.
|
||||
type IOContext struct {
|
||||
ioctx C.rados_ioctx_t
|
||||
}
|
||||
|
||||
// Pointer returns a uintptr representation of the IOContext.
|
||||
func (ioctx *IOContext) Pointer() uintptr {
|
||||
return uintptr(ioctx.ioctx)
|
||||
}
|
||||
|
||||
// SetNamespace sets the namespace for objects within this IO context (pool).
|
||||
// Setting namespace to a empty or zero length string sets the pool to the default namespace.
|
||||
func (ioctx *IOContext) SetNamespace(namespace string) {
|
||||
var c_ns *C.char
|
||||
if len(namespace) > 0 {
|
||||
c_ns = C.CString(namespace)
|
||||
defer C.free(unsafe.Pointer(c_ns))
|
||||
}
|
||||
C.rados_ioctx_set_namespace(ioctx.ioctx, c_ns)
|
||||
}
|
||||
|
||||
// Write writes len(data) bytes to the object with key oid starting at byte
|
||||
// offset offset. It returns an error, if any.
|
||||
func (ioctx *IOContext) Write(oid string, data []byte, offset uint64) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
dataPointer := unsafe.Pointer(nil)
|
||||
if len(data) > 0 {
|
||||
dataPointer = unsafe.Pointer(&data[0])
|
||||
}
|
||||
|
||||
ret := C.rados_write(ioctx.ioctx, c_oid,
|
||||
(*C.char)(dataPointer),
|
||||
(C.size_t)(len(data)),
|
||||
(C.uint64_t)(offset))
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// WriteFull writes len(data) bytes to the object with key oid.
|
||||
// The object is filled with the provided data. If the object exists,
|
||||
// it is atomically truncated and then written. It returns an error, if any.
|
||||
func (ioctx *IOContext) WriteFull(oid string, data []byte) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
ret := C.rados_write_full(ioctx.ioctx, c_oid,
|
||||
(*C.char)(unsafe.Pointer(&data[0])),
|
||||
(C.size_t)(len(data)))
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// Append appends len(data) bytes to the object with key oid.
|
||||
// The object is appended with the provided data. If the object exists,
|
||||
// it is atomically appended to. It returns an error, if any.
|
||||
func (ioctx *IOContext) Append(oid string, data []byte) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
ret := C.rados_append(ioctx.ioctx, c_oid,
|
||||
(*C.char)(unsafe.Pointer(&data[0])),
|
||||
(C.size_t)(len(data)))
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// Read reads up to len(data) bytes from the object with key oid starting at byte
|
||||
// offset offset. It returns the number of bytes read and an error, if any.
|
||||
func (ioctx *IOContext) Read(oid string, data []byte, offset uint64) (int, error) {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
var buf *C.char
|
||||
if len(data) > 0 {
|
||||
buf = (*C.char)(unsafe.Pointer(&data[0]))
|
||||
}
|
||||
|
||||
ret := C.rados_read(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
buf,
|
||||
(C.size_t)(len(data)),
|
||||
(C.uint64_t)(offset))
|
||||
|
||||
if ret >= 0 {
|
||||
return int(ret), nil
|
||||
} else {
|
||||
return 0, GetRadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Delete deletes the object with key oid. It returns an error, if any.
|
||||
func (ioctx *IOContext) Delete(oid string) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
return GetRadosError(int(C.rados_remove(ioctx.ioctx, c_oid)))
|
||||
}
|
||||
|
||||
// Truncate resizes the object with key oid to size size. If the operation
|
||||
// enlarges the object, the new area is logically filled with zeroes. If the
|
||||
// operation shrinks the object, the excess data is removed. It returns an
|
||||
// error, if any.
|
||||
func (ioctx *IOContext) Truncate(oid string, size uint64) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
return GetRadosError(int(C.rados_trunc(ioctx.ioctx, c_oid, (C.uint64_t)(size))))
|
||||
}
|
||||
|
||||
// Destroy informs librados that the I/O context is no longer in use.
|
||||
// Resources associated with the context may not be freed immediately, and the
|
||||
// context should not be used again after calling this method.
|
||||
func (ioctx *IOContext) Destroy() {
|
||||
C.rados_ioctx_destroy(ioctx.ioctx)
|
||||
}
|
||||
|
||||
// Stat returns a set of statistics about the pool associated with this I/O
|
||||
// context.
|
||||
func (ioctx *IOContext) GetPoolStats() (stat PoolStat, err error) {
|
||||
c_stat := C.struct_rados_pool_stat_t{}
|
||||
ret := C.rados_ioctx_pool_stat(ioctx.ioctx, &c_stat)
|
||||
if ret < 0 {
|
||||
return PoolStat{}, GetRadosError(int(ret))
|
||||
} else {
|
||||
return PoolStat{
|
||||
Num_bytes: uint64(c_stat.num_bytes),
|
||||
Num_kb: uint64(c_stat.num_kb),
|
||||
Num_objects: uint64(c_stat.num_objects),
|
||||
Num_object_clones: uint64(c_stat.num_object_clones),
|
||||
Num_object_copies: uint64(c_stat.num_object_copies),
|
||||
Num_objects_missing_on_primary: uint64(c_stat.num_objects_missing_on_primary),
|
||||
Num_objects_unfound: uint64(c_stat.num_objects_unfound),
|
||||
Num_objects_degraded: uint64(c_stat.num_objects_degraded),
|
||||
Num_rd: uint64(c_stat.num_rd),
|
||||
Num_rd_kb: uint64(c_stat.num_rd_kb),
|
||||
Num_wr: uint64(c_stat.num_wr),
|
||||
Num_wr_kb: uint64(c_stat.num_wr_kb),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetPoolName returns the name of the pool associated with the I/O context.
|
||||
func (ioctx *IOContext) GetPoolName() (name string, err error) {
|
||||
buf := make([]byte, 128)
|
||||
for {
|
||||
ret := C.rados_ioctx_get_pool_name(ioctx.ioctx,
|
||||
(*C.char)(unsafe.Pointer(&buf[0])), C.unsigned(len(buf)))
|
||||
if ret == -C.ERANGE {
|
||||
buf = make([]byte, len(buf)*2)
|
||||
continue
|
||||
} else if ret < 0 {
|
||||
return "", GetRadosError(int(ret))
|
||||
}
|
||||
name = C.GoStringN((*C.char)(unsafe.Pointer(&buf[0])), ret)
|
||||
return name, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectListFunc is the type of the function called for each object visited
|
||||
// by ListObjects.
|
||||
type ObjectListFunc func(oid string)
|
||||
|
||||
// ListObjects lists all of the objects in the pool associated with the I/O
|
||||
// context, and called the provided listFn function for each object, passing
|
||||
// to the function the name of the object. Call SetNamespace with
|
||||
// RadosAllNamespaces before calling this function to return objects from all
|
||||
// namespaces
|
||||
func (ioctx *IOContext) ListObjects(listFn ObjectListFunc) error {
|
||||
var ctx C.rados_list_ctx_t
|
||||
ret := C.rados_nobjects_list_open(ioctx.ioctx, &ctx)
|
||||
if ret < 0 {
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
defer func() { C.rados_nobjects_list_close(ctx) }()
|
||||
|
||||
for {
|
||||
var c_entry *C.char
|
||||
ret := C.rados_nobjects_list_next(ctx, &c_entry, nil, nil)
|
||||
if ret == -C.ENOENT {
|
||||
return nil
|
||||
} else if ret < 0 {
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
listFn(C.GoString(c_entry))
|
||||
}
|
||||
}
|
||||
|
||||
// Stat returns the size of the object and its last modification time
|
||||
func (ioctx *IOContext) Stat(object string) (stat ObjectStat, err error) {
|
||||
var c_psize C.uint64_t
|
||||
var c_pmtime C.time_t
|
||||
c_object := C.CString(object)
|
||||
defer C.free(unsafe.Pointer(c_object))
|
||||
|
||||
ret := C.rados_stat(
|
||||
ioctx.ioctx,
|
||||
c_object,
|
||||
&c_psize,
|
||||
&c_pmtime)
|
||||
|
||||
if ret < 0 {
|
||||
return ObjectStat{}, GetRadosError(int(ret))
|
||||
} else {
|
||||
return ObjectStat{
|
||||
Size: uint64(c_psize),
|
||||
ModTime: time.Unix(int64(c_pmtime), 0),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetXattr gets an xattr with key `name`, it returns the length of
|
||||
// the key read or an error if not successful
|
||||
func (ioctx *IOContext) GetXattr(object string, name string, data []byte) (int, error) {
|
||||
c_object := C.CString(object)
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_object))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
ret := C.rados_getxattr(
|
||||
ioctx.ioctx,
|
||||
c_object,
|
||||
c_name,
|
||||
(*C.char)(unsafe.Pointer(&data[0])),
|
||||
(C.size_t)(len(data)))
|
||||
|
||||
if ret >= 0 {
|
||||
return int(ret), nil
|
||||
} else {
|
||||
return 0, GetRadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Sets an xattr for an object with key `name` with value as `data`
|
||||
func (ioctx *IOContext) SetXattr(object string, name string, data []byte) error {
|
||||
c_object := C.CString(object)
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_object))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
ret := C.rados_setxattr(
|
||||
ioctx.ioctx,
|
||||
c_object,
|
||||
c_name,
|
||||
(*C.char)(unsafe.Pointer(&data[0])),
|
||||
(C.size_t)(len(data)))
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// function that lists all the xattrs for an object, since xattrs are
|
||||
// a k-v pair, this function returns a map of k-v pairs on
|
||||
// success, error code on failure
|
||||
func (ioctx *IOContext) ListXattrs(oid string) (map[string][]byte, error) {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
var it C.rados_xattrs_iter_t
|
||||
|
||||
ret := C.rados_getxattrs(ioctx.ioctx, c_oid, &it)
|
||||
if ret < 0 {
|
||||
return nil, GetRadosError(int(ret))
|
||||
}
|
||||
defer func() { C.rados_getxattrs_end(it) }()
|
||||
m := make(map[string][]byte)
|
||||
for {
|
||||
var c_name, c_val *C.char
|
||||
var c_len C.size_t
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_val))
|
||||
|
||||
ret := C.rados_getxattrs_next(it, &c_name, &c_val, &c_len)
|
||||
if ret < 0 {
|
||||
return nil, GetRadosError(int(ret))
|
||||
}
|
||||
// rados api returns a null name,val & 0-length upon
|
||||
// end of iteration
|
||||
if c_name == nil {
|
||||
return m, nil // stop iteration
|
||||
}
|
||||
m[C.GoString(c_name)] = C.GoBytes(unsafe.Pointer(c_val), (C.int)(c_len))
|
||||
}
|
||||
}
|
||||
|
||||
// Remove an xattr with key `name` from object `oid`
|
||||
func (ioctx *IOContext) RmXattr(oid string, name string) error {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
ret := C.rados_rmxattr(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name)
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// Append the map `pairs` to the omap `oid`
|
||||
func (ioctx *IOContext) SetOmap(oid string, pairs map[string][]byte) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
var s C.size_t
|
||||
var c *C.char
|
||||
ptrSize := unsafe.Sizeof(c)
|
||||
|
||||
c_keys := C.malloc(C.size_t(len(pairs)) * C.size_t(ptrSize))
|
||||
c_values := C.malloc(C.size_t(len(pairs)) * C.size_t(ptrSize))
|
||||
c_lengths := C.malloc(C.size_t(len(pairs)) * C.size_t(unsafe.Sizeof(s)))
|
||||
|
||||
defer C.free(unsafe.Pointer(c_keys))
|
||||
defer C.free(unsafe.Pointer(c_values))
|
||||
defer C.free(unsafe.Pointer(c_lengths))
|
||||
|
||||
i := 0
|
||||
for key, value := range pairs {
|
||||
// key
|
||||
c_key_ptr := (**C.char)(unsafe.Pointer(uintptr(c_keys) + uintptr(i)*ptrSize))
|
||||
*c_key_ptr = C.CString(key)
|
||||
defer C.free(unsafe.Pointer(*c_key_ptr))
|
||||
|
||||
// value and its length
|
||||
c_value_ptr := (**C.char)(unsafe.Pointer(uintptr(c_values) + uintptr(i)*ptrSize))
|
||||
|
||||
var c_length C.size_t
|
||||
if len(value) > 0 {
|
||||
*c_value_ptr = (*C.char)(unsafe.Pointer(&value[0]))
|
||||
c_length = C.size_t(len(value))
|
||||
} else {
|
||||
*c_value_ptr = nil
|
||||
c_length = C.size_t(0)
|
||||
}
|
||||
|
||||
c_length_ptr := (*C.size_t)(unsafe.Pointer(uintptr(c_lengths) + uintptr(i)*ptrSize))
|
||||
*c_length_ptr = c_length
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
op := C.rados_create_write_op()
|
||||
C.rados_write_op_omap_set(
|
||||
op,
|
||||
(**C.char)(c_keys),
|
||||
(**C.char)(c_values),
|
||||
(*C.size_t)(c_lengths),
|
||||
C.size_t(len(pairs)))
|
||||
|
||||
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
|
||||
C.rados_release_write_op(op)
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// OmapListFunc is the type of the function called for each omap key
|
||||
// visited by ListOmapValues
|
||||
type OmapListFunc func(key string, value []byte)
|
||||
|
||||
// Iterate on a set of keys and their values from an omap
|
||||
// `startAfter`: iterate only on the keys after this specified one
|
||||
// `filterPrefix`: iterate only on the keys beginning with this prefix
|
||||
// `maxReturn`: iterate no more than `maxReturn` key/value pairs
|
||||
// `listFn`: the function called at each iteration
|
||||
func (ioctx *IOContext) ListOmapValues(oid string, startAfter string, filterPrefix string, maxReturn int64, listFn OmapListFunc) error {
|
||||
c_oid := C.CString(oid)
|
||||
c_start_after := C.CString(startAfter)
|
||||
c_filter_prefix := C.CString(filterPrefix)
|
||||
c_max_return := C.uint64_t(maxReturn)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_start_after))
|
||||
defer C.free(unsafe.Pointer(c_filter_prefix))
|
||||
|
||||
op := C.rados_create_read_op()
|
||||
|
||||
var c_iter C.rados_omap_iter_t
|
||||
var c_prval C.int
|
||||
C.rados_read_op_omap_get_vals2(
|
||||
op,
|
||||
c_start_after,
|
||||
c_filter_prefix,
|
||||
c_max_return,
|
||||
&c_iter,
|
||||
nil,
|
||||
&c_prval,
|
||||
)
|
||||
|
||||
ret := C.rados_read_op_operate(op, ioctx.ioctx, c_oid, 0)
|
||||
|
||||
if int(ret) != 0 {
|
||||
return GetRadosError(int(ret))
|
||||
} else if int(c_prval) != 0 {
|
||||
return RadosError(int(c_prval))
|
||||
}
|
||||
|
||||
for {
|
||||
var c_key *C.char
|
||||
var c_val *C.char
|
||||
var c_len C.size_t
|
||||
|
||||
ret = C.rados_omap_get_next(c_iter, &c_key, &c_val, &c_len)
|
||||
|
||||
if int(ret) != 0 {
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
if c_key == nil {
|
||||
break
|
||||
}
|
||||
|
||||
listFn(C.GoString(c_key), C.GoBytes(unsafe.Pointer(c_val), C.int(c_len)))
|
||||
}
|
||||
|
||||
C.rados_omap_get_end(c_iter)
|
||||
C.rados_release_read_op(op)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fetch a set of keys and their values from an omap and returns then as a map
|
||||
// `startAfter`: retrieve only the keys after this specified one
|
||||
// `filterPrefix`: retrieve only the keys beginning with this prefix
|
||||
// `maxReturn`: retrieve no more than `maxReturn` key/value pairs
|
||||
func (ioctx *IOContext) GetOmapValues(oid string, startAfter string, filterPrefix string, maxReturn int64) (map[string][]byte, error) {
|
||||
omap := map[string][]byte{}
|
||||
|
||||
err := ioctx.ListOmapValues(
|
||||
oid, startAfter, filterPrefix, maxReturn,
|
||||
func(key string, value []byte) {
|
||||
omap[key] = value
|
||||
},
|
||||
)
|
||||
|
||||
return omap, err
|
||||
}
|
||||
|
||||
// Fetch all the keys and their values from an omap and returns then as a map
|
||||
// `startAfter`: retrieve only the keys after this specified one
|
||||
// `filterPrefix`: retrieve only the keys beginning with this prefix
|
||||
// `iteratorSize`: internal number of keys to fetch during a read operation
|
||||
func (ioctx *IOContext) GetAllOmapValues(oid string, startAfter string, filterPrefix string, iteratorSize int64) (map[string][]byte, error) {
|
||||
omap := map[string][]byte{}
|
||||
omapSize := 0
|
||||
|
||||
for {
|
||||
err := ioctx.ListOmapValues(
|
||||
oid, startAfter, filterPrefix, iteratorSize,
|
||||
func(key string, value []byte) {
|
||||
omap[key] = value
|
||||
startAfter = key
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return omap, err
|
||||
}
|
||||
|
||||
// End of omap
|
||||
if len(omap) == omapSize {
|
||||
break
|
||||
}
|
||||
|
||||
omapSize = len(omap)
|
||||
}
|
||||
|
||||
return omap, nil
|
||||
}
|
||||
|
||||
// Remove the specified `keys` from the omap `oid`
|
||||
func (ioctx *IOContext) RmOmapKeys(oid string, keys []string) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
var c *C.char
|
||||
ptrSize := unsafe.Sizeof(c)
|
||||
|
||||
c_keys := C.malloc(C.size_t(len(keys)) * C.size_t(ptrSize))
|
||||
defer C.free(unsafe.Pointer(c_keys))
|
||||
|
||||
i := 0
|
||||
for _, key := range keys {
|
||||
c_key_ptr := (**C.char)(unsafe.Pointer(uintptr(c_keys) + uintptr(i)*ptrSize))
|
||||
*c_key_ptr = C.CString(key)
|
||||
defer C.free(unsafe.Pointer(*c_key_ptr))
|
||||
i++
|
||||
}
|
||||
|
||||
op := C.rados_create_write_op()
|
||||
C.rados_write_op_omap_rm_keys(
|
||||
op,
|
||||
(**C.char)(c_keys),
|
||||
C.size_t(len(keys)))
|
||||
|
||||
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
|
||||
C.rados_release_write_op(op)
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
// Clear the omap `oid`
|
||||
func (ioctx *IOContext) CleanOmap(oid string) error {
|
||||
c_oid := C.CString(oid)
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
|
||||
op := C.rados_create_write_op()
|
||||
C.rados_write_op_omap_clear(op)
|
||||
|
||||
ret := C.rados_write_op_operate(op, ioctx.ioctx, c_oid, nil, 0)
|
||||
C.rados_release_write_op(op)
|
||||
|
||||
return GetRadosError(int(ret))
|
||||
}
|
||||
|
||||
type Iter struct {
|
||||
ctx C.rados_list_ctx_t
|
||||
err error
|
||||
entry string
|
||||
namespace string
|
||||
}
|
||||
|
||||
type IterToken uint32
|
||||
|
||||
// Return a Iterator object that can be used to list the object names in the current pool
|
||||
func (ioctx *IOContext) Iter() (*Iter, error) {
|
||||
iter := Iter{}
|
||||
if cerr := C.rados_nobjects_list_open(ioctx.ioctx, &iter.ctx); cerr < 0 {
|
||||
return nil, GetRadosError(int(cerr))
|
||||
}
|
||||
return &iter, nil
|
||||
}
|
||||
|
||||
// Returns a token marking the current position of the iterator. To be used in combination with Iter.Seek()
|
||||
func (iter *Iter) Token() IterToken {
|
||||
return IterToken(C.rados_nobjects_list_get_pg_hash_position(iter.ctx))
|
||||
}
|
||||
|
||||
func (iter *Iter) Seek(token IterToken) {
|
||||
C.rados_nobjects_list_seek(iter.ctx, C.uint32_t(token))
|
||||
}
|
||||
|
||||
// Next retrieves the next object name in the pool/namespace iterator.
|
||||
// Upon a successful invocation (return value of true), the Value method should
|
||||
// be used to obtain the name of the retrieved object name. When the iterator is
|
||||
// exhausted, Next returns false. The Err method should used to verify whether the
|
||||
// end of the iterator was reached, or the iterator received an error.
|
||||
//
|
||||
// Example:
|
||||
// iter := pool.Iter()
|
||||
// defer iter.Close()
|
||||
// for iter.Next() {
|
||||
// fmt.Printf("%v\n", iter.Value())
|
||||
// }
|
||||
// return iter.Err()
|
||||
//
|
||||
func (iter *Iter) Next() bool {
|
||||
var c_entry *C.char
|
||||
var c_namespace *C.char
|
||||
if cerr := C.rados_nobjects_list_next(iter.ctx, &c_entry, nil, &c_namespace); cerr < 0 {
|
||||
iter.err = GetRadosError(int(cerr))
|
||||
return false
|
||||
}
|
||||
iter.entry = C.GoString(c_entry)
|
||||
iter.namespace = C.GoString(c_namespace)
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns the current value of the iterator (object name), after a successful call to Next.
|
||||
func (iter *Iter) Value() string {
|
||||
if iter.err != nil {
|
||||
return ""
|
||||
}
|
||||
return iter.entry
|
||||
}
|
||||
|
||||
// Returns the namespace associated with the current value of the iterator (object name), after a successful call to Next.
|
||||
func (iter *Iter) Namespace() string {
|
||||
if iter.err != nil {
|
||||
return ""
|
||||
}
|
||||
return iter.namespace
|
||||
}
|
||||
|
||||
// Checks whether the iterator has encountered an error.
|
||||
func (iter *Iter) Err() error {
|
||||
if iter.err == RadosErrorNotFound {
|
||||
return nil
|
||||
}
|
||||
return iter.err
|
||||
}
|
||||
|
||||
// Closes the iterator cursor on the server. Be aware that iterators are not closed automatically
|
||||
// at the end of iteration.
|
||||
func (iter *Iter) Close() {
|
||||
C.rados_nobjects_list_close(iter.ctx)
|
||||
}
|
||||
|
||||
// Take an exclusive lock on an object.
|
||||
func (ioctx *IOContext) LockExclusive(oid, name, cookie, desc string, duration time.Duration, flags *byte) (int, error) {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
c_cookie := C.CString(cookie)
|
||||
c_desc := C.CString(desc)
|
||||
|
||||
var c_duration C.struct_timeval
|
||||
if duration != 0 {
|
||||
tv := syscall.NsecToTimeval(duration.Nanoseconds())
|
||||
c_duration = C.struct_timeval{tv_sec: C.ceph_time_t(tv.Sec), tv_usec: C.ceph_suseconds_t(tv.Usec)}
|
||||
}
|
||||
|
||||
var c_flags C.uint8_t
|
||||
if flags != nil {
|
||||
c_flags = C.uint8_t(*flags)
|
||||
}
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
defer C.free(unsafe.Pointer(c_desc))
|
||||
|
||||
ret := C.rados_lock_exclusive(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name,
|
||||
c_cookie,
|
||||
c_desc,
|
||||
&c_duration,
|
||||
c_flags)
|
||||
|
||||
// 0 on success, negative error code on failure
|
||||
// -EBUSY if the lock is already held by another (client, cookie) pair
|
||||
// -EEXIST if the lock is already held by the same (client, cookie) pair
|
||||
|
||||
switch ret {
|
||||
case 0:
|
||||
return int(ret), nil
|
||||
case -C.EBUSY:
|
||||
return int(ret), nil
|
||||
case -C.EEXIST:
|
||||
return int(ret), nil
|
||||
default:
|
||||
return int(ret), RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Take a shared lock on an object.
|
||||
func (ioctx *IOContext) LockShared(oid, name, cookie, tag, desc string, duration time.Duration, flags *byte) (int, error) {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
c_cookie := C.CString(cookie)
|
||||
c_tag := C.CString(tag)
|
||||
c_desc := C.CString(desc)
|
||||
|
||||
var c_duration C.struct_timeval
|
||||
if duration != 0 {
|
||||
tv := syscall.NsecToTimeval(duration.Nanoseconds())
|
||||
c_duration = C.struct_timeval{tv_sec: C.ceph_time_t(tv.Sec), tv_usec: C.ceph_suseconds_t(tv.Usec)}
|
||||
}
|
||||
|
||||
var c_flags C.uint8_t
|
||||
if flags != nil {
|
||||
c_flags = C.uint8_t(*flags)
|
||||
}
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
defer C.free(unsafe.Pointer(c_tag))
|
||||
defer C.free(unsafe.Pointer(c_desc))
|
||||
|
||||
ret := C.rados_lock_shared(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name,
|
||||
c_cookie,
|
||||
c_tag,
|
||||
c_desc,
|
||||
&c_duration,
|
||||
c_flags)
|
||||
|
||||
// 0 on success, negative error code on failure
|
||||
// -EBUSY if the lock is already held by another (client, cookie) pair
|
||||
// -EEXIST if the lock is already held by the same (client, cookie) pair
|
||||
|
||||
switch ret {
|
||||
case 0:
|
||||
return int(ret), nil
|
||||
case -C.EBUSY:
|
||||
return int(ret), nil
|
||||
case -C.EEXIST:
|
||||
return int(ret), nil
|
||||
default:
|
||||
return int(ret), RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// Release a shared or exclusive lock on an object.
|
||||
func (ioctx *IOContext) Unlock(oid, name, cookie string) (int, error) {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
c_cookie := C.CString(cookie)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
|
||||
// 0 on success, negative error code on failure
|
||||
// -ENOENT if the lock is not held by the specified (client, cookie) pair
|
||||
|
||||
ret := C.rados_unlock(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name,
|
||||
c_cookie)
|
||||
|
||||
switch ret {
|
||||
case 0:
|
||||
return int(ret), nil
|
||||
case -C.ENOENT:
|
||||
return int(ret), nil
|
||||
default:
|
||||
return int(ret), RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// List clients that have locked the named object lock and information about the lock.
|
||||
// The number of bytes required in each buffer is put in the corresponding size out parameter.
|
||||
// If any of the provided buffers are too short, -ERANGE is returned after these sizes are filled in.
|
||||
func (ioctx *IOContext) ListLockers(oid, name string) (*LockInfo, error) {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
|
||||
c_tag := (*C.char)(C.malloc(C.size_t(1024)))
|
||||
c_clients := (*C.char)(C.malloc(C.size_t(1024)))
|
||||
c_cookies := (*C.char)(C.malloc(C.size_t(1024)))
|
||||
c_addrs := (*C.char)(C.malloc(C.size_t(1024)))
|
||||
|
||||
var c_exclusive C.int
|
||||
c_tag_len := C.size_t(1024)
|
||||
c_clients_len := C.size_t(1024)
|
||||
c_cookies_len := C.size_t(1024)
|
||||
c_addrs_len := C.size_t(1024)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_tag))
|
||||
defer C.free(unsafe.Pointer(c_clients))
|
||||
defer C.free(unsafe.Pointer(c_cookies))
|
||||
defer C.free(unsafe.Pointer(c_addrs))
|
||||
|
||||
ret := C.rados_list_lockers(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name,
|
||||
&c_exclusive,
|
||||
c_tag,
|
||||
&c_tag_len,
|
||||
c_clients,
|
||||
&c_clients_len,
|
||||
c_cookies,
|
||||
&c_cookies_len,
|
||||
c_addrs,
|
||||
&c_addrs_len)
|
||||
|
||||
splitCString := func(items *C.char, itemsLen C.size_t) []string {
|
||||
currLen := 0
|
||||
clients := []string{}
|
||||
for currLen < int(itemsLen) {
|
||||
client := C.GoString(C.nextChunk(&items))
|
||||
clients = append(clients, client)
|
||||
currLen += len(client) + 1
|
||||
}
|
||||
return clients
|
||||
}
|
||||
|
||||
if ret < 0 {
|
||||
return nil, RadosError(int(ret))
|
||||
} else {
|
||||
return &LockInfo{int(ret), c_exclusive == 1, C.GoString(c_tag), splitCString(c_clients, c_clients_len), splitCString(c_cookies, c_cookies_len), splitCString(c_addrs, c_addrs_len)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Releases a shared or exclusive lock on an object, which was taken by the specified client.
|
||||
func (ioctx *IOContext) BreakLock(oid, name, client, cookie string) (int, error) {
|
||||
c_oid := C.CString(oid)
|
||||
c_name := C.CString(name)
|
||||
c_client := C.CString(client)
|
||||
c_cookie := C.CString(cookie)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_oid))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
defer C.free(unsafe.Pointer(c_client))
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
|
||||
// 0 on success, negative error code on failure
|
||||
// -ENOENT if the lock is not held by the specified (client, cookie) pair
|
||||
// -EINVAL if the client cannot be parsed
|
||||
|
||||
ret := C.rados_break_lock(
|
||||
ioctx.ioctx,
|
||||
c_oid,
|
||||
c_name,
|
||||
c_client,
|
||||
c_cookie)
|
||||
|
||||
switch ret {
|
||||
case 0:
|
||||
return int(ret), nil
|
||||
case -C.ENOENT:
|
||||
return int(ret), nil
|
||||
case -C.EINVAL: // -EINVAL
|
||||
return int(ret), nil
|
||||
default:
|
||||
return int(ret), RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
package rados
|
||||
|
||||
// #cgo LDFLAGS: -lrados
|
||||
// #include <errno.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <rados/librados.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type RadosError int
|
||||
|
||||
func (e RadosError) Error() string {
|
||||
return fmt.Sprintf("rados: %s", C.GoString(C.strerror(C.int(-e))))
|
||||
}
|
||||
|
||||
var RadosAllNamespaces = C.LIBRADOS_ALL_NSPACES
|
||||
|
||||
var RadosErrorNotFound = RadosError(-C.ENOENT)
|
||||
var RadosErrorPermissionDenied = RadosError(-C.EPERM)
|
||||
|
||||
func GetRadosError(err int) error {
|
||||
if err == 0 {
|
||||
return nil
|
||||
}
|
||||
return RadosError(err)
|
||||
}
|
||||
|
||||
// Version returns the major, minor, and patch components of the version of
|
||||
// the RADOS library linked against.
|
||||
func Version() (int, int, int) {
|
||||
var c_major, c_minor, c_patch C.int
|
||||
C.rados_version(&c_major, &c_minor, &c_patch)
|
||||
return int(c_major), int(c_minor), int(c_patch)
|
||||
}
|
||||
|
||||
func makeConn() *Conn {
|
||||
return &Conn{connected: false}
|
||||
}
|
||||
|
||||
func newConn(user *C.char) (*Conn, error) {
|
||||
conn := makeConn()
|
||||
ret := C.rados_create(&conn.cluster, user)
|
||||
|
||||
if ret == 0 {
|
||||
return conn, nil
|
||||
} else {
|
||||
return nil, RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
|
||||
// NewConn creates a new connection object. It returns the connection and an
|
||||
// error, if any.
|
||||
func NewConn() (*Conn, error) {
|
||||
return newConn(nil)
|
||||
}
|
||||
|
||||
// NewConnWithUser creates a new connection object with a custom username.
|
||||
// It returns the connection and an error, if any.
|
||||
func NewConnWithUser(user string) (*Conn, error) {
|
||||
c_user := C.CString(user)
|
||||
defer C.free(unsafe.Pointer(c_user))
|
||||
return newConn(c_user)
|
||||
}
|
||||
|
||||
// NewConnWithClusterAndUser creates a new connection object for a specific cluster and username.
|
||||
// It returns the connection and an error, if any.
|
||||
func NewConnWithClusterAndUser(clusterName string, userName string) (*Conn, error) {
|
||||
c_cluster_name := C.CString(clusterName)
|
||||
defer C.free(unsafe.Pointer(c_cluster_name))
|
||||
|
||||
c_name := C.CString(userName)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
conn := makeConn()
|
||||
ret := C.rados_create2(&conn.cluster, c_cluster_name, c_name, 0)
|
||||
if ret == 0 {
|
||||
return conn, nil
|
||||
} else {
|
||||
return nil, RadosError(int(ret))
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
/*
|
||||
Wrappers around librbd.
|
||||
*/
|
||||
package rbd
|
||||
-997
@@ -1,997 +0,0 @@
|
||||
package rbd
|
||||
|
||||
// #cgo LDFLAGS: -lrbd
|
||||
// #include <errno.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <rados/librados.h>
|
||||
// #include <rbd/librbd.h>
|
||||
// #include <rbd/features.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ceph/go-ceph/rados"
|
||||
)
|
||||
|
||||
const (
|
||||
// RBD features.
|
||||
RbdFeatureLayering = C.RBD_FEATURE_LAYERING
|
||||
RbdFeatureStripingV2 = C.RBD_FEATURE_STRIPINGV2
|
||||
RbdFeatureExclusiveLock = C.RBD_FEATURE_EXCLUSIVE_LOCK
|
||||
RbdFeatureObjectMap = C.RBD_FEATURE_OBJECT_MAP
|
||||
RbdFeatureFastDiff = C.RBD_FEATURE_FAST_DIFF
|
||||
RbdFeatureDeepFlatten = C.RBD_FEATURE_DEEP_FLATTEN
|
||||
RbdFeatureJournaling = C.RBD_FEATURE_JOURNALING
|
||||
RbdFeatureDataPool = C.RBD_FEATURE_DATA_POOL
|
||||
|
||||
RbdFeaturesDefault = C.RBD_FEATURES_DEFAULT
|
||||
|
||||
// Features that make an image inaccessible for read or write by clients that don't understand
|
||||
// them.
|
||||
RbdFeaturesIncompatible = C.RBD_FEATURES_INCOMPATIBLE
|
||||
|
||||
// Features that make an image unwritable by clients that don't understand them.
|
||||
RbdFeaturesRwIncompatible = C.RBD_FEATURES_RW_INCOMPATIBLE
|
||||
|
||||
// Features that may be dynamically enabled or disabled.
|
||||
RbdFeaturesMutable = C.RBD_FEATURES_MUTABLE
|
||||
|
||||
// Features that only work when used with a single client using the image for writes.
|
||||
RbdFeaturesSingleClient = C.RBD_FEATURES_SINGLE_CLIENT
|
||||
)
|
||||
|
||||
//
|
||||
type RBDError int
|
||||
|
||||
var (
|
||||
RbdErrorImageNotOpen = errors.New("RBD image not open")
|
||||
RbdErrorNotFound = errors.New("RBD image not found")
|
||||
)
|
||||
|
||||
//
|
||||
type ImageInfo struct {
|
||||
Size uint64
|
||||
Obj_size uint64
|
||||
Num_objs uint64
|
||||
Order int
|
||||
Block_name_prefix string
|
||||
Parent_pool int64
|
||||
Parent_name string
|
||||
}
|
||||
|
||||
//
|
||||
type SnapInfo struct {
|
||||
Id uint64
|
||||
Size uint64
|
||||
Name string
|
||||
}
|
||||
|
||||
//
|
||||
type Locker struct {
|
||||
Client string
|
||||
Cookie string
|
||||
Addr string
|
||||
}
|
||||
|
||||
//
|
||||
type Image struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
io.Seeker
|
||||
io.ReaderAt
|
||||
io.WriterAt
|
||||
name string
|
||||
offset int64
|
||||
ioctx *rados.IOContext
|
||||
image C.rbd_image_t
|
||||
}
|
||||
|
||||
//
|
||||
type Snapshot struct {
|
||||
image *Image
|
||||
name string
|
||||
}
|
||||
|
||||
// TrashInfo contains information about trashed RBDs.
|
||||
type TrashInfo struct {
|
||||
Id string // Id string, required to remove / restore trashed RBDs.
|
||||
Name string // Original name of trashed RBD.
|
||||
DeletionTime time.Time // Date / time at which the RBD was moved to the trash.
|
||||
DefermentEndTime time.Time // Date / time after which the trashed RBD may be permanently deleted.
|
||||
}
|
||||
|
||||
//
|
||||
func split(buf []byte) (values []string) {
|
||||
tmp := bytes.Split(buf[:len(buf)-1], []byte{0})
|
||||
for _, s := range tmp {
|
||||
if len(s) > 0 {
|
||||
go_s := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
|
||||
values = append(values, go_s)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
//
|
||||
func (e RBDError) Error() string {
|
||||
return fmt.Sprintf("rbd: ret=%d", e)
|
||||
}
|
||||
|
||||
//
|
||||
func GetError(err C.int) error {
|
||||
if err != 0 {
|
||||
if err == -C.ENOENT {
|
||||
return RbdErrorNotFound
|
||||
}
|
||||
return RBDError(err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
func Version() (int, int, int) {
|
||||
var c_major, c_minor, c_patch C.int
|
||||
C.rbd_version(&c_major, &c_minor, &c_patch)
|
||||
return int(c_major), int(c_minor), int(c_patch)
|
||||
}
|
||||
|
||||
// GetImageNames returns the list of current RBD images.
|
||||
func GetImageNames(ioctx *rados.IOContext) (names []string, err error) {
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
size := C.size_t(len(buf))
|
||||
ret := C.rbd_list(C.rados_ioctx_t(ioctx.Pointer()),
|
||||
(*C.char)(unsafe.Pointer(&buf[0])), &size)
|
||||
if ret == -C.ERANGE {
|
||||
buf = make([]byte, size)
|
||||
continue
|
||||
} else if ret < 0 {
|
||||
return nil, RBDError(ret)
|
||||
}
|
||||
tmp := bytes.Split(buf[:size-1], []byte{0})
|
||||
for _, s := range tmp {
|
||||
if len(s) > 0 {
|
||||
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
func GetImage(ioctx *rados.IOContext, name string) *Image {
|
||||
return &Image{
|
||||
ioctx: ioctx,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// int rbd_create(rados_ioctx_t io, const char *name, uint64_t size, int *order);
|
||||
// int rbd_create2(rados_ioctx_t io, const char *name, uint64_t size,
|
||||
// uint64_t features, int *order);
|
||||
// int rbd_create3(rados_ioctx_t io, const char *name, uint64_t size,
|
||||
// uint64_t features, int *order,
|
||||
// uint64_t stripe_unit, uint64_t stripe_count);
|
||||
func Create(ioctx *rados.IOContext, name string, size uint64, order int,
|
||||
args ...uint64) (image *Image, err error) {
|
||||
var ret C.int
|
||||
|
||||
c_order := C.int(order)
|
||||
c_name := C.CString(name)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
switch len(args) {
|
||||
case 3:
|
||||
ret = C.rbd_create3(C.rados_ioctx_t(ioctx.Pointer()),
|
||||
c_name, C.uint64_t(size),
|
||||
C.uint64_t(args[0]), &c_order,
|
||||
C.uint64_t(args[1]), C.uint64_t(args[2]))
|
||||
case 1:
|
||||
ret = C.rbd_create2(C.rados_ioctx_t(ioctx.Pointer()),
|
||||
c_name, C.uint64_t(size),
|
||||
C.uint64_t(args[0]), &c_order)
|
||||
case 0:
|
||||
ret = C.rbd_create(C.rados_ioctx_t(ioctx.Pointer()),
|
||||
c_name, C.uint64_t(size), &c_order)
|
||||
default:
|
||||
return nil, errors.New("Wrong number of argument")
|
||||
}
|
||||
|
||||
if ret < 0 {
|
||||
return nil, RBDError(ret)
|
||||
}
|
||||
|
||||
return &Image{
|
||||
ioctx: ioctx,
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
|
||||
// const char *p_snapname, rados_ioctx_t c_ioctx,
|
||||
// const char *c_name, uint64_t features, int *c_order);
|
||||
// int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
|
||||
// const char *p_snapname, rados_ioctx_t c_ioctx,
|
||||
// const char *c_name, uint64_t features, int *c_order,
|
||||
// uint64_t stripe_unit, int stripe_count);
|
||||
func (image *Image) Clone(snapname string, c_ioctx *rados.IOContext, c_name string, features uint64, order int) (*Image, error) {
|
||||
c_order := C.int(order)
|
||||
c_p_name := C.CString(image.name)
|
||||
c_p_snapname := C.CString(snapname)
|
||||
c_c_name := C.CString(c_name)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_p_name))
|
||||
defer C.free(unsafe.Pointer(c_p_snapname))
|
||||
defer C.free(unsafe.Pointer(c_c_name))
|
||||
|
||||
ret := C.rbd_clone(C.rados_ioctx_t(image.ioctx.Pointer()),
|
||||
c_p_name, c_p_snapname,
|
||||
C.rados_ioctx_t(c_ioctx.Pointer()),
|
||||
c_c_name, C.uint64_t(features), &c_order)
|
||||
if ret < 0 {
|
||||
return nil, RBDError(ret)
|
||||
}
|
||||
|
||||
return &Image{
|
||||
ioctx: c_ioctx,
|
||||
name: c_name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// int rbd_remove(rados_ioctx_t io, const char *name);
|
||||
// int rbd_remove_with_progress(rados_ioctx_t io, const char *name,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
func (image *Image) Remove() error {
|
||||
c_name := C.CString(image.name)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
return GetError(C.rbd_remove(C.rados_ioctx_t(image.ioctx.Pointer()), c_name))
|
||||
}
|
||||
|
||||
// Trash will move an image into the RBD trash, where it will be protected (i.e., salvageable) for
|
||||
// at least the specified delay.
|
||||
func (image *Image) Trash(delay time.Duration) error {
|
||||
c_name := C.CString(image.name)
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
return GetError(C.rbd_trash_move(C.rados_ioctx_t(image.ioctx.Pointer()), c_name,
|
||||
C.uint64_t(delay.Seconds())))
|
||||
}
|
||||
|
||||
// int rbd_rename(rados_ioctx_t src_io_ctx, const char *srcname, const char *destname);
|
||||
func (image *Image) Rename(destname string) error {
|
||||
c_srcname := C.CString(image.name)
|
||||
c_destname := C.CString(destname)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_srcname))
|
||||
defer C.free(unsafe.Pointer(c_destname))
|
||||
|
||||
err := RBDError(C.rbd_rename(C.rados_ioctx_t(image.ioctx.Pointer()),
|
||||
c_srcname, c_destname))
|
||||
if err == 0 {
|
||||
image.name = destname
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// int rbd_open(rados_ioctx_t io, const char *name, rbd_image_t *image, const char *snap_name);
|
||||
// int rbd_open_read_only(rados_ioctx_t io, const char *name, rbd_image_t *image,
|
||||
// const char *snap_name);
|
||||
func (image *Image) Open(args ...interface{}) error {
|
||||
var c_image C.rbd_image_t
|
||||
var c_snap_name *C.char
|
||||
var ret C.int
|
||||
var read_only bool
|
||||
|
||||
c_name := C.CString(image.name)
|
||||
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
for _, arg := range args {
|
||||
switch t := arg.(type) {
|
||||
case string:
|
||||
if t != "" {
|
||||
c_snap_name = C.CString(t)
|
||||
defer C.free(unsafe.Pointer(c_snap_name))
|
||||
}
|
||||
case bool:
|
||||
read_only = t
|
||||
default:
|
||||
return errors.New("Unexpected argument")
|
||||
}
|
||||
}
|
||||
|
||||
if read_only {
|
||||
ret = C.rbd_open_read_only(C.rados_ioctx_t(image.ioctx.Pointer()), c_name,
|
||||
&c_image, c_snap_name)
|
||||
} else {
|
||||
ret = C.rbd_open(C.rados_ioctx_t(image.ioctx.Pointer()), c_name,
|
||||
&c_image, c_snap_name)
|
||||
}
|
||||
|
||||
image.image = c_image
|
||||
|
||||
return GetError(ret)
|
||||
}
|
||||
|
||||
// int rbd_close(rbd_image_t image);
|
||||
func (image *Image) Close() error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_close(image.image); ret != 0 {
|
||||
return RBDError(ret)
|
||||
}
|
||||
|
||||
image.image = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// int rbd_resize(rbd_image_t image, uint64_t size);
|
||||
func (image *Image) Resize(size uint64) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
return GetError(C.rbd_resize(image.image, C.uint64_t(size)))
|
||||
}
|
||||
|
||||
// int rbd_stat(rbd_image_t image, rbd_image_info_t *info, size_t infosize);
|
||||
func (image *Image) Stat() (info *ImageInfo, err error) {
|
||||
if image.image == nil {
|
||||
return nil, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_stat C.rbd_image_info_t
|
||||
|
||||
if ret := C.rbd_stat(image.image, &c_stat, C.size_t(unsafe.Sizeof(info))); ret < 0 {
|
||||
return info, RBDError(ret)
|
||||
}
|
||||
|
||||
return &ImageInfo{
|
||||
Size: uint64(c_stat.size),
|
||||
Obj_size: uint64(c_stat.obj_size),
|
||||
Num_objs: uint64(c_stat.num_objs),
|
||||
Order: int(c_stat.order),
|
||||
Block_name_prefix: C.GoString((*C.char)(&c_stat.block_name_prefix[0])),
|
||||
Parent_pool: int64(c_stat.parent_pool),
|
||||
Parent_name: C.GoString((*C.char)(&c_stat.parent_name[0]))}, nil
|
||||
}
|
||||
|
||||
// int rbd_get_old_format(rbd_image_t image, uint8_t *old);
|
||||
func (image *Image) IsOldFormat() (old_format bool, err error) {
|
||||
if image.image == nil {
|
||||
return false, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_old_format C.uint8_t
|
||||
ret := C.rbd_get_old_format(image.image,
|
||||
&c_old_format)
|
||||
if ret < 0 {
|
||||
return false, RBDError(ret)
|
||||
}
|
||||
|
||||
return c_old_format != 0, nil
|
||||
}
|
||||
|
||||
// int rbd_size(rbd_image_t image, uint64_t *size);
|
||||
func (image *Image) GetSize() (size uint64, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_get_size(image.image, (*C.uint64_t)(&size)); ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// int rbd_get_features(rbd_image_t image, uint64_t *features);
|
||||
func (image *Image) GetFeatures() (features uint64, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_get_features(image.image, (*C.uint64_t)(&features)); ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
return features, nil
|
||||
}
|
||||
|
||||
// int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit);
|
||||
func (image *Image) GetStripeUnit() (stripe_unit uint64, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_get_stripe_unit(image.image, (*C.uint64_t)(&stripe_unit)); ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
return stripe_unit, nil
|
||||
}
|
||||
|
||||
// int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count);
|
||||
func (image *Image) GetStripeCount() (stripe_count uint64, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_get_stripe_count(image.image, (*C.uint64_t)(&stripe_count)); ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
return stripe_count, nil
|
||||
}
|
||||
|
||||
// int rbd_get_overlap(rbd_image_t image, uint64_t *overlap);
|
||||
func (image *Image) GetOverlap() (overlap uint64, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if ret := C.rbd_get_overlap(image.image, (*C.uint64_t)(&overlap)); ret < 0 {
|
||||
return overlap, RBDError(ret)
|
||||
}
|
||||
|
||||
return overlap, nil
|
||||
}
|
||||
|
||||
// int rbd_copy(rbd_image_t image, rados_ioctx_t dest_io_ctx, const char *destname);
|
||||
// int rbd_copy2(rbd_image_t src, rbd_image_t dest);
|
||||
// int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p, const char *destname,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
// int rbd_copy_with_progress2(rbd_image_t src, rbd_image_t dest,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
func (image *Image) Copy(args ...interface{}) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
switch t := args[0].(type) {
|
||||
case rados.IOContext:
|
||||
switch t2 := args[1].(type) {
|
||||
case string:
|
||||
c_destname := C.CString(t2)
|
||||
defer C.free(unsafe.Pointer(c_destname))
|
||||
return RBDError(C.rbd_copy(image.image,
|
||||
C.rados_ioctx_t(t.Pointer()),
|
||||
c_destname))
|
||||
default:
|
||||
return errors.New("Must specify destname")
|
||||
}
|
||||
case Image:
|
||||
var dest Image = t
|
||||
if dest.image == nil {
|
||||
return errors.New(fmt.Sprintf("RBD image %s is not open", dest.name))
|
||||
}
|
||||
return GetError(C.rbd_copy2(image.image, dest.image))
|
||||
default:
|
||||
return errors.New("Must specify either destination pool or destination image")
|
||||
}
|
||||
}
|
||||
|
||||
// int rbd_flatten(rbd_image_t image);
|
||||
func (image *Image) Flatten() error {
|
||||
if image.image == nil {
|
||||
return errors.New(fmt.Sprintf("RBD image %s is not open", image.name))
|
||||
}
|
||||
|
||||
return GetError(C.rbd_flatten(image.image))
|
||||
}
|
||||
|
||||
// ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len,
|
||||
// char *images, size_t *images_len);
|
||||
func (image *Image) ListChildren() (pools []string, images []string, err error) {
|
||||
if image.image == nil {
|
||||
return nil, nil, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_pools_len, c_images_len C.size_t
|
||||
|
||||
ret := C.rbd_list_children(image.image,
|
||||
nil, &c_pools_len,
|
||||
nil, &c_images_len)
|
||||
if ret == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if ret < 0 && ret != -C.ERANGE {
|
||||
return nil, nil, RBDError(ret)
|
||||
}
|
||||
|
||||
pools_buf := make([]byte, c_pools_len)
|
||||
images_buf := make([]byte, c_images_len)
|
||||
|
||||
ret = C.rbd_list_children(image.image,
|
||||
(*C.char)(unsafe.Pointer(&pools_buf[0])),
|
||||
&c_pools_len,
|
||||
(*C.char)(unsafe.Pointer(&images_buf[0])),
|
||||
&c_images_len)
|
||||
if ret < 0 {
|
||||
return nil, nil, RBDError(ret)
|
||||
}
|
||||
|
||||
tmp := bytes.Split(pools_buf[:c_pools_len-1], []byte{0})
|
||||
for _, s := range tmp {
|
||||
if len(s) > 0 {
|
||||
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
|
||||
pools = append(pools, name)
|
||||
}
|
||||
}
|
||||
|
||||
tmp = bytes.Split(images_buf[:c_images_len-1], []byte{0})
|
||||
for _, s := range tmp {
|
||||
if len(s) > 0 {
|
||||
name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
|
||||
images = append(images, name)
|
||||
}
|
||||
}
|
||||
|
||||
return pools, images, nil
|
||||
}
|
||||
|
||||
// ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
|
||||
// char *tag, size_t *tag_len,
|
||||
// char *clients, size_t *clients_len,
|
||||
// char *cookies, size_t *cookies_len,
|
||||
// char *addrs, size_t *addrs_len);
|
||||
func (image *Image) ListLockers() (tag string, lockers []Locker, err error) {
|
||||
if image.image == nil {
|
||||
return "", nil, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_exclusive C.int
|
||||
var c_tag_len, c_clients_len, c_cookies_len, c_addrs_len C.size_t
|
||||
var c_locker_cnt C.ssize_t
|
||||
|
||||
C.rbd_list_lockers(image.image, &c_exclusive,
|
||||
nil, (*C.size_t)(&c_tag_len),
|
||||
nil, (*C.size_t)(&c_clients_len),
|
||||
nil, (*C.size_t)(&c_cookies_len),
|
||||
nil, (*C.size_t)(&c_addrs_len))
|
||||
|
||||
// no locker held on rbd image when either c_clients_len,
|
||||
// c_cookies_len or c_addrs_len is *0*, so just quickly returned
|
||||
if int(c_clients_len) == 0 || int(c_cookies_len) == 0 ||
|
||||
int(c_addrs_len) == 0 {
|
||||
lockers = make([]Locker, 0)
|
||||
return "", lockers, nil
|
||||
}
|
||||
|
||||
tag_buf := make([]byte, c_tag_len)
|
||||
clients_buf := make([]byte, c_clients_len)
|
||||
cookies_buf := make([]byte, c_cookies_len)
|
||||
addrs_buf := make([]byte, c_addrs_len)
|
||||
|
||||
c_locker_cnt = C.rbd_list_lockers(image.image, &c_exclusive,
|
||||
(*C.char)(unsafe.Pointer(&tag_buf[0])), (*C.size_t)(&c_tag_len),
|
||||
(*C.char)(unsafe.Pointer(&clients_buf[0])), (*C.size_t)(&c_clients_len),
|
||||
(*C.char)(unsafe.Pointer(&cookies_buf[0])), (*C.size_t)(&c_cookies_len),
|
||||
(*C.char)(unsafe.Pointer(&addrs_buf[0])), (*C.size_t)(&c_addrs_len))
|
||||
|
||||
// rbd_list_lockers returns negative value for errors
|
||||
// and *0* means no locker held on rbd image.
|
||||
// but *0* is unexpected here because first rbd_list_lockers already
|
||||
// dealt with no locker case
|
||||
if int(c_locker_cnt) <= 0 {
|
||||
return "", nil, RBDError(c_locker_cnt)
|
||||
}
|
||||
|
||||
clients := split(clients_buf)
|
||||
cookies := split(cookies_buf)
|
||||
addrs := split(addrs_buf)
|
||||
|
||||
lockers = make([]Locker, c_locker_cnt)
|
||||
for i := 0; i < int(c_locker_cnt); i++ {
|
||||
lockers[i] = Locker{Client: clients[i],
|
||||
Cookie: cookies[i],
|
||||
Addr: addrs[i]}
|
||||
}
|
||||
|
||||
return string(tag_buf), lockers, nil
|
||||
}
|
||||
|
||||
// int rbd_lock_exclusive(rbd_image_t image, const char *cookie);
|
||||
func (image *Image) LockExclusive(cookie string) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_cookie := C.CString(cookie)
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
|
||||
return GetError(C.rbd_lock_exclusive(image.image, c_cookie))
|
||||
}
|
||||
|
||||
// int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag);
|
||||
func (image *Image) LockShared(cookie string, tag string) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_cookie := C.CString(cookie)
|
||||
c_tag := C.CString(tag)
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
defer C.free(unsafe.Pointer(c_tag))
|
||||
|
||||
return GetError(C.rbd_lock_shared(image.image, c_cookie, c_tag))
|
||||
}
|
||||
|
||||
// int rbd_lock_shared(rbd_image_t image, const char *cookie, const char *tag);
|
||||
func (image *Image) Unlock(cookie string) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_cookie := C.CString(cookie)
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
|
||||
return GetError(C.rbd_unlock(image.image, c_cookie))
|
||||
}
|
||||
|
||||
// int rbd_break_lock(rbd_image_t image, const char *client, const char *cookie);
|
||||
func (image *Image) BreakLock(client string, cookie string) error {
|
||||
if image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_client := C.CString(client)
|
||||
c_cookie := C.CString(cookie)
|
||||
defer C.free(unsafe.Pointer(c_client))
|
||||
defer C.free(unsafe.Pointer(c_cookie))
|
||||
|
||||
return GetError(C.rbd_break_lock(image.image, c_client, c_cookie))
|
||||
}
|
||||
|
||||
// ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len, char *buf);
|
||||
// TODO: int64_t rbd_read_iterate(rbd_image_t image, uint64_t ofs, size_t len,
|
||||
// int (*cb)(uint64_t, size_t, const char *, void *), void *arg);
|
||||
// TODO: int rbd_read_iterate2(rbd_image_t image, uint64_t ofs, uint64_t len,
|
||||
// int (*cb)(uint64_t, size_t, const char *, void *), void *arg);
|
||||
// TODO: int rbd_diff_iterate(rbd_image_t image,
|
||||
// const char *fromsnapname,
|
||||
// uint64_t ofs, uint64_t len,
|
||||
// int (*cb)(uint64_t, size_t, int, void *), void *arg);
|
||||
func (image *Image) Read(data []byte) (n int, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
ret := int(C.rbd_read(
|
||||
image.image,
|
||||
(C.uint64_t)(image.offset),
|
||||
(C.size_t)(len(data)),
|
||||
(*C.char)(unsafe.Pointer(&data[0]))))
|
||||
|
||||
if ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
image.offset += int64(ret)
|
||||
if ret < n {
|
||||
return ret, io.EOF
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len, const char *buf);
|
||||
func (image *Image) Write(data []byte) (n int, err error) {
|
||||
ret := int(C.rbd_write(image.image, C.uint64_t(image.offset),
|
||||
C.size_t(len(data)), (*C.char)(unsafe.Pointer(&data[0]))))
|
||||
|
||||
if ret >= 0 {
|
||||
image.offset += int64(ret)
|
||||
}
|
||||
|
||||
if ret != len(data) {
|
||||
err = RBDError(-C.EPERM)
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (image *Image) Seek(offset int64, whence int) (int64, error) {
|
||||
switch whence {
|
||||
case 0:
|
||||
image.offset = offset
|
||||
case 1:
|
||||
image.offset += offset
|
||||
case 2:
|
||||
stats, err := image.Stat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
image.offset = int64(stats.Size) - offset
|
||||
default:
|
||||
return 0, errors.New("Wrong value for whence")
|
||||
}
|
||||
return image.offset, nil
|
||||
}
|
||||
|
||||
// int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len);
|
||||
func (image *Image) Discard(ofs uint64, length uint64) error {
|
||||
return RBDError(C.rbd_discard(image.image, C.uint64_t(ofs),
|
||||
C.uint64_t(length)))
|
||||
}
|
||||
|
||||
func (image *Image) ReadAt(data []byte, off int64) (n int, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
ret := int(C.rbd_read(
|
||||
image.image,
|
||||
(C.uint64_t)(off),
|
||||
(C.size_t)(len(data)),
|
||||
(*C.char)(unsafe.Pointer(&data[0]))))
|
||||
|
||||
if ret < 0 {
|
||||
return 0, RBDError(ret)
|
||||
}
|
||||
|
||||
if ret < n {
|
||||
return ret, io.EOF
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (image *Image) WriteAt(data []byte, off int64) (n int, err error) {
|
||||
if image.image == nil {
|
||||
return 0, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
ret := int(C.rbd_write(image.image, C.uint64_t(off),
|
||||
C.size_t(len(data)), (*C.char)(unsafe.Pointer(&data[0]))))
|
||||
|
||||
if ret != len(data) {
|
||||
err = RBDError(-C.EPERM)
|
||||
}
|
||||
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// int rbd_flush(rbd_image_t image);
|
||||
func (image *Image) Flush() error {
|
||||
return GetError(C.rbd_flush(image.image))
|
||||
}
|
||||
|
||||
// int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps, int *max_snaps);
|
||||
// void rbd_snap_list_end(rbd_snap_info_t *snaps);
|
||||
func (image *Image) GetSnapshotNames() (snaps []SnapInfo, err error) {
|
||||
if image.image == nil {
|
||||
return nil, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_max_snaps C.int = 10
|
||||
var c_snaps []C.rbd_snap_info_t
|
||||
var snapCount C.int
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
c_snaps = make([]C.rbd_snap_info_t, c_max_snaps)
|
||||
snapCount = C.rbd_snap_list(image.image, &c_snaps[0], &c_max_snaps)
|
||||
if snapCount != -C.ERANGE {
|
||||
if snapCount >= 0 {
|
||||
break
|
||||
} else if snapCount < 0 {
|
||||
return nil, RBDError(snapCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snaps = make([]SnapInfo, snapCount)
|
||||
|
||||
for i := 0; i < int(snapCount); i++ {
|
||||
snaps[i] = SnapInfo{Id: uint64(c_snaps[i].id),
|
||||
Size: uint64(c_snaps[i].size),
|
||||
Name: C.GoString(c_snaps[i].name)}
|
||||
}
|
||||
|
||||
C.rbd_snap_list_end(&c_snaps[0])
|
||||
return snaps, nil
|
||||
}
|
||||
|
||||
// int rbd_snap_create(rbd_image_t image, const char *snapname);
|
||||
func (image *Image) CreateSnapshot(snapname string) (*Snapshot, error) {
|
||||
if image.image == nil {
|
||||
return nil, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapname)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
ret := C.rbd_snap_create(image.image, c_snapname)
|
||||
if ret < 0 {
|
||||
return nil, RBDError(ret)
|
||||
}
|
||||
|
||||
return &Snapshot{
|
||||
image: image,
|
||||
name: snapname,
|
||||
}, nil
|
||||
}
|
||||
|
||||
//
|
||||
func (image *Image) GetSnapshot(snapname string) *Snapshot {
|
||||
return &Snapshot{
|
||||
image: image,
|
||||
name: snapname,
|
||||
}
|
||||
}
|
||||
|
||||
// int rbd_get_parent_info(rbd_image_t image,
|
||||
// char *parent_pool_name, size_t ppool_namelen, char *parent_name,
|
||||
// size_t pnamelen, char *parent_snap_name, size_t psnap_namelen)
|
||||
func (image *Image) GetParentInfo(p_pool, p_name, p_snapname []byte) error {
|
||||
ret := C.rbd_get_parent_info(
|
||||
image.image,
|
||||
(*C.char)(unsafe.Pointer(&p_pool[0])),
|
||||
(C.size_t)(len(p_pool)),
|
||||
(*C.char)(unsafe.Pointer(&p_name[0])),
|
||||
(C.size_t)(len(p_name)),
|
||||
(*C.char)(unsafe.Pointer(&p_snapname[0])),
|
||||
(C.size_t)(len(p_snapname)))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
} else {
|
||||
return RBDError(ret)
|
||||
}
|
||||
}
|
||||
|
||||
// int rbd_snap_remove(rbd_image_t image, const char *snapname);
|
||||
func (snapshot *Snapshot) Remove() error {
|
||||
if snapshot.image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
return GetError(C.rbd_snap_remove(snapshot.image.image, c_snapname))
|
||||
}
|
||||
|
||||
// int rbd_snap_rollback(rbd_image_t image, const char *snapname);
|
||||
// int rbd_snap_rollback_with_progress(rbd_image_t image, const char *snapname,
|
||||
// librbd_progress_fn_t cb, void *cbdata);
|
||||
func (snapshot *Snapshot) Rollback() error {
|
||||
if snapshot.image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
return GetError(C.rbd_snap_rollback(snapshot.image.image, c_snapname))
|
||||
}
|
||||
|
||||
// int rbd_snap_protect(rbd_image_t image, const char *snap_name);
|
||||
func (snapshot *Snapshot) Protect() error {
|
||||
if snapshot.image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
return GetError(C.rbd_snap_protect(snapshot.image.image, c_snapname))
|
||||
}
|
||||
|
||||
// int rbd_snap_unprotect(rbd_image_t image, const char *snap_name);
|
||||
func (snapshot *Snapshot) Unprotect() error {
|
||||
if snapshot.image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
return GetError(C.rbd_snap_unprotect(snapshot.image.image, c_snapname))
|
||||
}
|
||||
|
||||
// int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
|
||||
// int *is_protected);
|
||||
func (snapshot *Snapshot) IsProtected() (bool, error) {
|
||||
if snapshot.image.image == nil {
|
||||
return false, RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
var c_is_protected C.int
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
ret := C.rbd_snap_is_protected(snapshot.image.image, c_snapname,
|
||||
&c_is_protected)
|
||||
if ret < 0 {
|
||||
return false, RBDError(ret)
|
||||
}
|
||||
|
||||
return c_is_protected != 0, nil
|
||||
}
|
||||
|
||||
// int rbd_snap_set(rbd_image_t image, const char *snapname);
|
||||
func (snapshot *Snapshot) Set() error {
|
||||
if snapshot.image.image == nil {
|
||||
return RbdErrorImageNotOpen
|
||||
}
|
||||
|
||||
c_snapname := C.CString(snapshot.name)
|
||||
defer C.free(unsafe.Pointer(c_snapname))
|
||||
|
||||
return GetError(C.rbd_snap_set(snapshot.image.image, c_snapname))
|
||||
}
|
||||
|
||||
// GetTrashList returns a slice of TrashInfo structs, containing information about all RBD images
|
||||
// currently residing in the trash.
|
||||
func GetTrashList(ioctx *rados.IOContext) ([]TrashInfo, error) {
|
||||
var num_entries C.size_t
|
||||
|
||||
// Call rbd_trash_list with nil pointer to get number of trash entries.
|
||||
if C.rbd_trash_list(C.rados_ioctx_t(ioctx.Pointer()), nil, &num_entries); num_entries == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
c_entries := make([]C.rbd_trash_image_info_t, num_entries)
|
||||
trashList := make([]TrashInfo, num_entries)
|
||||
|
||||
if ret := C.rbd_trash_list(C.rados_ioctx_t(ioctx.Pointer()), &c_entries[0], &num_entries); ret < 0 {
|
||||
return nil, RBDError(ret)
|
||||
}
|
||||
|
||||
for i, ti := range c_entries {
|
||||
trashList[i] = TrashInfo{
|
||||
Id: C.GoString(ti.id),
|
||||
Name: C.GoString(ti.name),
|
||||
DeletionTime: time.Unix(int64(ti.deletion_time), 0),
|
||||
DefermentEndTime: time.Unix(int64(ti.deferment_end_time), 0),
|
||||
}
|
||||
}
|
||||
|
||||
// Free rbd_trash_image_info_t pointers
|
||||
C.rbd_trash_list_cleanup(&c_entries[0], num_entries)
|
||||
|
||||
return trashList, nil
|
||||
}
|
||||
|
||||
// TrashRemove permanently deletes the trashed RBD with the specified id.
|
||||
func TrashRemove(ioctx *rados.IOContext, id string, force bool) error {
|
||||
c_id := C.CString(id)
|
||||
defer C.free(unsafe.Pointer(c_id))
|
||||
|
||||
return GetError(C.rbd_trash_remove(C.rados_ioctx_t(ioctx.Pointer()), c_id, C.bool(force)))
|
||||
}
|
||||
|
||||
// TrashRestore restores the trashed RBD with the specified id back to the pool from whence it
|
||||
// came, with the specified new name.
|
||||
func TrashRestore(ioctx *rados.IOContext, id, name string) error {
|
||||
c_id := C.CString(id)
|
||||
c_name := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c_id))
|
||||
defer C.free(unsafe.Pointer(c_name))
|
||||
|
||||
return GetError(C.rbd_trash_restore(C.rados_ioctx_t(ioctx.Pointer()), c_id, c_name))
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- tip
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
fast_finish: true
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- go test ./... -race -coverprofile=coverage.txt -covermode=atomic
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
notifications:
|
||||
email: false
|
||||
+1
-1
@@ -12,7 +12,6 @@ and parsing of UUIDs in different formats.
|
||||
|
||||
This package supports the following UUID versions:
|
||||
* Version 1, based on timestamp and MAC address (RFC-4122)
|
||||
* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
|
||||
* Version 3, based on MD5 hashing of a named value (RFC-4122)
|
||||
* Version 4, based on random numbers (RFC-4122)
|
||||
* Version 5, based on SHA-1 hashing of a named value (RFC-4122)
|
||||
@@ -107,3 +106,4 @@ func main() {
|
||||
|
||||
* [RFC-4122](https://tools.ietf.org/html/rfc4122)
|
||||
* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
|
||||
* [New UUID Formats RFC Draft (Peabody) Rev 02](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-02)
|
||||
|
||||
+5
-5
@@ -114,7 +114,7 @@ func (u *UUID) UnmarshalText(text []byte) error {
|
||||
case 41, 45:
|
||||
return u.decodeURN(text)
|
||||
default:
|
||||
return fmt.Errorf("uuid: incorrect UUID length: %s", text)
|
||||
return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(text), text)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func (u *UUID) UnmarshalText(text []byte) error {
|
||||
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
|
||||
func (u *UUID) decodeCanonical(t []byte) error {
|
||||
if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
|
||||
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||
return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
|
||||
}
|
||||
|
||||
src := t
|
||||
@@ -160,7 +160,7 @@ func (u *UUID) decodeBraced(t []byte) error {
|
||||
l := len(t)
|
||||
|
||||
if t[0] != '{' || t[l-1] != '}' {
|
||||
return fmt.Errorf("uuid: incorrect UUID format %s", t)
|
||||
return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
|
||||
}
|
||||
|
||||
return u.decodePlain(t[1 : l-1])
|
||||
@@ -175,7 +175,7 @@ func (u *UUID) decodeURN(t []byte) error {
|
||||
urnUUIDPrefix := t[:9]
|
||||
|
||||
if !bytes.Equal(urnUUIDPrefix, urnPrefix) {
|
||||
return fmt.Errorf("uuid: incorrect UUID format: %s", t)
|
||||
return fmt.Errorf("uuid: incorrect UUID format in string %q", t)
|
||||
}
|
||||
|
||||
return u.decodePlain(t[9:total])
|
||||
@@ -191,7 +191,7 @@ func (u *UUID) decodePlain(t []byte) error {
|
||||
case 36:
|
||||
return u.decodeCanonical(t)
|
||||
default:
|
||||
return fmt.Errorf("uuid: incorrect UUID length: %s", t)
|
||||
return fmt.Errorf("uuid: incorrect UUID length %d in string %q", len(t), t)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+309
-35
@@ -26,11 +26,11 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -47,21 +47,11 @@ type HWAddrFunc func() (net.HardwareAddr, error)
|
||||
// DefaultGenerator is the default UUID Generator used by this package.
|
||||
var DefaultGenerator Generator = NewGen()
|
||||
|
||||
var (
|
||||
posixUID = uint32(os.Getuid())
|
||||
posixGID = uint32(os.Getgid())
|
||||
)
|
||||
|
||||
// NewV1 returns a UUID based on the current timestamp and MAC address.
|
||||
func NewV1() (UUID, error) {
|
||||
return DefaultGenerator.NewV1()
|
||||
}
|
||||
|
||||
// NewV2 returns a DCE Security UUID based on the POSIX UID/GID.
|
||||
func NewV2(domain byte) (UUID, error) {
|
||||
return DefaultGenerator.NewV2(domain)
|
||||
}
|
||||
|
||||
// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
|
||||
func NewV3(ns UUID, name string) UUID {
|
||||
return DefaultGenerator.NewV3(ns, name)
|
||||
@@ -77,13 +67,45 @@ func NewV5(ns UUID, name string) UUID {
|
||||
return DefaultGenerator.NewV5(ns, name)
|
||||
}
|
||||
|
||||
// NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of
|
||||
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
|
||||
// order being adjusted to allow the UUID to be k-sortable.
|
||||
//
|
||||
// This is implemented based on revision 02 of the Peabody UUID draft, and may
|
||||
// be subject to change pending further revisions. Until the final specification
|
||||
// revision is finished, changes required to implement updates to the spec will
|
||||
// not be considered a breaking change. They will happen as a minor version
|
||||
// releases until the spec is final.
|
||||
func NewV6() (UUID, error) {
|
||||
return DefaultGenerator.NewV6()
|
||||
}
|
||||
|
||||
// NewV7 returns a k-sortable UUID based on the current UNIX epoch, with the
|
||||
// ability to configure the timestamp's precision from millisecond all the way
|
||||
// to nanosecond. The additional precision is supported by reducing the amount
|
||||
// of pseudorandom data that makes up the rest of the UUID.
|
||||
//
|
||||
// If an unknown Precision argument is passed to this method it will panic. As
|
||||
// such it's strongly encouraged to use the package-provided constants for this
|
||||
// value.
|
||||
//
|
||||
// This is implemented based on revision 02 of the Peabody UUID draft, and may
|
||||
// be subject to change pending further revisions. Until the final specification
|
||||
// revision is finished, changes required to implement updates to the spec will
|
||||
// not be considered a breaking change. They will happen as a minor version
|
||||
// releases until the spec is final.
|
||||
func NewV7(p Precision) (UUID, error) {
|
||||
return DefaultGenerator.NewV7(p)
|
||||
}
|
||||
|
||||
// Generator provides an interface for generating UUIDs.
|
||||
type Generator interface {
|
||||
NewV1() (UUID, error)
|
||||
NewV2(domain byte) (UUID, error)
|
||||
NewV3(ns UUID, name string) UUID
|
||||
NewV4() (UUID, error)
|
||||
NewV5(ns UUID, name string) UUID
|
||||
NewV6() (UUID, error)
|
||||
NewV7(Precision) (UUID, error)
|
||||
}
|
||||
|
||||
// Gen is a reference UUID generator based on the specifications laid out in
|
||||
@@ -109,6 +131,10 @@ type Gen struct {
|
||||
lastTime uint64
|
||||
clockSequence uint16
|
||||
hardwareAddr [6]byte
|
||||
|
||||
v7LastTime uint64
|
||||
v7LastSubsec uint64
|
||||
v7ClockSequence uint16
|
||||
}
|
||||
|
||||
// interface check -- build will fail if *Gen doesn't satisfy Generator
|
||||
@@ -164,28 +190,6 @@ func (g *Gen) NewV1() (UUID, error) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV2 returns a DCE Security UUID based on the POSIX UID/GID.
|
||||
func (g *Gen) NewV2(domain byte) (UUID, error) {
|
||||
u, err := g.NewV1()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
switch domain {
|
||||
case DomainPerson:
|
||||
binary.BigEndian.PutUint32(u[:], posixUID)
|
||||
case DomainGroup:
|
||||
binary.BigEndian.PutUint32(u[:], posixGID)
|
||||
}
|
||||
|
||||
u[9] = domain
|
||||
|
||||
u.SetVersion(V2)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
|
||||
func (g *Gen) NewV3(ns UUID, name string) UUID {
|
||||
u := newFromHash(md5.New(), ns, name)
|
||||
@@ -216,7 +220,39 @@ func (g *Gen) NewV5(ns UUID, name string) UUID {
|
||||
return u
|
||||
}
|
||||
|
||||
// Returns the epoch and clock sequence.
|
||||
// NewV6 returns a k-sortable UUID based on a timestamp and 48 bits of
|
||||
// pseudorandom data. The timestamp in a V6 UUID is the same as V1, with the bit
|
||||
// order being adjusted to allow the UUID to be k-sortable.
|
||||
//
|
||||
// This is implemented based on revision 02 of the Peabody UUID draft, and may
|
||||
// be subject to change pending further revisions. Until the final specification
|
||||
// revision is finished, changes required to implement updates to the spec will
|
||||
// not be considered a breaking change. They will happen as a minor version
|
||||
// releases until the spec is final.
|
||||
func (g *Gen) NewV6() (UUID, error) {
|
||||
var u UUID
|
||||
|
||||
if _, err := io.ReadFull(g.rand, u[10:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
timeNow, clockSeq, err := g.getClockSequence()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(u[0:], uint32(timeNow>>28)) // set time_high
|
||||
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>12)) // set time_mid
|
||||
binary.BigEndian.PutUint16(u[6:], uint16(timeNow&0xfff)) // set time_low (minus four version bits)
|
||||
binary.BigEndian.PutUint16(u[8:], clockSeq&0x3fff) // set clk_seq_hi_res (minus two variant bits)
|
||||
|
||||
u.SetVersion(V6)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// getClockSequence returns the epoch and clock sequence for V1 and V6 UUIDs.
|
||||
func (g *Gen) getClockSequence() (uint64, uint16, error) {
|
||||
var err error
|
||||
g.clockSequenceOnce.Do(func() {
|
||||
@@ -244,6 +280,244 @@ func (g *Gen) getClockSequence() (uint64, uint16, error) {
|
||||
return timeNow, g.clockSequence, nil
|
||||
}
|
||||
|
||||
// Precision is used to configure the V7 generator, to specify how precise the
|
||||
// timestamp within the UUID should be.
|
||||
type Precision byte
|
||||
|
||||
const (
|
||||
NanosecondPrecision Precision = iota
|
||||
MicrosecondPrecision
|
||||
MillisecondPrecision
|
||||
)
|
||||
|
||||
func (p Precision) String() string {
|
||||
switch p {
|
||||
case NanosecondPrecision:
|
||||
return "nanosecond"
|
||||
|
||||
case MicrosecondPrecision:
|
||||
return "microsecond"
|
||||
|
||||
case MillisecondPrecision:
|
||||
return "millisecond"
|
||||
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Duration returns the time.Duration for a specific precision. If the Precision
|
||||
// value is not known, this returns 0.
|
||||
func (p Precision) Duration() time.Duration {
|
||||
switch p {
|
||||
case NanosecondPrecision:
|
||||
return time.Nanosecond
|
||||
|
||||
case MicrosecondPrecision:
|
||||
return time.Microsecond
|
||||
|
||||
case MillisecondPrecision:
|
||||
return time.Millisecond
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// NewV7 returns a k-sortable UUID based on the current UNIX epoch, with the
|
||||
// ability to configure the timestamp's precision from millisecond all the way
|
||||
// to nanosecond. The additional precision is supported by reducing the amount
|
||||
// of pseudorandom data that makes up the rest of the UUID.
|
||||
//
|
||||
// If an unknown Precision argument is passed to this method it will panic. As
|
||||
// such it's strongly encouraged to use the package-provided constants for this
|
||||
// value.
|
||||
//
|
||||
// This is implemented based on revision 02 of the Peabody UUID draft, and may
|
||||
// be subject to change pending further revisions. Until the final specification
|
||||
// revision is finished, changes required to implement updates to the spec will
|
||||
// not be considered a breaking change. They will happen as a minor version
|
||||
// releases until the spec is final.
|
||||
func (g *Gen) NewV7(p Precision) (UUID, error) {
|
||||
var u UUID
|
||||
var err error
|
||||
|
||||
switch p {
|
||||
case NanosecondPrecision:
|
||||
u, err = g.newV7Nano()
|
||||
|
||||
case MicrosecondPrecision:
|
||||
u, err = g.newV7Micro()
|
||||
|
||||
case MillisecondPrecision:
|
||||
u, err = g.newV7Milli()
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown precision value %d", p))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
u.SetVersion(V7)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (g *Gen) newV7Milli() (UUID, error) {
|
||||
var u UUID
|
||||
|
||||
if _, err := io.ReadFull(g.rand, u[8:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
sec, nano, seq, err := g.getV7ClockSequence(MillisecondPrecision)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
msec := (nano / 1000000) & 0xfff
|
||||
|
||||
d := (sec << 28) // set unixts field
|
||||
d |= (msec << 16) // set msec field
|
||||
d |= (uint64(seq) & 0xfff) // set seq field
|
||||
|
||||
binary.BigEndian.PutUint64(u[:], d)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (g *Gen) newV7Micro() (UUID, error) {
|
||||
var u UUID
|
||||
|
||||
if _, err := io.ReadFull(g.rand, u[10:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
sec, nano, seq, err := g.getV7ClockSequence(MicrosecondPrecision)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
usec := nano / 1000
|
||||
usech := (usec << 4) & 0xfff0000
|
||||
usecl := usec & 0xfff
|
||||
|
||||
d := (sec << 28) // set unixts field
|
||||
d |= usech | usecl // set usec fields
|
||||
|
||||
binary.BigEndian.PutUint64(u[:], d)
|
||||
binary.BigEndian.PutUint16(u[8:], seq)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (g *Gen) newV7Nano() (UUID, error) {
|
||||
var u UUID
|
||||
|
||||
if _, err := io.ReadFull(g.rand, u[11:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
sec, nano, seq, err := g.getV7ClockSequence(NanosecondPrecision)
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
nano &= 0x3fffffffff
|
||||
nanoh := nano >> 26
|
||||
nanom := (nano >> 14) & 0xfff
|
||||
nanol := uint16(nano & 0x3fff)
|
||||
|
||||
d := (sec << 28) // set unixts field
|
||||
d |= (nanoh << 16) | nanom // set nsec high and med fields
|
||||
|
||||
binary.BigEndian.PutUint64(u[:], d)
|
||||
binary.BigEndian.PutUint16(u[8:], nanol) // set nsec low field
|
||||
|
||||
u[10] = byte(seq) // set seq field
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
const (
|
||||
maxSeq14 = (1 << 14) - 1
|
||||
maxSeq12 = (1 << 12) - 1
|
||||
maxSeq8 = (1 << 8) - 1
|
||||
)
|
||||
|
||||
// getV7ClockSequence returns the unix epoch, nanoseconds of current second, and
|
||||
// the sequence for V7 UUIDs.
|
||||
func (g *Gen) getV7ClockSequence(p Precision) (epoch uint64, nano uint64, seq uint16, err error) {
|
||||
g.storageMutex.Lock()
|
||||
defer g.storageMutex.Unlock()
|
||||
|
||||
tn := g.epochFunc()
|
||||
unix := uint64(tn.Unix())
|
||||
nsec := uint64(tn.Nanosecond())
|
||||
|
||||
// V7 UUIDs have more precise requirements around how the clock sequence
|
||||
// value is generated and used. Specifically they require that the sequence
|
||||
// be zero, unless we've already generated a UUID within this unit of time
|
||||
// (millisecond, microsecond, or nanosecond) at which point you should
|
||||
// increment the sequence. Likewise if time has warped backwards for some reason (NTP
|
||||
// adjustment?), we also increment the clock sequence to reduce the risk of a
|
||||
// collision.
|
||||
switch {
|
||||
case unix < g.v7LastTime:
|
||||
g.v7ClockSequence++
|
||||
|
||||
case unix > g.v7LastTime:
|
||||
g.v7ClockSequence = 0
|
||||
|
||||
case unix == g.v7LastTime:
|
||||
switch p {
|
||||
case NanosecondPrecision:
|
||||
if nsec <= g.v7LastSubsec {
|
||||
if g.v7ClockSequence >= maxSeq8 {
|
||||
return 0, 0, 0, errors.New("generating nanosecond precision UUIDv7s too fast: internal clock sequence would roll over")
|
||||
}
|
||||
|
||||
g.v7ClockSequence++
|
||||
} else {
|
||||
g.v7ClockSequence = 0
|
||||
}
|
||||
|
||||
case MicrosecondPrecision:
|
||||
if nsec/1000 <= g.v7LastSubsec/1000 {
|
||||
if g.v7ClockSequence >= maxSeq14 {
|
||||
return 0, 0, 0, errors.New("generating microsecond precision UUIDv7s too fast: internal clock sequence would roll over")
|
||||
}
|
||||
|
||||
g.v7ClockSequence++
|
||||
} else {
|
||||
g.v7ClockSequence = 0
|
||||
}
|
||||
|
||||
case MillisecondPrecision:
|
||||
if nsec/1000000 <= g.v7LastSubsec/1000000 {
|
||||
if g.v7ClockSequence >= maxSeq12 {
|
||||
return 0, 0, 0, errors.New("generating millisecond precision UUIDv7s too fast: internal clock sequence would roll over")
|
||||
}
|
||||
|
||||
g.v7ClockSequence++
|
||||
} else {
|
||||
g.v7ClockSequence = 0
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown precision value %d", p))
|
||||
}
|
||||
}
|
||||
|
||||
g.v7LastTime = unix
|
||||
g.v7LastSubsec = nsec
|
||||
|
||||
return unix, nsec, g.v7ClockSequence, nil
|
||||
}
|
||||
|
||||
// Returns the hardware address.
|
||||
func (g *Gen) getHardwareAddr() ([]byte, error) {
|
||||
var err error
|
||||
|
||||
+105
-7
@@ -19,20 +19,33 @@
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// Package uuid provides implementations of the Universally Unique Identifier (UUID), as specified in RFC-4122 and DCE 1.1.
|
||||
// Package uuid provides implementations of the Universally Unique Identifier
|
||||
// (UUID), as specified in RFC-4122 and the Peabody RFC Draft (revision 02).
|
||||
//
|
||||
// RFC-4122[1] provides the specification for versions 1, 3, 4, and 5.
|
||||
// RFC-4122[1] provides the specification for versions 1, 3, 4, and 5. The
|
||||
// Peabody UUID RFC Draft[2] provides the specification for the new k-sortable
|
||||
// UUIDs, versions 6 and 7.
|
||||
//
|
||||
// DCE 1.1[2] provides the specification for version 2.
|
||||
// DCE 1.1[3] provides the specification for version 2, but version 2 support
|
||||
// was removed from this package in v4 due to some concerns with the
|
||||
// specification itself. Reading the spec, it seems that it would result in
|
||||
// generating UUIDs that aren't very unique. In having read the spec it seemed
|
||||
// that our implementation did not meet the spec. It also seems to be at-odds
|
||||
// with RFC 4122, meaning we would need quite a bit of special code to support
|
||||
// it. Lastly, there were no Version 2 implementations that we could find to
|
||||
// ensure we were understanding the specification correctly.
|
||||
//
|
||||
// [1] https://tools.ietf.org/html/rfc4122
|
||||
// [2] http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01
|
||||
// [2] https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-02
|
||||
// [3] http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -46,10 +59,13 @@ type UUID [Size]byte
|
||||
const (
|
||||
_ byte = iota
|
||||
V1 // Version 1 (date-time and MAC address)
|
||||
V2 // Version 2 (date-time and MAC address, DCE security version)
|
||||
_ // Version 2 (date-time and MAC address, DCE security version) [removed]
|
||||
V3 // Version 3 (namespace name-based)
|
||||
V4 // Version 4 (random)
|
||||
V5 // Version 5 (namespace name-based)
|
||||
V6 // Version 6 (k-sortable timestamp and random data) [peabody draft]
|
||||
V7 // Version 7 (k-sortable timestamp, with configurable precision, and random data) [peabody draft]
|
||||
_ // Version 8 (k-sortable timestamp, meant for custom implementations) [peabody draft] [not implemented]
|
||||
)
|
||||
|
||||
// UUID layout variants.
|
||||
@@ -68,8 +84,8 @@ const (
|
||||
)
|
||||
|
||||
// Timestamp is the count of 100-nanosecond intervals since 00:00:00.00,
|
||||
// 15 October 1582 within a V1 UUID. This type has no meaning for V2-V5
|
||||
// UUIDs since they don't have an embedded timestamp.
|
||||
// 15 October 1582 within a V1 UUID. This type has no meaning for other
|
||||
// UUID versions since they don't have an embedded timestamp.
|
||||
type Timestamp uint64
|
||||
|
||||
const _100nsPerSecond = 10000000
|
||||
@@ -78,6 +94,7 @@ const _100nsPerSecond = 10000000
|
||||
func (t Timestamp) Time() (time.Time, error) {
|
||||
secs := uint64(t) / _100nsPerSecond
|
||||
nsecs := 100 * (uint64(t) % _100nsPerSecond)
|
||||
|
||||
return time.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil
|
||||
}
|
||||
|
||||
@@ -88,12 +105,34 @@ func TimestampFromV1(u UUID) (Timestamp, error) {
|
||||
err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version())
|
||||
return 0, err
|
||||
}
|
||||
|
||||
low := binary.BigEndian.Uint32(u[0:4])
|
||||
mid := binary.BigEndian.Uint16(u[4:6])
|
||||
hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff
|
||||
|
||||
return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil
|
||||
}
|
||||
|
||||
// TimestampFromV6 returns the Timestamp embedded within a V6 UUID. This
|
||||
// function returns an error if the UUID is any version other than 6.
|
||||
//
|
||||
// This is implemented based on revision 01 of the Peabody UUID draft, and may
|
||||
// be subject to change pending further revisions. Until the final specification
|
||||
// revision is finished, changes required to implement updates to the spec will
|
||||
// not be considered a breaking change. They will happen as a minor version
|
||||
// releases until the spec is final.
|
||||
func TimestampFromV6(u UUID) (Timestamp, error) {
|
||||
if u.Version() != 6 {
|
||||
return 0, fmt.Errorf("uuid: %s is version %d, not version 6", u, u.Version())
|
||||
}
|
||||
|
||||
hi := binary.BigEndian.Uint32(u[0:4])
|
||||
mid := binary.BigEndian.Uint16(u[4:6])
|
||||
low := binary.BigEndian.Uint16(u[6:8]) & 0xfff
|
||||
|
||||
return Timestamp(uint64(low) + (uint64(mid) << 12) + (uint64(hi) << 28)), nil
|
||||
}
|
||||
|
||||
// String parse helpers.
|
||||
var (
|
||||
urnPrefix = []byte("urn:uuid:")
|
||||
@@ -156,6 +195,65 @@ func (u UUID) String() string {
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter for UUID values.
|
||||
//
|
||||
// The behavior is as follows:
|
||||
// The 'x' and 'X' verbs output only the hex digits of the UUID, using a-f for 'x' and A-F for 'X'.
|
||||
// The 'v', '+v', 's' and 'q' verbs return the canonical RFC-4122 string representation.
|
||||
// The 'S' verb returns the RFC-4122 format, but with capital hex digits.
|
||||
// The '#v' verb returns the "Go syntax" representation, which is a 16 byte array initializer.
|
||||
// All other verbs not handled directly by the fmt package (like '%p') are unsupported and will return
|
||||
// "%!verb(uuid.UUID=value)" as recommended by the fmt package.
|
||||
func (u UUID) Format(f fmt.State, c rune) {
|
||||
switch c {
|
||||
case 'x', 'X':
|
||||
s := hex.EncodeToString(u.Bytes())
|
||||
if c == 'X' {
|
||||
s = strings.Map(toCapitalHexDigits, s)
|
||||
}
|
||||
_, _ = io.WriteString(f, s)
|
||||
case 'v':
|
||||
var s string
|
||||
if f.Flag('#') {
|
||||
s = fmt.Sprintf("%#v", [Size]byte(u))
|
||||
} else {
|
||||
s = u.String()
|
||||
}
|
||||
_, _ = io.WriteString(f, s)
|
||||
case 's', 'S':
|
||||
s := u.String()
|
||||
if c == 'S' {
|
||||
s = strings.Map(toCapitalHexDigits, s)
|
||||
}
|
||||
_, _ = io.WriteString(f, s)
|
||||
case 'q':
|
||||
_, _ = io.WriteString(f, `"`+u.String()+`"`)
|
||||
default:
|
||||
// invalid/unsupported format verb
|
||||
fmt.Fprintf(f, "%%!%c(uuid.UUID=%s)", c, u.String())
|
||||
}
|
||||
}
|
||||
|
||||
func toCapitalHexDigits(ch rune) rune {
|
||||
// convert a-f hex digits to A-F
|
||||
switch ch {
|
||||
case 'a':
|
||||
return 'A'
|
||||
case 'b':
|
||||
return 'B'
|
||||
case 'c':
|
||||
return 'C'
|
||||
case 'd':
|
||||
return 'D'
|
||||
case 'e':
|
||||
return 'E'
|
||||
case 'f':
|
||||
return 'F'
|
||||
default:
|
||||
return ch
|
||||
}
|
||||
}
|
||||
|
||||
// SetVersion sets the version bits.
|
||||
func (u *UUID) SetVersion(v byte) {
|
||||
u[6] = (u[6] & 0x0f) | (v << 4)
|
||||
|
||||
Vendored
+2
-5
@@ -208,9 +208,6 @@ github.com/boombuler/barcode/utils
|
||||
github.com/bradfitz/iter
|
||||
# github.com/c-bata/go-prompt v0.2.1
|
||||
github.com/c-bata/go-prompt
|
||||
# github.com/ceph/go-ceph v0.0.0-20181217221554-e32f9f0f2e94 => github.com/yunionio/go-ceph v0.0.0-20190912101231-6f05a06b3859
|
||||
github.com/ceph/go-ceph/rados
|
||||
github.com/ceph/go-ceph/rbd
|
||||
# github.com/cheggaaa/pb/v3 v3.0.8
|
||||
github.com/cheggaaa/pb/v3
|
||||
github.com/cheggaaa/pb/v3/termutil
|
||||
@@ -333,7 +330,7 @@ github.com/go-playground/validator/v10
|
||||
github.com/go-sql-driver/mysql
|
||||
# github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
github.com/go-yaml/yaml
|
||||
# github.com/gofrs/uuid v3.2.0+incompatible
|
||||
# github.com/gofrs/uuid v4.1.0+incompatible
|
||||
github.com/gofrs/uuid
|
||||
# github.com/gogo/protobuf v1.3.1
|
||||
github.com/gogo/protobuf/gogoproto
|
||||
@@ -1172,7 +1169,7 @@ sigs.k8s.io/yaml
|
||||
yunion.io/x/executor/apis
|
||||
yunion.io/x/executor/client
|
||||
yunion.io/x/executor/server
|
||||
# yunion.io/x/jsonutils v0.0.0-20210709075951-798a67800349
|
||||
# yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a
|
||||
yunion.io/x/jsonutils
|
||||
# yunion.io/x/log v0.0.0-20201210064738-43181789dc74
|
||||
yunion.io/x/log
|
||||
|
||||
+120
-71
@@ -33,13 +33,23 @@ import (
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
)
|
||||
|
||||
func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
if val.Len() == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if val.Kind() == reflect.Slice && val.IsNil() {
|
||||
if !omitEmpty {
|
||||
return JSONNull
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
objs := make([]JSONObject, val.Len())
|
||||
if val.Len() == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
}
|
||||
objs := make([]JSONObject, 0)
|
||||
for i := 0; i < val.Len(); i += 1 {
|
||||
objs[i] = marshalValue(val.Index(i), nil)
|
||||
val := marshalValue(val.Index(i), nil, omitEmpty)
|
||||
if val != nil {
|
||||
objs = append(objs, val)
|
||||
}
|
||||
}
|
||||
arr := NewArray(objs...)
|
||||
if info != nil && info.ForceString {
|
||||
@@ -49,16 +59,23 @@ func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONOb
|
||||
}
|
||||
}
|
||||
|
||||
func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if val.IsNil() {
|
||||
if !omitEmpty {
|
||||
return JSONNull
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
keys := val.MapKeys()
|
||||
if len(keys) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if len(keys) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
}
|
||||
objPairs := make([]JSONPair, 0)
|
||||
for i := 0; i < len(keys); i += 1 {
|
||||
key := keys[i]
|
||||
val := marshalValue(val.MapIndex(key), nil)
|
||||
if val != JSONNull {
|
||||
val := marshalValue(val.MapIndex(key), nil, omitEmpty)
|
||||
if val != nil {
|
||||
objPairs = append(objPairs, JSONPair{key: fmt.Sprintf("%s", key), val: val})
|
||||
}
|
||||
}
|
||||
@@ -70,10 +87,10 @@ func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObje
|
||||
}
|
||||
}
|
||||
|
||||
func marshalStruct(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
objPairs := struct2JSONPairs(val)
|
||||
if len(objPairs) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
func marshalStruct(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
objPairs := struct2JSONPairs(val, omitEmpty)
|
||||
if len(objPairs) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
}
|
||||
dict := NewDict(objPairs...)
|
||||
if info != nil && info.ForceString {
|
||||
@@ -92,7 +109,7 @@ func findValueByKey(pairs []JSONPair, key string) JSONObject {
|
||||
return nil
|
||||
}
|
||||
|
||||
func struct2JSONPairs(val reflect.Value) []JSONPair {
|
||||
func struct2JSONPairs(val reflect.Value, omitEmpty bool) []JSONPair {
|
||||
fields := reflectutils.FetchStructFieldValueSet(val)
|
||||
objPairs := make([]JSONPair, 0, len(fields))
|
||||
depFields := make(map[string]string)
|
||||
@@ -106,8 +123,8 @@ func struct2JSONPairs(val reflect.Value) []JSONPair {
|
||||
depFields[key] = deprecatedBy
|
||||
continue
|
||||
}
|
||||
val := marshalValue(fields[i].Value, jsonInfo)
|
||||
if val != nil && val != JSONNull {
|
||||
val := marshalValue(fields[i].Value, jsonInfo, omitEmpty)
|
||||
if val != nil {
|
||||
objPair := JSONPair{key: key, val: val}
|
||||
objPairs = append(objPairs, objPair)
|
||||
}
|
||||
@@ -140,9 +157,9 @@ func struct2JSONPairs(val reflect.Value) []JSONPair {
|
||||
return objPairs
|
||||
}
|
||||
|
||||
func marshalInt64(val int64, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
if val == 0 && info != nil && info.OmitZero {
|
||||
return JSONNull
|
||||
func marshalInt64(val int64, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if val == 0 && info != nil && info.OmitZero && omitEmpty {
|
||||
return nil
|
||||
} else if info != nil && info.ForceString {
|
||||
return NewString(fmt.Sprintf("%d", val))
|
||||
} else {
|
||||
@@ -150,9 +167,9 @@ func marshalInt64(val int64, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
}
|
||||
}
|
||||
|
||||
func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int) JSONObject {
|
||||
if val == 0.0 && info != nil && info.OmitZero {
|
||||
return JSONNull
|
||||
func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject {
|
||||
if val == 0.0 && info != nil && info.OmitZero && omitEmpty {
|
||||
return nil
|
||||
} else if info != nil && info.ForceString {
|
||||
return NewString(fmt.Sprintf("%f", val))
|
||||
} else {
|
||||
@@ -160,9 +177,9 @@ func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int) J
|
||||
}
|
||||
}
|
||||
|
||||
func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int) JSONObject {
|
||||
if val == 0.0 && info != nil && info.OmitZero {
|
||||
return JSONNull
|
||||
func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject {
|
||||
if val == 0.0 && info != nil && info.OmitZero && omitEmpty {
|
||||
return nil
|
||||
} else if info != nil && info.ForceString {
|
||||
return NewString(fmt.Sprintf("%f", val))
|
||||
} else {
|
||||
@@ -170,9 +187,9 @@ func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int) J
|
||||
}
|
||||
}
|
||||
|
||||
func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
if !val && info != nil && info.OmitFalse {
|
||||
return JSONNull
|
||||
func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if !val && info != nil && info.OmitFalse && omitEmpty {
|
||||
return nil
|
||||
} else if info != nil && info.ForceString {
|
||||
return NewString(fmt.Sprintf("%v", val))
|
||||
} else {
|
||||
@@ -184,28 +201,32 @@ func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
}
|
||||
}
|
||||
|
||||
func marshalTristate(val tristate.TriState, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
func marshalTristate(val tristate.TriState, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if val.IsTrue() {
|
||||
return JSONTrue
|
||||
} else if val.IsFalse() {
|
||||
return JSONFalse
|
||||
} else {
|
||||
return JSONNull
|
||||
if omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return JSONNull
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func marshalString(val string, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
if len(val) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
func marshalString(val string, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if len(val) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return NewString(val)
|
||||
}
|
||||
}
|
||||
|
||||
func marshalTime(val time.Time, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
func marshalTime(val time.Time, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
if val.IsZero() {
|
||||
if info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
}
|
||||
return NewString("")
|
||||
} else {
|
||||
@@ -222,123 +243,151 @@ func Marshal(obj interface{}) JSONObject {
|
||||
return JSONNull
|
||||
}
|
||||
objValue := reflect.Indirect(val)
|
||||
return marshalValue(objValue, nil)
|
||||
mval := marshalValue(objValue, nil, true)
|
||||
if mval == nil {
|
||||
return JSONNull
|
||||
}
|
||||
return mval
|
||||
}
|
||||
|
||||
func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
|
||||
func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
|
||||
switch objValue.Type() {
|
||||
case JSONDictPtrType, JSONArrayPtrType, JSONBoolPtrType, JSONIntPtrType, JSONFloatPtrType, JSONStringPtrType, JSONObjectType:
|
||||
if objValue.IsNil() {
|
||||
return JSONNull
|
||||
if omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return JSONNull
|
||||
}
|
||||
}
|
||||
return objValue.Interface().(JSONObject)
|
||||
case JSONDictType:
|
||||
json, ok := objValue.Interface().(JSONDict)
|
||||
if ok {
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case JSONArrayType:
|
||||
json, ok := objValue.Interface().(JSONArray)
|
||||
if ok {
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case JSONBoolType:
|
||||
json, ok := objValue.Interface().(JSONBool)
|
||||
if ok {
|
||||
if !json.data && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if !json.data && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case JSONIntType:
|
||||
json, ok := objValue.Interface().(JSONInt)
|
||||
if ok {
|
||||
if json.data == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if json.data == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case JSONFloatType:
|
||||
json, ok := objValue.Interface().(JSONFloat)
|
||||
if ok {
|
||||
if json.data == 0.0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if json.data == 0.0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case JSONStringType:
|
||||
json, ok := objValue.Interface().(JSONString)
|
||||
if ok {
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty {
|
||||
return JSONNull
|
||||
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return &json
|
||||
}
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
case tristate.TriStateType:
|
||||
tri, ok := objValue.Interface().(tristate.TriState)
|
||||
if ok {
|
||||
return marshalTristate(tri, info)
|
||||
return marshalTristate(tri, info, omitEmpty)
|
||||
} else {
|
||||
return JSONNull
|
||||
return nil
|
||||
}
|
||||
}
|
||||
switch objValue.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
return marshalSlice(objValue, info)
|
||||
return marshalSlice(objValue, info, omitEmpty)
|
||||
case reflect.Struct:
|
||||
if objValue.Type() == gotypes.TimeType {
|
||||
return marshalTime(objValue.Interface().(time.Time), info)
|
||||
return marshalTime(objValue.Interface().(time.Time), info, omitEmpty)
|
||||
} else {
|
||||
return marshalStruct(objValue, info)
|
||||
return marshalStruct(objValue, info, omitEmpty)
|
||||
}
|
||||
case reflect.Map:
|
||||
return marshalMap(objValue, info)
|
||||
return marshalMap(objValue, info, omitEmpty)
|
||||
case reflect.String:
|
||||
strValue := objValue.Convert(gotypes.StringType)
|
||||
return marshalString(strValue.Interface().(string), info)
|
||||
return marshalString(strValue.Interface().(string), info, omitEmpty)
|
||||
case reflect.Bool:
|
||||
return marshalBoolean(objValue.Interface().(bool), info)
|
||||
return marshalBoolean(objValue.Interface().(bool), info, omitEmpty)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
intValue := objValue.Convert(gotypes.Int64Type)
|
||||
return marshalInt64(intValue.Interface().(int64), info)
|
||||
return marshalInt64(intValue.Interface().(int64), info, omitEmpty)
|
||||
case reflect.Float32:
|
||||
floatVal := objValue.Convert(gotypes.Float32Type)
|
||||
return marshalFloat32(floatVal.Interface().(float32), info, 32)
|
||||
return marshalFloat32(floatVal.Interface().(float32), info, 32, omitEmpty)
|
||||
case reflect.Float64:
|
||||
floatVal := objValue.Convert(gotypes.Float64Type)
|
||||
return marshalFloat64(floatVal.Interface().(float64), info, 64)
|
||||
return marshalFloat64(floatVal.Interface().(float64), info, 64, omitEmpty)
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
if objValue.IsNil() {
|
||||
return JSONNull
|
||||
if omitEmpty {
|
||||
return nil
|
||||
} else {
|
||||
return JSONNull
|
||||
}
|
||||
}
|
||||
return marshalValue(objValue.Elem(), info)
|
||||
return marshalValue(objValue.Elem(), info, omitEmpty)
|
||||
default:
|
||||
log.Errorf("unsupport object %s %s", objValue.Type(), objValue.Interface())
|
||||
return JSONNull
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalAll(obj interface{}) JSONObject {
|
||||
if obj == nil {
|
||||
return JSONNull
|
||||
}
|
||||
val := reflect.ValueOf(obj)
|
||||
if kind := val.Kind(); val.IsZero() && kind == reflect.Ptr {
|
||||
return JSONNull
|
||||
}
|
||||
objValue := reflect.Indirect(val)
|
||||
mval := marshalValue(objValue, nil, false)
|
||||
if mval == nil {
|
||||
return JSONNull
|
||||
}
|
||||
return mval
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user