From 17175bc0a4d2b6748479696264316d0eed67546d Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 11 Oct 2018 23:01:06 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E6=94=B9=E8=BF=9B=EF=BC=9A1.=20=E9=83=A8?= =?UTF-8?q?=E7=BD=B2VM=E6=97=B6=E6=B3=A8=E5=85=A5=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E5=92=8C=E9=A1=B9=E7=9B=AE=E5=85=AC=E9=92=A5=202.=20=E5=AE=8C?= =?UTF-8?q?=E5=96=84keypair=E7=9A=84=E5=88=9B=E5=BB=BA=E5=92=8C=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=8A=9F=E8=83=BD=203.=20=E5=85=B6=E4=BB=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/servers.go | 42 ++++- pkg/cloudcommon/db/fetch.go | 14 +- pkg/cloudcommon/db/interface.go | 6 +- pkg/cloudcommon/db/modelbase.go | 6 +- pkg/cloudcommon/db/standalone.go | 10 +- pkg/cloudcommon/db/tenantcache.go | 4 +- pkg/cloudcommon/db/usercache.go | 4 +- pkg/cloudcommon/db/virtualjointbase.go | 2 +- pkg/cloudcommon/db/virtualresource.go | 10 +- pkg/cloudcommon/validators/validators.go | 15 +- pkg/cloudprovider/resources.go | 2 +- pkg/compute/guestdrivers/aliyun.go | 31 +++- pkg/compute/guestdrivers/azure.go | 32 +++- pkg/compute/models/cloudproviders.go | 8 +- pkg/compute/models/disks.go | 2 +- pkg/compute/models/elasticips.go | 10 +- pkg/compute/models/guests.go | 108 ++++++++++--- pkg/compute/models/hosts.go | 8 +- pkg/compute/models/isolated_devices.go | 2 +- pkg/compute/models/keypairs.go | 85 +++++++++- pkg/compute/models/networks.go | 16 +- pkg/compute/models/reservedips.go | 2 +- pkg/compute/models/schedtags.go | 2 +- pkg/compute/models/secgrouprules.go | 4 +- pkg/compute/models/sshkeypairs.go | 44 +++++ pkg/compute/models/storages.go | 2 +- pkg/compute/models/wires.go | 6 +- pkg/compute/models/zones.go | 2 +- pkg/compute/usages/handler.go | 2 +- pkg/mcclient/modules/mod_servers.go | 42 +++-- pkg/mcclient/options/servers.go | 6 + pkg/mcclient/token.go | 11 +- pkg/util/aliyun/host.go | 9 +- pkg/util/aliyun/instance.go | 7 +- pkg/util/aliyun/region.go | 2 +- pkg/util/azure/host.go | 10 +- pkg/util/azure/region.go | 2 +- pkg/util/cloudinit/cloudconfig.go | 198 +++++++++++++++++++++++ pkg/util/cloudinit/cloudconfig_test.go | 46 ++++++ pkg/util/esxi/host.go | 2 +- pkg/util/seclib2/aes.go | 108 +++++++++++++ pkg/util/seclib2/aes_test.go | 24 +++ pkg/util/seclib2/crypto.go | 118 ++++++++++++++ pkg/util/seclib2/ssh.go | 97 +++++++++++ pkg/util/seclib2/ssh_test.go | 153 ++++++++++++++++++ 45 files changed, 1194 insertions(+), 122 deletions(-) create mode 100644 pkg/compute/models/sshkeypairs.go create mode 100644 pkg/util/cloudinit/cloudconfig.go create mode 100644 pkg/util/cloudinit/cloudconfig_test.go create mode 100644 pkg/util/seclib2/aes.go create mode 100644 pkg/util/seclib2/aes_test.go create mode 100644 pkg/util/seclib2/crypto.go create mode 100644 pkg/util/seclib2/ssh.go create mode 100644 pkg/util/seclib2/ssh_test.go diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index d6957bfb8e..856edd1d75 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/options" + "io/ioutil" ) func init() { @@ -59,6 +60,14 @@ func init() { params.Add(jsonutils.JSONFalse, "reset_password") } + if len(opts.UserDataFile) > 0 { + userdata, err := ioutil.ReadFile(opts.UserDataFile) + if err != nil { + return err + } + params.Add(jsonutils.NewString(string(userdata)), "user_data") + } + count := options.IntV(opts.Count) if options.BoolV(opts.DryRun) { results, err := modules.SchedManager.DoScheduleListResult(s, params, count) @@ -88,12 +97,22 @@ func init() { return nil }) - R(&options.ServerIdOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, opts *options.ServerIdOptions) error { + R(&options.ServerLoginInfoOptions{}, "server-logininfo", "Get login info of a server", func(s *mcclient.ClientSession, opts *options.ServerLoginInfoOptions) error { srvid, e := modules.Servers.GetId(s, opts.ID, nil) if e != nil { return e } - i, e := modules.Servers.GetLoginInfo(s, srvid, nil) + var params *jsonutils.JSONDict + if len(opts.Key) > 0 { + privateKey, e := ioutil.ReadFile(opts.Key) + if e != nil { + return e + } + params = jsonutils.NewDict() + params.Add(jsonutils.NewString(string(privateKey)), "private_key") + } + + i, e := modules.Servers.GetLoginInfo(s, srvid, params) if e != nil { return e } @@ -467,4 +486,23 @@ func init() { printObject(result) return nil }) + + type ServerUserDataOptions struct { + ID string `help:"ID or name of server"` + FILE string `help:"Path to user data file"` + } + R(&ServerUserDataOptions{}, "server-set-user-data", "Update server user_data", func(s *mcclient.ClientSession, args *ServerUserDataOptions) error { + params := jsonutils.NewDict() + content, err := ioutil.ReadFile(args.FILE) + if err != nil { + return err + } + params.Add(jsonutils.NewString(string(content)), "user_data") + result, err := modules.Servers.PerformAction(s, args.ID, "user-data", params) + if err != nil { + return err + } + printObject(result) + return nil + }) } diff --git a/pkg/cloudcommon/db/fetch.go b/pkg/cloudcommon/db/fetch.go index 0297e57216..7168d07723 100644 --- a/pkg/cloudcommon/db/fetch.go +++ b/pkg/cloudcommon/db/fetch.go @@ -9,7 +9,7 @@ import ( "yunion.io/x/sqlchemy" ) -func fetchById(manager IModelManager, idStr string) (IModel, error) { +func FetchById(manager IModelManager, idStr string) (IModel, error) { q := manager.Query() q = manager.FilterById(q, idStr) count := q.Count() @@ -31,7 +31,11 @@ func fetchById(manager IModelManager, idStr string) (IModel, error) { } } -func fetchByName(manager IModelManager, owner string, idStr string) (IModel, error) { +func FetchByName(manager IModelManager, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + var owner string + if userCred != nil { + owner = manager.GetOwnerId(userCred) + } q := manager.Query() q = manager.FilterByName(q, idStr) q = manager.FilterByOwner(q, owner) @@ -54,10 +58,10 @@ func fetchByName(manager IModelManager, owner string, idStr string) (IModel, err } } -func fetchByIdOrName(manager IModelManager, ownerProjId string, idStr string) (IModel, error) { - obj, err := fetchById(manager, idStr) +func FetchByIdOrName(manager IModelManager, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + obj, err := FetchById(manager, idStr) if err == sql.ErrNoRows { - return fetchByName(manager, ownerProjId, idStr) + return FetchByName(manager, userCred, idStr) } else { return obj, err } diff --git a/pkg/cloudcommon/db/interface.go b/pkg/cloudcommon/db/interface.go index 4b0a7a3ac5..202bfc4a26 100644 --- a/pkg/cloudcommon/db/interface.go +++ b/pkg/cloudcommon/db/interface.go @@ -39,12 +39,12 @@ type IModelManager interface { FilterByName(q *sqlchemy.SQuery, name string) *sqlchemy.SQuery FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery - GetOwnerId(userCred mcclient.TokenCredential) string + GetOwnerId(userCred mcclient.IIdentityProvider) string // RawFetchById(idStr string) (IModel, error) FetchById(idStr string) (IModel, error) - FetchByName(ownerProjId string, idStr string) (IModel, error) - FetchByIdOrName(ownerProjId string, idStr string) (IModel, error) + FetchByName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) + FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) // create hooks AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool diff --git a/pkg/cloudcommon/db/modelbase.go b/pkg/cloudcommon/db/modelbase.go index 4e17ff01e9..b06106bccb 100644 --- a/pkg/cloudcommon/db/modelbase.go +++ b/pkg/cloudcommon/db/modelbase.go @@ -108,7 +108,7 @@ func (manager *SModelBaseManager) FilterByOwner(q *sqlchemy.SQuery, owner string return q } -func (manager *SModelBaseManager) GetOwnerId(userCred mcclient.TokenCredential) string { +func (manager *SModelBaseManager) GetOwnerId(userCred mcclient.IIdentityProvider) string { return "" } @@ -116,11 +116,11 @@ func (manager *SModelBaseManager) FetchById(idStr string) (IModel, error) { return nil, sql.ErrNoRows } -func (manager *SModelBaseManager) FetchByName(ownerProjId string, idStr string) (IModel, error) { +func (manager *SModelBaseManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { return nil, sql.ErrNoRows } -func (manager *SModelBaseManager) FetchByIdOrName(ownerProjId string, idStr string) (IModel, error) { +func (manager *SModelBaseManager) FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { return nil, sql.ErrNoRows } diff --git a/pkg/cloudcommon/db/standalone.go b/pkg/cloudcommon/db/standalone.go index 3a0137b525..edd00fe58b 100644 --- a/pkg/cloudcommon/db/standalone.go +++ b/pkg/cloudcommon/db/standalone.go @@ -70,15 +70,15 @@ func (manager *SStandaloneResourceBaseManager) ValidateName(name string) error { } func (manager *SStandaloneResourceBaseManager) FetchById(idStr string) (IModel, error) { - return fetchById(manager, idStr) + return FetchById(manager, idStr) } -func (manager *SStandaloneResourceBaseManager) FetchByName(ownerProjId string, idStr string) (IModel, error) { - return fetchByName(manager, ownerProjId, idStr) +func (manager *SStandaloneResourceBaseManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + return FetchByName(manager, userCred, idStr) } -func (manager *SStandaloneResourceBaseManager) FetchByIdOrName(ownerProjId string, idStr string) (IModel, error) { - return fetchByIdOrName(manager, ownerProjId, idStr) +func (manager *SStandaloneResourceBaseManager) FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + return FetchByIdOrName(manager, userCred, idStr) } func (manager *SStandaloneResourceBaseManager) FetchByExternalId(idStr string) (IStandaloneModel, error) { diff --git a/pkg/cloudcommon/db/tenantcache.go b/pkg/cloudcommon/db/tenantcache.go index 9fdf0866ea..bb756a7b63 100644 --- a/pkg/cloudcommon/db/tenantcache.go +++ b/pkg/cloudcommon/db/tenantcache.go @@ -35,7 +35,7 @@ func init() { } func (manager *STenantCacheManager) FetchTenantByIdOrName(ctx context.Context, idStr string) (*STenant, error) { - tenant, err := manager.FetchByIdOrName("", idStr) + tenant, err := manager.FetchByIdOrName(nil, idStr) if err != nil { if err == sql.ErrNoRows { return manager.fetchTenantFromKeystone(ctx, idStr) @@ -63,7 +63,7 @@ func (manager *STenantCacheManager) FetchTenantById(ctx context.Context, idStr s } func (manager *STenantCacheManager) FetchTenantByName(ctx context.Context, idStr string) (*STenant, error) { - tenant, err := manager.FetchByName("", idStr) + tenant, err := manager.FetchByName(nil, idStr) if err != nil { if err == sql.ErrNoRows { return manager.fetchTenantFromKeystone(ctx, idStr) diff --git a/pkg/cloudcommon/db/usercache.go b/pkg/cloudcommon/db/usercache.go index 917b5c8754..1fe3f560c5 100644 --- a/pkg/cloudcommon/db/usercache.go +++ b/pkg/cloudcommon/db/usercache.go @@ -29,7 +29,7 @@ func init() { } func (manager *SUserCacheManager) FetchUserByIdOrName(idStr string) (*SUser, error) { - obj, err := manager.SKeystoneCacheObjectManager.FetchByIdOrName("", idStr) + obj, err := manager.SKeystoneCacheObjectManager.FetchByIdOrName(nil, idStr) if err != nil { return nil, err } @@ -45,7 +45,7 @@ func (manager *SUserCacheManager) FetchUserById(idStr string) (*SUser, error) { } func (manager *SUserCacheManager) FetchUserByName(idStr string) (*SUser, error) { - obj, err := manager.SKeystoneCacheObjectManager.FetchByName("", idStr) + obj, err := manager.SKeystoneCacheObjectManager.FetchByName(nil, idStr) if err != nil { return nil, err } diff --git a/pkg/cloudcommon/db/virtualjointbase.go b/pkg/cloudcommon/db/virtualjointbase.go index 63e10c4c69..23565cc777 100644 --- a/pkg/cloudcommon/db/virtualjointbase.go +++ b/pkg/cloudcommon/db/virtualjointbase.go @@ -110,7 +110,7 @@ func (manager *SVirtualJointResourceBaseManager) ListItemFilter(ctx context.Cont } tenant, _ := query.GetString("tenant") if len(tenant) > 0 { - tc, _ := TenantCacheManager.FetchByIdOrName("", tenant) + tc, _ := TenantCacheManager.FetchTenantByIdOrName(ctx, tenant) if tc == nil { return nil, httperrors.NewTenantNotFoundError(fmt.Sprintf("tenant %s not found", tenant)) } diff --git a/pkg/cloudcommon/db/virtualresource.go b/pkg/cloudcommon/db/virtualresource.go index 6bf85de87f..16a9b44572 100644 --- a/pkg/cloudcommon/db/virtualresource.go +++ b/pkg/cloudcommon/db/virtualresource.go @@ -56,15 +56,15 @@ func (manager *SVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQuery, ow return q } -func (manager *SVirtualResourceBaseManager) FetchByName(ownerProjId string, idStr string) (IModel, error) { - return fetchByName(manager, ownerProjId, idStr) +func (manager *SVirtualResourceBaseManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + return FetchByName(manager, userCred, idStr) } -func (manager *SVirtualResourceBaseManager) FetchByIdOrName(ownerProjId string, idStr string) (IModel, error) { - return fetchByIdOrName(manager, ownerProjId, idStr) +func (manager *SVirtualResourceBaseManager) FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (IModel, error) { + return FetchByIdOrName(manager, userCred, idStr) } -func (manager *SVirtualResourceBaseManager) GetOwnerId(userCred mcclient.TokenCredential) string { +func (manager *SVirtualResourceBaseManager) GetOwnerId(userCred mcclient.IIdentityProvider) string { return userCred.GetProjectId() } diff --git a/pkg/cloudcommon/validators/validators.go b/pkg/cloudcommon/validators/validators.go index 163f04a549..a612b150ed 100644 --- a/pkg/cloudcommon/validators/validators.go +++ b/pkg/cloudcommon/validators/validators.go @@ -322,11 +322,24 @@ type ValidatorModelIdOrName struct { Validator ModelKeyword string ProjectId string + UserId string ModelManager db.IModelManager Model db.IModel modelIdKey string } +func (v *ValidatorModelIdOrName) GetProjectId() string { + return v.ProjectId +} + +func (v *ValidatorModelIdOrName) GetUserId() string { + return v.UserId +} + +func (v *ValidatorModelIdOrName) GetTenantId() string { + return v.ProjectId +} + func (v *ValidatorModelIdOrName) getValue() interface{} { return v.Model } @@ -361,7 +374,7 @@ func (v *ValidatorModelIdOrName) validate(data *jsonutils.JSONDict) error { return newModelManagerError(v.ModelKeyword) } v.ModelManager = modelManager - model, err := modelManager.FetchByIdOrName(v.ProjectId, modelIdOrName) + model, err := modelManager.FetchByIdOrName(v, modelIdOrName) if err != nil { return newModelNotFoundError(v.ModelKeyword, modelIdOrName, err) } diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index f93abdc326..9d88e68e17 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -135,7 +135,7 @@ type ICloudHost interface { GetManagerId() string CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string, - passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string) (ICloudVM, error) + passwd string, storageType string, diskSizes []int, publicKey string, extSecGrpId string, userData string) (ICloudVM, error) } type ICloudVM interface { diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index d081599979..890039b006 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -16,6 +16,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/onecloud/pkg/util/cloudinit" ) type SAliyunGuestDriver struct { @@ -139,6 +140,34 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu publicKey, _ := config.GetString("public_key") + adminPublicKey, _ := config.GetString("admin_public_key") + projectPublicKey, _ := config.GetString("project_public_key") + + var oCloudConfig *cloudinit.SCloudConfig + + oUserData, _ := config.GetString("user_data") + if len(oUserData) > 0 { + oCloudConfig, _ = cloudinit.ParseUserDataBase64(oUserData) + } + + cloudConfig := cloudinit.SCloudConfig{ + Users: []cloudinit.SUser { + { + Name: "root", + SshAuthorizedKeys: []string { + adminPublicKey, + projectPublicKey, + }, + }, + }, + } + + if oCloudConfig != nil { + cloudConfig.Merge(oCloudConfig) + } + + userData := cloudConfig.UserDataBase64() + resetPassword := jsonutils.QueryBoolean(config, "reset_password", false) passwd, _ := config.GetString("password") if resetPassword && len(passwd) == 0 { @@ -176,7 +205,7 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu } iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId) + desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData) if err != nil { return nil, err } diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 90cfe6d6ba..28bc67a032 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -14,6 +14,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/cloudinit" ) type SAzureGuestDriver struct { @@ -70,6 +71,35 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue if resetPassword && len(passwd) == 0 { passwd = seclib2.RandomPassword2(12) } + + adminPublicKey, _ := config.GetString("admin_public_key") + projectPublicKey, _ := config.GetString("project_public_key") + + var oCloudConfig *cloudinit.SCloudConfig + + oUserData, _ := config.GetString("user_data") + if len(oUserData) > 0 { + oCloudConfig, _ = cloudinit.ParseUserDataBase64(oUserData) + } + + cloudConfig := cloudinit.SCloudConfig{ + Users: []cloudinit.SUser { + { + Name: "root", + SshAuthorizedKeys: []string { + adminPublicKey, + projectPublicKey, + }, + }, + }, + } + + if oCloudConfig != nil { + cloudConfig.Merge(oCloudConfig) + } + + userData := cloudConfig.UserDataBase64() + desc := SManagedVMCreateConfig{} if err := config.Unmarshal(&desc, "desc"); err != nil { return err @@ -98,7 +128,7 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue } if iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId); err != nil { + desc.IpAddr, desc.Description, passwd, desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData); err != nil { return nil, err } else { log.Debugf("VMcreated %s, wait status running ...", iVM.GetGlobalId()) diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 31afc0984f..78bdcc43b5 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -197,7 +197,7 @@ func (sr *SSyncRange) NeedSyncInfo() bool { func (sr *SSyncRange) normalizeRegionIds() error { for i := 0; i < len(sr.Region); i += 1 { - obj, err := CloudregionManager.FetchByIdOrName("", sr.Region[i]) + obj, err := CloudregionManager.FetchByIdOrName(nil, sr.Region[i]) if err != nil { if err == sql.ErrNoRows { return httperrors.NewResourceNotFoundError("Region %s not found", sr.Region[i]) @@ -212,7 +212,7 @@ func (sr *SSyncRange) normalizeRegionIds() error { func (sr *SSyncRange) normalizeZoneIds() error { for i := 0; i < len(sr.Zone); i += 1 { - obj, err := ZoneManager.FetchByIdOrName("", sr.Zone[i]) + obj, err := ZoneManager.FetchByIdOrName(nil, sr.Zone[i]) if err != nil { if err == sql.ErrNoRows { return httperrors.NewResourceNotFoundError("Zone %s not found", sr.Zone[i]) @@ -227,7 +227,7 @@ func (sr *SSyncRange) normalizeZoneIds() error { func (sr *SSyncRange) normalizeHostIds() error { for i := 0; i < len(sr.Host); i += 1 { - obj, err := HostManager.FetchByIdOrName("", sr.Host[i]) + obj, err := HostManager.FetchByIdOrName(nil, sr.Host[i]) if err != nil { if err == sql.ErrNoRows { return httperrors.NewResourceNotFoundError("Host %s not found", sr.Host[i]) @@ -408,7 +408,7 @@ func (manager *SCloudproviderManager) FetchCloudproviderById(providerId string) } func (manager *SCloudproviderManager) FetchCloudproviderByIdOrName(providerId string) *SCloudprovider { - providerObj, err := manager.FetchByIdOrName("", providerId) + providerObj, err := manager.FetchByIdOrName(nil, providerId) if err != nil { if err != sql.ErrNoRows { log.Errorf("%s", err) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 5cc92da4f2..3bc15f0ecd 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -155,7 +155,7 @@ func (manager *SDiskManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu storageStr := jsonutils.GetAnyString(queryDict, []string{"storage", "storage_id"}) if len(storageStr) > 0 { - storageObj, err := StorageManager.FetchByIdOrName(userCred.GetProjectId(), storageStr) + storageObj, err := StorageManager.FetchByIdOrName(userCred, storageStr) if err != nil { return nil, httperrors.NewResourceNotFoundError("storage %s not found: %s", storageStr, err) } diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index 5c5ad97792..c6a4a6d6e7 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -84,7 +84,7 @@ func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchem managerFilter, _ := query.GetString("manager") if len(managerFilter) > 0 { - managerI, err := CloudproviderManager.FetchByIdOrName(userCred.GetProjectId(), managerFilter) + managerI, err := CloudproviderManager.FetchByIdOrName(userCred, managerFilter) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("cloud provider %s not found", managerFilter) @@ -97,7 +97,7 @@ func (manager *SElasticipManager) ListItemFilter(ctx context.Context, q *sqlchem regionFilter, _ := query.GetString("region") if len(regionFilter) > 0 { - regionObj, err := CloudregionManager.FetchByIdOrName(userCred.GetProjectId(), regionFilter) + regionObj, err := CloudregionManager.FetchByIdOrName(userCred, regionFilter) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("cloud region %s not found", regionFilter) @@ -362,7 +362,7 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr if len(regionStr) == 0 { return nil, httperrors.NewInputParameterError("Missing region/region_id") } - region, err := CloudregionManager.FetchByIdOrName("", regionStr) + region, err := CloudregionManager.FetchByIdOrName(nil, regionStr) if err != nil { if err != sql.ErrNoRows { return nil, httperrors.NewGeneralError(err) @@ -377,7 +377,7 @@ func (manager *SElasticipManager) ValidateCreateData(ctx context.Context, userCr return nil, httperrors.NewInputParameterError("Missing manager/manager_id") } - provider, err := CloudproviderManager.FetchByIdOrName("", managerStr) + provider, err := CloudproviderManager.FetchByIdOrName(nil, managerStr) if err != nil { if err != sql.ErrNoRows { return nil, httperrors.NewGeneralError(err) @@ -490,7 +490,7 @@ func (self *SElasticip) PerformAssociate(ctx context.Context, userCred mcclient. return nil, httperrors.NewInputParameterError("Unsupported %s", instanceType) } - vmObj, err := GuestManager.FetchByIdOrName(userCred.GetProjectId(), instanceId) + vmObj, err := GuestManager.FetchByIdOrName(userCred, instanceId) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("server %s not found", instanceId) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7d53b31407..208396d5b4 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -37,6 +37,7 @@ import ( "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/seclib2" + "encoding/base64" ) const ( @@ -222,7 +223,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ hostFilter, _ := queryDict.GetString("host") if len(hostFilter) > 0 { - host, _ := HostManager.FetchByIdOrName("", hostFilter) + host, _ := HostManager.FetchByIdOrName(nil, hostFilter) if host == nil { return nil, httperrors.NewResourceNotFoundError("host %s not found", hostFilter) } @@ -231,7 +232,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ secgrpFilter, _ := queryDict.GetString("secgroup") if len(secgrpFilter) > 0 { - secgrp, _ := SecurityGroupManager.FetchByIdOrName("", secgrpFilter) + secgrp, _ := SecurityGroupManager.FetchByIdOrName(nil, secgrpFilter) if secgrp == nil { return nil, httperrors.NewResourceNotFoundError("secgroup %s not found", secgrpFilter) } @@ -240,7 +241,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ zoneFilter, _ := queryDict.GetString("zone") if len(zoneFilter) > 0 { - zone, _ := ZoneManager.FetchByIdOrName("", zoneFilter) + zone, _ := ZoneManager.FetchByIdOrName(nil, zoneFilter) if zone == nil { return nil, httperrors.NewResourceNotFoundError("zone %s not found", zoneFilter) } @@ -253,7 +254,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ wireFilter, _ := queryDict.GetString("wire") if len(wireFilter) > 0 { - wire, _ := WireManager.FetchByIdOrName("", wireFilter) + wire, _ := WireManager.FetchByIdOrName(nil, wireFilter) if wire == nil { return nil, httperrors.NewResourceNotFoundError("wire %s not found", wireFilter) } @@ -265,7 +266,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ networkFilter, _ := queryDict.GetString("network") if len(networkFilter) > 0 { - netI, _ := NetworkManager.FetchByIdOrName(userCred.GetProjectId(), networkFilter) + netI, _ := NetworkManager.FetchByIdOrName(userCred, networkFilter) if netI == nil { return nil, httperrors.NewResourceNotFoundError("network %s not found", networkFilter) } @@ -279,7 +280,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ diskFilter, _ := queryDict.GetString("disk") if len(diskFilter) > 0 { - diskI, _ := DiskManager.FetchByIdOrName(userCred.GetProjectId(), diskFilter) + diskI, _ := DiskManager.FetchByIdOrName(userCred, diskFilter) if diskI == nil { return nil, httperrors.NewResourceNotFoundError("disk %s not found", diskFilter) } @@ -312,7 +313,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ managerFilter, _ := queryDict.GetString("manager") if len(managerFilter) > 0 { - managerI, _ := CloudproviderManager.FetchByIdOrName(userCred.GetProjectId(), managerFilter) + managerI, _ := CloudproviderManager.FetchByIdOrName(userCred, managerFilter) if managerI == nil { return nil, httperrors.NewResourceNotFoundError("cloud provider %s not found", managerFilter) } @@ -323,7 +324,7 @@ func (manager *SGuestManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQ regionFilter, _ := queryDict.GetString("region") if len(regionFilter) > 0 { - regionObj, err := CloudregionManager.FetchByIdOrName(userCred.GetProjectId(), regionFilter) + regionObj, err := CloudregionManager.FetchByIdOrName(userCred, regionFilter) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("cloud region %s not found", regionFilter) @@ -640,7 +641,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m if len(bmName) == 0 { bmName, _ = data.GetString("prefer_baremetal") } - bmObj, err := HostManager.FetchByIdOrName("", bmName) + bmObj, err := HostManager.FetchByIdOrName(nil, bmName) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("Host %s not found", bmName) @@ -804,7 +805,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m keypairId, _ = data.GetString("keypair_id") } if len(keypairId) > 0 { - keypairObj, err := KeypairManager.FetchByIdOrName(userCred.GetUserId(), keypairId) + keypairObj, err := KeypairManager.FetchByIdOrName(userCred, keypairId) if err != nil { return nil, httperrors.NewResourceNotFoundError("Keypair %s not found", keypairId) } @@ -815,7 +816,7 @@ func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred m if data.Contains("secgroup") { secGrpId, _ := data.GetString("secgroup") - secGrpObj, err := SecurityGroupManager.FetchByIdOrName(userCred.GetProjectId(), secGrpId) + secGrpObj, err := SecurityGroupManager.FetchByIdOrName(userCred, secGrpId) if err != nil { return nil, httperrors.NewResourceNotFoundError("Secgroup %s not found", secGrpId) } @@ -937,6 +938,11 @@ func (guest *SGuest) PostCreate(ctx context.Context, userCred mcclient.TokenCred if osProfileJson != nil { guest.setOSProfile(ctx, userCred, osProfileJson) } + + userData, _ := data.GetString("user_data") + if len(userData) > 0 { + guest.setUserData(ctx, userCred, userData) + } } func (guest *SGuest) setApptags(ctx context.Context, appTags []string, userCred mcclient.TokenCredential) { @@ -1764,9 +1770,10 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr if kwargs.Contains("__delete_keypair__") || kwargs.Contains("keypair") { doRestart = true var kpId string - if !jsonutils.QueryBoolean(kwargs, "__delete_keypair__", false) { + + if kwargs.Contains("keypair") { keypair, _ := kwargs.GetString("keypair") - iKp, err := KeypairManager.FetchByIdOrName(userCred.GetProjectId(), keypair) + iKp, err := KeypairManager.FetchByIdOrName(userCred, keypair) if err != nil { return nil, err } @@ -1776,11 +1783,18 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr kp := iKp.(*SKeypair) kpId = kp.Id } + if self.KeypairId != kpId { + okey := self.getKeypair() + if okey != nil { + kwargs.Set("delete_public_key", jsonutils.NewString(okey.PublicKey)) + } + self.GetModelManager().TableSpec().Update(self, func() error { self.KeypairId = kpId return nil }) + kwargs.Set("reset_password", jsonutils.JSONTrue) } } @@ -1795,6 +1809,7 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr } return nil, nil } + return nil, httperrors.NewServerStatusError("Cannot deploy in status %s", self.Status) } @@ -1830,7 +1845,7 @@ func (self *SGuest) PerformAttachdisk(ctx context.Context, userCred mcclient.Tok if diskId, err := data.GetString("disk_id"); err != nil { return nil, err } else { - if disk, err := DiskManager.FetchByIdOrName(userCred.GetProjectId(), diskId); err != nil { + if disk, err := DiskManager.FetchByIdOrName(userCred, diskId); err != nil { return nil, err } else if disk == nil { return nil, httperrors.NewResourceNotFoundError("Disk %s not found", diskId) @@ -2451,7 +2466,7 @@ func (self *SGuest) PerformAssignSecgroup(ctx context.Context, userCred mcclient } else { if secgrp, err := data.GetString("secgrp"); err != nil { return nil, err - } else if sg, err := SecurityGroupManager.FetchByIdOrName(userCred.GetProjectId(), secgrp); err != nil { + } else if sg, err := SecurityGroupManager.FetchByIdOrName(userCred, secgrp); err != nil { return nil, httperrors.NewNotFoundError("SecurityGroup %s not found", secgrp) } else { if _, err := self.GetModelManager().TableSpec().Update(self, func() error { @@ -2538,7 +2553,7 @@ func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.To keypairStr := jsonutils.GetAnyString(data, []string{"keypair", "keypair_id"}) if len(keypairStr) > 0 { - keypairObj, err := KeypairManager.FetchByIdOrName(userCred.GetUserId(), keypairStr) + keypairObj, err := KeypairManager.FetchByIdOrName(userCred, keypairStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("keypair %s not found", keypairStr) @@ -2680,7 +2695,7 @@ func (self *SGuest) PerformDetachdisk(ctx context.Context, userCred mcclient.Tok return nil, err } keepDisk := jsonutils.QueryBoolean(data, "keep_disk", false) - iDisk, err := DiskManager.FetchByIdOrName(userCred.GetProjectId(), diskId) + iDisk, err := DiskManager.FetchByIdOrName(userCred, diskId) if err != nil { return nil, err } @@ -2735,7 +2750,7 @@ func (self *SGuest) PerformDetachIsolatedDevice(ctx context.Context, userCred mc logclient.AddActionLog(self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false) return nil, httperrors.NewBadRequestError(msg) } - iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred.GetProjectId(), device) + iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device) if err != nil { msg := fmt.Sprintf("Isolated device %s not found", device) logclient.AddActionLog(self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false) @@ -2785,7 +2800,7 @@ func (self *SGuest) PerformAttachIsolatedDevice(ctx context.Context, userCred mc logclient.AddActionLog(self, logclient.ACT_GUEST_ATTACH_ISOLATED_DEVICE, msg, userCred, false) return nil, httperrors.NewBadRequestError(msg) } - iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred.GetProjectId(), device) + iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device) if err != nil { msg := fmt.Sprintf("Isolated device %s not found", device) logclient.AddActionLog(self, logclient.ACT_GUEST_ATTACH_ISOLATED_DEVICE, msg, userCred, false) @@ -3289,10 +3304,29 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, host *SHost, para if keypair != nil { config.Add(jsonutils.NewString(keypair.PublicKey), "public_key") } + deletePubKey, _ := params.GetString("delete_public_key") + if len(deletePubKey) > 0 { + config.Add(jsonutils.NewString(deletePubKey), "delete_public_key") + } } else { config.Add(jsonutils.JSONFalse, "reset_password") } + // add default public keys + _, adminPubKey, err := getSshAdminKeypair(ctx) + if err != nil { + log.Errorf("fail to get ssh admin public key %s", err) + } + + _, projPubKey, err := getSshProjectKeypair(ctx, self.ProjectId) + + if err != nil { + log.Errorf("fail to get ssh project public key %s", err) + } + + config.Add(jsonutils.NewString(adminPubKey), "admin_public_key") + config.Add(jsonutils.NewString(projPubKey), "project_public_key") + config.Add(jsonutils.NewString(deployAction), "action") onFinish := "shutdown" @@ -4343,7 +4377,7 @@ func (self *SGuest) PerformAssociateEip(ctx context.Context, userCred mcclient.T if len(eipStr) == 0 { return nil, httperrors.NewInputParameterError("missing eip or eip_id") } - eipObj, err := ElasticipManager.FetchByIdOrName(userCred.GetProjectId(), eipStr) + eipObj, err := ElasticipManager.FetchByIdOrName(userCred, eipStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("eip %s not found", eipStr) @@ -4496,3 +4530,37 @@ func (self *SGuest) getDefaultStorageType() string { } return STORAGE_LOCAL } + +func (self *SGuest) setUserData(ctx context.Context, userCred mcclient.TokenCredential, data string) error { + data = base64.StdEncoding.EncodeToString([]byte(data)) + if len(data) > 16*1024 { + return fmt.Errorf("User data is limited to 16 KB.") + } + err := self.SetMetadata(ctx, "user_data", data, userCred) + if err != nil { + return err + } + return nil +} + +func (self *SGuest) AllowPerformUserData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + return self.IsOwner(userCred) +} + +func (self *SGuest) PerformUserData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + userData, err := data.GetString("user_data") + if err != nil { + return nil, httperrors.NewInputParameterError("missing user_data %s", err) + } + err = self.setUserData(ctx, userCred, userData) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + if len(self.HostId) > 0 { + err = self.StartSyncTask(ctx, userCred, false, "") + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + } + return nil, nil +} diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index bec3cec6e7..80c153b325 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -153,7 +153,7 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu schedTagStr := jsonutils.GetAnyString(query, []string{"schedtag", "schedtag_id"}) if len(schedTagStr) > 0 { - schedTag, _ := SchedtagManager.FetchByIdOrName("", schedTagStr) + schedTag, _ := SchedtagManager.FetchByIdOrName(nil, schedTagStr) if schedTag == nil { return nil, httperrors.NewResourceNotFoundError("Schedtag %s not found", schedTagStr) } @@ -163,7 +163,7 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu wireStr := jsonutils.GetAnyString(query, []string{"wire", "wire_id"}) if len(wireStr) > 0 { - wire, _ := WireManager.FetchByIdOrName("", wireStr) + wire, _ := WireManager.FetchByIdOrName(nil, wireStr) if wire == nil { return nil, httperrors.NewResourceNotFoundError("Wire %s not found", wireStr) } @@ -173,7 +173,7 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu storageStr := jsonutils.GetAnyString(query, []string{"storage", "storage_id"}) if len(storageStr) > 0 { - storage, _ := StorageManager.FetchByIdOrName("", storageStr) + storage, _ := StorageManager.FetchByIdOrName(nil, storageStr) if storage == nil { return nil, httperrors.NewResourceNotFoundError("Storage %s not found", storageStr) } @@ -183,7 +183,7 @@ func (manager *SHostManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) if len(zoneStr) > 0 { - zone, _ := ZoneManager.FetchByIdOrName("", zoneStr) + zone, _ := ZoneManager.FetchByIdOrName(nil, zoneStr) if zone == nil { return nil, httperrors.NewResourceNotFoundError("Zone %s not found", zoneStr) } diff --git a/pkg/compute/models/isolated_devices.go b/pkg/compute/models/isolated_devices.go index 077518d6f1..d45aaa3231 100644 --- a/pkg/compute/models/isolated_devices.go +++ b/pkg/compute/models/isolated_devices.go @@ -115,7 +115,7 @@ func (manager *SIsolatedDeviceManager) ListItemFilter(ctx context.Context, q *sq } zoneStr := jsonutils.GetAnyString(query, []string{"zone", "zone_id"}) if len(zoneStr) > 0 { - zone, _ := ZoneManager.FetchByIdOrName("", zoneStr) + zone, _ := ZoneManager.FetchByIdOrName(nil, zoneStr) if zone == nil { return nil, httperrors.NewResourceNotFoundError("Zone %s not found", zoneStr) } diff --git a/pkg/compute/models/keypairs.go b/pkg/compute/models/keypairs.go index 84cb4f5b28..fa7973788f 100644 --- a/pkg/compute/models/keypairs.go +++ b/pkg/compute/models/keypairs.go @@ -3,11 +3,16 @@ package models import ( "context" + "yunion.io/x/log" "yunion.io/x/jsonutils" + "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/sqlchemy" + "yunion.io/x/onecloud/pkg/util/seclib2" + "golang.org/x/crypto/ssh" + "yunion.io/x/pkg/utils" ) type SKeypairManager struct { @@ -23,11 +28,11 @@ func init() { type SKeypair struct { db.SStandaloneResourceBase - Scheme string `width:"12" charset:"ascii" nullable:"true" default:"RSA" list:"user" create:"optional"` // Column(VARCHAR(length=12, charset='ascii'), nullable=True, default='RSA') - Fingerprint string `width:"48" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(length=48, charset='ascii'), nullable=False) - PrivateKey string `width:"2048" charset:"ascii" nullable:"false"` // Column(VARCHAR(length=2048, charset='ascii'), nullable=False) - PublicKey string `width:"1024" charset:"ascii" nullable:"false" list:"user"` // Column(VARCHAR(length=1024, charset='ascii'), nullable=False) - OwnerId string `width:"128" charset:"ascii" index:"true" nullable:"false"` // Column(VARCHAR(length=36, charset='ascii'), index=True, nullable=False) + Scheme string `width:"12" charset:"ascii" nullable:"true" default:"RSA" list:"user" create:"required"` // Column(VARCHAR(length=12, charset='ascii'), nullable=True, default='RSA') + Fingerprint string `width:"48" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=48, charset='ascii'), nullable=False) + PrivateKey string `width:"2048" charset:"ascii" nullable:"false" create:"optional"` // Column(VARCHAR(length=2048, charset='ascii'), nullable=False) + PublicKey string `width:"1024" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=1024, charset='ascii'), nullable=False) + OwnerId string `width:"128" charset:"ascii" index:"true" nullable:"false" create:"required"` // Column(VARCHAR(length=36, charset='ascii'), index=True, nullable=False) } func (manager *SKeypairManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { @@ -100,7 +105,40 @@ func (self *SKeypair) GetLinkedGuestsCount() int { } func (manager *SKeypairManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { - // XXX: TODO + publicKey, _ := data.GetString("public_key") + if len(publicKey) == 0 { + scheme, _ := data.GetString("scheme") + if len(scheme) > 0 { + if ! utils.IsInStringArray(scheme, []string{"RSA", "DSA"}) { + return nil, httperrors.NewInputParameterError("Unsupported scheme %s", scheme) + } + } else { + scheme = "RSA" + } + var privKey, pubKey string + var err error + if scheme == "RSA" { + privKey, pubKey, err = seclib2.GenerateRSASSHKeypair() + } else { + privKey, pubKey, err = seclib2.GenerateDSASSHKeypair() + } + if err != nil { + log.Errorf("fail to generate ssh keypair %s", err) + return nil, httperrors.NewGeneralError(err) + } + publicKey = pubKey + data.Set("public_key", jsonutils.NewString(pubKey)) + data.Set("private_key", jsonutils.NewString(privKey)) + } + pubKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey)) + if err != nil { + log.Errorf("invalid public key %s", err) + return nil, httperrors.NewInputParameterError("invalid public") + } + data.Set("fingerprint", jsonutils.NewString(ssh.FingerprintLegacyMD5(pubKey))) + data.Set("scheme", jsonutils.NewString(seclib2.GetPublicKeyScheme(pubKey))) + data.Set("owner_id", jsonutils.NewString(userCred.GetUserId())) + return manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data) } @@ -124,6 +162,37 @@ func (self *SKeypair) GetOwnerProjectId() string { return self.OwnerId } -func (manager *SKeypairManager) GetOwnerId(userCred mcclient.TokenCredential) string { +func (manager *SKeypairManager) GetOwnerId(userCred mcclient.IIdentityProvider) string { return userCred.GetUserId() } + +func (manager *SKeypairManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (db.IModel, error) { + return db.FetchByName(manager, userCred, idStr) +} + +func (manager *SKeypairManager) FetchByIdOrName(userCred mcclient.IIdentityProvider, idStr string) (db.IModel, error) { + return db.FetchByIdOrName(manager, userCred, idStr) +} + +func (keypair *SKeypair) AllowGetDetailsPrivatekey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return keypair.OwnerId == userCred.GetUserId() +} + +func (keypair *SKeypair) GetDetailsPrivatekey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + retval := jsonutils.NewDict() + if len(keypair.PrivateKey) > 0 { + retval.Add(jsonutils.NewString(keypair.PrivateKey), "private_key") + retval.Add(jsonutils.NewString(keypair.Name), "name") + retval.Add(jsonutils.NewString(keypair.Scheme), "scheme") + _, err := keypair.GetModelManager().TableSpec().Update(keypair, func() error { + keypair.PrivateKey = "" + return nil + }) + if err != nil { + return nil, err + } + + db.OpsLog.LogEvent(keypair, db.ACT_FETCH, nil, userCred) + } + return retval, nil +} \ No newline at end of file diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index e13d486e45..89d8506db2 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -691,7 +691,7 @@ func parseNetworkInfo(userCred mcclient.TokenCredential, info jsonutils.JSONObje } else if p == "[vip]" { netConfig.Vip = true } else { - netObj, err := NetworkManager.FetchByIdOrName(userCred.GetProjectId(), p) + netObj, err := NetworkManager.FetchByIdOrName(userCred, p) if err != nil { return nil, err } @@ -710,7 +710,7 @@ func (self *SNetwork) getFreeAddressCount() int { func isValidNetworkInfo(userCred mcclient.TokenCredential, netConfig *SNetworkConfig) error { if len(netConfig.Network) > 0 { - netObj, err := NetworkManager.FetchByIdOrName(userCred.GetProjectId(), netConfig.Network) + netObj, err := NetworkManager.FetchByIdOrName(userCred, netConfig.Network) if err != nil { return httperrors.NewResourceNotFoundError("Network %s not found %s", err) } @@ -971,7 +971,7 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred wireStr := jsonutils.GetAnyString(data, []string{"wire", "wire_id"}) if len(wireStr) > 0 { - wireObj, err := WireManager.FetchByIdOrName(userCred.GetProjectId(), wireStr) + wireObj, err := WireManager.FetchByIdOrName(userCred, wireStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("wire %s not found", wireStr) @@ -985,7 +985,7 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred if len(zoneStr) > 0 { vpcStr := jsonutils.GetAnyString(data, []string{"vpc", "vpc_id"}) if len(vpcStr) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(userCred.GetProjectId(), zoneStr) + zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("zone %s not found", zoneStr) @@ -993,7 +993,7 @@ func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred return nil, httperrors.NewInternalServerError("query zone %s error %s", zoneStr, err) } } - vpcObj, err := VpcManager.FetchByIdOrName(userCred.GetProjectId(), vpcStr) + vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("vpc %s not found", vpcStr) @@ -1277,7 +1277,7 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy. } zoneStr, _ := query.GetString("zone") if len(zoneStr) > 0 { - zoneObj, err := ZoneManager.FetchByIdOrName(userCred.GetProjectId(), zoneStr) + zoneObj, err := ZoneManager.FetchByIdOrName(userCred, zoneStr) if err != nil { return nil, httperrors.NewNotFoundError("Zone %s not found", zoneStr) } @@ -1286,7 +1286,7 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy. } vpcStr, _ := query.GetString("vpc") if len(vpcStr) > 0 { - vpcObj, err := VpcManager.FetchByIdOrName(userCred.GetProjectId(), vpcStr) + vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr) if err != nil { return nil, httperrors.NewNotFoundError("VPC %s not found", vpcStr) } @@ -1295,7 +1295,7 @@ func (manager *SNetworkManager) ListItemFilter(ctx context.Context, q *sqlchemy. } regionStr := jsonutils.GetAnyString(query, []string{"region_id", "region", "cloudregion_id", "cloudregion"}) if len(regionStr) > 0 { - region, err := CloudregionManager.FetchByIdOrName(userCred.GetProjectId(), regionStr) + region, err := CloudregionManager.FetchByIdOrName(userCred, regionStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("cloud region %s not found", regionStr) diff --git a/pkg/compute/models/reservedips.go b/pkg/compute/models/reservedips.go index 1f24d09131..e3b2401f56 100644 --- a/pkg/compute/models/reservedips.go +++ b/pkg/compute/models/reservedips.go @@ -122,7 +122,7 @@ func (manager *SReservedipManager) ListItemFilter(ctx context.Context, q *sqlche } network, _ := query.GetString("network") if len(network) > 0 { - netObj, _ := NetworkManager.FetchByIdOrName(userCred.GetProjectId(), network) + netObj, _ := NetworkManager.FetchByIdOrName(userCred, network) if netObj == nil { return nil, httperrors.NewResourceNotFoundError(fmt.Sprintf("network %s not found", network)) } diff --git a/pkg/compute/models/schedtags.go b/pkg/compute/models/schedtags.go index e0a91987c1..79134250e9 100644 --- a/pkg/compute/models/schedtags.go +++ b/pkg/compute/models/schedtags.go @@ -59,7 +59,7 @@ func (manager *SSchedtagManager) AllowCreateItem(ctx context.Context, userCred m func (manager *SSchedtagManager) ValidateSchedtags(userCred mcclient.TokenCredential, schedtags map[string]string) (map[string]string, error) { ret := make(map[string]string) for tag, act := range schedtags { - schedtagObj, err := manager.FetchByIdOrName("", tag) + schedtagObj, err := manager.FetchByIdOrName(nil, tag) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("Invalid schedtag %s", tag) diff --git a/pkg/compute/models/secgrouprules.go b/pkg/compute/models/secgrouprules.go index 24d83c9ba8..3514e720d2 100644 --- a/pkg/compute/models/secgrouprules.go +++ b/pkg/compute/models/secgrouprules.go @@ -98,7 +98,7 @@ func (manager *SSecurityGroupRuleManager) ListItemFilter(ctx context.Context, q return nil, err } if defsecgroup, _ := query.GetString("secgroup"); len(defsecgroup) > 0 { - if secgroup, _ := SecurityGroupManager.FetchByIdOrName(userCred.GetProjectId(), defsecgroup); secgroup != nil { + if secgroup, _ := SecurityGroupManager.FetchByIdOrName(userCred, defsecgroup); secgroup != nil { sql = sql.Equals("secgroup_id", secgroup.GetId()) } else { return nil, httperrors.NewNotFoundError(fmt.Sprintf("Security Group %s not found", defsecgroup)) @@ -130,7 +130,7 @@ func (manager *SSecurityGroupRuleManager) ValidateCreateData( data *jsonutils.JSONDict, ) (*jsonutils.JSONDict, error) { if defsecgroup, _ := data.GetString("secgroup"); len(defsecgroup) > 0 { - if secgroup, _ := SecurityGroupManager.FetchByIdOrName(userCred.GetProjectId(), defsecgroup); secgroup != nil { + if secgroup, _ := SecurityGroupManager.FetchByIdOrName(userCred, defsecgroup); secgroup != nil { data.Set("secgroup_id", jsonutils.NewString(secgroup.GetId())) } else { return nil, httperrors.NewNotFoundError(fmt.Sprintf("Security Group %s not found", defsecgroup)) diff --git a/pkg/compute/models/sshkeypairs.go b/pkg/compute/models/sshkeypairs.go new file mode 100644 index 0000000000..967e8b1055 --- /dev/null +++ b/pkg/compute/models/sshkeypairs.go @@ -0,0 +1,44 @@ +package models + +import ( + "context" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/mcclient/auth" +) + +const ( + sshAdminPrivateKey = "admin-ssh-private-key" + sshAdminPublicKey = "admin-ssh-public-key" + + sshPrivateKey = "project-ssh-private-key" + sshPublicKey = "project-ssh-public-key" +) + +func _getKeys(ctx context.Context, tenantId string, privateKey, publicKey string) (string, string, error) { + tenant, err := db.TenantCacheManager.FetchTenantById(ctx, tenantId) + if err != nil { + return "", "", err + } + private := tenant.GetMetadata(privateKey, nil) + public := tenant.GetMetadata(publicKey, nil) + userCred := auth.AdminCredential() + if len(private) == 0 || len(public) == 0 { + private, public, _ = seclib2.GenerateRSASSHKeypair() + private, _ = utils.EncryptAESBase64(tenantId, private) + tenant.SetMetadata(ctx, privateKey, private, userCred) + tenant.SetMetadata(ctx, publicKey, public, userCred) + } + private, _ = utils.DescryptAESBase64(tenantId, private) + return private, public, nil +} + +func getSshProjectKeypair(ctx context.Context, tenantId string) (string, string, error) { + return _getKeys(ctx, tenantId, sshPrivateKey, sshPublicKey) +} + +func getSshAdminKeypair(ctx context.Context) (string, string, error) { + userCred := auth.AdminCredential() + return _getKeys(ctx, userCred.GetProjectId(), sshAdminPrivateKey, sshAdminPublicKey) +} \ No newline at end of file diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 060c266c62..acc6346d25 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -675,7 +675,7 @@ func (manager *SStorageManager) ListItemFilter(ctx context.Context, q *sqlchemy. regionStr, _ := query.GetString("region") if len(regionStr) > 0 { - regionObj, err := CloudregionManager.FetchByIdOrName(userCred.GetProjectId(), regionStr) + regionObj, err := CloudregionManager.FetchByIdOrName(userCred, regionStr) if err != nil { return nil, httperrors.NewNotFoundError("Region %s not found: %s", regionStr, err) } diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 345de3fd12..45f93b10bb 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -54,7 +54,7 @@ func (manager *SWireManager) ValidateCreateData(ctx context.Context, userCred mc } if len(vpcStr) > 0 { - vpcObj, err := VpcManager.FetchByIdOrName(userCred.GetProjectId(), vpcStr) + vpcObj, err := VpcManager.FetchByIdOrName(userCred, vpcStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("Vpc %s not found", vpcStr) @@ -534,7 +534,7 @@ func (manager *SWireManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu vpcStr := jsonutils.GetAnyString(query, []string{"vpc_id", "vpc"}) if len(vpcStr) > 0 { - vpc, err := VpcManager.FetchByIdOrName(userCred.GetProjectId(), vpcStr) + vpc, err := VpcManager.FetchByIdOrName(userCred, vpcStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("vpc %s not found", vpcStr) @@ -547,7 +547,7 @@ func (manager *SWireManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQu regionStr := jsonutils.GetAnyString(query, []string{"region_id", "region", "cloudregion_id", "cloudregion"}) if len(regionStr) > 0 { - region, err := CloudregionManager.FetchByIdOrName(userCred.GetProjectId(), regionStr) + region, err := CloudregionManager.FetchByIdOrName(userCred, regionStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewNotFoundError("region %s not found", regionStr) diff --git a/pkg/compute/models/zones.go b/pkg/compute/models/zones.go index 8b1cc8c57e..8301f95680 100644 --- a/pkg/compute/models/zones.go +++ b/pkg/compute/models/zones.go @@ -523,7 +523,7 @@ func (manager *SZoneManager) ValidateCreateData(ctx context.Context, userCred mc regionStr := jsonutils.GetAnyString(query, []string{"region", "region_id", "cloudregion", "cloudregion_id"}) var regionId string if len(regionStr) > 0 { - regionObj, err := CloudregionManager.FetchByIdOrName("", regionStr) + regionObj, err := CloudregionManager.FetchByIdOrName(nil, regionStr) if err != nil { if err == sql.ErrNoRows { return nil, httperrors.NewResourceNotFoundError("Region %s not found", regionStr) diff --git a/pkg/compute/usages/handler.go b/pkg/compute/usages/handler.go index 6d05a20e46..b103afba26 100644 --- a/pkg/compute/usages/handler.go +++ b/pkg/compute/usages/handler.go @@ -64,7 +64,7 @@ func getRangeObj(ctx context.Context, man db.IStandaloneModelManager, userCred m if err != nil { return nil, err } - return man.FetchByIdOrName(userCred.GetProjectId(), id) + return man.FetchByIdOrName(userCred, id) } func rangeObjHandler( diff --git a/pkg/mcclient/modules/mod_servers.go b/pkg/mcclient/modules/mod_servers.go index 7b5c175f5b..b73b986178 100644 --- a/pkg/mcclient/modules/mod_servers.go +++ b/pkg/mcclient/modules/mod_servers.go @@ -6,6 +6,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/util/seclib2" ) type ServerManager struct { @@ -18,24 +19,35 @@ func (this *ServerManager) GetLoginInfo(s *mcclient.ClientSession, id string, pa return nil, e } ret := jsonutils.NewDict() - login_key, e := data.GetString("login_key") + loginKey, e := data.GetString("login_key") if e != nil { return nil, fmt.Errorf("No login key: %s", e) - } else { - passwd, e := utils.DescryptAESBase64(id, login_key) - if e != nil { - return nil, e - } - ret.Add(jsonutils.NewString(passwd), "password") - v, e := data.Get("login_account") - if e == nil { - ret.Add(v, "username") - } - v, e = data.Get("login_key_timestamp") - if e == nil { - ret.Add(v, "updated") - } } + + var privateKey string + if params != nil { + privateKey, _ = params.GetString("private_key") + } + + var passwd string + if len(privateKey) > 0 { + passwd, e = seclib2.DecryptBase64(privateKey, loginKey) + } else { + passwd, e = utils.DescryptAESBase64(id, loginKey) + } + if e != nil { + return nil, e + } + ret.Add(jsonutils.NewString(passwd), "password") + v, e := data.Get("login_account") + if e == nil { + ret.Add(v, "username") + } + v, e = data.Get("login_key_timestamp") + if e == nil { + ret.Add(v, "updated") + } + return ret, nil } diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index 06110971d5..bb5be54996 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -31,6 +31,11 @@ type ServerIdOptions struct { ID string `help:"ID or name of the server" json:"-"` } +type ServerLoginInfoOptions struct { + ID string `help:"ID or name of the server" json:"-"` + Key string `help:"File name of private key, if password is encrypted by key"` +} + type ServerIdsOptions struct { ID []string `help:"ID of servers to operate" metavar:"SERVER" json:"-"` } @@ -115,6 +120,7 @@ type ServerCreateOptions struct { Count *int `help:"Create multiple simultaneously" default:"1" json:"-"` DryRun *bool `help:"Dry run to test scheduler" json:"-"` RaidConfig []string `help:"Baremetal raid config" json:"-"` + UserDataFile string `help:"user_data file path" json:"-"` } func (opts *ServerCreateOptions) Params() (*jsonutils.JSONDict, error) { diff --git a/pkg/mcclient/token.go b/pkg/mcclient/token.go index 8c0e5e00ed..a7ca1b1afd 100644 --- a/pkg/mcclient/token.go +++ b/pkg/mcclient/token.go @@ -20,19 +20,24 @@ type Endpoint struct { Interface string } +type IIdentityProvider interface { + GetProjectId() string + GetUserId() string + GetTenantId() string +} + type TokenCredential interface { gotypes.ISerializable IServiceCatalog + IIdentityProvider + GetTokenString() string GetDomainId() string GetDomainName() string - GetTenantId() string GetTenantName() string - GetProjectId() string GetProjectName() string - GetUserId() string GetUserName() string GetRoles() []string GetExpires() time.Time diff --git a/pkg/util/aliyun/host.go b/pkg/util/aliyun/host.go index 8f116d6746..c79b40d1bc 100644 --- a/pkg/util/aliyun/host.go +++ b/pkg/util/aliyun/host.go @@ -165,8 +165,8 @@ func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string, passwd string, - storageType string, diskSizes []int, publicKey string, secgroupId string) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId) + storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, vswitchId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId, userData) if err != nil { return nil, err } @@ -180,7 +180,8 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string, passwd string, - storageType string, diskSizes []int, publicKey string, secgroupId string) (string, error) { + storageType string, diskSizes []int, publicKey string, secgroupId string, + userData string) (string, error) { net := self.zone.getNetworkById(vswitchId) if net == nil { return "", fmt.Errorf("invalid switch ID %s", vswitchId) @@ -260,7 +261,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int for _, instType := range instanceTypes { instanceTypeId := instType.InstanceTypeId log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err := self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair) + vmId, err := self.zone.region.CreateInstance(name, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData) if err != nil { log.Errorf("Failed for %s: %s", instanceTypeId, err) } else { diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index f564167f00..ed12a4f1e5 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -428,7 +428,7 @@ func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, securityGroupId string, zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string, - keypair string) (string, error) { + keypair string, userData string) (string, error) { params := make(map[string]string) params["RegionId"] = self.RegionId params["ImageId"] = imageId @@ -468,6 +468,11 @@ func (self *SRegion) CreateInstance(name string, imageId string, instanceType st if len(keypair) > 0 { params["KeyPairName"] = keypair } + + if len(userData) > 0 { + params["UserData"] = userData + } + params["ClientToken"] = utils.GenRequestId(20) body, err := self.ecsRequest("CreateInstance", params) diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index c080b4375b..55c177bbf1 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -422,7 +422,7 @@ func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, me log.Debugf("Search in zone %s", z.LocalName) net := z.getNetworkById(vswitchId) if net != nil { - inst, err := z.getHost().CreateVM(name, imgId, 0, cpu, memGB*1024, vswitchId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "") + inst, err := z.getHost().CreateVM(name, imgId, 0, cpu, memGB*1024, vswitchId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "", "") if err != nil { return nil, err } diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go index a41d838232..30b18a39ac 100644 --- a/pkg/util/azure/host.go +++ b/pkg/util/azure/host.go @@ -48,7 +48,7 @@ func (self *SHost) Refresh() error { return nil } -func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, networkId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string, secgroupId string) (cloudprovider.ICloudVM, error) { +func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, networkId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) { nicId := "" if net := self.zone.getNetworkById(networkId); net == nil { return nil, fmt.Errorf("invalid network ID %s", networkId) @@ -57,7 +57,7 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, } else { nicId = nic.ID } - vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, nicId, ipAddr, desc, passwd, storageType, diskSizes, publicKey) + vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, nicId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, userData) if err != nil { self.zone.region.DeleteNetworkInterface(nicId) return nil, err @@ -70,7 +70,7 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, } } -func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, nicId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string) (string, error) { +func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, nicId string, ipAddr string, desc string, passwd string, storageType string, diskSizes []int, publicKey string, userData string) (string, error) { computeClient := compute.NewVirtualMachinesClientWithBaseURI(self.zone.region.client.baseUrl, self.zone.region.client.subscriptionId) computeClient.Authorizer = self.zone.region.client.authorizer @@ -150,6 +150,10 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int properties.OsProfile.LinuxConfiguration.SSH = &compute.SSHConfiguration{PublicKeys: &sshKeys} } + if len(userData) > 0 { + properties.OsProfile.CustomData = &userData + } + params := compute.VirtualMachine{Location: &self.zone.region.Name, Name: &name, VirtualMachineProperties: &properties} //log.Debugf("Create instance params: %s", jsonutils.Marshal(params).PrettyString()) for _, profile := range self.zone.region.getHardwareProfile(cpu, memMB) { diff --git a/pkg/util/azure/region.go b/pkg/util/azure/region.go index 38527b827d..c68d1941d4 100644 --- a/pkg/util/azure/region.go +++ b/pkg/util/azure/region.go @@ -340,7 +340,7 @@ func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, me net := z.getNetworkById(networkId) if net != nil { passwd := seclib2.RandomPassword2(12) - inst, err := z.getHost().CreateVM(name, imgId, 30, cpu, memGB*1024, networkId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "") + inst, err := z.getHost().CreateVM(name, imgId, 30, cpu, memGB*1024, networkId, "", "", passwd, storageType, dataDiskSizesGB, publicKey, "", "") if err != nil { return nil, err } diff --git a/pkg/util/cloudinit/cloudconfig.go b/pkg/util/cloudinit/cloudconfig.go new file mode 100644 index 0000000000..f0c7d99597 --- /dev/null +++ b/pkg/util/cloudinit/cloudconfig.go @@ -0,0 +1,198 @@ +package cloudinit + +import ( + "bytes" + "encoding/base64" + + "github.com/yunionio/jsonutils" + "golang.org/x/crypto/bcrypt" + + "yunion.io/x/log" + "strings" + "fmt" + "yunion.io/x/pkg/utils" +) + +/* + * cloudconfig + * Reference: https://cloudinit.readthedocs.io/en/latest/topics/examples.html + * + */ + +const ( + CLOUD_CONFIG_HEADER = "#cloud-config\n" +) + +type SWriteFile struct { + Path string + Permissions string + Owner string + Encoding string + Content string +} + +type SUser struct { + Name string + Passwd string + SshAuthorizedKeys []string +} + +type SPhoneHome struct { + Url string +} + +type SCloudConfig struct { + Users []SUser + WriteFiles []SWriteFile + Runcmd []string + Bootcmd []string + Packages []string + PhoneHome *SPhoneHome +} + +func NewWriteFile(path string, content string, perm string, owner string, isBase64 bool) SWriteFile { + f := SWriteFile{} + + f.Path = path + f.Permissions = perm + f.Owner = owner + if isBase64 { + f.Encoding = "b64" + f.Content = base64.StdEncoding.EncodeToString([]byte(content)) + } else { + f.Content = content + } + + return f +} + +func NewUser(name string, passwd string, pubkeys []string, nohash bool) SUser { + u := SUser{} + + u.Name = name + if len(passwd) > 0 { + if nohash { + u.Passwd = passwd + } else { + hash, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost) + if err != nil { + log.Errorf("GenerateFromPassword error %s", err) + } else { + u.Passwd = string(hash) + } + } + } + u.SshAuthorizedKeys = pubkeys + + return u +} + +func (conf *SCloudConfig) UserData() string { + var buf bytes.Buffer + jsonConf := jsonutils.Marshal(conf) + buf.WriteString(CLOUD_CONFIG_HEADER) + buf.WriteString(jsonConf.YAMLString()) + return buf.String() +} + +func (conf *SCloudConfig) UserDataBase64() string { + data := conf.UserData() + return base64.StdEncoding.EncodeToString([]byte(data)) +} + +func ParseUserDataBase64(b64data string) (*SCloudConfig, error) { + data, err := base64.StdEncoding.DecodeString(b64data) + if err != nil { + return nil, err + } + return ParseUserData(string(data)) +} + +func ParseUserData(data string) (*SCloudConfig, error) { + if ! strings.HasPrefix(data, CLOUD_CONFIG_HEADER) { + msg := "invalid userdata, not starting with #cloud-config" + log.Errorf(msg) + return nil, fmt.Errorf(msg) + } + jsonConf, err := jsonutils.ParseYAML(data) + if err != nil { + log.Errorf("parse userdata yaml error %s", err) + return nil, err + } + config := SCloudConfig{} + err = jsonConf.Unmarshal(&config) + if err != nil { + log.Errorf("unable to unmarchal userdata %s", err) + return nil, err + } + return &config, nil +} + +func (conf *SCloudConfig) MergeUser(u SUser) { + for i := 0; i < len(conf.Users); i += 1 { + if u.Name == conf.Users[i].Name { + // find user, merge keys + for j := 0; j < len(u.SshAuthorizedKeys); j += 1 { + if !utils.IsInStringArray(u.SshAuthorizedKeys[j], conf.Users[i].SshAuthorizedKeys) { + conf.Users[i].SshAuthorizedKeys = append(conf.Users[i].SshAuthorizedKeys, u.SshAuthorizedKeys[j]) + } + } + return + } + } + // no such user + conf.Users = append(conf.Users, u) +} + +func (conf *SCloudConfig) MergeWriteFile(f SWriteFile, replace bool) { + for i := 0; i < len(conf.WriteFiles); i += 1 { + if conf.WriteFiles[i].Path == f.Path { + // find file + if replace { + conf.WriteFiles[i].Content = f.Content + conf.WriteFiles[i].Encoding = f.Encoding + conf.WriteFiles[i].Owner = f.Owner + conf.WriteFiles[i].Permissions = f.Permissions + } + return + } + } + // no such file + conf.WriteFiles = append(conf.WriteFiles, f) +} + +func (conf *SCloudConfig) MergeRuncmd(cmd string) { + if ! utils.IsInStringArray(cmd, conf.Runcmd) { + conf.Runcmd = append(conf.Runcmd, cmd) + } +} + +func (conf *SCloudConfig) MergeBootcmd(cmd string) { + if ! utils.IsInStringArray(cmd, conf.Bootcmd) { + conf.Bootcmd = append(conf.Bootcmd, cmd) + } +} + +func (conf *SCloudConfig) MergePackage(pkg string) { + if ! utils.IsInStringArray(pkg, conf.Packages) { + conf.Packages = append(conf.Packages, pkg) + } +} + +func (conf *SCloudConfig) Merge(conf2 *SCloudConfig) { + for _, u := range conf2.Users { + conf.MergeUser(u) + } + for _, f := range conf2.WriteFiles { + conf.MergeWriteFile(f, false) + } + for _, c := range conf2.Runcmd { + conf.MergeRuncmd(c) + } + for _, c := range conf2.Bootcmd { + conf.MergeBootcmd(c) + } + for _, p := range conf2.Packages { + conf.MergePackage(p) + } +} \ No newline at end of file diff --git a/pkg/util/cloudinit/cloudconfig_test.go b/pkg/util/cloudinit/cloudconfig_test.go new file mode 100644 index 0000000000..26dd45734a --- /dev/null +++ b/pkg/util/cloudinit/cloudconfig_test.go @@ -0,0 +1,46 @@ +package cloudinit + +import ( + "testing" +) + +func TestSCloudConfig_UserData(t *testing.T) { + usr1 := NewUser("root", "", []string{ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa4E8wmIOlmh1G8ZRcU2zpnl2frD2lLKdXpbTeUUZEKYFFlYM8TM5UrKrqrMCd3rFjaYGTKWiQwOiWroXlAXausbbVEI29KY+1Vd26qNyejj+CZO9MCj0naIrqa1V0of3TQY5I2U+ToIkyLqVFWhWVa57v/GUxsV2aNTmUS/qz0OPSCFPbGWWB35rsjwnFwq2jF6E8yJgTGDTYZcsghRi3IWfyfeHbSuWdvn6N8XrPBDmNg7h+GSvO6FJlp6MUw1hscECi13GwqXYgJnLG5RMiFH6s0vhozyHkue1vOTcryPHRQD0Jz/INUSaggH8L1HnYSUavOf4Cw25W9HfzgUBf", + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa4E8wmIOlmh1G8ZRcU2zpnl2frD2lLKdXpbTeUUZEKYFFlYM8TM5UrKrqrMCd3rFjaYGTKWiQwOiWroXlAXausbbVEI29KY+1Vd26qNyejj+CZO9MCj0naIrqa1V0of3TQY5I2U+ToIkyLqVFWhWVa57v/GUxsV2aNTmUS/qz0OPSCFPbGWWB35rsjwnFwq2jF6E8yJgTGDTYZcsghRi3IWfyfeHbSuWdvn6N8XrPBDmNg7h+GSvO6FJlp6MUw1hscECi13GwqXYgJnLG5RMiFH6s0vhozyHkue1vOTcryPHRQD0Jz/INUSaggH8L1HnYSUavOf4Cw25W9HfzgUBf", + }, false) + usr2 := NewUser("yunion", "123@yunion", nil, false) + file1 := NewWriteFile("/etc/ansible/hosts", "gobuild\ncloudev\n", "", "", true) + file2 := NewWriteFile("/etc/hosts", "127.0.0.1 localhost\n", "", "", false) + config := SCloudConfig{ + Users: []SUser{ + usr1, + usr2, + }, + WireFiles: []SWriteFile{ + file1, + file2, + }, + Runcmd: []string{ + "mkdir /var/run/httpd", + }, + PhoneHome: &SPhoneHome{ + Url: "http://www.yunion.io/$INSTANCE_ID", + }, + } + userData := config.UserData() + + t.Logf("%s", userData) + + config2, err := ParseUserData(userData) + if err != nil { + t.Errorf("%s", err) + } else { + userData2 := config2.UserData() + t.Logf("%s", userData2) + + if userData != userData2 { + t.Errorf("userData not equal to userData2") + } + } +} diff --git a/pkg/util/esxi/host.go b/pkg/util/esxi/host.go index fa098fa474..dc8c270ff8 100644 --- a/pkg/util/esxi/host.go +++ b/pkg/util/esxi/host.go @@ -358,7 +358,7 @@ func (self *SHost) GetManagerId() string { } func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, memMB int, vswitchId string, ipAddr string, desc string, - passwd string, storageType string, diskSizes []int, publicKey string, secGrpId string) (cloudprovider.ICloudVM, error) { + passwd string, storageType string, diskSizes []int, publicKey string, secGrpId string, userData string) (cloudprovider.ICloudVM, error) { log.Debugf("CreateVM") return nil, cloudprovider.ErrNotImplemented } \ No newline at end of file diff --git a/pkg/util/seclib2/aes.go b/pkg/util/seclib2/aes.go new file mode 100644 index 0000000000..527817c0ad --- /dev/null +++ b/pkg/util/seclib2/aes.go @@ -0,0 +1,108 @@ +package seclib2 + +import ( + "crypto/cipher" + "crypto/aes" + "fmt" + "io" + "crypto/rand" +) + +// https://stackoverflow.com/questions/23897809/different-results-in-go-and-pycrypto-when-using-aes-cfb +// CFB stream with 8 bit segment size +// See http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +type cfb8 struct { + b cipher.Block + blockSize int + in []byte + out []byte + + decrypt bool +} + +func (x *cfb8) XORKeyStream(dst, src []byte) { + for i := range src { + x.b.Encrypt(x.out, x.in) + copy(x.in[:x.blockSize-1], x.in[1:]) + if x.decrypt { + x.in[x.blockSize-1] = src[i] + } + dst[i] = src[i] ^ x.out[0] + if !x.decrypt { + x.in[x.blockSize-1] = dst[i] + } + } +} + +// NewCFB8Encrypter returns a Stream which encrypts with cipher feedback mode +// (segment size = 8), using the given Block. The iv must be the same length as +// the Block's block size. +func newCFB8Encrypter(block cipher.Block, iv []byte) cipher.Stream { + return newCFB8(block, iv, false) +} + +// NewCFB8Decrypter returns a Stream which decrypts with cipher feedback mode +// (segment size = 8), using the given Block. The iv must be the same length as +// the Block's block size. +func newCFB8Decrypter(block cipher.Block, iv []byte) cipher.Stream { + return newCFB8(block, iv, true) +} + +func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream { + blockSize := block.BlockSize() + if len(iv) != blockSize { + // stack trace will indicate whether it was de or encryption + panic("cipher.newCFB: IV length must equal block size") + } + x := &cfb8{ + b: block, + blockSize: blockSize, + out: make([]byte, blockSize), + in: make([]byte, blockSize), + decrypt: decrypt, + } + copy(x.in, iv) + + return x +} + +func toAESKey(k []byte) []byte { + if len(k) > 32 { + return k[0:32] + } else { + for len(k) < 32 { + k = append(k, '$') + } + return k + } +} + +func decryptAES(k, secret []byte) ([]byte, error) { + block, err := aes.NewCipher(toAESKey(k)) + if err != nil { + return nil, err + } + if len(secret) < aes.BlockSize { + return nil, fmt.Errorf("ciphertext too short") + } + iv := secret[:aes.BlockSize] + ciphertext := secret[aes.BlockSize:] + stream := newCFB8Decrypter(block, iv) + stream.XORKeyStream(ciphertext, ciphertext) + return ciphertext, nil +} + +func encryptAES(k, msg []byte) ([]byte, error) { + block, err := aes.NewCipher(toAESKey(k)) + if err != nil { + return nil, err + } + cipherText := make([]byte, aes.BlockSize+len(msg)) + iv := cipherText[:aes.BlockSize] + if _, err = io.ReadFull(rand.Reader, iv); err != nil { + return nil, err + } + stream := newCFB8Encrypter(block, iv) + stream.XORKeyStream(cipherText[aes.BlockSize:], msg) + return cipherText, nil +} diff --git a/pkg/util/seclib2/aes_test.go b/pkg/util/seclib2/aes_test.go new file mode 100644 index 0000000000..09a64b44b9 --- /dev/null +++ b/pkg/util/seclib2/aes_test.go @@ -0,0 +1,24 @@ +package seclib2 + +import "testing" + +func TestAes(t *testing.T) { + secret := "This is a secret for AES!!!" + key := "This is AES key" + + code, err := encryptAES([]byte(key), []byte(secret)) + if err != nil { + t.Errorf("encrypt error %s", err) + return + } + + secret2, err := decryptAES([]byte(key), code) + if err != nil { + t.Errorf("decrypt error %s", err) + return + } + + if secret != string(secret2) { + t.Errorf("aes encrypt/decrypt mismatch! %s != %s", secret, string(secret2)) + } +} diff --git a/pkg/util/seclib2/crypto.go b/pkg/util/seclib2/crypto.go new file mode 100644 index 0000000000..57af747284 --- /dev/null +++ b/pkg/util/seclib2/crypto.go @@ -0,0 +1,118 @@ +package seclib2 + +import ( + "crypto/rsa" + "crypto/rand" + "crypto/sha1" + + "golang.org/x/crypto/ssh" + + "yunion.io/x/log" + "fmt" + "crypto/dsa" + "crypto/ecdsa" + "encoding/base64" + "crypto" +) + +func exportSshPublicKey(pubkey interface{}) ([]byte, error) { + pub, err:= ssh.NewPublicKey(pubkey) + if err != nil { + return nil, err + } + return ssh.MarshalAuthorizedKey(pub), nil +} + +func ssh2CryptoPublicKey(key ssh.PublicKey) crypto.PublicKey { + cryptoPub := key.(ssh.CryptoPublicKey) + return cryptoPub.CryptoPublicKey() +} + +func ssh2rsaPublicKey(key ssh.PublicKey) *rsa.PublicKey { + cryptoKey := ssh2CryptoPublicKey(key) + return cryptoKey.(*rsa.PublicKey) +} + +func ssh2dsaPublicKey(key ssh.PublicKey) *dsa.PublicKey { + cryptoKey := ssh2CryptoPublicKey(key) + return cryptoKey.(*dsa.PublicKey) +} + +func ssh2ecdsaPublicKey(key ssh.PublicKey) *ecdsa.PublicKey { + cryptoKey := ssh2CryptoPublicKey(key) + return cryptoKey.(*ecdsa.PublicKey) +} + + +func Encrypt(publicKey, origData []byte) ([]byte, error) { + pub, _, _, _, err := ssh.ParseAuthorizedKey(publicKey) + if err != nil { + log.Errorf("parse authorized key error %s", err) + return nil, err + } + if pub.Type() == ssh.KeyAlgoRSA { + return rsa.EncryptOAEP(sha1.New(), rand.Reader, ssh2rsaPublicKey(pub), origData, nil) + } else { + var pubInf interface{} + switch pub.Type() { + case ssh.KeyAlgoDSA: + pubInf = ssh2dsaPublicKey(pub) + case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: + pubInf = ssh2ecdsaPublicKey(pub) + default: + return nil, fmt.Errorf("unsupported key type %s", pub.Type()) + } + pubStr, err := exportSshPublicKey(pubInf) + if err != nil { + return nil, err + } + return encryptAES(pubStr, origData) + } +} + +func Decrypt(privateKey, secret []byte) ([]byte, error) { + priv, err := ssh.ParseRawPrivateKey(privateKey) + if err != nil { + return nil, err + } + switch priv.(type) { + case *rsa.PrivateKey: + rsaPriv := priv.(*rsa.PrivateKey) + return rsa.DecryptOAEP(sha1.New(), rand.Reader, rsaPriv, secret, nil) + case *dsa.PrivateKey: + dsaPriv := priv.(*dsa.PrivateKey) + dsaPub, err := exportSshPublicKey(&dsaPriv.PublicKey) + if err != nil { + return nil, err + } + return decryptAES(dsaPub, secret) + case *ecdsa.PrivateKey: + ecdsaPriv := priv.(*ecdsa.PrivateKey) + ecdsaPub, err := exportSshPublicKey(&ecdsaPriv.PublicKey) + if err != nil { + return nil, err + } + return decryptAES(ecdsaPub, secret) + } + return nil, fmt.Errorf("unsupported") +} + +func EncryptBase64(publicKey string, message string) (string, error) { + secretBytes, err := Encrypt([]byte(publicKey), []byte(message)) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(secretBytes), nil +} + +func DecryptBase64(privateKey string, secret string) (string, error) { + secretBytes, err := base64.StdEncoding.DecodeString(secret) + if err != nil { + return "", err + } + msgBytes, err := Decrypt([]byte(privateKey), secretBytes) + if err != nil { + return "", err + } + return string(msgBytes), nil +} \ No newline at end of file diff --git a/pkg/util/seclib2/ssh.go b/pkg/util/seclib2/ssh.go new file mode 100644 index 0000000000..05f57c6fb2 --- /dev/null +++ b/pkg/util/seclib2/ssh.go @@ -0,0 +1,97 @@ +package seclib2 + +import ( + "crypto/rsa" + "crypto/rand" + "encoding/pem" + "crypto/x509" + + "golang.org/x/crypto/ssh" + "crypto/dsa" + + "yunion.io/x/log" + "encoding/asn1" + "math/big" +) + +func GenerateRSASSHKeypair() (string, string, error) { + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + log.Errorf("generate rsa key error %s", err) + return "", "", err + } + + privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} + privateStr := string(pem.EncodeToMemory(privateKeyPEM)) + + pub, err := exportSshPublicKey(&privateKey.PublicKey) + if err != nil { + return "", "", err + } + publicStr := string(pub) + + return privateStr, publicStr, nil +} + +func GenerateDSASSHKeypair() (string, string, error) { + var privateKey dsa.PrivateKey + + params := &privateKey.Parameters + err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160) + if err != nil { + log.Errorf("generateParameter error %s", err) + return "", "", err + } + err = dsa.GenerateKey(&privateKey, rand.Reader) + if err != nil { + log.Errorf("generate key error %s", err) + return "", "", err + } + + type DsaASN1 struct { + Version int + P *big.Int + Q *big.Int + G *big.Int + Pub *big.Int + Priv *big.Int + } + + k := DsaASN1{} + k.P = privateKey.P + k.Q = privateKey.Q + k.G = privateKey.G + k.Pub = privateKey.Y + k.Priv = privateKey.X + + privBytes, err := asn1.Marshal(k) + if err != nil { + log.Errorf("asn1 marshal error %s", err) + return "", "", err + } + + privateKeyPEM := &pem.Block{Type: "DSA PRIVATE KEY", Bytes: privBytes} + privateStr := string(pem.EncodeToMemory(privateKeyPEM)) + + pub, err := exportSshPublicKey(&privateKey.PublicKey) + if err != nil { + return "", "", err + } + publicStr := string(pub) + + return privateStr, publicStr, nil +} + +func GetPublicKeyScheme(pubkey ssh.PublicKey) string { + switch pubkey.Type() { + case ssh.KeyAlgoRSA: + return "RSA" + case ssh.KeyAlgoDSA: + return "DSA" + case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: + return "ECDSA" + // case ssh.KeyAlgoED25519: + // return "ED" + } + return "UNKNOWN" +} \ No newline at end of file diff --git a/pkg/util/seclib2/ssh_test.go b/pkg/util/seclib2/ssh_test.go new file mode 100644 index 0000000000..fcafae94b1 --- /dev/null +++ b/pkg/util/seclib2/ssh_test.go @@ -0,0 +1,153 @@ +package seclib2 + +import ( + "testing" + "encoding/pem" + "crypto/x509" + "fmt" + "golang.org/x/crypto/ssh" +) + +func TestGenerateRSASSHKeypair(t *testing.T) { + priv, pub , _ := GenerateRSASSHKeypair() + t.Logf("%s", priv) + t.Logf("%s", pub) +} + + +func TestGenerateDSASSHKeypair(t *testing.T) { + priv, pub , _ := GenerateDSASSHKeypair() + t.Logf("%s", priv) + t.Logf("%s", pub) +} + +func getPublicKeyPem(privateKey string) ([]byte, error) { + block, _ := pem.Decode([]byte(privateKey)) + if block == nil { + return nil, fmt.Errorf("invalid private key") + } + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + derPkix, err := x509.MarshalPKIXPublicKey(&priv.PublicKey) + if err != nil { + return nil, err + } + + block = &pem.Block{Type: "PUBLIC KEY", Bytes: derPkix} + return pem.EncodeToMemory(block), nil +} + +func getRSAPublicKeySsh(privateKey string) ([]byte, error) { + block, _ := pem.Decode([]byte(privateKey)) + if block == nil { + return nil, fmt.Errorf("invalid private key") + } + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + return exportSshPublicKey(&priv.PublicKey) +} + +func getDSAPublicKeySsh(privateKey string) ([]byte, error) { + block, _ := pem.Decode([]byte(privateKey)) + if block == nil { + return nil, fmt.Errorf("invalid private key") + } + priv, err := ssh.ParseDSAPrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + return exportSshPublicKey(&priv.PublicKey) +} + +func TestRsaDecryptEncrypt(t *testing.T) { + privateKey, publicKey, err := GenerateRSASSHKeypair() + if err != nil { + t.Errorf("fail to generate keypair %s", err) + return + } + /* publicKey2, err := getPublicKeyPem(privateKey) + if err != nil { + t.Errorf("fail to get public key in pem format %s", err) + return + } */ + pub3, err := getRSAPublicKeySsh(privateKey) + if err != nil { + t.Errorf("fail to get public key in ssh format %s", err) + return + } + + if publicKey != string(pub3) { + t.Errorf("public key mismatch! %s != %s", publicKey, pub3) + return + } + + t.Logf("%s", string(pub3)) + // t.Logf("%s", string(publicKey2)) + + secret := "this is a secret string!!!" + code, err := EncryptBase64(publicKey, secret) + if err != nil { + t.Errorf("rsa encrypt error %s", err) + return + } + t.Logf("%s", code) + secret2, err := DecryptBase64(privateKey, code) + if err != nil { + t.Errorf("rsa decrypt error %s", err) + return + } + if secret != secret2 { + t.Errorf("rsa decrypt/encrypt error! %s != %s", secret2, secret) + return + } +} + +func TestDsaDecryptEncrypt(t *testing.T) { + privateKey, publicKey, err := GenerateDSASSHKeypair() + if err != nil { + t.Errorf("fail to generate keypair %s", err) + return + } + /* publicKey2, err := getPublicKeyPem(privateKey) + if err != nil { + t.Errorf("fail to get public key in pem format %s", err) + return + } */ + pub3, err := getDSAPublicKeySsh(privateKey) + if err != nil { + t.Errorf("fail to get public key in ssh format %s", err) + return + } + + if publicKey != string(pub3) { + t.Errorf("public key mismatch! %s != %s", publicKey, pub3) + return + } + + t.Logf("%s", string(pub3)) + // t.Logf("%s", string(publicKey2)) + + secret := "this is a secret string!!!" + code, err := EncryptBase64(publicKey, secret) + if err != nil { + t.Errorf("dsa encrypt error %s", err) + return + } + t.Logf("%s", code) + secret2, err := DecryptBase64(privateKey, code) + if err != nil { + t.Errorf("rsa decrypt error %s", err) + return + } + if secret != secret2 { + t.Errorf("rsa decrypt/encrypt error! %s != %s", secret2, secret) + return + } +} \ No newline at end of file From ceee740315d8a268ab81ce74f2608b40b449fce5 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 12 Oct 2018 12:08:55 +0800 Subject: [PATCH 02/10] Update vendor --- Gopkg.lock | 9 +- vendor/golang.org/x/crypto/bcrypt/base64.go | 35 +++ vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 295 ++++++++++++++++++ vendor/golang.org/x/crypto/blowfish/block.go | 159 ++++++++++ vendor/golang.org/x/crypto/blowfish/cipher.go | 91 ++++++ vendor/golang.org/x/crypto/blowfish/const.go | 199 ++++++++++++ vendor/yunion.io/x/jsonutils/compond.go | 14 + vendor/yunion.io/x/jsonutils/interface.go | 40 +++ vendor/yunion.io/x/jsonutils/jsonutils.go | 2 + vendor/yunion.io/x/jsonutils/yamlutils.go | 61 ++-- 10 files changed, 876 insertions(+), 29 deletions(-) create mode 100644 vendor/golang.org/x/crypto/bcrypt/base64.go create mode 100644 vendor/golang.org/x/crypto/bcrypt/bcrypt.go create mode 100644 vendor/golang.org/x/crypto/blowfish/block.go create mode 100644 vendor/golang.org/x/crypto/blowfish/cipher.go create mode 100644 vendor/golang.org/x/crypto/blowfish/const.go create mode 100644 vendor/yunion.io/x/jsonutils/compond.go create mode 100644 vendor/yunion.io/x/jsonutils/interface.go diff --git a/Gopkg.lock b/Gopkg.lock index bcd51fb9d7..ad8588fa14 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -917,9 +917,11 @@ [[projects]] branch = "master" - digest = "1:71c5989353531072eeb9547066e05bdeaaf9ef0512673bca3b4b824092d70de3" + digest = "1:e132baa383407b5cb612c2a2ab6980566b5e11d98815db34a5a048f5f74835f4" name = "golang.org/x/crypto" packages = [ + "bcrypt", + "blowfish", "curve25519", "ed25519", "ed25519/internal/edwards25519", @@ -1223,11 +1225,11 @@ [[projects]] branch = "master" - digest = "1:49ffc35ec8d3f7789393cd132acd359e8ac1f5d38c7a2b91c484b041840c62c0" + digest = "1:09c49bf51d8da39e73f117d2448cea5a1bd287210378a4e14339a73ea27c0b5c" name = "yunion.io/x/jsonutils" packages = ["."] pruneopts = "UT" - revision = "d1290e94d4753c1748fc7c89f472a523cc0a5c08" + revision = "7b18aa76d7f1a25d0f77fdd579d86e9452ea9322" [[projects]] branch = "master" @@ -1369,6 +1371,7 @@ "github.com/vmware/govmomi/view", "github.com/vmware/govmomi/vim25/mo", "github.com/vmware/govmomi/vim25/types", + "golang.org/x/crypto/bcrypt", "golang.org/x/crypto/ssh", "gopkg.in/gin-gonic/gin.v1", "k8s.io/api/core/v1", diff --git a/vendor/golang.org/x/crypto/bcrypt/base64.go b/vendor/golang.org/x/crypto/bcrypt/base64.go new file mode 100644 index 0000000000..fc31160908 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/base64.go @@ -0,0 +1,35 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bcrypt + +import "encoding/base64" + +const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var bcEncoding = base64.NewEncoding(alphabet) + +func base64Encode(src []byte) []byte { + n := bcEncoding.EncodedLen(len(src)) + dst := make([]byte, n) + bcEncoding.Encode(dst, src) + for dst[n-1] == '=' { + n-- + } + return dst[:n] +} + +func base64Decode(src []byte) ([]byte, error) { + numOfEquals := 4 - (len(src) % 4) + for i := 0; i < numOfEquals; i++ { + src = append(src, '=') + } + + dst := make([]byte, bcEncoding.DecodedLen(len(src))) + n, err := bcEncoding.Decode(dst, src) + if err != nil { + return nil, err + } + return dst[:n], nil +} diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go new file mode 100644 index 0000000000..aeb73f81a1 --- /dev/null +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go @@ -0,0 +1,295 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing +// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf +package bcrypt // import "golang.org/x/crypto/bcrypt" + +// The code is a port of Provos and Mazières's C implementation. +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "fmt" + "io" + "strconv" + + "golang.org/x/crypto/blowfish" +) + +const ( + MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword + MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword + DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword +) + +// The error returned from CompareHashAndPassword when a password and hash do +// not match. +var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") + +// The error returned from CompareHashAndPassword when a hash is too short to +// be a bcrypt hash. +var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") + +// The error returned from CompareHashAndPassword when a hash was created with +// a bcrypt algorithm newer than this implementation. +type HashVersionTooNewError byte + +func (hv HashVersionTooNewError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) +} + +// The error returned from CompareHashAndPassword when a hash starts with something other than '$' +type InvalidHashPrefixError byte + +func (ih InvalidHashPrefixError) Error() string { + return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) +} + +type InvalidCostError int + +func (ic InvalidCostError) Error() string { + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) +} + +const ( + majorVersion = '2' + minorVersion = 'a' + maxSaltSize = 16 + maxCryptedHashSize = 23 + encodedSaltSize = 22 + encodedHashSize = 31 + minHashSize = 59 +) + +// magicCipherData is an IV for the 64 Blowfish encryption calls in +// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. +var magicCipherData = []byte{ + 0x4f, 0x72, 0x70, 0x68, + 0x65, 0x61, 0x6e, 0x42, + 0x65, 0x68, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, + 0x6f, 0x75, 0x62, 0x74, +} + +type hashed struct { + hash []byte + salt []byte + cost int // allowed range is MinCost to MaxCost + major byte + minor byte +} + +// GenerateFromPassword returns the bcrypt hash of the password at the given +// cost. If the cost given is less than MinCost, the cost will be set to +// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, +// to compare the returned hashed password with its cleartext version. +func GenerateFromPassword(password []byte, cost int) ([]byte, error) { + p, err := newFromPassword(password, cost) + if err != nil { + return nil, err + } + return p.Hash(), nil +} + +// CompareHashAndPassword compares a bcrypt hashed password with its possible +// plaintext equivalent. Returns nil on success, or an error on failure. +func CompareHashAndPassword(hashedPassword, password []byte) error { + p, err := newFromHash(hashedPassword) + if err != nil { + return err + } + + otherHash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return err + } + + otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} + if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { + return nil + } + + return ErrMismatchedHashAndPassword +} + +// Cost returns the hashing cost used to create the given hashed +// password. When, in the future, the hashing cost of a password system needs +// to be increased in order to adjust for greater computational power, this +// function allows one to establish which passwords need to be updated. +func Cost(hashedPassword []byte) (int, error) { + p, err := newFromHash(hashedPassword) + if err != nil { + return 0, err + } + return p.cost, nil +} + +func newFromPassword(password []byte, cost int) (*hashed, error) { + if cost < MinCost { + cost = DefaultCost + } + p := new(hashed) + p.major = majorVersion + p.minor = minorVersion + + err := checkCost(cost) + if err != nil { + return nil, err + } + p.cost = cost + + unencodedSalt := make([]byte, maxSaltSize) + _, err = io.ReadFull(rand.Reader, unencodedSalt) + if err != nil { + return nil, err + } + + p.salt = base64Encode(unencodedSalt) + hash, err := bcrypt(password, p.cost, p.salt) + if err != nil { + return nil, err + } + p.hash = hash + return p, err +} + +func newFromHash(hashedSecret []byte) (*hashed, error) { + if len(hashedSecret) < minHashSize { + return nil, ErrHashTooShort + } + p := new(hashed) + n, err := p.decodeVersion(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + n, err = p.decodeCost(hashedSecret) + if err != nil { + return nil, err + } + hashedSecret = hashedSecret[n:] + + // The "+2" is here because we'll have to append at most 2 '=' to the salt + // when base64 decoding it in expensiveBlowfishSetup(). + p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) + copy(p.salt, hashedSecret[:encodedSaltSize]) + + hashedSecret = hashedSecret[encodedSaltSize:] + p.hash = make([]byte, len(hashedSecret)) + copy(p.hash, hashedSecret) + + return p, nil +} + +func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { + cipherData := make([]byte, len(magicCipherData)) + copy(cipherData, magicCipherData) + + c, err := expensiveBlowfishSetup(password, uint32(cost), salt) + if err != nil { + return nil, err + } + + for i := 0; i < 24; i += 8 { + for j := 0; j < 64; j++ { + c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) + } + } + + // Bug compatibility with C bcrypt implementations. We only encode 23 of + // the 24 bytes encrypted. + hsh := base64Encode(cipherData[:maxCryptedHashSize]) + return hsh, nil +} + +func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { + csalt, err := base64Decode(salt) + if err != nil { + return nil, err + } + + // Bug compatibility with C bcrypt implementations. They use the trailing + // NULL in the key string during expansion. + // We copy the key to prevent changing the underlying array. + ckey := append(key[:len(key):len(key)], 0) + + c, err := blowfish.NewSaltedCipher(ckey, csalt) + if err != nil { + return nil, err + } + + var i, rounds uint64 + rounds = 1 << cost + for i = 0; i < rounds; i++ { + blowfish.ExpandKey(ckey, c) + blowfish.ExpandKey(csalt, c) + } + + return c, nil +} + +func (p *hashed) Hash() []byte { + arr := make([]byte, 60) + arr[0] = '$' + arr[1] = p.major + n := 2 + if p.minor != 0 { + arr[2] = p.minor + n = 3 + } + arr[n] = '$' + n++ + copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) + n += 2 + arr[n] = '$' + n++ + copy(arr[n:], p.salt) + n += encodedSaltSize + copy(arr[n:], p.hash) + n += encodedHashSize + return arr[:n] +} + +func (p *hashed) decodeVersion(sbytes []byte) (int, error) { + if sbytes[0] != '$' { + return -1, InvalidHashPrefixError(sbytes[0]) + } + if sbytes[1] > majorVersion { + return -1, HashVersionTooNewError(sbytes[1]) + } + p.major = sbytes[1] + n := 3 + if sbytes[2] != '$' { + p.minor = sbytes[2] + n++ + } + return n, nil +} + +// sbytes should begin where decodeVersion left off. +func (p *hashed) decodeCost(sbytes []byte) (int, error) { + cost, err := strconv.Atoi(string(sbytes[0:2])) + if err != nil { + return -1, err + } + err = checkCost(cost) + if err != nil { + return -1, err + } + p.cost = cost + return 3, nil +} + +func (p *hashed) String() string { + return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) +} + +func checkCost(cost int) error { + if cost < MinCost || cost > MaxCost { + return InvalidCostError(cost) + } + return nil +} diff --git a/vendor/golang.org/x/crypto/blowfish/block.go b/vendor/golang.org/x/crypto/blowfish/block.go new file mode 100644 index 0000000000..9d80f19521 --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/block.go @@ -0,0 +1,159 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blowfish + +// getNextWord returns the next big-endian uint32 value from the byte slice +// at the given position in a circular manner, updating the position. +func getNextWord(b []byte, pos *int) uint32 { + var w uint32 + j := *pos + for i := 0; i < 4; i++ { + w = w<<8 | uint32(b[j]) + j++ + if j >= len(b) { + j = 0 + } + } + *pos = j + return w +} + +// ExpandKey performs a key expansion on the given *Cipher. Specifically, it +// performs the Blowfish algorithm's key schedule which sets up the *Cipher's +// pi and substitution tables for calls to Encrypt. This is used, primarily, +// by the bcrypt package to reuse the Blowfish key schedule during its +// set up. It's unlikely that you need to use this directly. +func ExpandKey(key []byte, c *Cipher) { + j := 0 + for i := 0; i < 18; i++ { + // Using inlined getNextWord for performance. + var d uint32 + for k := 0; k < 4; k++ { + d = d<<8 | uint32(key[j]) + j++ + if j >= len(key) { + j = 0 + } + } + c.p[i] ^= d + } + + var l, r uint32 + for i := 0; i < 18; i += 2 { + l, r = encryptBlock(l, r, c) + c.p[i], c.p[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s0[i], c.s0[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s1[i], c.s1[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s2[i], c.s2[i+1] = l, r + } + for i := 0; i < 256; i += 2 { + l, r = encryptBlock(l, r, c) + c.s3[i], c.s3[i+1] = l, r + } +} + +// This is similar to ExpandKey, but folds the salt during the key +// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero +// salt passed in, reusing ExpandKey turns out to be a place of inefficiency +// and specializing it here is useful. +func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { + j := 0 + for i := 0; i < 18; i++ { + c.p[i] ^= getNextWord(key, &j) + } + + j = 0 + var l, r uint32 + for i := 0; i < 18; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.p[i], c.p[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s0[i], c.s0[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s1[i], c.s1[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s2[i], c.s2[i+1] = l, r + } + + for i := 0; i < 256; i += 2 { + l ^= getNextWord(salt, &j) + r ^= getNextWord(salt, &j) + l, r = encryptBlock(l, r, c) + c.s3[i], c.s3[i+1] = l, r + } +} + +func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { + xl, xr := l, r + xl ^= c.p[0] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] + xr ^= c.p[17] + return xr, xl +} + +func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { + xl, xr := l, r + xl ^= c.p[17] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] + xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] + xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] + xr ^= c.p[0] + return xr, xl +} diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go new file mode 100644 index 0000000000..2641dadd64 --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/cipher.go @@ -0,0 +1,91 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. +package blowfish // import "golang.org/x/crypto/blowfish" + +// The code is a port of Bruce Schneier's C implementation. +// See https://www.schneier.com/blowfish.html. + +import "strconv" + +// The Blowfish block size in bytes. +const BlockSize = 8 + +// A Cipher is an instance of Blowfish encryption using a particular key. +type Cipher struct { + p [18]uint32 + s0, s1, s2, s3 [256]uint32 +} + +type KeySizeError int + +func (k KeySizeError) Error() string { + return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k)) +} + +// NewCipher creates and returns a Cipher. +// The key argument should be the Blowfish key, from 1 to 56 bytes. +func NewCipher(key []byte) (*Cipher, error) { + var result Cipher + if k := len(key); k < 1 || k > 56 { + return nil, KeySizeError(k) + } + initCipher(&result) + ExpandKey(key, &result) + return &result, nil +} + +// NewSaltedCipher creates a returns a Cipher that folds a salt into its key +// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is +// sufficient and desirable. For bcrypt compatibility, the key can be over 56 +// bytes. +func NewSaltedCipher(key, salt []byte) (*Cipher, error) { + if len(salt) == 0 { + return NewCipher(key) + } + var result Cipher + if k := len(key); k < 1 { + return nil, KeySizeError(k) + } + initCipher(&result) + expandKeyWithSalt(key, salt, &result) + return &result, nil +} + +// BlockSize returns the Blowfish block size, 8 bytes. +// It is necessary to satisfy the Block interface in the +// package "crypto/cipher". +func (c *Cipher) BlockSize() int { return BlockSize } + +// Encrypt encrypts the 8-byte buffer src using the key k +// and stores the result in dst. +// Note that for amounts of data larger than a block, +// it is not safe to just call Encrypt on successive blocks; +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). +func (c *Cipher) Encrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + l, r = encryptBlock(l, r, c) + dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) + dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) +} + +// Decrypt decrypts the 8-byte buffer src using the key k +// and stores the result in dst. +func (c *Cipher) Decrypt(dst, src []byte) { + l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) + r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) + l, r = decryptBlock(l, r, c) + dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) + dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) +} + +func initCipher(c *Cipher) { + copy(c.p[0:], p[0:]) + copy(c.s0[0:], s0[0:]) + copy(c.s1[0:], s1[0:]) + copy(c.s2[0:], s2[0:]) + copy(c.s3[0:], s3[0:]) +} diff --git a/vendor/golang.org/x/crypto/blowfish/const.go b/vendor/golang.org/x/crypto/blowfish/const.go new file mode 100644 index 0000000000..d04077595a --- /dev/null +++ b/vendor/golang.org/x/crypto/blowfish/const.go @@ -0,0 +1,199 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The startup permutation array and substitution boxes. +// They are the hexadecimal digits of PI; see: +// https://www.schneier.com/code/constants.txt. + +package blowfish + +var s0 = [256]uint32{ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, + 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, + 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, + 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, + 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, + 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, + 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, + 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, + 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, + 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, + 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, + 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, + 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, + 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, + 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, + 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, + 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, + 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, + 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, + 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, + 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, + 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, +} + +var s1 = [256]uint32{ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, + 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, + 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, + 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, + 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, + 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, + 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, + 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, + 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, + 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, + 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, + 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, + 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, + 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, + 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, + 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, + 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, + 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, + 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, + 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, + 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, + 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, +} + +var s2 = [256]uint32{ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, + 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, + 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, + 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, + 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, + 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, + 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, + 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, + 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, + 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, + 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, + 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, + 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, + 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, + 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, + 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, + 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, + 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, + 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, + 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, + 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, + 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, +} + +var s3 = [256]uint32{ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, + 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, + 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, + 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, + 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, + 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, + 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, + 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, + 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, + 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, + 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, + 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, + 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, + 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, + 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, + 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, + 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, + 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, + 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, + 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, + 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, + 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, +} + +var p = [18]uint32{ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, + 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, +} diff --git a/vendor/yunion.io/x/jsonutils/compond.go b/vendor/yunion.io/x/jsonutils/compond.go new file mode 100644 index 0000000000..296a54e75c --- /dev/null +++ b/vendor/yunion.io/x/jsonutils/compond.go @@ -0,0 +1,14 @@ +package jsonutils + + +func (val *JSONValue) isCompond() bool { + return false +} + +func (val *JSONDict) isCompond() bool { + return true +} + +func (val *JSONArray) isCompond() bool { + return true +} diff --git a/vendor/yunion.io/x/jsonutils/interface.go b/vendor/yunion.io/x/jsonutils/interface.go new file mode 100644 index 0000000000..fee786412e --- /dev/null +++ b/vendor/yunion.io/x/jsonutils/interface.go @@ -0,0 +1,40 @@ +package jsonutils + + +func (self *JSONValue) Interface() interface{} { + return nil +} + +func (self *JSONBool) Interface() interface{} { + return self.data +} + +func (self *JSONInt) Interface() interface{} { + return self.data +} + +func (self *JSONFloat) Interface() interface{} { + return self.data +} + +func (self *JSONString) Interface() interface{} { + return self.data +} + +func (self *JSONArray) Interface() interface{} { + ret := make([]interface{}, len(self.data)) + for i := 0; i < len(self.data); i += 1 { + ret[i] = self.data[i].Interface() + } + return ret +} + +func (self *JSONDict) Interface() interface{} { + mapping := make(map[string]interface{}) + + for k, v := range self.data { + mapping[k] = v.Interface() + } + + return mapping +} diff --git a/vendor/yunion.io/x/jsonutils/jsonutils.go b/vendor/yunion.io/x/jsonutils/jsonutils.go index d3321d1caf..2b9f289cfe 100644 --- a/vendor/yunion.io/x/jsonutils/jsonutils.go +++ b/vendor/yunion.io/x/jsonutils/jsonutils.go @@ -65,6 +65,8 @@ type JSONObject interface { Equals(obj JSONObject) bool unmarshalValue(val reflect.Value) error // IsZero() bool + Interface() interface{} + isCompond() bool } type JSONValue struct { diff --git a/vendor/yunion.io/x/jsonutils/yamlutils.go b/vendor/yunion.io/x/jsonutils/yamlutils.go index 1daf0a63a3..05d9f0d5cb 100644 --- a/vendor/yunion.io/x/jsonutils/yamlutils.go +++ b/vendor/yunion.io/x/jsonutils/yamlutils.go @@ -61,43 +61,49 @@ func parseYAMLDict(lines []string) (map[string]JSONObject, error) { } else { key := lines[i][0:keypos] val := strings.Trim(lines[i][keypos+1:], " ") + if len(val) > 0 && val != "|" { - o, e := Parse([]byte(val)) - if e != nil { - return dict, e - } else { - dict[key] = o - } + dict[key] = NewString(val) i++ } else { + sublines := make([]string, 0) j := i + 1 for j < len(lines) && len(strings.Trim(lines[j], " ")) == 0 { + sublines = append(sublines, "") j++ } - if j >= len(lines) || lines[j][0] != ' ' { - return dict, fmt.Errorf("Illformat") - } - indent := 0 - for indent < len(lines[j]) && lines[j][indent] == ' ' { - indent++ - } - sublines := make([]string, 0) - for j < len(lines) { - if indent >= len(lines[j]) && len(strings.Trim(lines[j], " ")) == 0 { - j++ - } else if indent < len(lines[j]) && len(strings.Trim(lines[j][:indent], " ")) == 0 { - sublines = append(sublines, lines[j][indent:]) - j++ - } else { - break + if j < len(lines) { + if lines[j][0] != ' ' { + return dict, fmt.Errorf("Illformat") + } + + indent := 0 + for indent < len(lines[j]) && lines[j][indent] == ' ' { + indent++ + } + + for j < len(lines) { + if indent >= len(lines[j]) && len(strings.Trim(lines[j], " ")) == 0 { + sublines = append(sublines, "") + j++ + } else if indent < len(lines[j]) && len(strings.Trim(lines[j][:indent], " ")) == 0 { + sublines = append(sublines, lines[j][indent:]) + j++ + } else { + break + } } } - o, e := parseYAMLLines(sublines) - if e != nil { - return dict, e + if val == "|" { + dict[key] = NewString(strings.Join(sublines, "\n")) } else { + o, e := parseYAMLLines(sublines) + if e != nil { + return dict, e + } dict[key] = o } + i = j } } @@ -192,8 +198,11 @@ func (this *JSONDict) yamlLines() []string { var ret = make([]string, 0) for _, key := range this.SortedKeys() { val := this.data[key] + if val.IsZero() { + continue + } lines := val.yamlLines() - if len(lines) == 1 { + if ! val.isCompond() && len(lines) == 1 { ret = append(ret, fmt.Sprintf("%s: %s", key, lines[0])) } else { switch val.(type) { From deda9f70a622c9a6244bab06b419459a2aa9d4ab Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 12 Oct 2018 12:09:35 +0800 Subject: [PATCH 03/10] minor updates --- cmd/climc/shell/servers.go | 4 ++-- pkg/compute/models/quotas.go | 2 +- pkg/mcclient/modules/mod_servers.go | 3 ++- pkg/util/cloudinit/cloudconfig.go | 2 +- pkg/util/cloudinit/cloudconfig_test.go | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index 856edd1d75..3e739b8c36 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -102,13 +102,13 @@ func init() { if e != nil { return e } - var params *jsonutils.JSONDict + + params := jsonutils.NewDict() if len(opts.Key) > 0 { privateKey, e := ioutil.ReadFile(opts.Key) if e != nil { return e } - params = jsonutils.NewDict() params.Add(jsonutils.NewString(string(privateKey)), "private_key") } diff --git a/pkg/compute/models/quotas.go b/pkg/compute/models/quotas.go index ad73a7a1c9..43f9d92247 100644 --- a/pkg/compute/models/quotas.go +++ b/pkg/compute/models/quotas.go @@ -278,7 +278,7 @@ func (self *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error { if sreq.IsolatedDevice > 0 && self.IsolatedDevice > squota.IsolatedDevice { return ErrOutOfIsolatedDevice } - if self.Snapshot > squota.Snapshot { + if sreq.Snapshot > 0 && self.Snapshot > squota.Snapshot { return ErrOutOfSnapshot } return nil diff --git a/pkg/mcclient/modules/mod_servers.go b/pkg/mcclient/modules/mod_servers.go index b73b986178..d13fec5aaf 100644 --- a/pkg/mcclient/modules/mod_servers.go +++ b/pkg/mcclient/modules/mod_servers.go @@ -7,6 +7,7 @@ import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/util/seclib2" + "yunion.io/x/pkg/gotypes" ) type ServerManager struct { @@ -25,7 +26,7 @@ func (this *ServerManager) GetLoginInfo(s *mcclient.ClientSession, id string, pa } var privateKey string - if params != nil { + if params != nil && ! gotypes.IsNil(params) { privateKey, _ = params.GetString("private_key") } diff --git a/pkg/util/cloudinit/cloudconfig.go b/pkg/util/cloudinit/cloudconfig.go index f0c7d99597..1345e06f54 100644 --- a/pkg/util/cloudinit/cloudconfig.go +++ b/pkg/util/cloudinit/cloudconfig.go @@ -4,10 +4,10 @@ import ( "bytes" "encoding/base64" - "github.com/yunionio/jsonutils" "golang.org/x/crypto/bcrypt" "yunion.io/x/log" + "yunion.io/x/jsonutils" "strings" "fmt" "yunion.io/x/pkg/utils" diff --git a/pkg/util/cloudinit/cloudconfig_test.go b/pkg/util/cloudinit/cloudconfig_test.go index 26dd45734a..69e43a4667 100644 --- a/pkg/util/cloudinit/cloudconfig_test.go +++ b/pkg/util/cloudinit/cloudconfig_test.go @@ -17,7 +17,7 @@ func TestSCloudConfig_UserData(t *testing.T) { usr1, usr2, }, - WireFiles: []SWriteFile{ + WriteFiles: []SWriteFile{ file1, file2, }, From df2c4442f8396b9ca4259b8a3f6419e586336e38 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 12 Oct 2018 12:13:12 +0800 Subject: [PATCH 04/10] Force format before build --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ee09d3df04..372dde24df 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ install: prepare_dir done -build: prepare_dir +build: prepare_dir fmt @for PKG in $(CMDS); do \ echo build $$PKG; \ $(GO_BUILD) -o $(BIN_DIR)/`basename $${PKG}` $$PKG; \ @@ -58,11 +58,11 @@ test: prepare_dir done -cmd/%: prepare_dir +cmd/%: prepare_dir fmt $(GO_BUILD) -o $(BIN_DIR)/$(shell basename $@) $(REPO_PREFIX)/$@ -pkg/%: prepare_dir +pkg/%: prepare_dir fmt $(GO_INSTALL) $(REPO_PREFIX)/$@ From b17b24b232b1e7f8968b0ec9526e941cc5519536 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 12 Oct 2018 12:13:35 +0800 Subject: [PATCH 05/10] Update format --- cmd/climc/shell/account_balances.go | 2 +- cmd/climc/shell/ansible.go | 10 ++++----- cmd/climc/shell/capabilities.go | 1 - cmd/climc/shell/isolatedevices.go | 2 +- cmd/climc/shell/servers.go | 4 ++-- cmd/climc/shell/specs.go | 2 +- cmd/climc/shell/utils.go | 4 ++-- pkg/cloudcommon/validators/choices.go | 2 +- pkg/compute/guestdrivers/aliyun.go | 6 +++--- pkg/compute/guestdrivers/azure.go | 4 ++-- pkg/compute/models/billingresource.go | 6 +++--- pkg/compute/models/guestnetworks.go | 2 +- pkg/compute/models/guests.go | 2 +- pkg/compute/models/keypairs.go | 16 +++++++------- pkg/compute/models/quotas.go | 2 +- pkg/compute/models/sshkeypairs.go | 6 +++--- pkg/compute/models/wires.go | 2 +- pkg/mcclient/modules/mod_parameters.go | 2 +- pkg/mcclient/modules/mod_projecthosts.go | 4 ---- pkg/mcclient/modules/mod_res_results.go | 2 +- pkg/mcclient/modules/mod_servers.go | 4 ++-- pkg/mcclient/options/servers.go | 2 +- pkg/util/aliyun/disk.go | 3 +-- pkg/util/aliyun/vswitch.go | 2 +- pkg/util/azure/host.go | 2 +- pkg/util/azure/instance.go | 2 +- pkg/util/cloudinit/cloudconfig.go | 26 +++++++++++------------ pkg/util/esxi/host.go | 2 +- pkg/util/esxi/virtualmachine.go | 2 +- pkg/util/excelutils/excelutils.go | 20 +++++++++--------- pkg/util/excelutils/excelutils_test.go | 27 ++++++++++++------------ pkg/util/seclib2/aes.go | 4 ++-- pkg/util/seclib2/crypto.go | 13 ++++++------ pkg/util/seclib2/seclib.go | 8 +++---- pkg/util/seclib2/seclib_test.go | 8 +++---- pkg/util/seclib2/ssh.go | 14 ++++++------ pkg/util/seclib2/ssh_test.go | 11 +++++----- pkg/yunionconf/models/initdb.go | 2 +- pkg/yunionconf/options/options.go | 2 +- pkg/yunionconf/service/service.go | 2 +- 40 files changed, 113 insertions(+), 124 deletions(-) diff --git a/cmd/climc/shell/account_balances.go b/cmd/climc/shell/account_balances.go index 4346049bcb..377209a4c1 100644 --- a/cmd/climc/shell/account_balances.go +++ b/cmd/climc/shell/account_balances.go @@ -14,7 +14,7 @@ func init() { StatMonth string `help:"stat_month of the query"` StartDate string `help:"start_date of the query"` EndDate string `help:"end_date of the query"` - QueryType string `help:"query_type of the query"` + QueryType string `help:"query_type of the query"` Platform string `help:"platform of the query"` ProjectId string `help:"project_id of the query"` } diff --git a/cmd/climc/shell/ansible.go b/cmd/climc/shell/ansible.go index 38ba093498..69dbec5ea7 100644 --- a/cmd/climc/shell/ansible.go +++ b/cmd/climc/shell/ansible.go @@ -11,11 +11,11 @@ import ( ) type AnsibleHostsOptions struct { - List bool `help:"List all ansible inventory"` - Host string `help:"List of a host"` + List bool `help:"List all ansible inventory"` + Host string `help:"List of a host"` PrivateKey string `help:"path to private key to use for ansible"` - Port int `help:"optional port, if port is not 22"` - User string `help:"username to try"` + Port int `help:"optional port, if port is not 22"` + User string `help:"username to try"` UserBecome string `help:"username to sudo"` } @@ -35,7 +35,6 @@ func serverGetNameIP(srv jsonutils.JSONObject) (string, string, error) { return host, ipList[0], nil } - func doList(s *mcclient.ClientSession, args *AnsibleHostsOptions) error { hostVars := jsonutils.NewDict() hosts := jsonutils.NewArray() @@ -86,7 +85,6 @@ func doList(s *mcclient.ClientSession, args *AnsibleHostsOptions) error { return nil } - func doHost(s *mcclient.ClientSession, host string, args *AnsibleHostsOptions) error { srv, err := modules.Servers.Get(s, host, nil) if err != nil { diff --git a/cmd/climc/shell/capabilities.go b/cmd/climc/shell/capabilities.go index a1a02ff842..d51cfe763b 100644 --- a/cmd/climc/shell/capabilities.go +++ b/cmd/climc/shell/capabilities.go @@ -7,7 +7,6 @@ import ( func init() { type CapabilitiesOptions struct { - } R(&CapabilitiesOptions{}, "capabilities", "Show backend capabilities", func(s *mcclient.ClientSession, args *CapabilitiesOptions) error { result, err := modules.Capabilities.List(s, nil) diff --git a/cmd/climc/shell/isolatedevices.go b/cmd/climc/shell/isolatedevices.go index 48dc75c5e9..72515beb51 100644 --- a/cmd/climc/shell/isolatedevices.go +++ b/cmd/climc/shell/isolatedevices.go @@ -13,7 +13,7 @@ func init() { Unused bool `help:"Only show unused devices"` Gpu bool `help:"Only show gpu devices"` Host string `help:"Host ID or Name"` - Zone string `help:"Zone ID or Name"` + Zone string `help:"Zone ID or Name"` } R(&DeviceListOptions{}, "isolated-device-list", "List isolated devices like GPU", func(s *mcclient.ClientSession, args *DeviceListOptions) error { var params *jsonutils.JSONDict diff --git a/cmd/climc/shell/servers.go b/cmd/climc/shell/servers.go index 3e739b8c36..0f947d663a 100644 --- a/cmd/climc/shell/servers.go +++ b/cmd/climc/shell/servers.go @@ -3,11 +3,11 @@ package shell import ( "fmt" + "io/ioutil" "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/options" - "io/ioutil" ) func init() { @@ -488,7 +488,7 @@ func init() { }) type ServerUserDataOptions struct { - ID string `help:"ID or name of server"` + ID string `help:"ID or name of server"` FILE string `help:"Path to user data file"` } R(&ServerUserDataOptions{}, "server-set-user-data", "Update server user_data", func(s *mcclient.ClientSession, args *ServerUserDataOptions) error { diff --git a/cmd/climc/shell/specs.go b/cmd/climc/shell/specs.go index 68f8f1e9aa..011ba7bee7 100644 --- a/cmd/climc/shell/specs.go +++ b/cmd/climc/shell/specs.go @@ -15,7 +15,7 @@ func init() { Model string `help:"Specified model specs" choices:"hosts|isolated_devices|guests"` HostType string `help:"Host type filter" choices:"baremetal|hypervisor|esxi|kubelet|hyperv"` Gpu bool `help:"Only show gpu devices"` - Zone string `help:"Filter by zone id or name"` + Zone string `help:"Filter by zone id or name"` } R(&ListOptions{}, "spec", "List all kinds of model specs", func(s *mcclient.ClientSession, args *ListOptions) error { var params *jsonutils.JSONDict diff --git a/cmd/climc/shell/utils.go b/cmd/climc/shell/utils.go index b66d7ee548..67061edbe6 100644 --- a/cmd/climc/shell/utils.go +++ b/cmd/climc/shell/utils.go @@ -5,8 +5,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient/modules" - "yunion.io/x/onecloud/pkg/util/printutils" "yunion.io/x/onecloud/pkg/util/excelutils" + "yunion.io/x/onecloud/pkg/util/printutils" ) func printList(list *modules.ListResult, columns []string) { @@ -35,7 +35,7 @@ func exportList(list *modules.ListResult, file string, exportKeys string, export if len(exportKeys) > 0 { keys = strings.Split(exportKeys, ",") texts = strings.Split(exportTexts, ",") - }else { + } else { keys = columns texts = columns } diff --git a/pkg/cloudcommon/validators/choices.go b/pkg/cloudcommon/validators/choices.go index 83188a7ef0..1ad80cba49 100644 --- a/pkg/cloudcommon/validators/choices.go +++ b/pkg/cloudcommon/validators/choices.go @@ -23,7 +23,7 @@ func (cs Choices) Has(choice string) bool { func (cs Choices) String() string { choices := make([]string, len(cs)) i := 0 - for choice, _ := range cs { + for choice := range cs { choices[i] = choice i++ } diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 890039b006..7473051ffb 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -15,8 +15,8 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/util/seclib2" "yunion.io/x/onecloud/pkg/util/cloudinit" + "yunion.io/x/onecloud/pkg/util/seclib2" ) type SAliyunGuestDriver struct { @@ -151,10 +151,10 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu } cloudConfig := cloudinit.SCloudConfig{ - Users: []cloudinit.SUser { + Users: []cloudinit.SUser{ { Name: "root", - SshAuthorizedKeys: []string { + SshAuthorizedKeys: []string{ adminPublicKey, projectPublicKey, }, diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 28bc67a032..4106490efa 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -83,10 +83,10 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue } cloudConfig := cloudinit.SCloudConfig{ - Users: []cloudinit.SUser { + Users: []cloudinit.SUser{ { Name: "root", - SshAuthorizedKeys: []string { + SshAuthorizedKeys: []string{ adminPublicKey, projectPublicKey, }, diff --git a/pkg/compute/models/billingresource.go b/pkg/compute/models/billingresource.go index 612919afdc..8633f4b3a1 100644 --- a/pkg/compute/models/billingresource.go +++ b/pkg/compute/models/billingresource.go @@ -4,12 +4,12 @@ import "time" const ( BILLING_TYPE_POSTPAID = "postpaid" - BILLING_TYPE_PREPAID = "prepaid" + BILLING_TYPE_PREPAID = "prepaid" ) type SBillingResourceBase struct { - BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional"` - ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"` + BillingType string `width:"36" charset:"ascii" nullable:"true" default:"postpaid" list:"user" create:"optional"` + ExpiredAt time.Time `nullable:"true" list:"user" create:"optional"` } func (self *SBillingResourceBase) GetChargeType() string { diff --git a/pkg/compute/models/guestnetworks.go b/pkg/compute/models/guestnetworks.go index b2cc9b7df5..0f951c74dc 100644 --- a/pkg/compute/models/guestnetworks.go +++ b/pkg/compute/models/guestnetworks.go @@ -578,4 +578,4 @@ func (manager *SGuestnetworkManager) getRecentlyReleasedIPAddresses(networkId st } } return ret -} \ No newline at end of file +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 208396d5b4..d7d91d11de 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -24,6 +24,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" + "encoding/base64" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" @@ -37,7 +38,6 @@ import ( "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/seclib2" - "encoding/base64" ) const ( diff --git a/pkg/compute/models/keypairs.go b/pkg/compute/models/keypairs.go index fa7973788f..82ece4aa91 100644 --- a/pkg/compute/models/keypairs.go +++ b/pkg/compute/models/keypairs.go @@ -3,15 +3,15 @@ package models import ( "context" - "yunion.io/x/log" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/sqlchemy" + "golang.org/x/crypto/ssh" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/seclib2" - "golang.org/x/crypto/ssh" "yunion.io/x/pkg/utils" ) @@ -29,10 +29,10 @@ type SKeypair struct { db.SStandaloneResourceBase Scheme string `width:"12" charset:"ascii" nullable:"true" default:"RSA" list:"user" create:"required"` // Column(VARCHAR(length=12, charset='ascii'), nullable=True, default='RSA') - Fingerprint string `width:"48" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=48, charset='ascii'), nullable=False) - PrivateKey string `width:"2048" charset:"ascii" nullable:"false" create:"optional"` // Column(VARCHAR(length=2048, charset='ascii'), nullable=False) - PublicKey string `width:"1024" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=1024, charset='ascii'), nullable=False) - OwnerId string `width:"128" charset:"ascii" index:"true" nullable:"false" create:"required"` // Column(VARCHAR(length=36, charset='ascii'), index=True, nullable=False) + Fingerprint string `width:"48" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=48, charset='ascii'), nullable=False) + PrivateKey string `width:"2048" charset:"ascii" nullable:"false" create:"optional"` // Column(VARCHAR(length=2048, charset='ascii'), nullable=False) + PublicKey string `width:"1024" charset:"ascii" nullable:"false" list:"user" create:"required"` // Column(VARCHAR(length=1024, charset='ascii'), nullable=False) + OwnerId string `width:"128" charset:"ascii" index:"true" nullable:"false" create:"required"` // Column(VARCHAR(length=36, charset='ascii'), index=True, nullable=False) } func (manager *SKeypairManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) { @@ -109,7 +109,7 @@ func (manager *SKeypairManager) ValidateCreateData(ctx context.Context, userCred if len(publicKey) == 0 { scheme, _ := data.GetString("scheme") if len(scheme) > 0 { - if ! utils.IsInStringArray(scheme, []string{"RSA", "DSA"}) { + if !utils.IsInStringArray(scheme, []string{"RSA", "DSA"}) { return nil, httperrors.NewInputParameterError("Unsupported scheme %s", scheme) } } else { @@ -195,4 +195,4 @@ func (keypair *SKeypair) GetDetailsPrivatekey(ctx context.Context, userCred mccl db.OpsLog.LogEvent(keypair, db.ACT_FETCH, nil, userCred) } return retval, nil -} \ No newline at end of file +} diff --git a/pkg/compute/models/quotas.go b/pkg/compute/models/quotas.go index 43f9d92247..152095735e 100644 --- a/pkg/compute/models/quotas.go +++ b/pkg/compute/models/quotas.go @@ -7,9 +7,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/pkg/tristate" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/pkg/tristate" ) var QuotaManager *quotas.SQuotaManager diff --git a/pkg/compute/models/sshkeypairs.go b/pkg/compute/models/sshkeypairs.go index 967e8b1055..f226230540 100644 --- a/pkg/compute/models/sshkeypairs.go +++ b/pkg/compute/models/sshkeypairs.go @@ -3,9 +3,9 @@ package models import ( "context" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/seclib2" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/mcclient/auth" ) const ( @@ -16,7 +16,7 @@ const ( sshPublicKey = "project-ssh-public-key" ) -func _getKeys(ctx context.Context, tenantId string, privateKey, publicKey string) (string, string, error) { +func _getKeys(ctx context.Context, tenantId string, privateKey, publicKey string) (string, string, error) { tenant, err := db.TenantCacheManager.FetchTenantById(ctx, tenantId) if err != nil { return "", "", err @@ -41,4 +41,4 @@ func getSshProjectKeypair(ctx context.Context, tenantId string) (string, string, func getSshAdminKeypair(ctx context.Context) (string, string, error) { userCred := auth.AdminCredential() return _getKeys(ctx, userCred.GetProjectId(), sshAdminPrivateKey, sshAdminPublicKey) -} \ No newline at end of file +} diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index 45f93b10bb..56883ff6bd 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -605,4 +605,4 @@ func (self *SWire) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict } } return extra -} \ No newline at end of file +} diff --git a/pkg/mcclient/modules/mod_parameters.go b/pkg/mcclient/modules/mod_parameters.go index dad5bfe83d..cea308a80b 100644 --- a/pkg/mcclient/modules/mod_parameters.go +++ b/pkg/mcclient/modules/mod_parameters.go @@ -14,4 +14,4 @@ func init() { []string{"namespace", "namespace_id", "created_by", "updated_by"}, )} register(&Parameters) -} \ No newline at end of file +} diff --git a/pkg/mcclient/modules/mod_projecthosts.go b/pkg/mcclient/modules/mod_projecthosts.go index 3b93b2a7e7..8bcf66cadf 100644 --- a/pkg/mcclient/modules/mod_projecthosts.go +++ b/pkg/mcclient/modules/mod_projecthosts.go @@ -1,9 +1,5 @@ package modules -import ( - -) - type ProjectNodeManager struct { ResourceManager } diff --git a/pkg/mcclient/modules/mod_res_results.go b/pkg/mcclient/modules/mod_res_results.go index 35aaae8a6b..bfa28eb628 100644 --- a/pkg/mcclient/modules/mod_res_results.go +++ b/pkg/mcclient/modules/mod_res_results.go @@ -7,7 +7,7 @@ var ( func init() { ResResults = NewMeterManager("res_result", "res_results", []string{"res_id", "res_name", "cpu", "mem", "sys_disk", "data_disk", "ips", "res_type", "band_width", "os_distribution", "os_version", "platform", "region_id", - "project_name", "user_name", "start_time", "end_time", "time_length", "cpu_amount", "mem_amount", "disk_amount", "baremetal_amount", "gpu_amount", "res_fee"}, + "project_name", "user_name", "start_time", "end_time", "time_length", "cpu_amount", "mem_amount", "disk_amount", "baremetal_amount", "gpu_amount", "res_fee"}, []string{}, ) register(&ResResults) diff --git a/pkg/mcclient/modules/mod_servers.go b/pkg/mcclient/modules/mod_servers.go index d13fec5aaf..4515c97c12 100644 --- a/pkg/mcclient/modules/mod_servers.go +++ b/pkg/mcclient/modules/mod_servers.go @@ -5,9 +5,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/util/seclib2" "yunion.io/x/pkg/gotypes" + "yunion.io/x/pkg/utils" ) type ServerManager struct { @@ -26,7 +26,7 @@ func (this *ServerManager) GetLoginInfo(s *mcclient.ClientSession, id string, pa } var privateKey string - if params != nil && ! gotypes.IsNil(params) { + if params != nil && !gotypes.IsNil(params) { privateKey, _ = params.GetString("private_key") } diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index bb5be54996..3d84e591c2 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -32,7 +32,7 @@ type ServerIdOptions struct { } type ServerLoginInfoOptions struct { - ID string `help:"ID or name of the server" json:"-"` + ID string `help:"ID or name of the server" json:"-"` Key string `help:"File name of private key, if password is encrypted by key"` } diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index ab592b2c5e..d71f9f44b1 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -358,7 +358,6 @@ func (self *SDisk) Reset(snapshotId string) error { return self.storage.zone.region.resetDisk(self.DiskId, snapshotId) } - func (self *SDisk) GetBillingType() string { switch self.DiskChargeType { case PrePaidInstanceChargeType: @@ -372,4 +371,4 @@ func (self *SDisk) GetBillingType() string { func (self *SDisk) GetExpiredAt() time.Time { return self.ExpiredTime -} \ No newline at end of file +} diff --git a/pkg/util/aliyun/vswitch.go b/pkg/util/aliyun/vswitch.go index 02a1cf1039..9b93a16603 100644 --- a/pkg/util/aliyun/vswitch.go +++ b/pkg/util/aliyun/vswitch.go @@ -155,4 +155,4 @@ func (self *SVSwitch) Delete() error { func (self *SVSwitch) GetAllocTimeoutSeconds() int { return 120 // 2 minutes -} \ No newline at end of file +} diff --git a/pkg/util/azure/host.go b/pkg/util/azure/host.go index 30b18a39ac..cfcf396fe9 100644 --- a/pkg/util/azure/host.go +++ b/pkg/util/azure/host.go @@ -119,7 +119,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int, cpu int // //StorageURI: // }, // } - sshKeys := []compute.SSHPublicKey{compute.SSHPublicKey{KeyData: &publicKey}} + sshKeys := []compute.SSHPublicKey{{KeyData: &publicKey}} properties := compute.VirtualMachineProperties{ HardwareProfile: &compute.HardwareProfile{}, StorageProfile: &compute.StorageProfile{ diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index a7d9a3e39c..fba0af7994 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -565,7 +565,7 @@ func (region *SRegion) ReplaceSystemDisk(instanceId, imageId, passwd, publicKey } else { osType := compute.OperatingSystemTypes(image.GetOsType()) disk, _ := region.GetDisk(diskId) - sshKeys := []compute.SSHPublicKey{compute.SSHPublicKey{KeyData: &publicKey}} + sshKeys := []compute.SSHPublicKey{{KeyData: &publicKey}} params := compute.VirtualMachineUpdate{ VirtualMachineProperties: &compute.VirtualMachineProperties{ StorageProfile: &compute.StorageProfile{ diff --git a/pkg/util/cloudinit/cloudconfig.go b/pkg/util/cloudinit/cloudconfig.go index 1345e06f54..4fc1ef7ba9 100644 --- a/pkg/util/cloudinit/cloudconfig.go +++ b/pkg/util/cloudinit/cloudconfig.go @@ -6,10 +6,10 @@ import ( "golang.org/x/crypto/bcrypt" - "yunion.io/x/log" - "yunion.io/x/jsonutils" - "strings" "fmt" + "strings" + "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/utils" ) @@ -42,12 +42,12 @@ type SPhoneHome struct { } type SCloudConfig struct { - Users []SUser + Users []SUser WriteFiles []SWriteFile - Runcmd []string - Bootcmd []string - Packages []string - PhoneHome *SPhoneHome + Runcmd []string + Bootcmd []string + Packages []string + PhoneHome *SPhoneHome } func NewWriteFile(path string, content string, perm string, owner string, isBase64 bool) SWriteFile { @@ -109,7 +109,7 @@ func ParseUserDataBase64(b64data string) (*SCloudConfig, error) { } func ParseUserData(data string) (*SCloudConfig, error) { - if ! strings.HasPrefix(data, CLOUD_CONFIG_HEADER) { + if !strings.HasPrefix(data, CLOUD_CONFIG_HEADER) { msg := "invalid userdata, not starting with #cloud-config" log.Errorf(msg) return nil, fmt.Errorf(msg) @@ -162,19 +162,19 @@ func (conf *SCloudConfig) MergeWriteFile(f SWriteFile, replace bool) { } func (conf *SCloudConfig) MergeRuncmd(cmd string) { - if ! utils.IsInStringArray(cmd, conf.Runcmd) { + if !utils.IsInStringArray(cmd, conf.Runcmd) { conf.Runcmd = append(conf.Runcmd, cmd) } } func (conf *SCloudConfig) MergeBootcmd(cmd string) { - if ! utils.IsInStringArray(cmd, conf.Bootcmd) { + if !utils.IsInStringArray(cmd, conf.Bootcmd) { conf.Bootcmd = append(conf.Bootcmd, cmd) } } func (conf *SCloudConfig) MergePackage(pkg string) { - if ! utils.IsInStringArray(pkg, conf.Packages) { + if !utils.IsInStringArray(pkg, conf.Packages) { conf.Packages = append(conf.Packages, pkg) } } @@ -195,4 +195,4 @@ func (conf *SCloudConfig) Merge(conf2 *SCloudConfig) { for _, p := range conf2.Packages { conf.MergePackage(p) } -} \ No newline at end of file +} diff --git a/pkg/util/esxi/host.go b/pkg/util/esxi/host.go index dc8c270ff8..2ab2bd5350 100644 --- a/pkg/util/esxi/host.go +++ b/pkg/util/esxi/host.go @@ -361,4 +361,4 @@ func (self *SHost) CreateVM(name string, imgId string, sysDiskSize int, cpu int, passwd string, storageType string, diskSizes []int, publicKey string, secGrpId string, userData string) (cloudprovider.ICloudVM, error) { log.Debugf("CreateVM") return nil, cloudprovider.ErrNotImplemented -} \ No newline at end of file +} diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index 680a28c654..a4ef5dce3a 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -244,4 +244,4 @@ func (self *SVirtualMachine) GetBillingType() string { func (self *SVirtualMachine) GetExpiredAt() time.Time { return time.Time{} -} \ No newline at end of file +} diff --git a/pkg/util/excelutils/excelutils.go b/pkg/util/excelutils/excelutils.go index f5c1f487d6..3e8cd0f65b 100644 --- a/pkg/util/excelutils/excelutils.go +++ b/pkg/util/excelutils/excelutils.go @@ -1,9 +1,9 @@ package excelutils import ( - "io" "bytes" "fmt" + "io" "os" "github.com/360EntSecGroup-Skylar/excelize" @@ -21,7 +21,7 @@ func decimalBaseMaxWidth(decNum int, base int) int { } width := 0 for decNum > 0 { - decNum = decNum/base + decNum = decNum / base width += 1 } return width @@ -29,9 +29,9 @@ func decimalBaseMaxWidth(decNum int, base int) int { func decimalBaseN(decNum int, base int, width int) (int, int) { b := 1 - for i := 0; i < width - 1; i += 1 { - decNum = decNum/base - b = b*base + for i := 0; i < width-1; i += 1 { + decNum = decNum / base + b = b * base } return decNum, b } @@ -41,8 +41,8 @@ func decimal2Base(decNum int, base int) []int { ret := make([]int, width) for i := width; i > 0; i -= 1 { ith, divider := decimalBaseN(decNum, base, i) - decNum -= ith*divider - ret[width - i] = ith + decNum -= ith * divider + ret[width-i] = ith } return ret } @@ -84,18 +84,18 @@ func Export(data []jsonutils.JSONObject, keys []string, texts []string, writer i exportHeader(xlsx, texts, 1) for i := 0; i < len(data); i += 1 { - exportRow(xlsx, data[i], keys, i + 2) + exportRow(xlsx, data[i], keys, i+2) } return xlsx.Write(writer) } func ExportFile(data []jsonutils.JSONObject, keys []string, texts []string, filename string) error { - writer, err:= os.Create(filename) + writer, err := os.Create(filename) if err != nil { return err } defer writer.Close() return Export(data, keys, texts, writer) -} \ No newline at end of file +} diff --git a/pkg/util/excelutils/excelutils_test.go b/pkg/util/excelutils/excelutils_test.go index 548c9d5eff..c03e408a87 100644 --- a/pkg/util/excelutils/excelutils_test.go +++ b/pkg/util/excelutils/excelutils_test.go @@ -2,7 +2,6 @@ package excelutils import "testing" - func arrayEqual(a1, a2 []int) bool { if len(a1) != len(a2) { return false @@ -17,10 +16,10 @@ func arrayEqual(a1, a2 []int) bool { func TestDecimalBaseMaxWidth(t *testing.T) { cases := []struct { - decIn int + decIn int baseIn int - want int - } { + want int + }{ {100, 10, 3}, {16, 16, 2}, {15, 16, 1}, @@ -33,12 +32,12 @@ func TestDecimalBaseMaxWidth(t *testing.T) { } cases2 := []struct { - decIn int + decIn int baseIn int - width int - want int - want2 int - } { + width int + want int + want2 int + }{ {100, 10, 3, 1, 100}, {16, 16, 2, 1, 16}, {15, 16, 1, 15, 1}, @@ -52,10 +51,10 @@ func TestDecimalBaseMaxWidth(t *testing.T) { } cases3 := []struct { - decIn int + decIn int baseIn int - want []int - } { + want []int + }{ {100, 10, []int{1, 0, 0}}, {16, 16, []int{1, 0}}, {0, 16, []int{0}}, @@ -76,8 +75,8 @@ func TestDecimalBaseMaxWidth(t *testing.T) { cases4 := []struct { decIn int - want string - } { + want string + }{ {0, "A"}, {1, "B"}, {25, "Z"}, diff --git a/pkg/util/seclib2/aes.go b/pkg/util/seclib2/aes.go index 527817c0ad..dccffa452a 100644 --- a/pkg/util/seclib2/aes.go +++ b/pkg/util/seclib2/aes.go @@ -1,11 +1,11 @@ package seclib2 import ( - "crypto/cipher" "crypto/aes" + "crypto/cipher" + "crypto/rand" "fmt" "io" - "crypto/rand" ) // https://stackoverflow.com/questions/23897809/different-results-in-go-and-pycrypto-when-using-aes-cfb diff --git a/pkg/util/seclib2/crypto.go b/pkg/util/seclib2/crypto.go index 57af747284..7e15b58509 100644 --- a/pkg/util/seclib2/crypto.go +++ b/pkg/util/seclib2/crypto.go @@ -1,22 +1,22 @@ package seclib2 import ( - "crypto/rsa" "crypto/rand" + "crypto/rsa" "crypto/sha1" "golang.org/x/crypto/ssh" - "yunion.io/x/log" - "fmt" + "crypto" "crypto/dsa" "crypto/ecdsa" "encoding/base64" - "crypto" + "fmt" + "yunion.io/x/log" ) func exportSshPublicKey(pubkey interface{}) ([]byte, error) { - pub, err:= ssh.NewPublicKey(pubkey) + pub, err := ssh.NewPublicKey(pubkey) if err != nil { return nil, err } @@ -43,7 +43,6 @@ func ssh2ecdsaPublicKey(key ssh.PublicKey) *ecdsa.PublicKey { return cryptoKey.(*ecdsa.PublicKey) } - func Encrypt(publicKey, origData []byte) ([]byte, error) { pub, _, _, _, err := ssh.ParseAuthorizedKey(publicKey) if err != nil { @@ -115,4 +114,4 @@ func DecryptBase64(privateKey string, secret string) (string, error) { return "", err } return string(msgBytes), nil -} \ No newline at end of file +} diff --git a/pkg/util/seclib2/seclib.go b/pkg/util/seclib2/seclib.go index 017cc307aa..c83a9aea00 100644 --- a/pkg/util/seclib2/seclib.go +++ b/pkg/util/seclib2/seclib.go @@ -13,17 +13,17 @@ const ( UPPERS = "ABCDEFGHJKMNPRSTUVWXYZ" PUNC = "()~@#$%^&*-+={}[]:;<>,.?/" - ALL_DIGITS = "0123456789" + ALL_DIGITS = "0123456789" ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz" ALL_UPPERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - ALL_PUNC = "~`!@#$%^&*()-_=+[]{}|:';\",./<>?" + ALL_PUNC = "~`!@#$%^&*()-_=+[]{}|:';\",./<>?" ) type PasswordStrength struct { - Digits int + Digits int Lowercases int Uppercases int - Punctuats int + Punctuats int } var CHARS = fmt.Sprintf("%s%s%s%s", DIGITS, LETTERS, UPPERS, PUNC) diff --git a/pkg/util/seclib2/seclib_test.go b/pkg/util/seclib2/seclib_test.go index 9921aa09fb..cab70f211b 100644 --- a/pkg/util/seclib2/seclib_test.go +++ b/pkg/util/seclib2/seclib_test.go @@ -1,8 +1,8 @@ package seclib2 import ( - "testing" "math/rand" + "testing" "time" ) @@ -12,10 +12,10 @@ func TestRandomPassword2(t *testing.T) { } func TestMeetComplxity(t *testing.T) { - cases := [] struct { - in string + cases := []struct { + in string want bool - } { + }{ {"123456", false}, {"123abcABC!@#", true}, } diff --git a/pkg/util/seclib2/ssh.go b/pkg/util/seclib2/ssh.go index 05f57c6fb2..0019c0d6f7 100644 --- a/pkg/util/seclib2/ssh.go +++ b/pkg/util/seclib2/ssh.go @@ -1,17 +1,17 @@ package seclib2 import ( - "crypto/rsa" "crypto/rand" - "encoding/pem" + "crypto/rsa" "crypto/x509" + "encoding/pem" - "golang.org/x/crypto/ssh" "crypto/dsa" + "golang.org/x/crypto/ssh" - "yunion.io/x/log" "encoding/asn1" "math/big" + "yunion.io/x/log" ) func GenerateRSASSHKeypair() (string, string, error) { @@ -90,8 +90,8 @@ func GetPublicKeyScheme(pubkey ssh.PublicKey) string { return "DSA" case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: return "ECDSA" - // case ssh.KeyAlgoED25519: - // return "ED" + // case ssh.KeyAlgoED25519: + // return "ED" } return "UNKNOWN" -} \ No newline at end of file +} diff --git a/pkg/util/seclib2/ssh_test.go b/pkg/util/seclib2/ssh_test.go index fcafae94b1..0672b7ce41 100644 --- a/pkg/util/seclib2/ssh_test.go +++ b/pkg/util/seclib2/ssh_test.go @@ -1,22 +1,21 @@ package seclib2 import ( - "testing" - "encoding/pem" "crypto/x509" + "encoding/pem" "fmt" "golang.org/x/crypto/ssh" + "testing" ) func TestGenerateRSASSHKeypair(t *testing.T) { - priv, pub , _ := GenerateRSASSHKeypair() + priv, pub, _ := GenerateRSASSHKeypair() t.Logf("%s", priv) t.Logf("%s", pub) } - func TestGenerateDSASSHKeypair(t *testing.T) { - priv, pub , _ := GenerateDSASSHKeypair() + priv, pub, _ := GenerateDSASSHKeypair() t.Logf("%s", priv) t.Logf("%s", pub) } @@ -150,4 +149,4 @@ func TestDsaDecryptEncrypt(t *testing.T) { t.Errorf("rsa decrypt/encrypt error! %s != %s", secret2, secret) return } -} \ No newline at end of file +} diff --git a/pkg/yunionconf/models/initdb.go b/pkg/yunionconf/models/initdb.go index 29e63b6006..caa5cad49c 100644 --- a/pkg/yunionconf/models/initdb.go +++ b/pkg/yunionconf/models/initdb.go @@ -16,4 +16,4 @@ func InitDB() error { } } return nil -} \ No newline at end of file +} diff --git a/pkg/yunionconf/options/options.go b/pkg/yunionconf/options/options.go index edf1773e82..009856d54e 100644 --- a/pkg/yunionconf/options/options.go +++ b/pkg/yunionconf/options/options.go @@ -8,4 +8,4 @@ type YunionConfOptions struct { var ( Options YunionConfOptions -) \ No newline at end of file +) diff --git a/pkg/yunionconf/service/service.go b/pkg/yunionconf/service/service.go index a83c89a6d5..ad43746fa1 100644 --- a/pkg/yunionconf/service/service.go +++ b/pkg/yunionconf/service/service.go @@ -37,4 +37,4 @@ func StartService() { log.Errorf("InitDB fail: %s", err) } } -} \ No newline at end of file +} From 383ec5966a23a1f9c3826d25fef4bcbc75df8639 Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Fri, 12 Oct 2018 17:50:00 +0800 Subject: [PATCH 06/10] add snapshot details --- cmd/climc/shell/disks.go | 8 ++++++-- pkg/compute/models/disks.go | 19 ++++++++++++------- pkg/compute/models/guests.go | 2 +- pkg/compute/models/quotas.go | 4 ++-- pkg/compute/models/snapshots.go | 26 ++++++++++++++++++++++++++ pkg/compute/tasks/disk_reset_task.go | 16 ++++++++++++++++ pkg/mcclient/modules/mod_snapshots.go | 2 +- 7 files changed, 64 insertions(+), 13 deletions(-) diff --git a/cmd/climc/shell/disks.go b/cmd/climc/shell/disks.go index 716d557c08..7d239376b0 100644 --- a/cmd/climc/shell/disks.go +++ b/cmd/climc/shell/disks.go @@ -202,12 +202,16 @@ func init() { return nil }) type DiskResetOptions struct { - DISK string `help:"ID or name of disk"` - SNAPSHOT string `help:"snapshots ID of disk` + DISK string `help:"ID or name of disk"` + SNAPSHOT string `help:"snapshots ID of disk` + AutoStart bool `help:"Autostart guest"` } R(&DiskResetOptions{}, "disk-reset", "Resize a disk", func(s *mcclient.ClientSession, args *DiskResetOptions) error { params := jsonutils.NewDict() params.Add(jsonutils.NewString(args.SNAPSHOT), "snapshot_id") + if args.AutoStart { + params.Add(jsonutils.JSONTrue, "auto_start") + } disk, err := modules.Disks.PerformAction(s, args.DISK, "disk-reset", params) if err != nil { return err diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 5cc92da4f2..c5d872f206 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -38,6 +38,7 @@ const ( DISK_STARTALLOC = "start_alloc" DISK_ALLOCATING = "allocating" DISK_READY = "ready" + DISK_RESET = "reset" DISK_DEALLOC = "deallocating" DISK_DEALLOC_FAILED = "dealloc_failed" DISK_UNKNOWN = "unknown" @@ -391,10 +392,8 @@ func (self *SDisk) CleanUpDiskSnapshots(ctx context.Context, userCred mcclient.T convertSnapshots := jsonutils.NewArray() deleteSnapshots := jsonutils.NewArray() for i := 0; i < len(dest); i++ { - if dest[i].CreatedBy == MANUAL && !dest[i].FakeDeleted { - if !dest[i].OutOfChain { - convertSnapshots.Add(jsonutils.NewString(dest[i].Id)) - } + if !dest[i].FakeDeleted && !dest[i].OutOfChain { + convertSnapshots.Add(jsonutils.NewString(dest[i].Id)) } else { deleteSnapshots.Add(jsonutils.NewString(dest[i].Id)) } @@ -416,6 +415,9 @@ func (self *SDisk) AllowPerformDiskReset(ctx context.Context, userCred mcclient. } func (self *SDisk) PerformDiskReset(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.Status != DISK_READY { + return nil, httperrors.NewInvalidStatusError("Cannot reset disk in status %s", self.Status) + } snapshotId, err := data.GetString("snapshot_id") if err != nil { return nil, err @@ -436,13 +438,16 @@ func (self *SDisk) PerformDiskReset(ctx context.Context, userCred mcclient.Token if snapshot.Status != SNAPSHOT_READY { return nil, httperrors.NewBadRequestError("Cannot reset disk with snapshot in status %s", snapshot.Status) } - self.StartResetDisk(ctx, userCred, snapshotId) + autoStart := jsonutils.QueryBoolean(data, "auto_start", false) + self.StartResetDisk(ctx, userCred, snapshotId, autoStart) return nil, nil } -func (self *SDisk) StartResetDisk(ctx context.Context, userCred mcclient.TokenCredential, snapshotId string) error { +func (self *SDisk) StartResetDisk(ctx context.Context, userCred mcclient.TokenCredential, snapshotId string, autoStart bool) error { + self.SetStatus(userCred, DISK_RESET, "") params := jsonutils.NewDict() params.Set("snapshot_id", jsonutils.NewString(snapshotId)) + params.Set("auto_start", jsonutils.NewBool(autoStart)) task, err := taskman.TaskManager.NewTask(ctx, "DiskResetTask", self, userCred, params, "", "", nil) if err != nil { return err @@ -1249,7 +1254,7 @@ func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mccl continue } // name - name := guests[0].Name + time.Now().Format("2006-01-02#15:04:05") + name := "Auto-" + guests[0].Name + time.Now().Format("2006-01-02#15:04:05") snap, err := SnapshotManager.CreateSnapshot(ctx, userCred, AUTO, disk.Id, guests[0].Id, "", name) if err != nil { log.Errorln(err) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7d53b31407..2972098f76 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -555,7 +555,7 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To err = self.checkUpdateQuota(ctx, userCred, vcpuCount, vmemSize) if err != nil { - return nil, err + return nil, httperrors.NewOutOfQuotaError(err.Error()) } if data.Contains("name") { diff --git a/pkg/compute/models/quotas.go b/pkg/compute/models/quotas.go index ad73a7a1c9..152095735e 100644 --- a/pkg/compute/models/quotas.go +++ b/pkg/compute/models/quotas.go @@ -7,9 +7,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/pkg/tristate" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/pkg/tristate" ) var QuotaManager *quotas.SQuotaManager @@ -278,7 +278,7 @@ func (self *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error { if sreq.IsolatedDevice > 0 && self.IsolatedDevice > squota.IsolatedDevice { return ErrOutOfIsolatedDevice } - if self.Snapshot > squota.Snapshot { + if sreq.Snapshot > 0 && self.Snapshot > squota.Snapshot { return ErrOutOfSnapshot } return nil diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 43ed994217..02d1011d94 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -89,6 +89,32 @@ func (manager *SSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy return q, nil } +func (self *SSnapshot) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query) + return self.getMoreDetails(extra) +} + +func (self *SSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query) + return self.getMoreDetails(extra) +} + +func (self *SSnapshot) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict { + disk, _ := self.GetDisk() + if disk != nil { + extra.Add(jsonutils.NewString(disk.DiskType), "disk_type") + guests := disk.GetGuests() + if len(guests) == 1 { + extra.Add(jsonutils.NewString(guests[0].Id), "guest") + extra.Add(jsonutils.NewString(guests[0].Status), "guest_status") + } + } + if cloudprovider := self.GetCloudprovider(); cloudprovider != nil { + extra.Add(jsonutils.NewString(cloudprovider.Provider), "provider") + } + return extra +} + func (self *SSnapshot) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return false } diff --git a/pkg/compute/tasks/disk_reset_task.go b/pkg/compute/tasks/disk_reset_task.go index 1d74fd1ae3..7f3ac4cc63 100644 --- a/pkg/compute/tasks/disk_reset_task.go +++ b/pkg/compute/tasks/disk_reset_task.go @@ -25,11 +25,13 @@ func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, disk := obj.(*models.SDisk) storage := disk.GetStorage() if storage == nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, "Disk storage not found") return } host := storage.GetMasterHost() if host == nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, "Storage master host not found") return } @@ -39,6 +41,7 @@ func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SDisk, host *models.SHost) { snapshotId, err := self.Params.GetString("snapshot_id") if err != nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, fmt.Sprintf("Get snapshotId error %s", err.Error())) return } @@ -58,6 +61,7 @@ func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SD self.SetStage("OnRequestResetDisk", nil) err = host.GetHostDriver().RequestResetDisk(ctx, host, disk, params, self) if err != nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, err.Error()) } } @@ -83,6 +87,18 @@ func (self *DiskResetTask) OnRequestResetDisk(ctx context.Context, disk *models. return } } + if jsonutils.QueryBoolean(self.Params, "auto_start", false) { + guest := disk.GetGuests()[0] + self.SetStage("OnStartGuest", nil) + guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId()) + } else { + disk.SetStatus(self.UserCred, models.DISK_READY, "") + self.SetStageComplete(ctx, nil) + } +} + +func (self *DiskResetTask) OnStartGuest(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageComplete(ctx, nil) } diff --git a/pkg/mcclient/modules/mod_snapshots.go b/pkg/mcclient/modules/mod_snapshots.go index 8def8e7e3f..edb86378c1 100644 --- a/pkg/mcclient/modules/mod_snapshots.go +++ b/pkg/mcclient/modules/mod_snapshots.go @@ -8,7 +8,7 @@ func init() { Snapshots = NewComputeManager("snapshot", "snapshots", []string{"ID", "Name", "Size", "Status", "Disk_id", "Guest_id", "Created_at"}, - []string{"Storage_id", "Create_by", "Location", "Out_of_chain"}) + []string{"Storage_id", "Create_by", "Location", "Out_of_chain", "disk_type", "provider"}) registerCompute(&Snapshots) } From c42360a8b775b7e3c81965796d4250dfe830baaa Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Sat, 13 Oct 2018 18:05:27 +0800 Subject: [PATCH 07/10] climc: k8s v1.12 option support --- cmd/climc/shell/disks.go | 16 +++++++++++----- pkg/mcclient/options/k8s/cluster.go | 10 +++++++--- pkg/mcclient/options/k8s/tiller.go | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/cmd/climc/shell/disks.go b/cmd/climc/shell/disks.go index 716d557c08..4d5ccbde7d 100644 --- a/cmd/climc/shell/disks.go +++ b/cmd/climc/shell/disks.go @@ -74,12 +74,18 @@ func init() { return nil }) - R(&DiskDetailOptions{}, "disk-delete", "Delete a disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error { - disk, e := modules.Disks.Delete(s, args.ID, nil) - if e != nil { - return e + type DiskDeleteOptions struct { + ID []string `help:"ID of disks to delete" metavar:"DISK"` + OverridePendingDelete bool `help:"Delete disk directly instead of pending delete"` + } + + R(&DiskDeleteOptions{}, "disk-delete", "Delete a disk", func(s *mcclient.ClientSession, args *DiskDeleteOptions) error { + params := jsonutils.NewDict() + if args.OverridePendingDelete { + params.Add(jsonutils.JSONTrue, "override_pending_delete") } - printObject(disk) + ret := modules.Disks.BatchDeleteWithParam(s, args.ID, params, nil) + printBatchResults(ret, modules.Disks.GetColumns(s)) return nil }) diff --git a/pkg/mcclient/options/k8s/cluster.go b/pkg/mcclient/options/k8s/cluster.go index 18e47522f0..b26974cc58 100644 --- a/pkg/mcclient/options/k8s/cluster.go +++ b/pkg/mcclient/options/k8s/cluster.go @@ -24,10 +24,14 @@ func (o ClusterListOptions) Params() *jsonutils.JSONDict { return params } +type K8sSupportVersion struct { + K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.10.5|v1.11.3|v1.12.0"` +} + type ClusterCreateOptions struct { + K8sSupportVersion NAME string `help:"Name of cluster"` Mode string `help:"Cluster mode" choices:"internal"` - K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0"` InfraImage string `help:"Cluster kubelet infra container image"` Cidr string `help:"Cluster service CIDR, e.g. 10.43.0.0/16"` Domain string `help:"Cluster pod domain, e.g. cluster.local"` @@ -70,8 +74,8 @@ func (o ClusterImportOptions) Params() (*jsonutils.JSONDict, error) { } type ClusterUpdateOptions struct { - NAME string `help:"Name of cluster"` - K8sVersion string `help:"Cluster kubernetes components version" choices:"v1.8.10|v1.9.5|v1.10.0"` + NAME string `help:"Name of cluster"` + K8sSupportVersion } func (o ClusterUpdateOptions) Params() *jsonutils.JSONDict { diff --git a/pkg/mcclient/options/k8s/tiller.go b/pkg/mcclient/options/k8s/tiller.go index a1a6a64552..4af8fbbb24 100644 --- a/pkg/mcclient/options/k8s/tiller.go +++ b/pkg/mcclient/options/k8s/tiller.go @@ -16,7 +16,7 @@ type TillerCreateOptions struct { Canary bool `json:"canary_image"` // Override Tiller image - Image string `json:"tiller_image" default:"yunion/tiller:v2.9.0"` + Image string `json:"tiller_image" default:"yunion/tiller:v2.9.1"` // Limit the maximum number of revisions saved per release. Use 0 for no limit. MaxHistory int `json:"history_max"` } From 2063b0d385d84c786f3eff0fa3056a1b86f9ffc2 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 13 Oct 2018 20:35:21 +0800 Subject: [PATCH 08/10] Update vendor --- Gopkg.lock | 22 +- Gopkg.toml | 8 + vendor/github.com/tredoe/osutil/AUTHORS.md | 16 + .../github.com/tredoe/osutil/CONTRIBUTORS.md | 18 + .../github.com/tredoe/osutil/LICENSE-MPL.txt | 374 ++++++++++++++++++ .../tredoe/osutil/user/crypt/AUTHORS.md | 8 + .../tredoe/osutil/user/crypt/LICENSE | 27 ++ .../tredoe/osutil/user/crypt/README.md | 25 ++ .../tredoe/osutil/user/crypt/common/base64.go | 60 +++ .../tredoe/osutil/user/crypt/common/doc.go | 13 + .../tredoe/osutil/user/crypt/common/salt.go | 105 +++++ .../tredoe/osutil/user/crypt/crypt.go | 108 +++++ .../user/crypt/sha512_crypt/sha512_crypt.go | 254 ++++++++++++ vendor/golang.org/x/crypto/bcrypt/base64.go | 35 -- vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 295 -------------- vendor/golang.org/x/crypto/blowfish/block.go | 159 -------- vendor/golang.org/x/crypto/blowfish/cipher.go | 91 ----- vendor/golang.org/x/crypto/blowfish/const.go | 199 ---------- vendor/yunion.io/x/jsonutils/compond.go | 1 - vendor/yunion.io/x/jsonutils/interface.go | 1 - vendor/yunion.io/x/jsonutils/yamlutils.go | 9 +- 21 files changed, 1038 insertions(+), 790 deletions(-) create mode 100644 vendor/github.com/tredoe/osutil/AUTHORS.md create mode 100644 vendor/github.com/tredoe/osutil/CONTRIBUTORS.md create mode 100644 vendor/github.com/tredoe/osutil/LICENSE-MPL.txt create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/LICENSE create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/README.md create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/common/base64.go create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/common/doc.go create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/common/salt.go create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/crypt.go create mode 100644 vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go delete mode 100644 vendor/golang.org/x/crypto/bcrypt/base64.go delete mode 100644 vendor/golang.org/x/crypto/bcrypt/bcrypt.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/block.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/cipher.go delete mode 100644 vendor/golang.org/x/crypto/blowfish/const.go diff --git a/Gopkg.lock b/Gopkg.lock index ad8588fa14..1b124ff00a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -884,6 +884,18 @@ pruneopts = "UT" revision = "d188e65d659ef53fcdb0691c12f1bba64928b649" +[[projects]] + branch = "master" + digest = "1:119cf7d2c3bc4a3c675e8c30cadf00c8c2ab34a20ba373211dd3a7d66f3e5f32" + name = "github.com/tredoe/osutil" + packages = [ + "user/crypt", + "user/crypt/common", + "user/crypt/sha512_crypt", + ] + pruneopts = "UT" + revision = "7d3ee1afa71c90fd1514c8f557ae6c5f414208eb" + [[projects]] digest = "1:98e5cda86f67cd1ac95389d98670b66dea8cae480fe6292b83bccccfe60b4106" name = "github.com/ugorji/go" @@ -917,11 +929,9 @@ [[projects]] branch = "master" - digest = "1:e132baa383407b5cb612c2a2ab6980566b5e11d98815db34a5a048f5f74835f4" + digest = "1:71c5989353531072eeb9547066e05bdeaaf9ef0512673bca3b4b824092d70de3" name = "golang.org/x/crypto" packages = [ - "bcrypt", - "blowfish", "curve25519", "ed25519", "ed25519/internal/edwards25519", @@ -1225,11 +1235,11 @@ [[projects]] branch = "master" - digest = "1:09c49bf51d8da39e73f117d2448cea5a1bd287210378a4e14339a73ea27c0b5c" + digest = "1:36db56d9ed25cc9cbd34d5553c14d5e1d4ef6501feaddb752c66aeb294e481e6" name = "yunion.io/x/jsonutils" packages = ["."] pruneopts = "UT" - revision = "7b18aa76d7f1a25d0f77fdd579d86e9452ea9322" + revision = "191bb9c0726440a0b239c344c70b9df567536302" [[projects]] branch = "master" @@ -1364,6 +1374,7 @@ "github.com/moul/http2curl", "github.com/serialx/hashring", "github.com/stretchr/testify/assert", + "github.com/tredoe/osutil/user/crypt/sha512_crypt", "github.com/vmware/govmomi", "github.com/vmware/govmomi/object", "github.com/vmware/govmomi/property", @@ -1371,7 +1382,6 @@ "github.com/vmware/govmomi/view", "github.com/vmware/govmomi/vim25/mo", "github.com/vmware/govmomi/vim25/types", - "golang.org/x/crypto/bcrypt", "golang.org/x/crypto/ssh", "gopkg.in/gin-gonic/gin.v1", "k8s.io/api/core/v1", diff --git a/Gopkg.toml b/Gopkg.toml index 2feb622afe..b70428fdfc 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -109,3 +109,11 @@ [[constraint]] name = "github.com/360EntSecGroup-Skylar/excelize" version = "v1.3.0" + +[[constraint]] + branch = "master" + name = "github.com/tredoe/osutil" + +[[constraint]] + branch = "master" + name = "golang.org/x/crypto" diff --git a/vendor/github.com/tredoe/osutil/AUTHORS.md b/vendor/github.com/tredoe/osutil/AUTHORS.md new file mode 100644 index 0000000000..1a575d3f3b --- /dev/null +++ b/vendor/github.com/tredoe/osutil/AUTHORS.md @@ -0,0 +1,16 @@ +# Authors + +This is the official list of authors for copyright purposes. +This file is distinct from the 'CONTRIBUTORS' file. See the latter for an explanation. + +Names should be added to this file as: + + Name or Organization / (url address) + +(The email address is not required for organizations) + +Please keep the list sorted. + +## Code + +* Jonas mg (https://github.com/tredoe) \ No newline at end of file diff --git a/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md new file mode 100644 index 0000000000..879ecc2386 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md @@ -0,0 +1,18 @@ +# Contributors + +This is the official list of people who can contribute (and typically +have contributed) to the repository. + +The 'AUTHORS' file lists the copyright holders; this file lists people. For +example, the employees of an organization are listed here but not in 'AUTHORS', +because the organization holds the copyright. + +Names should be added to this file as: + + Name / (url address) + +Please keep the list sorted. + +## Code + +* Jonas mg (https://github.com/tredoe) \ No newline at end of file diff --git a/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt b/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt new file mode 100644 index 0000000000..52d135112e --- /dev/null +++ b/vendor/github.com/tredoe/osutil/LICENSE-MPL.txt @@ -0,0 +1,374 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + diff --git a/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md b/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md new file mode 100644 index 0000000000..8eb23dd0c6 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/AUTHORS.md @@ -0,0 +1,8 @@ +### Initial author + +[Jeramey Crawford](https://github.com/jeramey) + +### Other authors + +[Jonas mg](https://github.com/tredoe) + diff --git a/vendor/github.com/tredoe/osutil/user/crypt/LICENSE b/vendor/github.com/tredoe/osutil/user/crypt/LICENSE new file mode 100644 index 0000000000..c39e0de5d0 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2012, Jeramey Crawford +Copyright (c) 2013, Jonas mg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/tredoe/osutil/user/crypt/README.md b/vendor/github.com/tredoe/osutil/user/crypt/README.md new file mode 100644 index 0000000000..cbcfb2e523 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/README.md @@ -0,0 +1,25 @@ +crypt +===== +A password hashing library. + +The goal of crypt is to bring a library of many common and popular password +hashing algorithms to Go and to provide a simple and consistent interface to +each of them. As every hashing method is implemented in pure Go, this library +should be as portable as Go itself. + +All hashing methods come with a test suite which verifies their operation +against itself as well as the output of other password hashing implementations +to ensure compatibility with them. + +I hope you find this library to be useful and easy to use! + +Note: forked from + +## Installation + + go get github.com/tredoe/osutil/user/crypt + +## License + +The source files are distributed under a BSD-style license that can be found +in the LICENSE file. diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go b/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go new file mode 100644 index 0000000000..ed057d5c93 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/common/base64.go @@ -0,0 +1,60 @@ +// Copyright 2012, Jeramey Crawford +// Copyright 2013, Jonas mg +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package common + +const alphabet = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +// Base64_24Bit is a variant of Base64 encoding, commonly used with password +// hashing algorithms to encode the result of their checksum output. +// +// The algorithm operates on up to 3 bytes at a time, encoding the following +// 6-bit sequences into up to 4 hash64 ASCII bytes. +// +// 1. Bottom 6 bits of the first byte +// 2. Top 2 bits of the first byte, and bottom 4 bits of the second byte. +// 3. Top 4 bits of the second byte, and bottom 2 bits of the third byte. +// 4. Top 6 bits of the third byte. +// +// This encoding method does not emit padding bytes as Base64 does. +func Base64_24Bit(src []byte) (hash []byte) { + if len(src) == 0 { + return []byte{} // TODO: return nil + } + + hashSize := (len(src) * 8) / 6 + if (len(src) % 6) != 0 { + hashSize += 1 + } + hash = make([]byte, hashSize) + + dst := hash + for len(src) > 0 { + switch len(src) { + default: + dst[0] = alphabet[src[0]&0x3f] + dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f] + dst[2] = alphabet[((src[1]>>4)|(src[2]<<4))&0x3f] + dst[3] = alphabet[(src[2]>>2)&0x3f] + src = src[3:] + dst = dst[4:] + case 2: + dst[0] = alphabet[src[0]&0x3f] + dst[1] = alphabet[((src[0]>>6)|(src[1]<<2))&0x3f] + dst[2] = alphabet[(src[1]>>4)&0x3f] + src = src[2:] + dst = dst[3:] + case 1: + dst[0] = alphabet[src[0]&0x3f] + dst[1] = alphabet[(src[0]>>6)&0x3f] + src = src[1:] + dst = dst[2:] + } + } + + return +} diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go b/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go new file mode 100644 index 0000000000..8eb6aff2d3 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/common/doc.go @@ -0,0 +1,13 @@ +// Copyright 2012, Jeramey Crawford +// Copyright 2013, Jonas mg +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// Package common contains routines used by multiple password hashing +// algorithms. +// +// Generally, you will never import this package directly. Many of the +// *_crypt packages will import this package if they require it. +package common diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go new file mode 100644 index 0000000000..22f51cc677 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go @@ -0,0 +1,105 @@ +// Copyright 2012, Jeramey Crawford +// Copyright 2013, Jonas mg +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +package common + +import ( + "crypto/rand" + "errors" + "strconv" +) + +var ( + ErrSaltPrefix = errors.New("invalid magic prefix") + ErrSaltFormat = errors.New("invalid salt format") + ErrSaltRounds = errors.New("invalid rounds") +) + +// Salt represents a salt. +type Salt struct { + MagicPrefix []byte + + SaltLenMin int + SaltLenMax int + + RoundsMin int + RoundsMax int + RoundsDefault int +} + +// Generate generates a random salt of a given length. +// +// The length is set thus: +// +// length > SaltLenMax: length = SaltLenMax +// length < SaltLenMin: length = SaltLenMin +func (s *Salt) Generate(length int) []byte { + if length > s.SaltLenMax { + length = s.SaltLenMax + } else if length < s.SaltLenMin { + length = s.SaltLenMin + } + + saltLen := (length * 6 / 8) + if (length*6)%8 != 0 { + saltLen += 1 + } + salt := make([]byte, saltLen) + rand.Read(salt) + + out := make([]byte, len(s.MagicPrefix)+length) + copy(out, s.MagicPrefix) + copy(out[len(s.MagicPrefix):], Base64_24Bit(salt)) + return out +} + +// GenerateWRounds creates a random salt with the random bytes being of the +// length provided, and the rounds parameter set as specified. +// +// The parameters are set thus: +// +// length > SaltLenMax: length = SaltLenMax +// length < SaltLenMin: length = SaltLenMin +// +// rounds < 0: rounds = RoundsDefault +// rounds < RoundsMin: rounds = RoundsMin +// rounds > RoundsMax: rounds = RoundsMax +// +// If rounds is equal to RoundsDefault, then the "rounds=" part of the salt is +// removed. +func (s *Salt) GenerateWRounds(length, rounds int) []byte { + if length > s.SaltLenMax { + length = s.SaltLenMax + } else if length < s.SaltLenMin { + length = s.SaltLenMin + } + if rounds < 0 { + rounds = s.RoundsDefault + } else if rounds < s.RoundsMin { + rounds = s.RoundsMin + } else if rounds > s.RoundsMax { + rounds = s.RoundsMax + } + + saltLen := (length * 6 / 8) + if (length*6)%8 != 0 { + saltLen += 1 + } + salt := make([]byte, saltLen) + rand.Read(salt) + + roundsText := "" + if rounds != s.RoundsDefault { + roundsText = "rounds=" + strconv.Itoa(rounds) + } + + out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length) + copy(out, s.MagicPrefix) + copy(out[len(s.MagicPrefix):], []byte(roundsText)) + copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt)) + return out +} diff --git a/vendor/github.com/tredoe/osutil/user/crypt/crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/crypt.go new file mode 100644 index 0000000000..5ded2da8c6 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/crypt.go @@ -0,0 +1,108 @@ +// Copyright 2013, Jonas mg +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// Package crypt provides interface for password crypt functions and collects +// common constants. +package crypt + +import ( + "errors" + "strings" + + "github.com/tredoe/osutil/user/crypt/common" +) + +var ErrKeyMismatch = errors.New("hashed value is not the hash of the given password") + +// Crypter is the common interface implemented by all crypt functions. +type Crypter interface { + // Generate performs the hashing algorithm, returning a full hash suitable + // for storage and later password verification. + // + // If the salt is empty, a randomly-generated salt will be generated with a + // length of SaltLenMax and number RoundsDefault of rounds. + // + // Any error only can be got when the salt argument is not empty. + Generate(key, salt []byte) (string, error) + + // Verify compares a hashed key with its possible key equivalent. + // Returns nil on success, or an error on failure; if the hashed key is + // diffrent, the error is "ErrKeyMismatch". + Verify(hashedKey string, key []byte) error + + // Cost returns the hashing cost (in rounds) used to create the given hashed + // key. + // + // When, in the future, the hashing cost of a key needs to be increased in + // order to adjust for greater computational power, this function allows one + // to establish which keys need to be updated. + // + // The algorithms based in MD5-crypt use a fixed value of rounds. + Cost(hashedKey string) (int, error) + + // SetSalt sets a different salt. It is used to easily create derivated + // algorithms, i.e. "apr1_crypt" from "md5_crypt". + SetSalt(salt common.Salt) +} + +// Crypt identifies a crypt function that is implemented in another package. +type Crypt uint + +const ( + APR1 Crypt = iota + 1 // import "github.com/tredoe/osutil/user/crypt/apr1_crypt" + MD5 // import "github.com/tredoe/osutil/user/crypt/md5_crypt" + SHA256 // import "github.com/tredoe/osutil/user/crypt/sha256_crypt" + SHA512 // import "github.com/tredoe/osutil/user/crypt/sha512_crypt" + maxCrypt +) + +var cryptPrefixes = make([]string, maxCrypt) + +var crypts = make([]func() Crypter, maxCrypt) + +// RegisterCrypt registers a function that returns a new instance of the given +// crypt function. This is intended to be called from the init function in +// packages that implement crypt functions. +func RegisterCrypt(c Crypt, f func() Crypter, prefix string) { + if c >= maxCrypt { + panic("crypt: RegisterHash of unknown crypt function") + } + crypts[c] = f + cryptPrefixes[c] = prefix +} + +// New returns a new crypter. +func New(c Crypt) Crypter { + f := crypts[c] + if f != nil { + return f() + } + panic("crypt: requested crypt function is unavailable") +} + +// NewFromHash returns a new Crypter using the prefix in the given hashed key. +func NewFromHash(hashedKey string) Crypter { + var f func() Crypter + + if strings.HasPrefix(hashedKey, cryptPrefixes[SHA512]) { + f = crypts[SHA512] + } else if strings.HasPrefix(hashedKey, cryptPrefixes[SHA256]) { + f = crypts[SHA256] + } else if strings.HasPrefix(hashedKey, cryptPrefixes[MD5]) { + f = crypts[MD5] + } else if strings.HasPrefix(hashedKey, cryptPrefixes[APR1]) { + f = crypts[APR1] + } else { + toks := strings.SplitN(hashedKey, "$", 3) + prefix := "$" + toks[1] + "$" + panic("crypt: unknown cryp function from prefix: " + prefix) + } + + if f != nil { + return f() + } + panic("crypt: requested cryp function is unavailable") +} diff --git a/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go b/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go new file mode 100644 index 0000000000..fd55e88124 --- /dev/null +++ b/vendor/github.com/tredoe/osutil/user/crypt/sha512_crypt/sha512_crypt.go @@ -0,0 +1,254 @@ +// Copyright 2012, Jeramey Crawford +// Copyright 2013, Jonas mg +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file. + +// Package sha512_crypt implements Ulrich Drepper's SHA512-crypt password +// hashing algorithm. +// +// The specification for this algorithm can be found here: +// http://www.akkadia.org/drepper/SHA-crypt.txt +package sha512_crypt + +import ( + "bytes" + "crypto/sha512" + "strconv" + + "github.com/tredoe/osutil/user/crypt" + "github.com/tredoe/osutil/user/crypt/common" +) + +func init() { + crypt.RegisterCrypt(crypt.SHA512, New, MagicPrefix) +} + +const ( + MagicPrefix = "$6$" + SaltLenMin = 1 + SaltLenMax = 16 + RoundsMin = 1000 + RoundsMax = 999999999 + RoundsDefault = 5000 +) + +var _rounds = []byte("rounds=") + +type crypter struct{ Salt common.Salt } + +// New returns a new crypt.Crypter computing the SHA512-crypt password hashing. +func New() crypt.Crypter { + return &crypter{GetSalt()} +} + +func (c *crypter) Generate(key, salt []byte) (string, error) { + var rounds int + var isRoundsDef bool + + if len(salt) == 0 { + salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault) + } + if !bytes.HasPrefix(salt, c.Salt.MagicPrefix) { + return "", common.ErrSaltPrefix + } + + saltToks := bytes.Split(salt, []byte{'$'}) + if len(saltToks) < 3 { + return "", common.ErrSaltFormat + } + + if bytes.HasPrefix(saltToks[2], _rounds) { + isRoundsDef = true + pr, err := strconv.ParseInt(string(saltToks[2][7:]), 10, 32) + if err != nil { + return "", common.ErrSaltRounds + } + rounds = int(pr) + if rounds < RoundsMin { + rounds = RoundsMin + } else if rounds > RoundsMax { + rounds = RoundsMax + } + salt = saltToks[3] + } else { + rounds = RoundsDefault + salt = saltToks[2] + } + + if len(salt) > SaltLenMax { + salt = salt[0:SaltLenMax] + } + + // Compute alternate SHA512 sum with input KEY, SALT, and KEY. + Alternate := sha512.New() + Alternate.Write(key) + Alternate.Write(salt) + Alternate.Write(key) + AlternateSum := Alternate.Sum(nil) // 64 bytes + + A := sha512.New() + A.Write(key) + A.Write(salt) + // Add for any character in the key one byte of the alternate sum. + i := len(key) + for ; i > 64; i -= 64 { + A.Write(AlternateSum) + } + A.Write(AlternateSum[0:i]) + + // Take the binary representation of the length of the key and for every add + // the alternate sum, for every 0 the key. + for i = len(key); i > 0; i >>= 1 { + if (i & 1) != 0 { + A.Write(AlternateSum) + } else { + A.Write(key) + } + } + Asum := A.Sum(nil) + + // Start computation of P byte sequence. + P := sha512.New() + // For every character in the password add the entire password. + for i = 0; i < len(key); i++ { + P.Write(key) + } + Psum := P.Sum(nil) + // Create byte sequence P. + Pseq := make([]byte, 0, len(key)) + for i = len(key); i > 64; i -= 64 { + Pseq = append(Pseq, Psum...) + } + Pseq = append(Pseq, Psum[0:i]...) + + // Start computation of S byte sequence. + S := sha512.New() + for i = 0; i < (16 + int(Asum[0])); i++ { + S.Write(salt) + } + Ssum := S.Sum(nil) + // Create byte sequence S. + Sseq := make([]byte, 0, len(salt)) + for i = len(salt); i > 64; i -= 64 { + Sseq = append(Sseq, Ssum...) + } + Sseq = append(Sseq, Ssum[0:i]...) + + Csum := Asum + + // Repeatedly run the collected hash value through SHA512 to burn CPU cycles. + for i = 0; i < rounds; i++ { + C := sha512.New() + + // Add key or last result. + if (i & 1) != 0 { + C.Write(Pseq) + } else { + C.Write(Csum) + } + // Add salt for numbers not divisible by 3. + if (i % 3) != 0 { + C.Write(Sseq) + } + // Add key for numbers not divisible by 7. + if (i % 7) != 0 { + C.Write(Pseq) + } + // Add key or last result. + if (i & 1) != 0 { + C.Write(Csum) + } else { + C.Write(Pseq) + } + + Csum = C.Sum(nil) + } + + out := make([]byte, 0, 123) + out = append(out, c.Salt.MagicPrefix...) + if isRoundsDef { + out = append(out, []byte("rounds="+strconv.Itoa(rounds)+"$")...) + } + out = append(out, salt...) + out = append(out, '$') + out = append(out, common.Base64_24Bit([]byte{ + Csum[42], Csum[21], Csum[0], + Csum[1], Csum[43], Csum[22], + Csum[23], Csum[2], Csum[44], + Csum[45], Csum[24], Csum[3], + Csum[4], Csum[46], Csum[25], + Csum[26], Csum[5], Csum[47], + Csum[48], Csum[27], Csum[6], + Csum[7], Csum[49], Csum[28], + Csum[29], Csum[8], Csum[50], + Csum[51], Csum[30], Csum[9], + Csum[10], Csum[52], Csum[31], + Csum[32], Csum[11], Csum[53], + Csum[54], Csum[33], Csum[12], + Csum[13], Csum[55], Csum[34], + Csum[35], Csum[14], Csum[56], + Csum[57], Csum[36], Csum[15], + Csum[16], Csum[58], Csum[37], + Csum[38], Csum[17], Csum[59], + Csum[60], Csum[39], Csum[18], + Csum[19], Csum[61], Csum[40], + Csum[41], Csum[20], Csum[62], + Csum[63], + })...) + + // Clean sensitive data. + A.Reset() + Alternate.Reset() + P.Reset() + for i = 0; i < len(Asum); i++ { + Asum[i] = 0 + } + for i = 0; i < len(AlternateSum); i++ { + AlternateSum[i] = 0 + } + for i = 0; i < len(Pseq); i++ { + Pseq[i] = 0 + } + + return string(out), nil +} + +func (c *crypter) Verify(hashedKey string, key []byte) error { + newHash, err := c.Generate(key, []byte(hashedKey)) + if err != nil { + return err + } + if newHash != hashedKey { + return crypt.ErrKeyMismatch + } + return nil +} + +func (c *crypter) Cost(hashedKey string) (int, error) { + saltToks := bytes.Split([]byte(hashedKey), []byte{'$'}) + if len(saltToks) < 3 { + return 0, common.ErrSaltFormat + } + + if !bytes.HasPrefix(saltToks[2], _rounds) { + return RoundsDefault, nil + } + roundToks := bytes.Split(saltToks[2], []byte{'='}) + cost, err := strconv.ParseInt(string(roundToks[1]), 10, 0) + return int(cost), err +} + +func (c *crypter) SetSalt(salt common.Salt) { c.Salt = salt } + +func GetSalt() common.Salt { + return common.Salt{ + MagicPrefix: []byte(MagicPrefix), + SaltLenMin: SaltLenMin, + SaltLenMax: SaltLenMax, + RoundsDefault: RoundsDefault, + RoundsMin: RoundsMin, + RoundsMax: RoundsMax, + } +} diff --git a/vendor/golang.org/x/crypto/bcrypt/base64.go b/vendor/golang.org/x/crypto/bcrypt/base64.go deleted file mode 100644 index fc31160908..0000000000 --- a/vendor/golang.org/x/crypto/bcrypt/base64.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bcrypt - -import "encoding/base64" - -const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - -var bcEncoding = base64.NewEncoding(alphabet) - -func base64Encode(src []byte) []byte { - n := bcEncoding.EncodedLen(len(src)) - dst := make([]byte, n) - bcEncoding.Encode(dst, src) - for dst[n-1] == '=' { - n-- - } - return dst[:n] -} - -func base64Decode(src []byte) ([]byte, error) { - numOfEquals := 4 - (len(src) % 4) - for i := 0; i < numOfEquals; i++ { - src = append(src, '=') - } - - dst := make([]byte, bcEncoding.DecodedLen(len(src))) - n, err := bcEncoding.Decode(dst, src) - if err != nil { - return nil, err - } - return dst[:n], nil -} diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go deleted file mode 100644 index aeb73f81a1..0000000000 --- a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing -// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf -package bcrypt // import "golang.org/x/crypto/bcrypt" - -// The code is a port of Provos and Mazières's C implementation. -import ( - "crypto/rand" - "crypto/subtle" - "errors" - "fmt" - "io" - "strconv" - - "golang.org/x/crypto/blowfish" -) - -const ( - MinCost int = 4 // the minimum allowable cost as passed in to GenerateFromPassword - MaxCost int = 31 // the maximum allowable cost as passed in to GenerateFromPassword - DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword -) - -// The error returned from CompareHashAndPassword when a password and hash do -// not match. -var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password") - -// The error returned from CompareHashAndPassword when a hash is too short to -// be a bcrypt hash. -var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password") - -// The error returned from CompareHashAndPassword when a hash was created with -// a bcrypt algorithm newer than this implementation. -type HashVersionTooNewError byte - -func (hv HashVersionTooNewError) Error() string { - return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion) -} - -// The error returned from CompareHashAndPassword when a hash starts with something other than '$' -type InvalidHashPrefixError byte - -func (ih InvalidHashPrefixError) Error() string { - return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih)) -} - -type InvalidCostError int - -func (ic InvalidCostError) Error() string { - return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) -} - -const ( - majorVersion = '2' - minorVersion = 'a' - maxSaltSize = 16 - maxCryptedHashSize = 23 - encodedSaltSize = 22 - encodedHashSize = 31 - minHashSize = 59 -) - -// magicCipherData is an IV for the 64 Blowfish encryption calls in -// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes. -var magicCipherData = []byte{ - 0x4f, 0x72, 0x70, 0x68, - 0x65, 0x61, 0x6e, 0x42, - 0x65, 0x68, 0x6f, 0x6c, - 0x64, 0x65, 0x72, 0x53, - 0x63, 0x72, 0x79, 0x44, - 0x6f, 0x75, 0x62, 0x74, -} - -type hashed struct { - hash []byte - salt []byte - cost int // allowed range is MinCost to MaxCost - major byte - minor byte -} - -// GenerateFromPassword returns the bcrypt hash of the password at the given -// cost. If the cost given is less than MinCost, the cost will be set to -// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, -// to compare the returned hashed password with its cleartext version. -func GenerateFromPassword(password []byte, cost int) ([]byte, error) { - p, err := newFromPassword(password, cost) - if err != nil { - return nil, err - } - return p.Hash(), nil -} - -// CompareHashAndPassword compares a bcrypt hashed password with its possible -// plaintext equivalent. Returns nil on success, or an error on failure. -func CompareHashAndPassword(hashedPassword, password []byte) error { - p, err := newFromHash(hashedPassword) - if err != nil { - return err - } - - otherHash, err := bcrypt(password, p.cost, p.salt) - if err != nil { - return err - } - - otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor} - if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 { - return nil - } - - return ErrMismatchedHashAndPassword -} - -// Cost returns the hashing cost used to create the given hashed -// password. When, in the future, the hashing cost of a password system needs -// to be increased in order to adjust for greater computational power, this -// function allows one to establish which passwords need to be updated. -func Cost(hashedPassword []byte) (int, error) { - p, err := newFromHash(hashedPassword) - if err != nil { - return 0, err - } - return p.cost, nil -} - -func newFromPassword(password []byte, cost int) (*hashed, error) { - if cost < MinCost { - cost = DefaultCost - } - p := new(hashed) - p.major = majorVersion - p.minor = minorVersion - - err := checkCost(cost) - if err != nil { - return nil, err - } - p.cost = cost - - unencodedSalt := make([]byte, maxSaltSize) - _, err = io.ReadFull(rand.Reader, unencodedSalt) - if err != nil { - return nil, err - } - - p.salt = base64Encode(unencodedSalt) - hash, err := bcrypt(password, p.cost, p.salt) - if err != nil { - return nil, err - } - p.hash = hash - return p, err -} - -func newFromHash(hashedSecret []byte) (*hashed, error) { - if len(hashedSecret) < minHashSize { - return nil, ErrHashTooShort - } - p := new(hashed) - n, err := p.decodeVersion(hashedSecret) - if err != nil { - return nil, err - } - hashedSecret = hashedSecret[n:] - n, err = p.decodeCost(hashedSecret) - if err != nil { - return nil, err - } - hashedSecret = hashedSecret[n:] - - // The "+2" is here because we'll have to append at most 2 '=' to the salt - // when base64 decoding it in expensiveBlowfishSetup(). - p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2) - copy(p.salt, hashedSecret[:encodedSaltSize]) - - hashedSecret = hashedSecret[encodedSaltSize:] - p.hash = make([]byte, len(hashedSecret)) - copy(p.hash, hashedSecret) - - return p, nil -} - -func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) { - cipherData := make([]byte, len(magicCipherData)) - copy(cipherData, magicCipherData) - - c, err := expensiveBlowfishSetup(password, uint32(cost), salt) - if err != nil { - return nil, err - } - - for i := 0; i < 24; i += 8 { - for j := 0; j < 64; j++ { - c.Encrypt(cipherData[i:i+8], cipherData[i:i+8]) - } - } - - // Bug compatibility with C bcrypt implementations. We only encode 23 of - // the 24 bytes encrypted. - hsh := base64Encode(cipherData[:maxCryptedHashSize]) - return hsh, nil -} - -func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) { - csalt, err := base64Decode(salt) - if err != nil { - return nil, err - } - - // Bug compatibility with C bcrypt implementations. They use the trailing - // NULL in the key string during expansion. - // We copy the key to prevent changing the underlying array. - ckey := append(key[:len(key):len(key)], 0) - - c, err := blowfish.NewSaltedCipher(ckey, csalt) - if err != nil { - return nil, err - } - - var i, rounds uint64 - rounds = 1 << cost - for i = 0; i < rounds; i++ { - blowfish.ExpandKey(ckey, c) - blowfish.ExpandKey(csalt, c) - } - - return c, nil -} - -func (p *hashed) Hash() []byte { - arr := make([]byte, 60) - arr[0] = '$' - arr[1] = p.major - n := 2 - if p.minor != 0 { - arr[2] = p.minor - n = 3 - } - arr[n] = '$' - n++ - copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost))) - n += 2 - arr[n] = '$' - n++ - copy(arr[n:], p.salt) - n += encodedSaltSize - copy(arr[n:], p.hash) - n += encodedHashSize - return arr[:n] -} - -func (p *hashed) decodeVersion(sbytes []byte) (int, error) { - if sbytes[0] != '$' { - return -1, InvalidHashPrefixError(sbytes[0]) - } - if sbytes[1] > majorVersion { - return -1, HashVersionTooNewError(sbytes[1]) - } - p.major = sbytes[1] - n := 3 - if sbytes[2] != '$' { - p.minor = sbytes[2] - n++ - } - return n, nil -} - -// sbytes should begin where decodeVersion left off. -func (p *hashed) decodeCost(sbytes []byte) (int, error) { - cost, err := strconv.Atoi(string(sbytes[0:2])) - if err != nil { - return -1, err - } - err = checkCost(cost) - if err != nil { - return -1, err - } - p.cost = cost - return 3, nil -} - -func (p *hashed) String() string { - return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor) -} - -func checkCost(cost int) error { - if cost < MinCost || cost > MaxCost { - return InvalidCostError(cost) - } - return nil -} diff --git a/vendor/golang.org/x/crypto/blowfish/block.go b/vendor/golang.org/x/crypto/blowfish/block.go deleted file mode 100644 index 9d80f19521..0000000000 --- a/vendor/golang.org/x/crypto/blowfish/block.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package blowfish - -// getNextWord returns the next big-endian uint32 value from the byte slice -// at the given position in a circular manner, updating the position. -func getNextWord(b []byte, pos *int) uint32 { - var w uint32 - j := *pos - for i := 0; i < 4; i++ { - w = w<<8 | uint32(b[j]) - j++ - if j >= len(b) { - j = 0 - } - } - *pos = j - return w -} - -// ExpandKey performs a key expansion on the given *Cipher. Specifically, it -// performs the Blowfish algorithm's key schedule which sets up the *Cipher's -// pi and substitution tables for calls to Encrypt. This is used, primarily, -// by the bcrypt package to reuse the Blowfish key schedule during its -// set up. It's unlikely that you need to use this directly. -func ExpandKey(key []byte, c *Cipher) { - j := 0 - for i := 0; i < 18; i++ { - // Using inlined getNextWord for performance. - var d uint32 - for k := 0; k < 4; k++ { - d = d<<8 | uint32(key[j]) - j++ - if j >= len(key) { - j = 0 - } - } - c.p[i] ^= d - } - - var l, r uint32 - for i := 0; i < 18; i += 2 { - l, r = encryptBlock(l, r, c) - c.p[i], c.p[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s0[i], c.s0[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s1[i], c.s1[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s2[i], c.s2[i+1] = l, r - } - for i := 0; i < 256; i += 2 { - l, r = encryptBlock(l, r, c) - c.s3[i], c.s3[i+1] = l, r - } -} - -// This is similar to ExpandKey, but folds the salt during the key -// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero -// salt passed in, reusing ExpandKey turns out to be a place of inefficiency -// and specializing it here is useful. -func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) { - j := 0 - for i := 0; i < 18; i++ { - c.p[i] ^= getNextWord(key, &j) - } - - j = 0 - var l, r uint32 - for i := 0; i < 18; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.p[i], c.p[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s0[i], c.s0[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s1[i], c.s1[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s2[i], c.s2[i+1] = l, r - } - - for i := 0; i < 256; i += 2 { - l ^= getNextWord(salt, &j) - r ^= getNextWord(salt, &j) - l, r = encryptBlock(l, r, c) - c.s3[i], c.s3[i+1] = l, r - } -} - -func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { - xl, xr := l, r - xl ^= c.p[0] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16] - xr ^= c.p[17] - return xr, xl -} - -func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) { - xl, xr := l, r - xl ^= c.p[17] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3] - xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2] - xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1] - xr ^= c.p[0] - return xr, xl -} diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go deleted file mode 100644 index 2641dadd64..0000000000 --- a/vendor/golang.org/x/crypto/blowfish/cipher.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. -package blowfish // import "golang.org/x/crypto/blowfish" - -// The code is a port of Bruce Schneier's C implementation. -// See https://www.schneier.com/blowfish.html. - -import "strconv" - -// The Blowfish block size in bytes. -const BlockSize = 8 - -// A Cipher is an instance of Blowfish encryption using a particular key. -type Cipher struct { - p [18]uint32 - s0, s1, s2, s3 [256]uint32 -} - -type KeySizeError int - -func (k KeySizeError) Error() string { - return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k)) -} - -// NewCipher creates and returns a Cipher. -// The key argument should be the Blowfish key, from 1 to 56 bytes. -func NewCipher(key []byte) (*Cipher, error) { - var result Cipher - if k := len(key); k < 1 || k > 56 { - return nil, KeySizeError(k) - } - initCipher(&result) - ExpandKey(key, &result) - return &result, nil -} - -// NewSaltedCipher creates a returns a Cipher that folds a salt into its key -// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is -// sufficient and desirable. For bcrypt compatibility, the key can be over 56 -// bytes. -func NewSaltedCipher(key, salt []byte) (*Cipher, error) { - if len(salt) == 0 { - return NewCipher(key) - } - var result Cipher - if k := len(key); k < 1 { - return nil, KeySizeError(k) - } - initCipher(&result) - expandKeyWithSalt(key, salt, &result) - return &result, nil -} - -// BlockSize returns the Blowfish block size, 8 bytes. -// It is necessary to satisfy the Block interface in the -// package "crypto/cipher". -func (c *Cipher) BlockSize() int { return BlockSize } - -// Encrypt encrypts the 8-byte buffer src using the key k -// and stores the result in dst. -// Note that for amounts of data larger than a block, -// it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). -func (c *Cipher) Encrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - l, r = encryptBlock(l, r, c) - dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) - dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) -} - -// Decrypt decrypts the 8-byte buffer src using the key k -// and stores the result in dst. -func (c *Cipher) Decrypt(dst, src []byte) { - l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - l, r = decryptBlock(l, r, c) - dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) - dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r) -} - -func initCipher(c *Cipher) { - copy(c.p[0:], p[0:]) - copy(c.s0[0:], s0[0:]) - copy(c.s1[0:], s1[0:]) - copy(c.s2[0:], s2[0:]) - copy(c.s3[0:], s3[0:]) -} diff --git a/vendor/golang.org/x/crypto/blowfish/const.go b/vendor/golang.org/x/crypto/blowfish/const.go deleted file mode 100644 index d04077595a..0000000000 --- a/vendor/golang.org/x/crypto/blowfish/const.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The startup permutation array and substitution boxes. -// They are the hexadecimal digits of PI; see: -// https://www.schneier.com/code/constants.txt. - -package blowfish - -var s0 = [256]uint32{ - 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, - 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, - 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, - 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, - 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, - 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, - 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, - 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, - 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, - 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, - 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, - 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, - 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, - 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, - 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, - 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, - 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, - 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, - 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, - 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, - 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, - 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, - 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, - 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, - 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, - 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, - 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, - 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, - 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, - 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, - 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, - 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, - 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, - 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, - 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, - 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, - 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, - 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, - 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, - 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, - 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, - 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, - 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, -} - -var s1 = [256]uint32{ - 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, - 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, - 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, - 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, - 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, - 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, - 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, - 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, - 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, - 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, - 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, - 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, - 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, - 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, - 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, - 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, - 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, - 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, - 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, - 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, - 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, - 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, - 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, - 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, - 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, - 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, - 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, - 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, - 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, - 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, - 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, - 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, - 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, - 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, - 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, - 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, - 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, - 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, - 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, - 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, - 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, - 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, - 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, -} - -var s2 = [256]uint32{ - 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, - 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, - 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, - 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, - 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, - 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, - 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, - 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, - 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, - 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, - 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, - 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, - 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, - 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, - 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, - 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, - 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, - 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, - 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, - 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, - 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, - 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, - 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, - 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, - 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, - 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, - 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, - 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, - 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, - 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, - 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, - 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, - 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, - 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, - 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, - 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, - 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, - 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, - 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, - 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, - 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, - 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, - 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, -} - -var s3 = [256]uint32{ - 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, - 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, - 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, - 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, - 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, - 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, - 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, - 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, - 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, - 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, - 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, - 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, - 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, - 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, - 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, - 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, - 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, - 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, - 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, - 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, - 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, - 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, - 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, - 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, - 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, - 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, - 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, - 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, - 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, - 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, - 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, - 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, - 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, - 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, - 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, - 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, - 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, - 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, - 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, - 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, - 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, - 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, - 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6, -} - -var p = [18]uint32{ - 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, - 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, - 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b, -} diff --git a/vendor/yunion.io/x/jsonutils/compond.go b/vendor/yunion.io/x/jsonutils/compond.go index 296a54e75c..1ffc930c35 100644 --- a/vendor/yunion.io/x/jsonutils/compond.go +++ b/vendor/yunion.io/x/jsonutils/compond.go @@ -1,6 +1,5 @@ package jsonutils - func (val *JSONValue) isCompond() bool { return false } diff --git a/vendor/yunion.io/x/jsonutils/interface.go b/vendor/yunion.io/x/jsonutils/interface.go index fee786412e..3ee19a10f6 100644 --- a/vendor/yunion.io/x/jsonutils/interface.go +++ b/vendor/yunion.io/x/jsonutils/interface.go @@ -1,6 +1,5 @@ package jsonutils - func (self *JSONValue) Interface() interface{} { return nil } diff --git a/vendor/yunion.io/x/jsonutils/yamlutils.go b/vendor/yunion.io/x/jsonutils/yamlutils.go index 05d9f0d5cb..fd2b978882 100644 --- a/vendor/yunion.io/x/jsonutils/yamlutils.go +++ b/vendor/yunion.io/x/jsonutils/yamlutils.go @@ -61,7 +61,7 @@ func parseYAMLDict(lines []string) (map[string]JSONObject, error) { } else { key := lines[i][0:keypos] val := strings.Trim(lines[i][keypos+1:], " ") - + if len(val) > 0 && val != "|" { dict[key] = NewString(val) i++ @@ -199,10 +199,13 @@ func (this *JSONDict) yamlLines() []string { for _, key := range this.SortedKeys() { val := this.data[key] if val.IsZero() { - continue + switch val.(type) { + case *JSONString, *JSONDict, *JSONArray, *JSONValue: + continue + } } lines := val.yamlLines() - if ! val.isCompond() && len(lines) == 1 { + if !val.isCompond() && len(lines) == 1 { ret = append(ret, fmt.Sprintf("%s: %s", key, lines[0])) } else { switch val.(type) { From 23443c07bca7f7ae99ed130589af5a78425054a3 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 13 Oct 2018 20:36:15 +0800 Subject: [PATCH 09/10] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9A1.=20=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=E8=87=AA=E5=8A=A8=E8=AE=BE=E7=BD=AEImport/Ex?= =?UTF-8?q?port=20image=20ram=E6=8E=88=E6=9D=83=EF=BC=8C=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E6=89=8B=E5=8A=A8=E6=8E=88=E6=9D=83=202.=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=85=AC=E6=9C=89=E4=BA=91=E6=B3=A8=E5=85=A5?= =?UTF-8?q?userdata=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/sshkeypairs.go | 42 ++++ pkg/cloudprovider/resources.go | 2 + pkg/compute/guestdrivers/aliyun.go | 40 ++-- pkg/compute/guestdrivers/azure.go | 25 +- pkg/compute/guestdrivers/userdata.go | 32 +++ pkg/compute/handlers.go | 2 + pkg/compute/models/guests.go | 11 +- pkg/compute/sshkeys/doc.go | 1 + pkg/compute/sshkeys/handler.go | 85 +++++++ .../{models => sshkeys}/sshkeypairs.go | 10 +- pkg/httperrors/httperrors.go | 12 + pkg/mcclient/modules/mod_capabilities.go | 2 +- pkg/mcclient/modules/mod_snapshots.go | 2 +- pkg/mcclient/modules/mod_sshkeypairs.go | 37 +++ pkg/mcclient/modules/register.go | 8 + pkg/util/aliyun/aliyun.go | 99 +------- pkg/util/aliyun/business.go | 104 ++++++++ pkg/util/aliyun/instance.go | 4 + pkg/util/aliyun/ram.go | 222 ++++++++++++++++++ pkg/util/aliyun/ramimage.go | 172 ++++++++++++++ pkg/util/aliyun/region.go | 7 +- pkg/util/aliyun/shell/ram.go | 80 +++++++ pkg/util/aliyun/snapshot.go | 12 +- pkg/util/aliyun/storagecache.go | 20 +- pkg/util/ansible/const.go | 5 + pkg/util/ansible/doc.go | 1 + pkg/util/azure/doc.go | 1 + pkg/util/azure/instance.go | 8 + pkg/util/cloudinit/cloudconfig.go | 75 ++++-- pkg/util/cloudinit/cloudconfig_test.go | 13 +- pkg/util/cloudinit/doc.go | 1 + pkg/util/esxi/virtualmachine.go | 4 + pkg/util/excelutils/doc.go | 1 + pkg/util/imagetools/doc.go | 1 + pkg/util/seclib2/passwd.go | 20 ++ pkg/util/seclib2/passwd_test.go | 18 ++ 36 files changed, 990 insertions(+), 189 deletions(-) create mode 100644 cmd/climc/shell/sshkeypairs.go create mode 100644 pkg/compute/guestdrivers/userdata.go create mode 100644 pkg/compute/sshkeys/doc.go create mode 100644 pkg/compute/sshkeys/handler.go rename pkg/compute/{models => sshkeys}/sshkeypairs.go (89%) create mode 100644 pkg/mcclient/modules/mod_sshkeypairs.go create mode 100644 pkg/util/aliyun/business.go create mode 100644 pkg/util/aliyun/ram.go create mode 100644 pkg/util/aliyun/ramimage.go create mode 100644 pkg/util/aliyun/shell/ram.go create mode 100644 pkg/util/ansible/const.go create mode 100644 pkg/util/ansible/doc.go create mode 100644 pkg/util/azure/doc.go create mode 100644 pkg/util/cloudinit/doc.go create mode 100644 pkg/util/excelutils/doc.go create mode 100644 pkg/util/imagetools/doc.go create mode 100644 pkg/util/seclib2/passwd.go create mode 100644 pkg/util/seclib2/passwd_test.go diff --git a/cmd/climc/shell/sshkeypairs.go b/cmd/climc/shell/sshkeypairs.go new file mode 100644 index 0000000000..d68aa940b5 --- /dev/null +++ b/cmd/climc/shell/sshkeypairs.go @@ -0,0 +1,42 @@ +package shell + +import ( + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +func init() { + type SshkeypairQueryOptions struct { + Project string `help:"get keypair for specific project"` + Admin bool `help:"get admin keypair, sysadmin ONLY option"` + } + R(&SshkeypairQueryOptions{}, "sshkeypair-show", "Get ssh keypairs", func(s *mcclient.ClientSession, args *SshkeypairQueryOptions) error { + query := jsonutils.NewDict() + if args.Admin { + query.Add(jsonutils.JSONTrue, "admin") + } + var keys jsonutils.JSONObject + if len(args.Project) == 0 { + listResult, err := modules.Sshkeypairs.List(s, query) + if err != nil { + return err + } + keys = listResult.Data[0] + } else { + result, err := modules.Sshkeypairs.GetById(s, args.Project, query) + if err != nil { + return err + } + keys = result + } + privKey, _ := keys.GetString("private_key") + pubKey, _ := keys.GetString("public_key") + + fmt.Print(privKey) + fmt.Print(pubKey) + + return nil + }) +} diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 9d88e68e17..912009d0a3 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -174,6 +174,8 @@ type ICloudVM interface { UpdateVM(name string) error + UpdateUserData(userData string) error + RebuildRoot(imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) DeployVM(name string, password string, publicKey string, deleteKeypair bool, description string) error diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 7473051ffb..468ac48afc 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -15,7 +15,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/util/cloudinit" "yunion.io/x/onecloud/pkg/util/seclib2" ) @@ -142,31 +141,9 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu adminPublicKey, _ := config.GetString("admin_public_key") projectPublicKey, _ := config.GetString("project_public_key") - - var oCloudConfig *cloudinit.SCloudConfig - oUserData, _ := config.GetString("user_data") - if len(oUserData) > 0 { - oCloudConfig, _ = cloudinit.ParseUserDataBase64(oUserData) - } - cloudConfig := cloudinit.SCloudConfig{ - Users: []cloudinit.SUser{ - { - Name: "root", - SshAuthorizedKeys: []string{ - adminPublicKey, - projectPublicKey, - }, - }, - }, - } - - if oCloudConfig != nil { - cloudConfig.Merge(oCloudConfig) - } - - userData := cloudConfig.UserDataBase64() + userData := generateUserData(adminPublicKey, projectPublicKey, oUserData) resetPassword := jsonutils.QueryBoolean(config, "reset_password", false) passwd, _ := config.GetString("password") @@ -311,6 +288,13 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if len(userData) > 0 { + err := iVM.UpdateUserData(userData) + if err != nil { + log.Errorf("update userdata fail %s", err) + } + } + err := iVM.DeployVM(name, passwd, publicKey, deleteKeypair, description) if err != nil { return nil, err @@ -335,6 +319,7 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu return data, nil }) } else if action == "rebuild" { + iVM, err := ihost.GetIVMById(guest.GetExternalId()) if err != nil || iVM == nil { log.Errorf("cannot find vm %s", err) @@ -342,6 +327,13 @@ func (self *SAliyunGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gu } taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if len(userData) > 0 { + err := iVM.UpdateUserData(userData) + if err != nil { + log.Errorf("update userdata fail %s", err) + } + } + diskId, err := iVM.RebuildRoot(desc.ExternalImageId, passwd, publicKey, desc.SysDiskSize) if err != nil { return nil, err diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 4106490efa..c557b70bc5 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -14,7 +14,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/onecloud/pkg/util/cloudinit" ) type SAzureGuestDriver struct { @@ -74,31 +73,9 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue adminPublicKey, _ := config.GetString("admin_public_key") projectPublicKey, _ := config.GetString("project_public_key") - - var oCloudConfig *cloudinit.SCloudConfig - oUserData, _ := config.GetString("user_data") - if len(oUserData) > 0 { - oCloudConfig, _ = cloudinit.ParseUserDataBase64(oUserData) - } - cloudConfig := cloudinit.SCloudConfig{ - Users: []cloudinit.SUser{ - { - Name: "root", - SshAuthorizedKeys: []string{ - adminPublicKey, - projectPublicKey, - }, - }, - }, - } - - if oCloudConfig != nil { - cloudConfig.Merge(oCloudConfig) - } - - userData := cloudConfig.UserDataBase64() + userData := generateUserData(adminPublicKey, projectPublicKey, oUserData) desc := SManagedVMCreateConfig{} if err := config.Unmarshal(&desc, "desc"); err != nil { diff --git a/pkg/compute/guestdrivers/userdata.go b/pkg/compute/guestdrivers/userdata.go new file mode 100644 index 0000000000..0f711a2099 --- /dev/null +++ b/pkg/compute/guestdrivers/userdata.go @@ -0,0 +1,32 @@ +package guestdrivers + +import ( + "yunion.io/x/onecloud/pkg/util/ansible" + "yunion.io/x/onecloud/pkg/util/cloudinit" +) + +func generateUserData(adminPublicKey, projectPublicKey, oUserData string) string { + var oCloudConfig *cloudinit.SCloudConfig = nil + + if len(oUserData) > 0 { + oCloudConfig, _ = cloudinit.ParseUserDataBase64(oUserData) + } + + ansibleUser := cloudinit.NewUser(ansible.PUBLIC_CLOUD_ANSIBLE_USER) + ansibleUser.SshKey(adminPublicKey).SshKey(projectPublicKey).SudoPolicy(cloudinit.USER_SUDO_NOPASSWD) + + cloudConfig := cloudinit.SCloudConfig{ + DisableRoot: 0, + SshPwauth: 1, + + Users: []cloudinit.SUser{ + ansibleUser, + }, + } + + if oCloudConfig != nil { + cloudConfig.Merge(oCloudConfig) + } + + return cloudConfig.UserDataBase64() +} diff --git a/pkg/compute/handlers.go b/pkg/compute/handlers.go index 50453c5816..f44a9ac639 100644 --- a/pkg/compute/handlers.go +++ b/pkg/compute/handlers.go @@ -11,6 +11,7 @@ import ( "yunion.io/x/onecloud/pkg/compute/capabilities" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/specs" + "yunion.io/x/onecloud/pkg/compute/sshkeys" "yunion.io/x/onecloud/pkg/compute/usages" ) @@ -21,6 +22,7 @@ func InitHandlers(app *appsrv.Application) { usages.AddUsageHandler("", app) capabilities.AddCapabilityHandler("", app) specs.AddSpecHandler("", app) + sshkeys.AddSshKeysHandler("", app) taskman.AddTaskHandler("", app) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index d7d91d11de..7222cd828b 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "database/sql" + "encoding/base64" "fmt" "net/http" "strconv" @@ -24,20 +25,22 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" - "encoding/base64" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" + "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/seclib2" + + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/compute/sshkeys" ) const ( @@ -3313,12 +3316,12 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, host *SHost, para } // add default public keys - _, adminPubKey, err := getSshAdminKeypair(ctx) + _, adminPubKey, err := sshkeys.GetSshAdminKeypair(ctx) if err != nil { log.Errorf("fail to get ssh admin public key %s", err) } - _, projPubKey, err := getSshProjectKeypair(ctx, self.ProjectId) + _, projPubKey, err := sshkeys.GetSshProjectKeypair(ctx, self.ProjectId) if err != nil { log.Errorf("fail to get ssh project public key %s", err) diff --git a/pkg/compute/sshkeys/doc.go b/pkg/compute/sshkeys/doc.go new file mode 100644 index 0000000000..ad943a49e4 --- /dev/null +++ b/pkg/compute/sshkeys/doc.go @@ -0,0 +1 @@ +package sshkeys // import "yunion.io/x/onecloud/pkg/compute/sshkeys" diff --git a/pkg/compute/sshkeys/handler.go b/pkg/compute/sshkeys/handler.go new file mode 100644 index 0000000000..f6bda5d2cf --- /dev/null +++ b/pkg/compute/sshkeys/handler.go @@ -0,0 +1,85 @@ +package sshkeys + +import ( + "context" + "database/sql" + "fmt" + "net/http" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/appctx" + "yunion.io/x/onecloud/pkg/appsrv" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" +) + +func AddSshKeysHandler(prefix string, app *appsrv.Application) { + app.AddHandler2("GET", fmt.Sprintf("%s/sshkeypairs", prefix), auth.Authenticate(sshKeysHandler), nil, "get_sshkeys", nil) + app.AddHandler2("GET", fmt.Sprintf("%s/sshkeypairs/", prefix), auth.Authenticate(adminSshKeysHandler), nil, "get_sshkeys", nil) +} + +func adminSshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { + publicOnly := false + userCred := auth.FetchUserCredential(ctx) + if !userCred.IsSystemAdmin() { + publicOnly = true + } + params := appctx.AppContextParams(ctx) + projectId := params[""] + if len(projectId) == 0 { + httperrors.InputParameterError(w, "empty project_id/tenant_id") + return + } + tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, projectId) + if err != nil { + if err == sql.ErrNoRows { + httperrors.ResourceNotFoundError(w, "tenant/project %s not found", projectId) + return + } else { + httperrors.GeneralServerError(w, err) + return + } + } + query, err := jsonutils.ParseQueryString(r.URL.RawQuery) + if err != nil { + httperrors.GeneralServerError(w, err) + return + } + isAdmin := jsonutils.QueryBoolean(query, "admin", false) + + sendSshKey(ctx, w, userCred, tenant.Id, isAdmin, publicOnly) +} + +func sshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) { + userCred := auth.FetchUserCredential(ctx) + query, err := jsonutils.ParseQueryString(r.URL.RawQuery) + if err != nil { + httperrors.GeneralServerError(w, err) + return + } + isAdmin := jsonutils.QueryBoolean(query, "admin", false) + + sendSshKey(ctx, w, userCred, userCred.GetProjectId(), isAdmin, false) +} + +func sendSshKey(ctx context.Context, w http.ResponseWriter, userCred mcclient.TokenCredential, projectId string, isAdmin bool, publicOnly bool) { + var privKey, pubKey string + + if isAdmin && userCred.IsSystemAdmin() { + privKey, pubKey, _ = GetSshAdminKeypair(ctx) + } else { + privKey, pubKey, _ = GetSshProjectKeypair(ctx, projectId) + } + + ret := jsonutils.NewDict() + + if !publicOnly { + ret.Add(jsonutils.NewString(privKey), "private_key") + } + ret.Add(jsonutils.NewString(pubKey), "public_key") + body := jsonutils.NewDict() + body.Add(ret, "sshkeypair") + appsrv.SendJSON(w, body) +} diff --git a/pkg/compute/models/sshkeypairs.go b/pkg/compute/sshkeys/sshkeypairs.go similarity index 89% rename from pkg/compute/models/sshkeypairs.go rename to pkg/compute/sshkeys/sshkeypairs.go index f226230540..7f1e71b9fa 100644 --- a/pkg/compute/models/sshkeypairs.go +++ b/pkg/compute/sshkeys/sshkeypairs.go @@ -1,11 +1,13 @@ -package models +package sshkeys import ( "context" + + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/seclib2" - "yunion.io/x/pkg/utils" ) const ( @@ -34,11 +36,11 @@ func _getKeys(ctx context.Context, tenantId string, privateKey, publicKey string return private, public, nil } -func getSshProjectKeypair(ctx context.Context, tenantId string) (string, string, error) { +func GetSshProjectKeypair(ctx context.Context, tenantId string) (string, string, error) { return _getKeys(ctx, tenantId, sshPrivateKey, sshPublicKey) } -func getSshAdminKeypair(ctx context.Context) (string, string, error) { +func GetSshAdminKeypair(ctx context.Context) (string, string, error) { userCred := auth.AdminCredential() return _getKeys(ctx, userCred.GetProjectId(), sshAdminPrivateKey, sshAdminPublicKey) } diff --git a/pkg/httperrors/httperrors.go b/pkg/httperrors/httperrors.go index b9be4abbaf..55d0b1288e 100644 --- a/pkg/httperrors/httperrors.go +++ b/pkg/httperrors/httperrors.go @@ -71,6 +71,10 @@ func InvalidInputError(w http.ResponseWriter, msg string, params ...interface{}) JsonClientError(w, NewInputParameterError(msg, params...)) } +func InputParameterError(w http.ResponseWriter, msg string, params ...interface{}) { + JsonClientError(w, NewInputParameterError(msg, params...)) +} + func MissingParameterError(w http.ResponseWriter, param string) { JsonClientError(w, NewMissingParameterError(param)) } @@ -94,3 +98,11 @@ func TenantNotFoundError(w http.ResponseWriter, msg string, params ...interface{ func OutOfQuotaError(w http.ResponseWriter, msg string, params ...interface{}) { JsonClientError(w, NewOutOfQuotaError(msg, params...)) } + +func NotSufficientPrivilegeError(w http.ResponseWriter, msg string, params ...interface{}) { + JsonClientError(w, NewNotSufficientPrivilegeError(msg, params...)) +} + +func ResourceNotFoundError(w http.ResponseWriter, msg string, params ...interface{}) { + JsonClientError(w, NewResourceNotFoundError(msg, params...)) +} diff --git a/pkg/mcclient/modules/mod_capabilities.go b/pkg/mcclient/modules/mod_capabilities.go index 76e058c8d8..4b6fa33124 100644 --- a/pkg/mcclient/modules/mod_capabilities.go +++ b/pkg/mcclient/modules/mod_capabilities.go @@ -26,5 +26,5 @@ func init() { Capabilities = SCapabilityManager{ ResourceManager: NewComputeManager("capability", "capabilities", []string{}, []string{}), } - registerCompute(&Capabilities) + registerComputeV2(&Capabilities) } diff --git a/pkg/mcclient/modules/mod_snapshots.go b/pkg/mcclient/modules/mod_snapshots.go index 8def8e7e3f..a0203f7887 100644 --- a/pkg/mcclient/modules/mod_snapshots.go +++ b/pkg/mcclient/modules/mod_snapshots.go @@ -10,5 +10,5 @@ func init() { "Disk_id", "Guest_id", "Created_at"}, []string{"Storage_id", "Create_by", "Location", "Out_of_chain"}) - registerCompute(&Snapshots) + registerComputeV2(&Snapshots) } diff --git a/pkg/mcclient/modules/mod_sshkeypairs.go b/pkg/mcclient/modules/mod_sshkeypairs.go new file mode 100644 index 0000000000..335d59907e --- /dev/null +++ b/pkg/mcclient/modules/mod_sshkeypairs.go @@ -0,0 +1,37 @@ +package modules + +import ( + "fmt" + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" +) + +type SSshkeypairManager struct { + ResourceManager +} + +func (this *SSshkeypairManager) List(s *mcclient.ClientSession, params jsonutils.JSONObject) (*ListResult, error) { + url := "/sshkeypairs" + queryStr := params.QueryString() + if len(queryStr) > 0 { + url = fmt.Sprintf("%s?%s", url, queryStr) + } + body, err := this._get(s, url, "sshkeypair") + if err != nil { + return nil, err + } + result := ListResult{Data: []jsonutils.JSONObject{body}} + return &result, nil +} + +var ( + Sshkeypairs SSshkeypairManager +) + +func init() { + Sshkeypairs = SSshkeypairManager{NewComputeManager("sshkeypair", "sshkeypairs", + []string{}, + []string{})} + + registerComputeV2(&Sshkeypairs) +} diff --git a/pkg/mcclient/modules/register.go b/pkg/mcclient/modules/register.go index de6072cb31..0c4a389a63 100644 --- a/pkg/mcclient/modules/register.go +++ b/pkg/mcclient/modules/register.go @@ -1,7 +1,15 @@ package modules func registerCompute(mod BaseManagerInterface) { + registerComputeV1(mod) + registerComputeV2(mod) +} + +func registerComputeV1(mod BaseManagerInterface) { _register("v1", mod) +} + +func registerComputeV2(mod BaseManagerInterface) { _register("v2", mod) } diff --git a/pkg/util/aliyun/aliyun.go b/pkg/util/aliyun/aliyun.go index 5a82934320..0ed7a8ed33 100644 --- a/pkg/util/aliyun/aliyun.go +++ b/pkg/util/aliyun/aliyun.go @@ -4,8 +4,6 @@ import ( "github.com/aliyun/alibaba-cloud-sdk-go/sdk" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" - "time" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudprovider" @@ -21,6 +19,8 @@ const ( ALIYUN_API_VERSION = "2014-05-26" ALIYUN_BSS_API_VERSION = "2017-12-14" + + ALIYUN_RAM_API_VERSION = "2015-05-01" ) type SAliyunClient struct { @@ -44,10 +44,6 @@ func jsonRequest(client *sdk.Client, apiName string, params map[string]string) ( return _jsonRequest(client, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params) } -func businessRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return _jsonRequest(client, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params) -} - func _jsonRequest(client *sdk.Client, domain string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) { req := requests.NewCommonRequest() req.Domain = domain @@ -58,6 +54,7 @@ func _jsonRequest(client *sdk.Client, domain string, version string, apiName str req.QueryParams[k] = v } } + req.Scheme = "https" resp, err := client.ProcessCommonRequest(req) if err != nil { @@ -94,14 +91,6 @@ func (self *SAliyunClient) jsonRequest(apiName string, params map[string]string) return jsonRequest(cli, apiName, params) } -func (self *SAliyunClient) businessRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - cli, err := self.getDefaultClient() - if err != nil { - return nil, err - } - return businessRequest(cli, apiName, params) -} - func (self *SAliyunClient) fetchRegions() error { body, err := self.jsonRequest("DescribeRegions", nil) if err != nil { @@ -208,85 +197,3 @@ func (self *SAliyunClient) GetIStoragecacheById(id string) (cloudprovider.ICloud } return nil, cloudprovider.ErrNotFound } - -type SAccountBalance struct { - AvailableAmount float64 - AvailableCashAmount float64 - CreditAmount float64 - MybankCreditAmount float64 - Currency string -} - -type SCashCoupon struct { - ApplicableProducts string - ApplicableScenarios string - Balance float64 - CashCouponId string - CashCouponNo string - EffectiveTime time.Time - ExpiryTime time.Time - GrantedTime time.Time - NominalValue float64 - Status string -} - -type SPrepaidCard struct { - PrepaidCardId string - PrepaidCardNo string - GrantedTime time.Time - EffectiveTime time.Time - ExpiryTime time.Time - NominalValue float64 - Balance float64 - ApplicableProducts string - ApplicableScenarios string -} - -func (self *SAliyunClient) QueryAccountBalance() (*SAccountBalance, error) { - body, err := self.businessRequest("QueryAccountBalance", nil) - if err != nil { - log.Errorf("QueryAccountBalance fail %s", err) - return nil, err - } - balance := SAccountBalance{} - err = body.Unmarshal(&balance, "Data") - if err != nil { - log.Errorf("Unmarshal AccountBalance fail %s", err) - return nil, err - } - return &balance, nil -} - -func (self *SAliyunClient) QueryCashCoupons() ([]SCashCoupon, error) { - params := make(map[string]string) - params["EffectiveOrNot"] = "True" - body, err := self.businessRequest("QueryCashCoupons", params) - if err != nil { - log.Errorf("QueryCashCoupons fail %s", err) - return nil, err - } - coupons := make([]SCashCoupon, 0) - err = body.Unmarshal(&coupons, "Data", "CashCoupon") - if err != nil { - log.Errorf("Unmarshal fail %s", err) - return nil, err - } - return coupons, nil -} - -func (self *SAliyunClient) QueryPrepaidCards() ([]SPrepaidCard, error) { - params := make(map[string]string) - params["EffectiveOrNot"] = "True" - body, err := self.businessRequest("QueryPrepaidCards", params) - if err != nil { - log.Errorf("QueryPrepaidCards fail %s", err) - return nil, err - } - cards := make([]SPrepaidCard, 0) - err = body.Unmarshal(&cards, "Data", "PrepaidCard") - if err != nil { - log.Errorf("Unmarshal fail %s", err) - return nil, err - } - return cards, nil -} diff --git a/pkg/util/aliyun/business.go b/pkg/util/aliyun/business.go new file mode 100644 index 0000000000..544b0f81f0 --- /dev/null +++ b/pkg/util/aliyun/business.go @@ -0,0 +1,104 @@ +package aliyun + +import ( + "time" + + "github.com/aliyun/alibaba-cloud-sdk-go/sdk" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" +) + +func businessRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return _jsonRequest(client, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params) +} + +func (self *SAliyunClient) businessRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := self.getDefaultClient() + if err != nil { + return nil, err + } + return businessRequest(cli, apiName, params) +} + +type SAccountBalance struct { + AvailableAmount float64 + AvailableCashAmount float64 + CreditAmount float64 + MybankCreditAmount float64 + Currency string +} + +type SCashCoupon struct { + ApplicableProducts string + ApplicableScenarios string + Balance float64 + CashCouponId string + CashCouponNo string + EffectiveTime time.Time + ExpiryTime time.Time + GrantedTime time.Time + NominalValue float64 + Status string +} + +type SPrepaidCard struct { + PrepaidCardId string + PrepaidCardNo string + GrantedTime time.Time + EffectiveTime time.Time + ExpiryTime time.Time + NominalValue float64 + Balance float64 + ApplicableProducts string + ApplicableScenarios string +} + +func (self *SAliyunClient) QueryAccountBalance() (*SAccountBalance, error) { + body, err := self.businessRequest("QueryAccountBalance", nil) + if err != nil { + log.Errorf("QueryAccountBalance fail %s", err) + return nil, err + } + balance := SAccountBalance{} + err = body.Unmarshal(&balance, "Data") + if err != nil { + log.Errorf("Unmarshal AccountBalance fail %s", err) + return nil, err + } + return &balance, nil +} + +func (self *SAliyunClient) QueryCashCoupons() ([]SCashCoupon, error) { + params := make(map[string]string) + params["EffectiveOrNot"] = "True" + body, err := self.businessRequest("QueryCashCoupons", params) + if err != nil { + log.Errorf("QueryCashCoupons fail %s", err) + return nil, err + } + coupons := make([]SCashCoupon, 0) + err = body.Unmarshal(&coupons, "Data", "CashCoupon") + if err != nil { + log.Errorf("Unmarshal fail %s", err) + return nil, err + } + return coupons, nil +} + +func (self *SAliyunClient) QueryPrepaidCards() ([]SPrepaidCard, error) { + params := make(map[string]string) + params["EffectiveOrNot"] = "True" + body, err := self.businessRequest("QueryPrepaidCards", params) + if err != nil { + log.Errorf("QueryPrepaidCards fail %s", err) + return nil, err + } + cards := make([]SPrepaidCard, 0) + err = body.Unmarshal(&cards, "Data", "PrepaidCard") + if err != nil { + log.Errorf("Unmarshal fail %s", err) + return nil, err + } + return cards, nil +} diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index ed12a4f1e5..31e7c1b1b2 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -793,3 +793,7 @@ func (self *SInstance) GetBillingType() string { func (self *SInstance) GetExpiredAt() time.Time { return self.ExpiredTime } + +func (self *SInstance) UpdateUserData(userData string) error { + return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) +} diff --git a/pkg/util/aliyun/ram.go b/pkg/util/aliyun/ram.go new file mode 100644 index 0000000000..8e0d2814fb --- /dev/null +++ b/pkg/util/aliyun/ram.go @@ -0,0 +1,222 @@ +package aliyun + +import ( + "time" + + "github.com/aliyun/alibaba-cloud-sdk-go/sdk" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +func ramRequest(client *sdk.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return _jsonRequest(client, "ram.aliyuncs.com", ALIYUN_RAM_API_VERSION, apiName, params) +} + +func (self *SAliyunClient) ramRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := self.getDefaultClient() + if err != nil { + return nil, err + } + return ramRequest(cli, apiName, params) +} + +type SRole struct { + Arn string + CreateDate time.Time + Description string + RoleId string + RoleName string + + AssumeRolePolicyDocument string +} + +func (self *SAliyunClient) ListRoles() ([]SRole, error) { + body, err := self.ramRequest("ListRoles", nil) + if err != nil { + log.Errorf("listRoles fail %s", err) + return nil, err + } + + roles := make([]SRole, 0) + + err = body.Unmarshal(&roles, "Roles", "Role") + if err != nil { + return nil, err + } + + return roles, nil +} + +func (self *SAliyunClient) GetRole(roleName string) (*SRole, error) { + params := make(map[string]string) + params["RoleName"] = roleName + + body, err := self.ramRequest("GetRole", params) + if err != nil { + if isError(err, "EntityNotExist.Role") { + return nil, cloudprovider.ErrNotFound + } + return nil, err + } + + role := SRole{} + + err = body.Unmarshal(&role, "Role") + if err != nil { + return nil, err + } + + return &role, nil +} + +func (self *SAliyunClient) createRole(roleName string, document string, desc string) (*SRole, error) { + params := make(map[string]string) + params["RoleName"] = roleName + params["AssumeRolePolicyDocument"] = document + if len(desc) > 0 { + params["Description"] = desc + } + + body, err := self.ramRequest("CreateRole", params) + if err != nil { + return nil, err + } + + role := SRole{} + + err = body.Unmarshal(&role, "Role") + if err != nil { + return nil, err + } + + return &role, nil +} + +/** + {"AttachmentCount":0, +"CreateDate":"2018-10-12T05:05:16Z", +"DefaultVersion":"v1", +"Description":"只读访问Data Lake Analytics的权限", +"PolicyName":"AliyunDLAReadOnlyAccess", +"PolicyType":"System", +"UpdateDate":"2018-10-12T05:05:16Z"} +*/ + +type SPolicy struct { + AttachmentCount int + CreateDate time.Time + UpdateDate time.Time + DefaultVersion string + Description string + PolicyName string + PolicyType string +} + +func (self *SAliyunClient) ListPolicies(policyType string, role string) ([]SPolicy, error) { + var action string + params := make(map[string]string) + if len(role) > 0 { + params["RoleName"] = role + action = "ListPoliciesForRole" + } else { + params["MaxItems"] = "1000" + if len(policyType) > 0 { + params["PolicyType"] = policyType + } + action = "ListPolicies" + } + + body, err := self.ramRequest(action, params) + if err != nil { + log.Errorf("listPolicies fail %s", err) + return nil, err + } + + policies := make([]SPolicy, 0) + + err = body.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, err + } + + return policies, nil +} + +func (self *SAliyunClient) GetPolicy(policyType string, policyName string) (*SPolicy, error) { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + + body, err := self.ramRequest("GetPolicy", params) + if err != nil { + if isError(err, "EntityNotExist.Role") { + return nil, cloudprovider.ErrNotFound + } + return nil, err + } + + policy := SPolicy{} + + err = body.Unmarshal(&policy, "Policy") + if err != nil { + return nil, err + } + + return &policy, nil +} + +func (self *SAliyunClient) createPolicy(name string, document string, desc string) (*SPolicy, error) { + params := make(map[string]string) + params["PolicyName"] = name + params["PolicyDocument"] = document + if len(desc) > 0 { + params["Description"] = desc + } + + body, err := self.ramRequest("CreatePolicy", params) + if err != nil { + return nil, err + } + + policy := SPolicy{} + + err = body.Unmarshal(&policy, "Policy") + if err != nil { + return nil, err + } + + return &policy, nil +} + +func (self *SAliyunClient) DeletePolicy(policyType string, policyName string) error { + params := make(map[string]string) + params["PolicyName"] = policyName + params["PolicyType"] = policyType + + _, err := self.ramRequest("DeletePolicy", params) + return err +} + +func (self *SAliyunClient) DeleteRole(roleName string) error { + params := make(map[string]string) + params["RoleName"] = roleName + + _, err := self.ramRequest("DeleteRole", params) + return err +} + +func (self *SAliyunClient) attachPolicy2Role(policyType string, policyName string, roleName string) error { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + params["RoleName"] = roleName + + _, err := self.ramRequest("AttachPolicyToRole", params) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/util/aliyun/ramimage.go b/pkg/util/aliyun/ramimage.go new file mode 100644 index 0000000000..4236b6b03d --- /dev/null +++ b/pkg/util/aliyun/ramimage.go @@ -0,0 +1,172 @@ +package aliyun + +import ( + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +const ( + AliyunECSImageImportRole = "AliyunECSImageImportDefaultRole" + AliyunECSImageImportRoleDocument = `{ +"Statement": [ +{ +"Action": "sts:AssumeRole", +"Effect": "Allow", +"Principal": { + "Service": [ + "ecs.aliyuncs.com" + ] +} +} +], +"Version": "1" +}` + + AliyunECSImageImportRolePolicyType = "System" + AliyunECSImageImportRolePolicy = "AliyunECSImageImportRolePolicy" + AliyunECSImageImportRolePolicyDocument = `{ +"Version": "1", +"Statement": [ +{ +"Action": [ + "oss:GetObject", + "oss:GetBucketLocation" +], +"Resource": "*", +"Effect": "Allow" +} +] +}` +) + +func (self *SAliyunClient) EnableImageImport() error { + _, err := self.GetRole(AliyunECSImageImportRole) + if err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createRole(AliyunECSImageImportRole, + AliyunECSImageImportRoleDocument, + "Allow Import External Image from OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(AliyunECSImageImportRolePolicy, + AliyunECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPolicies("", AliyunECSImageImportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == AliyunECSImageImportRolePolicyType && + policies[i].PolicyName == AliyunECSImageImportRolePolicy { + return nil // find policy + } + } + + err = self.attachPolicy2Role(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy, AliyunECSImageImportRole) + if err != nil { + return err + } + + return nil +} + +const ( + AliyunECSImageExportRole = "AliyunECSImageExportDefaultRole" + AliyunECSImageExportRoleDocument = `{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ecs.aliyuncs.com" + ] + } + } + ], + "Version": "1" +}` + + AliyunECSImageExportRolePolicyType = "System" + AliyunECSImageExportRolePolicy = "AliyunECSImageExportRolePolicy" + AliyunECSImageExportRolePolicyDocument = `{ + "Version": "1", + "Statement": [ + { + "Action": [ + "oss:GetObject", + "oss:PutObject", + "oss:DeleteObject", + "oss:GetBucketLocation", + "oss:AbortMultipartUpload", + "oss:ListMultipartUploads", + "oss:ListParts" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + }` +) + +func (self *SAliyunClient) EnableImageExport() error { + _, err := self.GetRole(AliyunECSImageExportRole) + if err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createRole(AliyunECSImageExportRole, + AliyunECSImageExportRoleDocument, + "Allow Export Import to OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(AliyunECSImageImportRolePolicy, + AliyunECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPolicies("", AliyunECSImageExportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == AliyunECSImageExportRolePolicyType && + policies[i].PolicyName == AliyunECSImageExportRolePolicy { + return nil // find policy + } + } + + err = self.attachPolicy2Role(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy, AliyunECSImageExportRole) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index 55c177bbf1..e264f52efb 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -548,7 +548,7 @@ func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStorag return nil, cloudprovider.ErrNotFound } -func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname string) error { +func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { params := make(map[string]string) params["InstanceId"] = instId if len(name) > 0 { @@ -563,12 +563,15 @@ func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname if len(hostname) > 0 { params["HostName"] = hostname } + if len(userData) > 0 { + params["UserData"] = userData + } _, err := self.ecsRequest("ModifyInstanceAttribute", params) return err } func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { - return self.updateInstance(instId, "", "", passwd, "") + return self.updateInstance(instId, "", "", passwd, "", "") } // func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { diff --git a/pkg/util/aliyun/shell/ram.go b/pkg/util/aliyun/shell/ram.go new file mode 100644 index 0000000000..86cc18a953 --- /dev/null +++ b/pkg/util/aliyun/shell/ram.go @@ -0,0 +1,80 @@ +package shell + +import ( + "yunion.io/x/onecloud/pkg/util/aliyun" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ListRolesOptions struct { + } + shellutils.R(&ListRolesOptions{}, "role-list", "List ram roles", func(cli *aliyun.SRegion, args *ListRolesOptions) error { + roles, err := cli.GetClient().ListRoles() + if err != nil { + return err + } + printList(roles, 0, 0, 0, []string{}) + return nil + }) + + type GetRoleOptions struct { + ROLENAME string + } + shellutils.R(&GetRoleOptions{}, "role-show", "Show ram role", func(cli *aliyun.SRegion, args *GetRoleOptions) error { + role, err := cli.GetClient().GetRole(args.ROLENAME) + if err != nil { + return err + } + printObject(role) + return nil + }) + + type ListPoliciesOptions struct { + PolicyType string + Role string + } + shellutils.R(&ListPoliciesOptions{}, "policy-list", "List ram policies", func(cli *aliyun.SRegion, args *ListPoliciesOptions) error { + policies, err := cli.GetClient().ListPolicies(args.PolicyType, args.Role) + if err != nil { + return err + } + printList(policies, 0, 0, 0, []string{}) + return nil + }) + + type GetPolicyOptions struct { + POLICYTYPE string + POLICYNAME string + } + shellutils.R(&GetPolicyOptions{}, "policy-show", "Show ram policy", func(cli *aliyun.SRegion, args *GetPolicyOptions) error { + policy, err := cli.GetClient().GetPolicy(args.POLICYTYPE, args.POLICYNAME) + if err != nil { + return err + } + printObject(policy) + return nil + }) + + type DeletePolicyOptions struct { + POLICYTYPE string + POLICYNAME string + } + shellutils.R(&DeletePolicyOptions{}, "policy-delete", "Delete policy", func(cli *aliyun.SRegion, args *DeletePolicyOptions) error { + return cli.GetClient().DeletePolicy(args.POLICYTYPE, args.POLICYNAME) + }) + + type DeleteRoleOptions struct { + NAME string + } + shellutils.R(&DeleteRoleOptions{}, "role-delete", "Delete role", func(cli *aliyun.SRegion, args *DeleteRoleOptions) error { + return cli.GetClient().DeleteRole(args.NAME) + }) + + shellutils.R(&ListRolesOptions{}, "enable-image-import", "Enable image import privilege", func(cli *aliyun.SRegion, args *ListRolesOptions) error { + return cli.GetClient().EnableImageImport() + }) + + shellutils.R(&ListRolesOptions{}, "enable-image-export", "Enable image export privilege", func(cli *aliyun.SRegion, args *ListRolesOptions) error { + return cli.GetClient().EnableImageExport() + }) +} diff --git a/pkg/util/aliyun/snapshot.go b/pkg/util/aliyun/snapshot.go index f5ce2908d0..30e9e7fb6c 100644 --- a/pkg/util/aliyun/snapshot.go +++ b/pkg/util/aliyun/snapshot.go @@ -107,10 +107,7 @@ func (self *SSnapshot) Delete() error { if self.region == nil { return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) } - params := make(map[string]string) - params["SnapshotId"] = self.SnapshotId - _, err := self.region.ecsRequest("DeleteSnapshot", params) - return err + return self.region.DeleteSnapshot(self.SnapshotId) } func (self *SSnapshot) GetMetadata() *jsonutils.JSONDict { @@ -166,3 +163,10 @@ func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSn return &snapshots[0], nil } } + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + params := make(map[string]string) + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("DeleteSnapshot", params) + return err +} diff --git a/pkg/util/aliyun/storagecache.go b/pkg/util/aliyun/storagecache.go index 595907a14e..960e9cab88 100644 --- a/pkg/util/aliyun/storagecache.go +++ b/pkg/util/aliyun/storagecache.go @@ -120,7 +120,7 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI log.Errorf("GetOssClient err %s", err) return "", err } - bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), self.region.client.providerId)) + bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), imageId)) exist, err := oss.IsBucketExist(bucketName) if err != nil { log.Errorf("IsBucketExist err %s", err) @@ -136,6 +136,9 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI } else { log.Debugf("Bucket %s exists", bucketName) } + + defer oss.DeleteBucket(bucketName) // remove bucket + bucket, err := oss.Bucket(bucketName) if err != nil { log.Errorf("Bucket error %s %s", bucketName, err) @@ -148,6 +151,8 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI return "", err } + defer bucket.DeleteObject(imageId) // remove object + imageBaseName := imageId if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { imageBaseName = fmt.Sprintf("img%s", imageId) @@ -171,6 +176,13 @@ func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageI log.Debugf("Import image %s", imageName) + // ensure privileges + err = self.region.GetClient().EnableImageImport() + if err != nil { + log.Errorf("fail to enable import privileges: %s", err) + return "", err + } + task, err := self.region.ImportImage(imageName, osArch, osType, osDist, bucketName, imageId) if err != nil { @@ -282,6 +294,12 @@ func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { } func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + err := self.region.GetClient().EnableImageExport() + if err != nil { + log.Errorf("fail to enable export privileges: %s", err) + return nil, err + } + tmpImageFile, err := ioutil.TempFile(path, extId) if err != nil { return nil, err diff --git a/pkg/util/ansible/const.go b/pkg/util/ansible/const.go new file mode 100644 index 0000000000..06ac34ff47 --- /dev/null +++ b/pkg/util/ansible/const.go @@ -0,0 +1,5 @@ +package ansible + +const ( + PUBLIC_CLOUD_ANSIBLE_USER = "yunionroot" +) diff --git a/pkg/util/ansible/doc.go b/pkg/util/ansible/doc.go new file mode 100644 index 0000000000..611028f5ee --- /dev/null +++ b/pkg/util/ansible/doc.go @@ -0,0 +1 @@ +package ansible // import "yunion.io/x/onecloud/pkg/util/ansible" diff --git a/pkg/util/azure/doc.go b/pkg/util/azure/doc.go new file mode 100644 index 0000000000..34145ae03c --- /dev/null +++ b/pkg/util/azure/doc.go @@ -0,0 +1 @@ +package azure // import "yunion.io/x/onecloud/pkg/util/azure" diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index fba0af7994..012618a303 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -859,3 +859,11 @@ func (self *SInstance) GetBillingType() string { func (self *SInstance) GetExpiredAt() time.Time { return time.Now() } + +func (self *SInstance) UpdateUserData(userData string) error { + params := compute.VirtualMachineUpdate{} + params.OsProfile = &compute.OSProfile{ + CustomData: &userData, + } + return self.host.zone.region.UpdateInstance(self.ID, params) +} diff --git a/pkg/util/cloudinit/cloudconfig.go b/pkg/util/cloudinit/cloudconfig.go index 4fc1ef7ba9..b622846ca7 100644 --- a/pkg/util/cloudinit/cloudconfig.go +++ b/pkg/util/cloudinit/cloudconfig.go @@ -4,12 +4,11 @@ import ( "bytes" "encoding/base64" - "golang.org/x/crypto/bcrypt" - "fmt" "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/util/seclib2" "yunion.io/x/pkg/utils" ) @@ -19,8 +18,15 @@ import ( * */ +type TSudoPolicy string + const ( CLOUD_CONFIG_HEADER = "#cloud-config\n" + + USER_SUDO_NOPASSWD = TSudoPolicy("sudo_nopasswd") + USER_SUDO = TSudoPolicy("sudo") + USER_SUDO_DENY = TSudoPolicy("sudo_deny") + USER_SUDO_NONE = TSudoPolicy("") ) type SWriteFile struct { @@ -34,7 +40,9 @@ type SWriteFile struct { type SUser struct { Name string Passwd string + LockPassword string SshAuthorizedKeys []string + Sudo string } type SPhoneHome struct { @@ -42,12 +50,14 @@ type SPhoneHome struct { } type SCloudConfig struct { - Users []SUser - WriteFiles []SWriteFile - Runcmd []string - Bootcmd []string - Packages []string - PhoneHome *SPhoneHome + Users []SUser + WriteFiles []SWriteFile + Runcmd []string + Bootcmd []string + Packages []string + PhoneHome *SPhoneHome + DisableRoot int + SshPwauth int } func NewWriteFile(path string, content string, perm string, owner string, isBase64 bool) SWriteFile { @@ -66,24 +76,43 @@ func NewWriteFile(path string, content string, perm string, owner string, isBase return f } -func NewUser(name string, passwd string, pubkeys []string, nohash bool) SUser { - u := SUser{} +func NewUser(name string) SUser { + u := SUser{Name: name} + return u +} - u.Name = name - if len(passwd) > 0 { - if nohash { - u.Passwd = passwd - } else { - hash, err := bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost) - if err != nil { - log.Errorf("GenerateFromPassword error %s", err) - } else { - u.Passwd = string(hash) - } - } +func (u *SUser) SudoPolicy(policy TSudoPolicy) *SUser { + switch policy { + case USER_SUDO_NOPASSWD: + u.Sudo = "ALL=(ALL) NOPASSWD:ALL" + case USER_SUDO: + u.Sudo = "ALL=(ALL) ALL" + case USER_SUDO_DENY: + u.Sudo = "False" + default: + u.Sudo = "" } - u.SshAuthorizedKeys = pubkeys + return u +} +func (u *SUser) SshKey(key string) *SUser { + if u.SshAuthorizedKeys == nil { + u.SshAuthorizedKeys = make([]string, 0) + } + u.SshAuthorizedKeys = append(u.SshAuthorizedKeys, key) + return u +} + +func (u *SUser) Password(passwd string) *SUser { + if len(passwd) > 0 { + hash, err := seclib2.GeneratePassword(passwd) + if err != nil { + log.Errorf("GeneratePassword error %s", err) + } else { + u.Passwd = hash + } + u.LockPassword = "false" + } return u } diff --git a/pkg/util/cloudinit/cloudconfig_test.go b/pkg/util/cloudinit/cloudconfig_test.go index 69e43a4667..f7589c4c69 100644 --- a/pkg/util/cloudinit/cloudconfig_test.go +++ b/pkg/util/cloudinit/cloudconfig_test.go @@ -5,11 +5,12 @@ import ( ) func TestSCloudConfig_UserData(t *testing.T) { - usr1 := NewUser("root", "", []string{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa4E8wmIOlmh1G8ZRcU2zpnl2frD2lLKdXpbTeUUZEKYFFlYM8TM5UrKrqrMCd3rFjaYGTKWiQwOiWroXlAXausbbVEI29KY+1Vd26qNyejj+CZO9MCj0naIrqa1V0of3TQY5I2U+ToIkyLqVFWhWVa57v/GUxsV2aNTmUS/qz0OPSCFPbGWWB35rsjwnFwq2jF6E8yJgTGDTYZcsghRi3IWfyfeHbSuWdvn6N8XrPBDmNg7h+GSvO6FJlp6MUw1hscECi13GwqXYgJnLG5RMiFH6s0vhozyHkue1vOTcryPHRQD0Jz/INUSaggH8L1HnYSUavOf4Cw25W9HfzgUBf", - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa4E8wmIOlmh1G8ZRcU2zpnl2frD2lLKdXpbTeUUZEKYFFlYM8TM5UrKrqrMCd3rFjaYGTKWiQwOiWroXlAXausbbVEI29KY+1Vd26qNyejj+CZO9MCj0naIrqa1V0of3TQY5I2U+ToIkyLqVFWhWVa57v/GUxsV2aNTmUS/qz0OPSCFPbGWWB35rsjwnFwq2jF6E8yJgTGDTYZcsghRi3IWfyfeHbSuWdvn6N8XrPBDmNg7h+GSvO6FJlp6MUw1hscECi13GwqXYgJnLG5RMiFH6s0vhozyHkue1vOTcryPHRQD0Jz/INUSaggH8L1HnYSUavOf4Cw25W9HfzgUBf", - }, false) - usr2 := NewUser("yunion", "123@yunion", nil, false) + usr1 := NewUser("root") + usr1.SshKey("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa4E8wmIOlmh1G8ZRcU2zpnl2frD2lLKdXpbTeUUZEKYFFlYM8TM5UrKrqrMCd3rFjaYGTKWiQwOiWroXlAXausbbVEI29KY+1Vd26qNyejj+CZO9MCj0naIrqa1V0of3TQY5I2U+ToIkyLqVFWhWVa57v/GUxsV2aNTmUS/qz0OPSCFPbGWWB35rsjwnFwq2jF6E8yJgTGDTYZcsghRi3IWfyfeHbSuWdvn6N8XrPBDmNg7h+GSvO6FJlp6MUw1hscECi13GwqXYgJnLG5RMiFH6s0vhozyHkue1vOTcryPHRQD0Jz/INUSaggH8L1HnYSUavOf4Cw25W9HfzgUBf") + + usr2 := NewUser("yunion") + usr2.Password("123@yunion").SudoPolicy(USER_SUDO_NOPASSWD) + file1 := NewWriteFile("/etc/ansible/hosts", "gobuild\ncloudev\n", "", "", true) file2 := NewWriteFile("/etc/hosts", "127.0.0.1 localhost\n", "", "", false) config := SCloudConfig{ @@ -27,6 +28,8 @@ func TestSCloudConfig_UserData(t *testing.T) { PhoneHome: &SPhoneHome{ Url: "http://www.yunion.io/$INSTANCE_ID", }, + DisableRoot: 0, + SshPwauth: 1, } userData := config.UserData() diff --git a/pkg/util/cloudinit/doc.go b/pkg/util/cloudinit/doc.go new file mode 100644 index 0000000000..7157b9c1db --- /dev/null +++ b/pkg/util/cloudinit/doc.go @@ -0,0 +1 @@ +package cloudinit // import "yunion.io/x/onecloud/pkg/util/cloudinit" diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index a4ef5dce3a..623a4da458 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -245,3 +245,7 @@ func (self *SVirtualMachine) GetBillingType() string { func (self *SVirtualMachine) GetExpiredAt() time.Time { return time.Time{} } + +func (self *SVirtualMachine) UpdateUserData(userData string) error { + return nil +} diff --git a/pkg/util/excelutils/doc.go b/pkg/util/excelutils/doc.go new file mode 100644 index 0000000000..ec5b477f9a --- /dev/null +++ b/pkg/util/excelutils/doc.go @@ -0,0 +1 @@ +package excelutils // import "yunion.io/x/onecloud/pkg/util/excelutils" diff --git a/pkg/util/imagetools/doc.go b/pkg/util/imagetools/doc.go new file mode 100644 index 0000000000..a19b49421b --- /dev/null +++ b/pkg/util/imagetools/doc.go @@ -0,0 +1 @@ +package imagetools // import "yunion.io/x/onecloud/pkg/util/imagetools" diff --git a/pkg/util/seclib2/passwd.go b/pkg/util/seclib2/passwd.go new file mode 100644 index 0000000000..46179b5b8a --- /dev/null +++ b/pkg/util/seclib2/passwd.go @@ -0,0 +1,20 @@ +package seclib2 + +import ( + "fmt" + + "github.com/tredoe/osutil/user/crypt/sha512_crypt" + + "yunion.io/x/pkg/util/seclib" +) + +func GeneratePassword(passwd string) (string, error) { + salt := seclib.RandomPassword(8) + sha512Crypt := sha512_crypt.New() + return sha512Crypt.Generate([]byte(passwd), []byte(fmt.Sprintf("$6$%s", salt))) +} + +func VerifyPassword(passwd string, hash string) error { + sha512Crypt := sha512_crypt.New() + return sha512Crypt.Verify(hash, []byte(passwd)) +} diff --git a/pkg/util/seclib2/passwd_test.go b/pkg/util/seclib2/passwd_test.go new file mode 100644 index 0000000000..4c0c17b5c8 --- /dev/null +++ b/pkg/util/seclib2/passwd_test.go @@ -0,0 +1,18 @@ +package seclib2 + +import "testing" + +func TestGeneratePassword(t *testing.T) { + passwd := "Hello world!" + dk, err := GeneratePassword(passwd) + if err != nil { + t.Errorf("%s", err) + return + } + t.Logf("%s", dk) + + err = VerifyPassword(passwd, dk) + if err != nil { + t.Errorf("fail to verify %s", err) + } +} From cfa4f5db945dcef09137c712370edcb3d8e33593 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sat, 13 Oct 2018 22:23:50 +0800 Subject: [PATCH 10/10] server show expired_at column --- pkg/mcclient/modules/mod_servers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/mcclient/modules/mod_servers.go b/pkg/mcclient/modules/mod_servers.go index 4515c97c12..95e75b4f0a 100644 --- a/pkg/mcclient/modules/mod_servers.go +++ b/pkg/mcclient/modules/mod_servers.go @@ -69,7 +69,8 @@ func init() { "Secgroup", "Secgrp_id", "vrouter", "vrouter_id", "Created_at", "Group_name", - "Group_id", "Hypervisor", "os_type"}, + "Group_id", "Hypervisor", "os_type", + "expired_at"}, []string{"Host", "Tenant", "is_system", "auto_delete_at"})} registerCompute(&Servers)