yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/objectstore/objectstore.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package objectstore 16 17 import ( 18 "net/url" 19 "os" 20 "strings" 21 22 "yunion.io/x/jsonutils" 23 "yunion.io/x/log" 24 "yunion.io/x/pkg/errors" 25 "yunion.io/x/pkg/util/secrules" 26 "yunion.io/x/s3cli" 27 28 api "yunion.io/x/cloudmux/pkg/apis/compute" 29 "yunion.io/x/onecloud/pkg/cloudcommon/object" 30 "yunion.io/x/cloudmux/pkg/cloudprovider" 31 "yunion.io/x/cloudmux/pkg/multicloud" 32 "yunion.io/x/onecloud/pkg/util/httputils" 33 ) 34 35 type ObjectStoreClientConfig struct { 36 cpcfg cloudprovider.ProviderConfig 37 38 endpoint string 39 accessKey string 40 accessSecret string 41 42 debug bool 43 } 44 45 func NewObjectStoreClientConfig(endpoint, accessKey, accessSecret string) *ObjectStoreClientConfig { 46 cfg := &ObjectStoreClientConfig{ 47 endpoint: endpoint, 48 accessKey: accessKey, 49 accessSecret: accessSecret, 50 } 51 return cfg 52 } 53 54 func (cfg *ObjectStoreClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *ObjectStoreClientConfig { 55 cfg.cpcfg = cpcfg 56 return cfg 57 } 58 59 func (cfg *ObjectStoreClientConfig) Debug(debug bool) *ObjectStoreClientConfig { 60 cfg.debug = debug 61 return cfg 62 } 63 64 func (cfg *ObjectStoreClientConfig) GetCloudproviderConfig() cloudprovider.ProviderConfig { 65 return cfg.cpcfg 66 } 67 68 func (cfg *ObjectStoreClientConfig) GetEndpoint() string { 69 return cfg.endpoint 70 } 71 72 func (cfg *ObjectStoreClientConfig) GetAccessKey() string { 73 return cfg.accessKey 74 } 75 76 func (cfg *ObjectStoreClientConfig) GetAccessSecret() string { 77 return cfg.accessSecret 78 } 79 80 func (cfg *ObjectStoreClientConfig) GetDebug() bool { 81 return cfg.debug 82 } 83 84 type SObjectStoreClient struct { 85 object.SObject 86 87 *ObjectStoreClientConfig 88 89 cloudprovider.SFakeOnPremiseRegion 90 multicloud.SRegion 91 92 ownerId string 93 ownerName string 94 95 iBuckets []cloudprovider.ICloudBucket 96 97 client *s3cli.Client 98 } 99 100 func NewObjectStoreClient(cfg *ObjectStoreClientConfig) (*SObjectStoreClient, error) { 101 return NewObjectStoreClientAndFetch(cfg, true) 102 } 103 104 func NewObjectStoreClientAndFetch(cfg *ObjectStoreClientConfig, doFetch bool) (*SObjectStoreClient, error) { 105 client := SObjectStoreClient{ 106 ObjectStoreClientConfig: cfg, 107 } 108 parts, err := url.Parse(cfg.endpoint) 109 if err != nil { 110 return nil, errors.Wrap(err, "url.Parse endpoint") 111 } 112 useSsl := false 113 if parts.Scheme == "https" { 114 useSsl = true 115 } 116 cli, err := s3cli.New( 117 parts.Host, 118 client.accessKey, 119 client.accessSecret, 120 useSsl, 121 client.debug, 122 ) 123 if err != nil { 124 return nil, errors.Wrap(err, "minio.New") 125 } 126 127 tr := httputils.GetTransport(true) 128 tr.Proxy = cfg.cpcfg.ProxyFunc 129 cli.SetCustomTransport(tr) 130 131 client.client = cli 132 client.SetVirtualObject(&client) 133 134 if client.debug { 135 cli.TraceOn(os.Stderr) 136 } 137 138 if doFetch { 139 err = client.FetchBuckets() 140 if err != nil { 141 return nil, errors.Wrap(err, "fetchBuckets") 142 } 143 } 144 145 return &client, nil 146 } 147 148 func (cli *SObjectStoreClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { 149 subAccount := cloudprovider.SSubAccount{ 150 Account: cli.accessKey, 151 Name: cli.cpcfg.Name, 152 HealthStatus: api.CLOUD_PROVIDER_HEALTH_NORMAL, 153 } 154 return []cloudprovider.SSubAccount{subAccount}, nil 155 } 156 157 func (cli *SObjectStoreClient) GetAccountId() string { 158 return cli.ownerId 159 } 160 161 func (cli *SObjectStoreClient) GetIRegion() cloudprovider.ICloudRegion { 162 return cli.GetVirtualObject().(cloudprovider.ICloudRegion) 163 } 164 165 func (cli *SObjectStoreClient) GetIBucketProvider() IBucketProvider { 166 return cli.GetVirtualObject().(IBucketProvider) 167 } 168 169 func (cli *SObjectStoreClient) GetI18n() cloudprovider.SModelI18nTable { 170 table := cloudprovider.SModelI18nTable{} 171 table["name"] = cloudprovider.NewSModelI18nEntry(cli.GetName()).CN(cli.GetName()) 172 return table 173 } 174 175 func (cli *SObjectStoreClient) GetVersion() string { 176 return "" 177 } 178 179 func (cli *SObjectStoreClient) About() jsonutils.JSONObject { 180 about := jsonutils.NewDict() 181 return about 182 } 183 184 func (cli *SObjectStoreClient) GetProvider() string { 185 return api.CLOUD_PROVIDER_GENERICS3 186 } 187 188 func (cli *SObjectStoreClient) GetCloudEnv() string { 189 return "" 190 } 191 192 ////////////////////////////// IBucketProvider ////////////////////////////// 193 194 func (cli *SObjectStoreClient) NewBucket(bucket s3cli.BucketInfo) cloudprovider.ICloudBucket { 195 return &SBucket{ 196 client: cli.GetIBucketProvider(), 197 Name: bucket.Name, 198 CreatedAt: bucket.CreationDate, 199 } 200 } 201 202 func (cli *SObjectStoreClient) GetEndpoint() string { 203 return cli.endpoint 204 } 205 206 func (cli *SObjectStoreClient) S3Client() *s3cli.Client { 207 return cli.client 208 } 209 210 func (cli *SObjectStoreClient) GetClientRC() map[string]string { 211 return map[string]string{ 212 "S3_ACCESS_KEY": cli.accessKey, 213 "S3_SECRET": cli.accessSecret, 214 "S3_ACCESS_URL": cli.endpoint, 215 "S3_BACKEND": api.CLOUD_PROVIDER_GENERICS3, 216 } 217 } 218 219 ///////////////////////////////// fake impletementations ////////////////////// 220 221 func (cli *SObjectStoreClient) GetIZones() ([]cloudprovider.ICloudZone, error) { 222 return nil, cloudprovider.ErrNotSupported 223 } 224 225 func (cli *SObjectStoreClient) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { 226 return nil, cloudprovider.ErrNotSupported 227 } 228 229 func (cli *SObjectStoreClient) GetIEips() ([]cloudprovider.ICloudEIP, error) { 230 return nil, cloudprovider.ErrNotSupported 231 } 232 233 func (cli *SObjectStoreClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { 234 return nil, cloudprovider.ErrNotSupported 235 } 236 237 func (cli *SObjectStoreClient) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { 238 return nil, cloudprovider.ErrNotSupported 239 } 240 241 func (cli *SObjectStoreClient) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { 242 return nil, cloudprovider.ErrNotSupported 243 } 244 245 func (cli *SObjectStoreClient) GetIVMById(id string) (cloudprovider.ICloudVM, error) { 246 return nil, cloudprovider.ErrNotSupported 247 } 248 249 func (cli *SObjectStoreClient) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { 250 return nil, cloudprovider.ErrNotSupported 251 } 252 253 func (cli *SObjectStoreClient) SyncSecurityGroup(secgroupId string, vpcId string, name string, desc string, rules []secrules.SecurityRule) (string, error) { 254 return "", cloudprovider.ErrNotSupported 255 } 256 257 func (cli *SObjectStoreClient) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { 258 return nil, cloudprovider.ErrNotSupported 259 } 260 261 func (cli *SObjectStoreClient) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { 262 return nil, cloudprovider.ErrNotSupported 263 } 264 265 func (cli *SObjectStoreClient) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { 266 return nil, cloudprovider.ErrNotSupported 267 } 268 269 func (cli *SObjectStoreClient) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { 270 return nil, cloudprovider.ErrNotSupported 271 } 272 273 func (cli *SObjectStoreClient) CreateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput) (string, error) { 274 return "", cloudprovider.ErrNotSupported 275 } 276 277 func (cli *SObjectStoreClient) DeleteSnapshotPolicy(string) error { 278 return cloudprovider.ErrNotSupported 279 } 280 281 func (cli *SObjectStoreClient) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { 282 return cloudprovider.ErrNotSupported 283 } 284 285 func (cli *SObjectStoreClient) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { 286 return cloudprovider.ErrNotSupported 287 } 288 289 func (cli *SObjectStoreClient) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { 290 return nil, cloudprovider.ErrNotSupported 291 } 292 293 func (cli *SObjectStoreClient) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { 294 return nil, cloudprovider.ErrNotSupported 295 } 296 297 func (cli *SObjectStoreClient) GetIHosts() ([]cloudprovider.ICloudHost, error) { 298 return nil, cloudprovider.ErrNotSupported 299 } 300 301 func (cli *SObjectStoreClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) { 302 return nil, cloudprovider.ErrNotSupported 303 } 304 305 func (cli *SObjectStoreClient) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 306 return nil, cloudprovider.ErrNotSupported 307 } 308 309 func (cli *SObjectStoreClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 310 return nil, cloudprovider.ErrNotSupported 311 } 312 313 func (cli *SObjectStoreClient) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { 314 return nil, cloudprovider.ErrNotSupported 315 } 316 317 func (cli *SObjectStoreClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { 318 return nil, cloudprovider.ErrNotSupported 319 } 320 321 func (cli *SObjectStoreClient) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { 322 return nil, cloudprovider.ErrNotSupported 323 } 324 325 func (cli *SObjectStoreClient) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { 326 return nil, cloudprovider.ErrNotSupported 327 } 328 329 func (cli *SObjectStoreClient) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { 330 return nil, cloudprovider.ErrNotSupported 331 } 332 333 func (cli *SObjectStoreClient) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { 334 return nil, cloudprovider.ErrNotSupported 335 } 336 337 func (cli *SObjectStoreClient) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { 338 return nil, cloudprovider.ErrNotSupported 339 } 340 341 func (cli *SObjectStoreClient) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { 342 return nil, cloudprovider.ErrNotSupported 343 } 344 345 func (cli *SObjectStoreClient) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { 346 return nil, cloudprovider.ErrNotSupported 347 } 348 349 func (cli *SObjectStoreClient) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { 350 return nil, cloudprovider.ErrNotSupported 351 } 352 353 func (cli *SObjectStoreClient) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { 354 return nil, cloudprovider.ErrNotSupported 355 } 356 357 func (cli *SObjectStoreClient) GetISkus() ([]cloudprovider.ICloudSku, error) { 358 return nil, cloudprovider.ErrNotSupported 359 } 360 361 func (cli *SObjectStoreClient) CreateISku(opts *cloudprovider.SServerSkuCreateOption) (cloudprovider.ICloudSku, error) { 362 return nil, cloudprovider.ErrNotSupported 363 } 364 365 ////////////////////////////////// S3 API /////////////////////////////////// 366 367 func (cli *SObjectStoreClient) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { 368 return cli.getIBuckets() 369 } 370 371 func (self *SObjectStoreClient) invalidateIBuckets() { 372 self.iBuckets = nil 373 } 374 375 func (self *SObjectStoreClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) { 376 if self.iBuckets == nil { 377 err := self.FetchBuckets() 378 if err != nil { 379 return nil, errors.Wrap(err, "fetchBuckets") 380 } 381 } 382 return self.iBuckets, nil 383 } 384 385 func (cli *SObjectStoreClient) FetchBuckets() error { 386 result, err := cli.client.ListBuckets() 387 if err != nil { 388 return errors.Wrap(err, "client.ListBuckets") 389 } 390 cli.ownerId = result.Owner.ID 391 cli.ownerName = result.Owner.DisplayName 392 buckets := result.Buckets.Bucket 393 cli.iBuckets = make([]cloudprovider.ICloudBucket, len(buckets)) 394 for i := range buckets { 395 b := cli.GetIBucketProvider().NewBucket(buckets[i]) 396 cli.iBuckets[i] = b 397 } 398 return nil 399 } 400 401 func (cli *SObjectStoreClient) CreateIBucket(name string, storageClass string, acl string) error { 402 err := cli.client.MakeBucket(name, "") 403 if err != nil { 404 return errors.Wrap(err, "MakeBucket") 405 } 406 cli.invalidateIBuckets() 407 return nil 408 } 409 410 func minioErrCode(err error) int { 411 if srvErr, ok := err.(s3cli.ErrorResponse); ok { 412 return srvErr.StatusCode 413 } 414 if srvErr, ok := err.(*s3cli.ErrorResponse); ok { 415 return srvErr.StatusCode 416 } 417 return -1 418 } 419 420 func (cli *SObjectStoreClient) DeleteIBucket(name string) error { 421 err := cli.client.RemoveBucket(name) 422 if err != nil { 423 if minioErrCode(err) == 404 { 424 return nil 425 } 426 return errors.Wrap(err, "RemoveBucket") 427 } 428 cli.invalidateIBuckets() 429 return nil 430 } 431 432 func (cli *SObjectStoreClient) GetIBucketLocation(name string) (string, error) { 433 info, err := cli.client.GetBucketLocation(name) 434 if err != nil { 435 return "", errors.Wrap(err, "GetBucketLocation") 436 } 437 return info, nil 438 } 439 440 func (cli *SObjectStoreClient) GetIBucketWebsite(name string) (string, error) { 441 info, err := cli.client.GetBucketWebsite(name) 442 if err != nil { 443 return "", errors.Wrap(err, "GetBucketWebsite") 444 } 445 return info, nil 446 } 447 448 func (cli *SObjectStoreClient) GetIBucketReferer(name string) (string, error) { 449 info, err := cli.client.GetBucketReferer(name) 450 if err != nil { 451 return "", errors.Wrap(err, "GetBucketReferer") 452 } 453 return info, nil 454 } 455 456 func (cli *SObjectStoreClient) GetIBucketCors(name string) (string, error) { 457 info, err := cli.client.GetBucketCors(name) 458 if err != nil { 459 return "", errors.Wrap(err, "GetBucketCors") 460 } 461 return info, nil 462 } 463 464 func (cli *SObjectStoreClient) GetIBucketLogging(name string) (*s3cli.BucketLoggingStatus, error) { 465 info, err := cli.client.GetBucketLogging(name) 466 if err != nil { 467 return nil, errors.Wrap(err, "GetBucketLogging") 468 } 469 return info, nil 470 } 471 472 func (cli *SObjectStoreClient) SetIBucketLogging(name string, target string, targetPrefix string, email string) error { 473 conf := s3cli.BucketLoggingStatus{} 474 if len(target) > 0 { 475 conf.LoggingEnabled.TargetBucket = target 476 conf.LoggingEnabled.TargetPrefix = targetPrefix 477 conf.LoggingEnabled.TargetGrants.Grant = []s3cli.Grant{ 478 { 479 Grantee: s3cli.Grantee{ 480 Type: s3cli.GRANTEE_TYPE_EMAIL, 481 EmailAddress: email, 482 }, 483 Permission: s3cli.PERMISSION_FULL_CONTROL, 484 }, 485 } 486 } 487 err := cli.client.SetBucketLogging(name, conf) 488 if err != nil { 489 return errors.Wrap(err, "SetBucketLogging") 490 } 491 return nil 492 } 493 494 func (cli *SObjectStoreClient) GetIBucketInfo(name string) (string, error) { 495 info, err := cli.client.GetBucketInfo(name) 496 if err != nil { 497 return "", errors.Wrap(err, "GetBucketInfo") 498 } 499 return info, nil 500 } 501 502 func (cli *SObjectStoreClient) GetIBucketAcl(name string) (cloudprovider.TBucketACLType, error) { 503 acl, err := cli.client.GetBucketAcl(name) 504 if err != nil { 505 return "", errors.Wrap(err, "GetBucketAcl") 506 } 507 return cloudprovider.TBucketACLType(acl.GetCannedACL()), nil 508 } 509 510 func (cli *SObjectStoreClient) SetIBucketAcl(name string, cannedAcl cloudprovider.TBucketACLType) error { 511 acl := s3cli.CannedAcl(cli.ownerId, cli.ownerName, string(cannedAcl)) 512 err := cli.client.SetBucketAcl(name, acl) 513 if err != nil { 514 if strings.Contains(err.Error(), "not implemented") { 515 // ignore not implemented error 516 return nil // cloudprovider.ErrNotImplemented 517 } else { 518 return errors.Wrap(err, "SetBucketAcl") 519 } 520 } 521 return nil 522 } 523 524 func (cli *SObjectStoreClient) GetObjectAcl(bucket, key string) (cloudprovider.TBucketACLType, error) { 525 acl, err := cli.client.GetObjectACL(bucket, key) 526 if err != nil { 527 return "", errors.Wrap(err, "GetBucketAcl") 528 } 529 return cloudprovider.TBucketACLType(acl.GetCannedACL()), nil 530 } 531 532 func (cli *SObjectStoreClient) SetObjectAcl(bucket, key string, cannedAcl cloudprovider.TBucketACLType) error { 533 acl := s3cli.CannedAcl(cli.ownerId, cli.ownerName, string(cannedAcl)) 534 err := cli.client.SetObjectAcl(bucket, key, acl) 535 if err != nil { 536 return errors.Wrap(err, "SetObjectAcl") 537 } 538 return nil 539 } 540 541 func (cli *SObjectStoreClient) GetIBucketPolicy(name string) (string, error) { 542 policy, err := cli.client.GetBucketPolicy(name) 543 if err != nil { 544 return "", errors.Wrap(err, "GetBucketPolicy") 545 } 546 return policy, nil 547 } 548 549 func (cli *SObjectStoreClient) SetIBucketPolicy(name string, policy string) error { 550 err := cli.client.SetBucketPolicy(name, policy) 551 if err != nil { 552 return errors.Wrap(err, "SetBucketPolicy") 553 } 554 return nil 555 } 556 557 func (cli *SObjectStoreClient) GetIBucketLiftcycle(name string) (string, error) { 558 liftcycle, err := cli.client.GetBucketLifecycle(name) 559 if err != nil { 560 return "", errors.Wrap(err, "GetBucketLifecycle") 561 } 562 return liftcycle, nil 563 } 564 565 func (cli *SObjectStoreClient) IBucketExist(name string) (bool, error) { 566 exist, header, err := cli.client.BucketExists(name) 567 if err != nil { 568 return false, errors.Wrap(err, "BucketExists") 569 } 570 if header != nil { 571 log.Debugf("header: %s", jsonutils.Marshal(header)) 572 } 573 return exist, nil 574 } 575 576 func (cli *SObjectStoreClient) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { 577 return cloudprovider.GetIBucketById(cli, name) 578 } 579 580 func (cli *SObjectStoreClient) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { 581 return cli.GetIBucketById(name) 582 } 583 584 func (self *SObjectStoreClient) GetCapabilities() []string { 585 caps := []string{ 586 // cloudprovider.CLOUD_CAPABILITY_PROJECT, 587 // cloudprovider.CLOUD_CAPABILITY_COMPUTE, 588 // cloudprovider.CLOUD_CAPABILITY_NETWORK, 589 // cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, 590 cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, 591 // cloudprovider.CLOUD_CAPABILITY_RDS, 592 // cloudprovider.CLOUD_CAPABILITY_CACHE, 593 // cloudprovider.CLOUD_CAPABILITY_EVENT, 594 } 595 return caps 596 }