Merge branch 'release/2.4.0' of ssh://git.yunion.io/~quxuan/onecloud into release/2.4.0

This commit is contained in:
屈轩
2018-11-19 15:01:51 +08:00
55 changed files with 1035 additions and 509 deletions
+35 -123
View File
@@ -1,64 +1,16 @@
package shell
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type DNSRecordOptions struct {
A []string `help:"DNS A record" metavar:"A_RECORD" positional:"false"`
AAAA []string `help:"DNS AAAA record" metavar:"AAAA_RECORD" positional:"false"`
CNAME string `help:"DNS CNAME record" metavar:"CNAME_RECORD" positional:"false"`
PTR string `help:"DNS PTR record" metavar:"PTR_RECORD" positional:"false"`
SRVHost string `help:"(deprecated) DNS SRV record, server of service" metavar:"SRV_RECORD_HOST" positional:"false"`
SRVPort int64 `help:"(deprecated) DNS SRV record, port of service" metavar:"SRV_RECORD_PORT" positional:"false"`
SRV []string `help:"DNS SRV record, in the format of host:port:weight:priority" metavar:"SRV_RECORD" positional:"false"`
}
func parseDNSRecords(args *DNSRecordOptions, params *jsonutils.JSONDict) {
if len(args.A) > 0 || len(args.AAAA) > 0 {
for i, a := range args.A {
params.Add(jsonutils.NewString(a), fmt.Sprintf("A.%d", i))
}
for i, a := range args.AAAA {
params.Add(jsonutils.NewString(a), fmt.Sprintf("AAAA.%d", i))
}
} else if len(args.CNAME) > 0 {
params.Add(jsonutils.NewString(args.CNAME), "CNAME")
} else if len(args.SRV) > 0 || (len(args.SRVHost) > 0 && args.SRVPort > 0) {
for i, s := range args.SRV {
params.Set(fmt.Sprintf("SRV.%d", i), jsonutils.NewString(s))
}
// Keep using the original argument passing method in case a
// newer climc is used against old service
if len(args.SRVHost) > 0 && args.SRVPort > 0 {
params.Set("SRV_host", jsonutils.NewString(args.SRVHost))
params.Set("SRV_port", jsonutils.NewInt(args.SRVPort))
}
} else if len(args.PTR) > 0 {
params.Add(jsonutils.NewString(args.PTR), "PTR")
}
}
func init() {
type DNSListOptions struct {
options.BaseListOptions
}
R(&DNSListOptions{}, "dns-list", "List dns records", func(s *mcclient.ClientSession, suboptions *DNSListOptions) error {
var params *jsonutils.JSONDict
{
var err error
params, err = suboptions.BaseListOptions.Params()
if err != nil {
return err
}
R(&options.DNSListOptions{}, "dns-list", "List dns records", func(s *mcclient.ClientSession, opts *options.DNSListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.DNSRecords.List(s, params)
if err != nil {
@@ -68,24 +20,10 @@ func init() {
return nil
})
type DNSCreateOptions struct {
NAME string `help:"DNS name to create"`
TTL int64 `help:"TTL in seconds" positional:"false"`
Desc string `help:"Description" metavar:"DESCRIPTION"`
DNSRecordOptions
}
R(&DNSCreateOptions{}, "dns-create", "Create dns record", func(s *mcclient.ClientSession, args *DNSCreateOptions) error {
params := jsonutils.NewDict()
parseDNSRecords(&args.DNSRecordOptions, params)
if params.Size() == 0 {
return fmt.Errorf("No records to create")
}
params.Add(jsonutils.NewString(args.NAME), "name")
if args.TTL > 0 {
params.Add(jsonutils.NewInt(args.TTL), "ttl")
}
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
R(&options.DNSCreateOptions{}, "dns-create", "Create dns record", func(s *mcclient.ClientSession, opts *options.DNSCreateOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
rec, e := modules.DNSRecords.Create(s, params)
if e != nil {
@@ -95,11 +33,8 @@ func init() {
return nil
})
type DNSShowOptions struct {
ID string `help:"ID of DNS record to show"`
}
R(&DNSShowOptions{}, "dns-show", "Show details of a dns records", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.Get(s, args.ID, nil)
R(&options.DNSGetOptions{}, "dns-show", "Show details of a dns records", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.Get(s, opts.ID, nil)
if e != nil {
return e
}
@@ -107,29 +42,12 @@ func init() {
return nil
})
type DNSUpdateOptions struct {
ID string `help:"ID of DNS record to update"`
Name string `help:"Domain name"`
TTL int64 `help:"TTL in seconds" positional:"false"`
Desc string `help:"Description"`
DNSRecordOptions
}
R(&DNSUpdateOptions{}, "dns-update", "Update details of a dns records", func(s *mcclient.ClientSession, args *DNSUpdateOptions) error {
params := jsonutils.NewDict()
if len(args.Name) > 0 {
params.Add(jsonutils.NewString(args.Name), "name")
R(&options.DNSUpdateOptions{}, "dns-update", "Update details of a dns records", func(s *mcclient.ClientSession, opts *options.DNSUpdateOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if args.TTL > 0 {
params.Add(jsonutils.NewInt(args.TTL), "ttl")
}
parseDNSRecords(&args.DNSRecordOptions, params)
if params.Size() == 0 {
return InvalidUpdateError()
}
dns, e := modules.DNSRecords.Update(s, args.ID, params)
dns, e := modules.DNSRecords.Update(s, opts.ID, params)
if e != nil {
return e
}
@@ -137,8 +55,8 @@ func init() {
return nil
})
R(&DNSShowOptions{}, "dns-delete", "Delete a dns record", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.Delete(s, args.ID, nil)
R(&options.DNSGetOptions{}, "dns-delete", "Delete a dns record", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.Delete(s, opts.ID, nil)
if e != nil {
return e
}
@@ -146,8 +64,8 @@ func init() {
return nil
})
R(&DNSShowOptions{}, "dns-public", "Make a dns record publicly available", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "public", nil)
R(&options.DNSGetOptions{}, "dns-public", "Make a dns record publicly available", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "public", nil)
if e != nil {
return e
}
@@ -155,8 +73,8 @@ func init() {
return nil
})
R(&DNSShowOptions{}, "dns-private", "Make a dns record private", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "private", nil)
R(&options.DNSGetOptions{}, "dns-private", "Make a dns record private", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "private", nil)
if e != nil {
return e
}
@@ -164,8 +82,8 @@ func init() {
return nil
})
R(&DNSShowOptions{}, "dns-enable", "Enable dns record", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "enable", nil)
R(&options.DNSGetOptions{}, "dns-enable", "Enable dns record", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "enable", nil)
if e != nil {
return e
}
@@ -173,8 +91,8 @@ func init() {
return nil
})
R(&DNSShowOptions{}, "dns-disable", "Disable dns record", func(s *mcclient.ClientSession, args *DNSShowOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "disable", nil)
R(&options.DNSGetOptions{}, "dns-disable", "Disable dns record", func(s *mcclient.ClientSession, opts *options.DNSGetOptions) error {
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "disable", nil)
if e != nil {
return e
}
@@ -182,17 +100,12 @@ func init() {
return nil
})
type DNSUpdateRecordsOptions struct {
ID string `help:"ID of dns record to modify"`
DNSRecordOptions
}
R(&DNSUpdateRecordsOptions{}, "dns-add-records", "Add DNS records to a name", func(s *mcclient.ClientSession, args *DNSUpdateRecordsOptions) error {
params := jsonutils.NewDict()
parseDNSRecords(&args.DNSRecordOptions, params)
if params.Size() == 0 {
return fmt.Errorf("Nothing to add")
R(&options.DNSUpdateRecordsOptions{}, "dns-add-records", "Add DNS records to a name", func(s *mcclient.ClientSession, opts *options.DNSUpdateRecordsOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "add-records", params)
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "add-records", params)
if e != nil {
return e
}
@@ -200,13 +113,12 @@ func init() {
return nil
})
R(&DNSUpdateRecordsOptions{}, "dns-remove-records", "Remove DNS records from a name", func(s *mcclient.ClientSession, args *DNSUpdateRecordsOptions) error {
params := jsonutils.NewDict()
parseDNSRecords(&args.DNSRecordOptions, params)
if params.Size() == 0 {
return fmt.Errorf("Nothing to remove")
R(&options.DNSUpdateRecordsOptions{}, "dns-remove-records", "Remove DNS records from a name", func(s *mcclient.ClientSession, opts *options.DNSUpdateRecordsOptions) error {
params, err := opts.Params()
if err != nil {
return err
}
dns, e := modules.DNSRecords.PerformAction(s, args.ID, "remove-records", params)
dns, e := modules.DNSRecords.PerformAction(s, opts.ID, "remove-records", params)
if e != nil {
return e
}
+12
View File
@@ -111,6 +111,18 @@ func init() {
return nil
})
type SchedpoliciesShowOptions struct {
ID string `help:"ID or name of the sched policy"`
}
R(&SchedpoliciesShowOptions{}, "sched-policy-show", "show details of a sched policy", func(s *mcclient.ClientSession, args *SchedpoliciesShowOptions) error {
result, err := modules.Schedpolicies.Get(s, args.ID, nil)
if err != nil {
return err
}
printObject(result)
return nil
})
type SchedpoliciesEvaluateOptions struct {
ID string `help:"ID or name of the sched policy"`
SERVER string `help:"ID or name of the server"`
+50 -28
View File
@@ -57,12 +57,16 @@ func (dispatcher *DBModelDispatcher) ContextKeywordPlural() []string {
}
func (dispatcher *DBModelDispatcher) Filter(f appsrv.FilterHandler) appsrv.FilterHandler {
return auth.Authenticate(f)
if consts.IsRbacEnabled() {
return auth.AuthenticateWithDelayDecision(f, true)
} else {
return auth.Authenticate(f)
}
}
func fetchUserCredential(ctx context.Context) mcclient.TokenCredential {
token := auth.FetchUserCredential(ctx)
if token == nil {
if token == nil && !consts.IsRbacEnabled() {
log.Fatalf("user token credential not found?")
}
return token
@@ -479,14 +483,14 @@ func listItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
retConut := len(retList)
retCount := len(retList)
// apply customizeFilters
retList, err = customizeFilters.DoApply(retList)
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
if len(retList) != retConut {
if len(retList) != retCount {
totalCnt = int64(len(retList))
}
paginate := false
@@ -500,7 +504,7 @@ func listItems(manager IModelManager, ctx context.Context, userCred mcclient.Tok
func calculateListResult(data []jsonutils.JSONObject, total, limit, offset int64, paginate bool) *modules.ListResult {
if paginate {
// do offset first
if offset != 0 {
if offset > 0 {
if total > offset {
data = data[offset:]
} else {
@@ -508,11 +512,13 @@ func calculateListResult(data []jsonutils.JSONObject, total, limit, offset int64
}
}
// do limit
if total > limit {
if limit > 0 && total > limit {
data = data[:limit]
}
}
retResult := modules.ListResult{Data: data, Total: int(total), Limit: int(limit), Offset: int(offset)}
return &retResult
}
@@ -725,7 +731,7 @@ func fetchOwnerProjectId(ctx context.Context, manager IModelManager, userCred mc
if consts.IsRbacEnabled() {
result := policy.PolicyManager.Allow(true, userCred,
consts.GetServiceType(), policy.PolicyDelegation, "")
if result == rbacutils.Allow {
if result == rbacutils.AdminAllow {
isAllow = true
}
} else {
@@ -957,6 +963,34 @@ func (dispatcher *DBModelDispatcher) BatchCreate(ctx context.Context, query json
return results, nil
}
func managerPerformCheckCreateData(
manager IModelManager,
ctx context.Context,
userCred mcclient.TokenCredential,
action string,
ownerProjId string,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) (jsonutils.JSONObject, error) {
body, err := data.(*jsonutils.JSONDict).Get(manager.Keyword())
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
bodyDict := body.(*jsonutils.JSONDict)
var isAllow bool
if consts.IsRbacEnabled() {
isAllow = isClassActionRbacAllowed(manager, userCred, ownerProjId, policy.PolicyActionPerform, action)
} else {
isAllow = manager.AllowPerformCheckCreateData(ctx, userCred, query, data)
}
if !isAllow {
return nil, httperrors.NewForbiddenError("not allow to perform %s", action)
}
return manager.ValidateCreateData(ctx, userCred, ownerProjId, query, bodyDict)
}
func (dispatcher *DBModelDispatcher) PerformClassAction(ctx context.Context, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
userCred := fetchUserCredential(ctx)
@@ -969,25 +1003,8 @@ func (dispatcher *DBModelDispatcher) PerformClassAction(ctx context.Context, act
defer lockman.ReleaseClass(ctx, dispatcher.modelManager, ownerProjId)
if action == "check-create-data" {
manager := dispatcher.modelManager
body, err := data.(*jsonutils.JSONDict).Get(manager.Keyword())
if err != nil {
return nil, httperrors.NewGeneralError(err)
}
data := body.(*jsonutils.JSONDict)
var isAllow bool
if consts.IsRbacEnabled() {
isAllow = isClassActionRbacAllowed(manager, userCred, ownerProjId, policy.PolicyActionPerform, action)
} else {
isAllow = manager.AllowPerformCheckCreateData(ctx, userCred, query, data)
}
if !isAllow {
return nil, httperrors.NewForbiddenError("not allow to perform %s", action)
}
return manager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
return managerPerformCheckCreateData(dispatcher.modelManager,
ctx, userCred, action, ownerProjId, query, data)
}
managerValue := reflect.ValueOf(dispatcher.modelManager)
@@ -1022,8 +1039,8 @@ func objectPerformAction(dispatcher *DBModelDispatcher, model IModel, modelValue
isGeneral := false
funcName := fmt.Sprintf("Perform%s", utils.Kebab2Camel(action, "-"))
funcValue := modelValue.MethodByName(funcName)
if !funcValue.IsValid() || funcValue.IsNil() {
funcValue = modelValue.MethodByName(generalFuncName)
if !funcValue.IsValid() || funcValue.IsNil() {
@@ -1057,7 +1074,12 @@ func objectPerformAction(dispatcher *DBModelDispatcher, model IModel, modelValue
var isAllow bool
if consts.IsRbacEnabled() {
isAllow = isObjectRbacAllowed(dispatcher.modelManager, model, userCred, policy.PolicyActionPerform, action)
if model == nil {
ownerProjId, _ := fetchOwnerProjectId(ctx, dispatcher.modelManager, userCred, data)
isAllow = isClassActionRbacAllowed(dispatcher.modelManager, userCred, ownerProjId, policy.PolicyActionPerform, action)
} else {
isAllow = isObjectRbacAllowed(dispatcher.modelManager, model, userCred, policy.PolicyActionPerform, action)
}
} else {
allowFuncName := "Allow" + funcName
allowFuncValue := modelValue.MethodByName(allowFuncName)
+5 -5
View File
@@ -91,7 +91,7 @@ func getQuotaHanlder(ctx context.Context, w http.ResponseWriter, r *http.Request
if consts.IsRbacEnabled() {
result := policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
policy.PolicyDelegation, policy.PolicyActionGet)
isAllow = result == rbacutils.Allow
isAllow = result == rbacutils.AdminAllow
} else {
isAllow = userCred.IsSystemAdmin()
}
@@ -101,7 +101,7 @@ func getQuotaHanlder(ctx context.Context, w http.ResponseWriter, r *http.Request
}
if consts.IsRbacEnabled() {
if policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
"quotas", policy.PolicyActionGet) != rbacutils.Allow {
"quotas", policy.PolicyActionGet) != rbacutils.AdminAllow {
httperrors.ForbiddenError(w, "not allow to query quota")
return
}
@@ -138,7 +138,7 @@ func setQuotaHanlder(ctx context.Context, w http.ResponseWriter, r *http.Request
var isAllow bool
if consts.IsRbacEnabled() {
isAllow = policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
"quotas", policy.PolicyActionUpdate) == rbacutils.Allow
"quotas", policy.PolicyActionUpdate) == rbacutils.AdminAllow
} else {
isAllow = userCred.IsSystemAdmin()
}
@@ -201,7 +201,7 @@ func checkQuotaHanlder(ctx context.Context, w http.ResponseWriter, r *http.Reque
isAllow := false
if consts.IsRbacEnabled() {
isAllow = policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
policy.PolicyDelegation, policy.PolicyActionGet) == rbacutils.Allow
policy.PolicyDelegation, policy.PolicyActionGet) == rbacutils.AdminAllow
} else {
isAllow = userCred.IsSystemAdmin()
}
@@ -211,7 +211,7 @@ func checkQuotaHanlder(ctx context.Context, w http.ResponseWriter, r *http.Reque
}
if consts.IsRbacEnabled() {
if policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
"quotas", policy.PolicyActionGet) != rbacutils.Allow {
"quotas", policy.PolicyActionGet) != rbacutils.AdminAllow {
httperrors.ForbiddenError(w, "not allow to query quota")
return
}
+33 -12
View File
@@ -28,14 +28,22 @@ func isListRbacAllowedInternal(manager IModelManager, resource string, userCred
}
result := policy.PolicyManager.Allow(false, userCred, consts.GetServiceType(),
resource, policy.PolicyActionList)
log.Debugf("allow list for non-admin %s %v ownerId: %s", result, requireAdmin, ownerId)
if (result == rbacutils.OwnerAllow && !requireAdmin) || (result == rbacutils.Allow && requireAdmin) {
switch {
case result == rbacutils.GuestAllow:
return true
case result == rbacutils.UserAllow && userCred != nil && userCred.IsValid():
return true
case result == rbacutils.OwnerAllow && !requireAdmin:
return true
case result == rbacutils.AdminAllow && requireAdmin:
return true
}
result = policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
resource, policy.PolicyActionList)
log.Debugf("allow list for admin %s %v ownerId: %s", result, requireAdmin, ownerId)
return result == rbacutils.Allow
return result == rbacutils.AdminAllow
}
func isJointListRbacAllowed(manager IJointModelManager, userCred mcclient.TokenCredential, isAdminMode bool) bool {
@@ -54,16 +62,23 @@ func isClassActionRbacAllowed(manager IModelManager, userCred mcclient.TokenCred
} else {
requireAdmin = true
}
// if !requireAdmin {
result := policy.PolicyManager.Allow(false, userCred, consts.GetServiceType(),
manager.KeywordPlural(), action, extra...)
if result == rbacutils.Allow || (!requireAdmin && result == rbacutils.OwnerAllow) {
switch {
case result == rbacutils.GuestAllow:
return true
case result == rbacutils.UserAllow && userCred != nil && userCred.IsValid():
return true
case result == rbacutils.OwnerAllow && !requireAdmin:
return true
case result == rbacutils.AdminAllow && requireAdmin:
return true
}
// }
result = policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
manager.KeywordPlural(), action, extra...)
return result == rbacutils.Allow
return result == rbacutils.AdminAllow
}
func isObjectRbacAllowed(manager IModelManager, model IModel, userCred mcclient.TokenCredential, action string, extra ...string) bool {
@@ -85,16 +100,22 @@ func isObjectRbacAllowed(manager IModelManager, model IModel, userCred mcclient.
requireAdmin = true
}
//if !requireAdmin {
result := policy.PolicyManager.Allow(false, userCred, consts.GetServiceType(),
manager.KeywordPlural(), action, extra...)
if result == rbacutils.Allow || (!requireAdmin && result == rbacutils.OwnerAllow && isOwner) {
switch {
case result == rbacutils.GuestAllow:
return true
case result == rbacutils.UserAllow && userCred != nil && userCred.IsValid():
return true
case result == rbacutils.OwnerAllow && isOwner && !requireAdmin:
return true
case result == rbacutils.AdminAllow && (requireAdmin || isOwner):
return true
}
//}
result = policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
manager.KeywordPlural(), action, extra...)
return result == rbacutils.Allow
return result == rbacutils.AdminAllow
}
func isJointObjectRbacAllowed(manager IJointModelManager, item IJointModel, userCred mcclient.TokenCredential, action string, extra ...string) bool {
+1 -1
View File
@@ -11,7 +11,7 @@ import (
type SSharableVirtualResourceBase struct {
SVirtualResourceBase
IsPublic bool `default:"false" nullable:"false" list:"user"`
IsPublic bool `default:"false" nullable:"false" create:"admin_optional" list:"user"`
}
type SSharableVirtualResourceBaseManager struct {
+14 -5
View File
@@ -89,10 +89,6 @@ func (manager *STaskManager) FilterByName(q *sqlchemy.SQuery, name string) *sqlc
return q
}
func (manager *STaskManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
return q
}
func (manager *STaskManager) AllowPerformAction(ctx context.Context, userCred mcclient.TokenCredential, action string, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return true
}
@@ -105,6 +101,19 @@ func (manager *STaskManager) PerformAction(ctx context.Context, userCred mcclien
return resp, nil
}
func (manager *STaskManager) GetOwnerId(userCred mcclient.IIdentityProvider) string {
return userCred.GetProjectId()
}
func (self *STask) GetOwnerProjectId() string {
return self.UserCred.GetProjectId()
}
func (manager *STaskManager) FilterByOwner(q *sqlchemy.SQuery, owner string) *sqlchemy.SQuery {
q = q.Contains("user_cred", owner)
return q
}
func (self *STask) AllowGetDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return userCred.IsSystemAdmin() || userCred.GetProjectId() == self.UserCred.GetProjectId()
}
@@ -414,7 +423,7 @@ func execITask(taskValue reflect.Value, task *STask, odata jsonutils.JSONObject,
return
}
log.Debugf("Call %s %s: %s with %s", task.TaskName, stageName, funcValue, params)
log.Debugf("Call %s %s", task.TaskName, stageName)
funcValue.Call(params)
// call save request context
+1 -1
View File
@@ -40,7 +40,7 @@ type Options struct {
SslCertfile string `help:"ssl certification file"`
SslKeyfile string `help:"ssl certification key file"`
EnableRbac bool `help:"Switch on Role-based Access Control" default:"false"`
EnableRbac bool `help:"Switch on Role-based Access Control" default:"true"`
RbacDebug bool `help:"turn on rbac debug log" default:"false"`
RbacPolicySyncPeriodSeconds int `help:"policy sync interval in seconds, default 15 minutes" default:"900"`
RbacPolicySyncFailedRetrySeconds int `help:"seconds to wait after a failed sync, default 30 seconds" default:"30"`
+60 -9
View File
@@ -30,8 +30,37 @@ const (
var (
PolicyManager *SPolicyManager
PolicyFailedRetryInterval = 15 * time.Second
PolicyRefreshInterval = 15 * time.Minute
defaultRules = []rbacutils.SRbacRule{
{
Resource: "tasks",
Action: PolicyActionPerform,
Result: rbacutils.UserAllow,
},
{
Service: "compute",
Resource: "zones",
Action: PolicyActionList,
Result: rbacutils.UserAllow,
},
{
Service: "compute",
Resource: "zones",
Action: PolicyActionGet,
Result: rbacutils.UserAllow,
},
{
Service: "compute",
Resource: "cloudregions",
Action: PolicyActionList,
Result: rbacutils.UserAllow,
},
{
Service: "compute",
Resource: "cloudregions",
Action: PolicyActionGet,
Result: rbacutils.UserAllow,
},
}
)
func init() {
@@ -41,7 +70,11 @@ func init() {
type SPolicyManager struct {
policies map[string]rbacutils.SRbacPolicy
adminPolicies map[string]rbacutils.SRbacPolicy
defaultPolicy *rbacutils.SRbacPolicy
lastSync time.Time
failedRetryInterval time.Duration
refreshInterval time.Duration
}
func parseJsonPolicy(obj jsonutils.JSONObject) (string, rbacutils.SRbacPolicy, error) {
@@ -114,8 +147,13 @@ func fetchPolicies() (map[string]rbacutils.SRbacPolicy, map[string]rbacutils.SRb
func (manager *SPolicyManager) start(refreshInterval time.Duration, retryInterval time.Duration) {
log.Infof("PolicyManager start to fetch policies ...")
PolicyRefreshInterval = refreshInterval
PolicyFailedRetryInterval = retryInterval
manager.refreshInterval = refreshInterval
manager.failedRetryInterval = retryInterval
if len(defaultRules) > 0 {
manager.defaultPolicy = &rbacutils.SRbacPolicy{
Rules: rbacutils.CompactRules(defaultRules),
}
}
manager.sync()
}
@@ -124,13 +162,14 @@ func (manager *SPolicyManager) sync() {
policies, adminPolicies, err := fetchPolicies()
if err != nil {
log.Errorf("sync policy fail %s", err)
time.AfterFunc(PolicyFailedRetryInterval, manager.sync)
time.AfterFunc(manager.failedRetryInterval, manager.sync)
return
}
manager.policies = policies
manager.adminPolicies = adminPolicies
manager.lastSync = time.Now()
time.AfterFunc(PolicyRefreshInterval, manager.sync)
time.AfterFunc(manager.refreshInterval, manager.sync)
}
func (manager *SPolicyManager) Allow(isAdmin bool, userCred mcclient.TokenCredential, service string, resource string, action string, extra ...string) rbacutils.TRbacResult {
@@ -148,7 +187,13 @@ func (manager *SPolicyManager) Allow(isAdmin bool, userCred mcclient.TokenCreden
currentPriv := rbacutils.Deny
for _, p := range policies {
result := p.Allow(userCredJson, service, resource, action, extra...)
if result.IsHigherPrivilege(currentPriv) {
if currentPriv.StricterThan(result) {
currentPriv = result
}
}
if manager.defaultPolicy != nil {
result := manager.defaultPolicy.Allow(userCredJson, service, resource, action, extra...)
if currentPriv.StricterThan(result) {
currentPriv = result
}
}
@@ -165,8 +210,10 @@ func (manager *SPolicyManager) explainPolicy(userCred mcclient.TokenCredential,
}
isAdmin, _ := policySeq[0].Bool()
if !consts.IsRbacEnabled() {
if !isAdmin || (isAdmin && userCred.IsSystemAdmin()) {
return rbacutils.Allow, nil
if !isAdmin {
return rbacutils.OwnerAllow, nil
} else if isAdmin && userCred.IsSystemAdmin() {
return rbacutils.AdminAllow, nil
} else {
return rbacutils.Deny, httperrors.NewForbiddenError("operation not allowed")
}
@@ -210,6 +257,10 @@ func (manager *SPolicyManager) ExplainRpc(userCred mcclient.TokenCredential, par
}
func (manager *SPolicyManager) IsAdminCapable(userCred mcclient.TokenCredential) bool {
if !consts.IsRbacEnabled() && userCred.IsSystemAdmin() {
return true
}
userCredJson := userCred.ToJson()
for _, p := range manager.adminPolicies {
match, _ := conditionparser.Eval(p.Condition, userCredJson)
-2
View File
@@ -251,12 +251,10 @@ type ICloudDisk interface {
type ICloudSnapshot interface {
ICloudResource
GetManagerId() string
GetSize() int32
GetDiskId() string
GetDiskType() string
Delete() error
GetRegionId() string
}
type ICloudVpc interface {
-27
View File
@@ -504,30 +504,3 @@ func (self *SAliyunGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Contex
func (self *SAliyunGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SAliyunGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
res.Set("manager_id", jsonutils.NewString(cloudSnapshot.GetManagerId()))
cloudRegion, err := models.CloudregionManager.FetchByExternalId("Aliyun/" + cloudSnapshot.GetRegionId())
if err != nil {
return nil, fmt.Errorf("Cloud region not found? %s", err)
}
res.Set("cloudregion_id", jsonutils.NewString(cloudRegion.GetId()))
return res, nil
})
return nil
}
+4 -25
View File
@@ -5,6 +5,8 @@ import (
"fmt"
"time"
"yunion.io/x/onecloud/pkg/util/ansible"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
@@ -158,7 +160,7 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest
return nil, err
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action)
return data, nil
})
case "rebuild":
@@ -210,7 +212,7 @@ func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest
}
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action)
return data, nil
})
@@ -288,29 +290,6 @@ func (self *SAwsGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context,
return nil
}
func (self *SAwsGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
res.Set("manager_id", jsonutils.NewString(cloudSnapshot.GetManagerId()))
res.Set("cloudregion_id", jsonutils.NewString(cloudSnapshot.GetRegionId()))
return res, nil
})
return nil
}
func init() {
driver := SAwsGuestDriver{}
models.RegisterGuestDriver(&driver)
+4 -7
View File
@@ -9,6 +9,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/ansible"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/x/pkg/utils"
@@ -22,10 +23,6 @@ type SAzureGuestDriver struct {
SManagedVirtualizedGuestDriver
}
const (
DEFAULT_USER = "yunion"
)
func init() {
driver := SAzureGuestDriver{}
models.RegisterGuestDriver(&driver)
@@ -169,7 +166,7 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue
return nil, err
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action)
return data, nil
}
})
@@ -192,7 +189,7 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue
if err != nil {
return nil, err
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action)
return data, nil
})
} else if action == "rebuild" {
@@ -209,7 +206,7 @@ func (self *SAzureGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gue
}
log.Debugf("VMrebuildRoot %s, and status is ready", iVM.GetGlobalId())
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
data := fetchIVMinfo(desc, iVM, guest.Id, ansible.PUBLIC_CLOUD_ANSIBLE_USER, passwd, action)
return data, nil
})
+11 -11
View File
@@ -49,29 +49,29 @@ func (self *SKVMGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *
}
func (self *SKVMGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
url := fmt.Sprintf("/servers/%s/snapshot", guest.Id)
host := guest.GetHost()
url := fmt.Sprintf("%s/servers/%s/snapshot", host.ManagerUri, guest.Id)
body := jsonutils.NewDict()
body.Set("disk_id", jsonutils.NewString(diskId))
body.Set("snapshot_id", jsonutils.NewString(snapshotId))
header := self.getTaskRequestHeader(task)
host := guest.GetHost()
_, err := host.Request(task.GetUserCred(), "POST", url, header, body)
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
return err
}
func (self *SKVMGuestDriver) RequestDeleteSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, params *jsonutils.JSONDict) error {
url := fmt.Sprintf("/servers/%s/delete-snapshot", guest.Id)
header := self.getTaskRequestHeader(task)
host := guest.GetHost()
_, err := host.Request(task.GetUserCred(), "POST", url, header, params)
url := fmt.Sprintf("%s/servers/%s/delete-snapshot", host.ManagerUri, guest.Id)
header := self.getTaskRequestHeader(task)
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, params, false)
return err
}
func (self *SKVMGuestDriver) RequestReloadDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, params *jsonutils.JSONDict) error {
url := fmt.Sprintf("/servers/%s/reload-disk-snapshot", guest.Id)
header := self.getTaskRequestHeader(task)
host := guest.GetHost()
_, err := host.Request(task.GetUserCred(), "POST", url, header, params)
url := fmt.Sprintf("%s/servers/%s/reload-disk-snapshot", host.ManagerUri, guest.Id)
header := self.getTaskRequestHeader(task)
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, params, false)
return err
}
@@ -294,9 +294,9 @@ func (self *SKVMGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest
if fw_only, _ := task.GetParams().Bool("fw_only"); fw_only {
body.Add(jsonutils.JSONTrue, "fw_only")
}
url := fmt.Sprintf("/servers/%s/sync", guest.Id)
url := fmt.Sprintf("%s/servers/%s/sync", host.ManagerUri, guest.Id)
header := self.getTaskRequestHeader(task)
_, err := host.Request(task.GetUserCred(), "POST", url, header, body)
_, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
return err
}
@@ -351,3 +351,24 @@ func (self *SManagedVirtualizedGuestDriver) RequestSyncConfigOnHost(ctx context.
})
return nil
}
func (self *SManagedVirtualizedGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
return res, nil
})
return nil
}
-27
View File
@@ -345,30 +345,3 @@ func (self *SQcloudGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Contex
func (self *SQcloudGuestDriver) AllowReconfigGuest() bool {
return true
}
func (self *SQcloudGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
res.Set("manager_id", jsonutils.NewString(cloudSnapshot.GetManagerId()))
cloudRegion, err := models.CloudregionManager.FetchByExternalId("Aliyun/" + cloudSnapshot.GetRegionId())
if err != nil {
return nil, fmt.Errorf("Cloud region not found? %s", err)
}
res.Set("cloudregion_id", jsonutils.NewString(cloudRegion.GetId()))
return res, nil
})
return nil
}
+2 -1
View File
@@ -147,7 +147,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use
if err == cloudprovider.ErrNoSuchProvder {
return nil, httperrors.NewResourceNotFoundError("no such provider %s", provider)
}
return nil, httperrors.NewInvalidCredentialError("invalid cloud account info")
return nil, httperrors.NewInputParameterError("invalid cloud account info")
}
return manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
@@ -386,6 +386,7 @@ func (self *SCloudaccount) ImportSubAccount(ctx context.Context, userCred mcclie
newCloudprovider.CloudaccountId = self.Id
newCloudprovider.Provider = self.Provider
newCloudprovider.Enabled = true
newCloudprovider.Status = CLOUD_PROVIDER_CONNECTED
newCloudprovider.Name = subAccount.Name
if !autoCreateProject {
newCloudprovider.ProjectId = auth.AdminCredential().GetProjectId()
+2
View File
@@ -1101,6 +1101,7 @@ type DiskInfo struct {
MediumType string
Driver string
Cache string
DiskType string
}
func (self *SDisk) ToDiskInfo() DiskInfo {
@@ -1110,6 +1111,7 @@ func (self *SDisk) ToDiskInfo() DiskInfo {
MountPoint: self.GetMountPoint(),
Format: self.DiskFormat,
Size: int64(self.DiskSize),
DiskType: self.DiskType,
}
storage := self.GetStorage()
if storage == nil {
+1
View File
@@ -3915,6 +3915,7 @@ func (self *SGuest) GetSpec(checkStatus bool) *jsonutils.JSONDict {
diskSpec.Set("size", jsonutils.NewInt(info.Size))
diskSpec.Set("backend", jsonutils.NewString(info.Backend))
diskSpec.Set("medium_type", jsonutils.NewString(info.MediumType))
diskSpec.Set("disk_type", jsonutils.NewString(info.DiskType))
diskSpecs.Add(diskSpec)
}
spec.Set("disk", diskSpecs)
+15 -3
View File
@@ -958,7 +958,7 @@ func (manager *SHostManager) getHostsByZone(zone *SZone, provider *SCloudprovide
return hosts, nil
}
func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, zone *SZone, hosts []cloudprovider.ICloudHost) ([]SHost, []cloudprovider.ICloudHost, compare.SyncResult) {
func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, zone *SZone, hosts []cloudprovider.ICloudHost, projectSync bool) ([]SHost, []cloudprovider.ICloudHost, compare.SyncResult) {
localHosts := make([]SHost, 0)
remoteHosts := make([]cloudprovider.ICloudHost, 0)
syncResult := compare.SyncResult{}
@@ -1002,7 +1002,7 @@ func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.To
}
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].syncWithCloudHost(commonext[i])
err = commondb[i].syncWithCloudHost(commonext[i], projectSync)
if err != nil {
syncResult.UpdateError(err)
} else {
@@ -1025,7 +1025,7 @@ func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.To
return localHosts, remoteHosts, syncResult
}
func (self *SHost) syncWithCloudHost(extHost cloudprovider.ICloudHost) error {
func (self *SHost) syncWithCloudHost(extHost cloudprovider.ICloudHost, projectSync bool) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Name = extHost.GetName()
self.Status = extHost.GetStatus()
@@ -1052,6 +1052,13 @@ func (self *SHost) syncWithCloudHost(extHost cloudprovider.ICloudHost) error {
if err != nil {
log.Errorf("syncWithCloudZone error %s", err)
}
if projectSync {
if err := HostManager.ClearSchedDescCache(self.Id); err != nil {
log.Errorf("ClearSchedDescCache for host %s error %v", self.Name, err)
}
}
return err
}
@@ -1089,6 +1096,11 @@ func (manager *SHostManager) newFromCloudHost(extHost cloudprovider.ICloudHost,
log.Errorf("newFromCloudHost fail %s", err)
return nil, err
}
if err := manager.ClearSchedDescCache(host.Id); err != nil {
log.Errorf("ClearSchedDescCache for host %s error %v", host.Name, err)
}
return &host, nil
}
@@ -43,6 +43,7 @@ type SLoadbalancerListenerRule struct {
func loadbalancerListenerRuleCheckUniqueness(ctx context.Context, lbls *SLoadbalancerListener, domain, path string) error {
q := LoadbalancerListenerRuleManager.Query().
IsFalse("pending_deleted").
Equals("listener_id", lbls.Id).
Equals("domain", domain).
Equals("path", path)
+24 -10
View File
@@ -104,6 +104,7 @@ type SLoadbalancerListener struct {
func (man *SLoadbalancerListenerManager) checkListenerUniqueness(ctx context.Context, lb *SLoadbalancer, listenerType string, listenerPort int64) error {
q := man.Query().
IsFalse("pending_deleted").
Equals("loadbalancer_id", lb.Id).
Equals("listener_port", listenerPort)
switch listenerType {
@@ -260,16 +261,8 @@ func (man *SLoadbalancerListenerManager) ValidateCreateData(ctx context.Context,
}
}
}
{
if aclStatusV.Value == LB_BOOL_ON {
acl := aclV.Model.(*SLoadbalancerAcl)
if acl == nil {
return nil, fmt.Errorf("missing acl")
}
if len(aclTypeV.Value) == 0 {
return nil, fmt.Errorf("missing acl_type")
}
}
if err := man.validateAcl(aclStatusV, aclTypeV, aclV, data); err != nil {
return nil, err
}
return man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data)
}
@@ -287,6 +280,20 @@ func (man *SLoadbalancerListenerManager) checkTypeV(listenerType string) validat
return nil
}
func (man *SLoadbalancerListenerManager) validateAcl(aclStatusV *validators.ValidatorStringChoices, aclTypeV *validators.ValidatorStringChoices, aclV *validators.ValidatorModelIdOrName, data *jsonutils.JSONDict) error {
if aclStatusV.Value == LB_BOOL_ON {
if aclV.Model == nil {
return httperrors.NewInputParameterError("missing acl")
}
if len(aclTypeV.Value) == 0 {
return httperrors.NewInputParameterError("missing acl_type")
}
} else {
data.Set("acl_id", jsonutils.NewString(""))
}
return nil
}
func (lblis *SLoadbalancerListener) AllowPerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
return lblis.IsOwner(userCred) || userCred.IsSystemAdmin()
}
@@ -295,7 +302,11 @@ func (lblis *SLoadbalancerListener) ValidateUpdateData(ctx context.Context, user
ownerProjId := lblis.GetOwnerProjectId()
backendGroupV := validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerProjId)
aclStatusV := validators.NewStringChoicesValidator("acl_status", LB_BOOL_VALUES)
aclStatusV.Default(lblis.AclStatus)
aclTypeV := validators.NewStringChoicesValidator("acl_type", LB_ACL_TYPES)
if LB_ACL_TYPES.Has(lblis.AclType) {
aclTypeV.Default(lblis.AclType)
}
aclV := validators.NewModelIdOrNameValidator("acl", "loadbalanceracl", ownerProjId)
certV := validators.NewModelIdOrNameValidator("certificate", "loadbalancercertificate", ownerProjId)
tlsCipherPolicyV := validators.NewStringChoicesValidator("tls_cipher_policy", LB_TLS_CIPHER_POLICIES).Default(LB_TLS_CIPHER_POLICY_1_2)
@@ -344,6 +355,9 @@ func (lblis *SLoadbalancerListener) ValidateUpdateData(ctx context.Context, user
return nil, err
}
}
if err := LoadbalancerListenerManager.validateAcl(aclStatusV, aclTypeV, aclV, data); err != nil {
return nil, err
}
{
if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.LoadbalancerId != lblis.LoadbalancerId {
return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s instead of %s",
+11 -1
View File
@@ -145,7 +145,12 @@ func (self *SNetwork) ValidateDeleteCondition(ctx context.Context) error {
}
func (self *SNetwork) GetTotalNicCount() int {
return self.GetGuestnicsCount() + self.GetGroupNicsCount() + self.GetBaremetalNicsCount() + self.GetReservedNicsCount()
total := self.GetGuestnicsCount() +
self.GetGroupNicsCount() +
self.GetBaremetalNicsCount() +
self.GetReservedNicsCount() +
self.GetLoadbalancerIpsCount()
return total
}
func (self *SNetwork) GetGuestnicsCount() int {
@@ -164,6 +169,10 @@ func (self *SNetwork) GetReservedNicsCount() int {
return ReservedipManager.Query().Equals("network_id", self.Id).Count()
}
func (self *SNetwork) GetLoadbalancerIpsCount() int {
return LoadbalancernetworkManager.Query().Equals("network_id", self.Id).Count()
}
func (self *SNetwork) GetUsedAddresses() map[string]bool {
used := make(map[string]bool)
@@ -818,6 +827,7 @@ func (self *SNetwork) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSOND
extra.Add(jsonutils.JSONFalse, "exit")
}
extra.Add(jsonutils.NewInt(int64(self.getIPRange().AddressCount())), "ports")
extra.Add(jsonutils.NewInt(int64(self.GetTotalNicCount())), "ports_used")
extra.Add(jsonutils.NewInt(int64(self.GetGuestnicsCount())), "vnics")
extra.Add(jsonutils.NewInt(int64(self.GetBaremetalNicsCount())), "bm_vnics")
extra.Add(jsonutils.NewInt(int64(self.GetGroupNicsCount())), "group_vnics")
+10 -5
View File
@@ -300,6 +300,7 @@ func (self *SSnapshotManager) CreateSnapshot(ctx context.Context, userCred mccli
return nil, err
}
disk := iDisk.(*SDisk)
storage := disk.GetStorage()
snapshot := &SSnapshot{}
snapshot.SetModelManager(self)
snapshot.ProjectId = userCred.GetProjectId()
@@ -311,6 +312,8 @@ func (self *SSnapshotManager) CreateSnapshot(ctx context.Context, userCred mccli
snapshot.DiskType = disk.DiskType
snapshot.Location = location
snapshot.CreatedBy = createdBy
snapshot.ManagerId = storage.ManagerId
snapshot.CloudregionId = storage.getZone().GetRegion().GetId()
snapshot.Name = name
snapshot.Status = SNAPSHOT_CREATING
err = SnapshotManager.TableSpec().Insert(snapshot)
@@ -467,13 +470,15 @@ func totalSnapshotCount(projectId string) int {
}
// Only sync snapshot status
func (self *SSnapshot) SyncWithCloudSnapshot(userCred mcclient.TokenCredential, ext cloudprovider.ICloudSnapshot, projectId string, projectSync bool) error {
func (self *SSnapshot) SyncWithCloudSnapshot(userCred mcclient.TokenCredential, ext cloudprovider.ICloudSnapshot, projectId string, projectSync bool, region *SCloudregion) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Name = ext.GetName()
self.Status = ext.GetStatus()
self.DiskType = ext.GetDiskType()
if projectSync && len(projectId) > 0 {
self.ProjectId = projectId
}
self.CloudregionId = region.Id
return nil
})
if err != nil {
@@ -482,7 +487,7 @@ func (self *SSnapshot) SyncWithCloudSnapshot(userCred mcclient.TokenCredential,
return err
}
func (manager *SSnapshotManager) newFromCloudSnapshot(userCred mcclient.TokenCredential, extSnapshot cloudprovider.ICloudSnapshot, region *SCloudregion, projectId string) (*SSnapshot, error) {
func (manager *SSnapshotManager) newFromCloudSnapshot(userCred mcclient.TokenCredential, extSnapshot cloudprovider.ICloudSnapshot, region *SCloudregion, projectId string, provider *SCloudprovider) (*SSnapshot, error) {
snapshot := SSnapshot{}
snapshot.SetModelManager(manager)
@@ -500,7 +505,7 @@ func (manager *SSnapshotManager) newFromCloudSnapshot(userCred mcclient.TokenCre
snapshot.DiskType = extSnapshot.GetDiskType()
snapshot.Size = int(extSnapshot.GetSize()) * 1024
snapshot.ManagerId = extSnapshot.GetManagerId()
snapshot.ManagerId = provider.Id
snapshot.CloudregionId = region.Id
snapshot.ProjectId = userCred.GetProjectId()
@@ -555,7 +560,7 @@ func (manager *SSnapshotManager) SyncSnapshots(ctx context.Context, userCred mcc
}
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithCloudSnapshot(userCred, commonext[i], projectId, projectSync)
err = commondb[i].SyncWithCloudSnapshot(userCred, commonext[i], projectId, projectSync, region)
if err != nil {
syncResult.UpdateError(err)
} else {
@@ -563,7 +568,7 @@ func (manager *SSnapshotManager) SyncSnapshots(ctx context.Context, userCred mcc
}
}
for i := 0; i < len(added); i += 1 {
_, err := manager.newFromCloudSnapshot(userCred, added[i], region, projectId)
_, err := manager.newFromCloudSnapshot(userCred, added[i], region, projectId, provider)
if err != nil {
syncResult.AddError(err)
} else {
+1 -1
View File
@@ -37,7 +37,7 @@ func AttachUsageQuery(
case "vcenter":
q = q.Filter(sqlchemy.Equals(hosts.Field("manager_id"), rangeObjId))
case "schedtag":
aggHosts := SchedtagManager.Query().SubQuery()
aggHosts := HostschedtagManager.Query().SubQuery()
q = q.Join(aggHosts, sqlchemy.AND(
sqlchemy.Equals(hosts.Field("id"), aggHosts.Field("host_id")),
sqlchemy.IsFalse(aggHosts.Field("deleted")))).
-4
View File
@@ -353,10 +353,6 @@ func (manager *SVpcManager) ValidateCreateData(ctx context.Context, userCred mcc
return nil, httperrors.NewInputParameterError("Invalid cloudregion_id")
}
if region.isManaged() {
if region.GetVpcCount() >= MAX_VPC_PER_REGION {
return nil, httperrors.NewNotAcceptableError("Too many vpcs per region")
}
managerStr, _ := data.GetString("manager_id")
if len(managerStr) == 0 {
managerStr, _ = data.GetString("manager")
@@ -343,7 +343,7 @@ func syncZoneHosts(ctx context.Context, provider *models.SCloudprovider, task *C
logSyncFailed(provider, task, msg)
return
}
localHosts, remoteHosts, result := models.HostManager.SyncHosts(ctx, task.UserCred, provider, localZone, hosts)
localHosts, remoteHosts, result := models.HostManager.SyncHosts(ctx, task.UserCred, provider, localZone, hosts, syncRange.ProjectSync)
msg := result.Result()
notes := fmt.Sprintf("SyncHosts for zone %s result: %s", localZone.Name, msg)
log.Infof(notes)
+3 -10
View File
@@ -52,32 +52,25 @@ func (self *GuestDiskSnapshotTask) DoDiskSnapshot(ctx context.Context, guest *mo
func (self *GuestDiskSnapshotTask) OnDiskSnapshotComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
res := data.(*jsonutils.JSONDict)
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
if guest.Hypervisor == models.HYPERVISOR_KVM {
location, err := res.GetString("location")
if err != nil {
log.Infof("OnDiskSnapshotComplete called with data no location")
return
}
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.Location = location
snapshot.Status = models.SNAPSHOT_READY
return nil
})
} else {
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
extSnapshotId, _ := data.GetString("snapshot_id")
cloudregionId, _ := data.GetString("cloudregion_id")
managerId, _ := data.GetString("manager_id")
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.CloudregionId = cloudregionId
snapshot.ExternalId = extSnapshotId
snapshot.Status = models.SNAPSHOT_READY
snapshot.ManagerId = managerId
return nil
})
}
+3 -2
View File
@@ -48,8 +48,9 @@ func (self *GuestStartTask) startStart(ctx context.Context, guest *models.SGuest
self.onStartGuestFailed(ctx, guest, err)
} else {
if result != nil && jsonutils.QueryBoolean(result, "is_running", false) {
guest.SetStatus(self.UserCred, models.VM_RUNNING, "start")
self.taskComplete(ctx, guest)
self.OnStartComplete(ctx, guest, nil)
// guest.SetStatus(self.UserCred, models.VM_RUNNING, "start")
// self.taskComplete(ctx, guest)
}
}
}
+1 -1
View File
@@ -272,7 +272,7 @@ func ReportGeneralUsage(userCred mcclient.TokenCredential, rangeObj db.IStandalo
if consts.IsRbacEnabled() {
if policy.PolicyManager.Allow(true, userCred, consts.GetServiceType(),
"usages", policy.PolicyActionGet) == rbacutils.Allow {
"usages", policy.PolicyActionGet) == rbacutils.AdminAllow {
isAdmin = true
}
} else {
+9 -76
View File
@@ -7,7 +7,6 @@ import (
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/coredns/coredns/plugin"
@@ -26,7 +25,6 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"yunion.io/x/jsonutils"
ylog "yunion.io/x/log"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
@@ -35,7 +33,6 @@ import (
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
kubeserver "yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
"yunion.io/x/onecloud/pkg/util/k8s"
)
@@ -74,14 +71,11 @@ type SRegionDNS struct {
AdminUser string
AdminPassword string
Region string
k8sConfigLock *sync.RWMutex
k8sConfig string
K8sManager *k8s.SKubeClusterManager
}
func New() *SRegionDNS {
r := &SRegionDNS{
k8sConfigLock: new(sync.RWMutex),
}
r := &SRegionDNS{}
return r
}
@@ -106,6 +100,12 @@ func (r *SRegionDNS) initDB(c *caddy.Controller) error {
return nil
}
func (r *SRegionDNS) initK8s() {
r.initAuth()
r.K8sManager = k8s.NewKubeClusterManager(r.Region, 30*time.Second)
r.K8sManager.Start()
}
func (r *SRegionDNS) getAdminSession() *mcclient.ClientSession {
return auth.GetAdminSession(r.Region, "")
}
@@ -115,68 +115,6 @@ func (r *SRegionDNS) initAuth() {
auth.Init(authInfo, false, true, "", "")
}
func (r *SRegionDNS) getKubeClusterConfig() (string, error) {
session := r.getAdminSession()
params := jsonutils.NewDict()
params.Add(jsonutils.JSONTrue, "directly")
ret, err := kubeserver.Clusters.PerformAction(session, "default", "generate-kubeconfig", params)
if err != nil {
return "", err
}
return ret.GetString("kubeconfig")
}
func (r *SRegionDNS) getK8sConfig() string {
r.k8sConfigLock.RLock()
defer r.k8sConfigLock.RUnlock()
return r.k8sConfig
}
func (r *SRegionDNS) setK8sConfig(conf string) {
r.k8sConfigLock.Lock()
defer r.k8sConfigLock.Unlock()
r.k8sConfig = conf
}
func (r *SRegionDNS) isK8sHealthy() bool {
if r.getK8sConfig() == "" {
return false
}
cli, err := r.getK8sClient()
if err != nil {
return false
}
_, err = cli.Discovery().ServerVersion()
if err != nil {
ylog.Errorf("Discovery k8s version: %v", err)
return false
}
return true
}
func (r *SRegionDNS) startRefreshKubeConfig() {
r.initAuth()
r.refreshKubeConfig()
tick := time.Tick(30 * time.Second)
for {
select {
case <-tick:
r.refreshKubeConfig()
}
}
}
func (r *SRegionDNS) refreshKubeConfig() {
if r.isK8sHealthy() {
return
}
kubeConfig, err := r.getKubeClusterConfig()
if err != nil {
ylog.Errorf("Get default k8s config from kube server error: %v", err)
}
r.setK8sConfig(kubeConfig)
}
func (r *SRegionDNS) ServeDNS(ctx context.Context, w dns.ResponseWriter, rmsg *dns.Msg) (int, error) {
var (
records []dns.RR
@@ -341,12 +279,7 @@ func getK8sServiceBackends(cli *kubernetes.Clientset, req *recordRequest) ([]str
}
func (r *SRegionDNS) getK8sClient() (*kubernetes.Clientset, error) {
cli, err := k8s.NewClientByContent([]byte(r.getK8sConfig()), nil)
if err != nil {
ylog.Warningf("Init kubernetes client error: %v", err)
return nil, err
}
return cli, nil
return r.K8sManager.GetK8sClient()
}
func getK8sServicePods(cli *kubernetes.Clientset, namespace, name string) ([]v1.Pod, error) {
+1 -1
View File
@@ -36,7 +36,7 @@ func setup(c *caddy.Controller) error {
return plugin.Error(PluginName, err)
}
go rDNS.startRefreshKubeConfig()
go rDNS.initK8s()
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
rDNS.Next = next
+18 -5
View File
@@ -17,25 +17,38 @@ const (
)
func Authenticate(f appsrv.FilterHandler) appsrv.FilterHandler {
return AuthenticateWithDelayDecision(f, false)
}
func AuthenticateWithDelayDecision(f appsrv.FilterHandler, delayDecision bool) appsrv.FilterHandler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
tokenStr := r.Header.Get(mcclient.AUTH_TOKEN)
if len(tokenStr) == 0 {
httperrors.UnauthorizedError(w, "Unauthorized")
return
log.Errorf("no auth_token found!")
if !delayDecision {
httperrors.UnauthorizedError(w, "Unauthorized")
return
}
}
token, err := Verify(tokenStr)
if err != nil {
log.Errorf("Verify token failed: %s", err)
httperrors.UnauthorizedError(w, "InvalidToken")
return
if !delayDecision {
httperrors.UnauthorizedError(w, "InvalidToken")
return
}
}
ctx = context.WithValue(ctx, AUTH_TOKEN, token)
if token != nil {
ctx = context.WithValue(ctx, AUTH_TOKEN, token)
}
if taskId := r.Header.Get(mcclient.TASK_ID); taskId != "" {
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_TASK_ID, taskId)
}
if taskNotifyUrl := r.Header.Get(mcclient.TASK_NOTIFY_URL); taskNotifyUrl != "" {
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_TASK_NOTIFY_URL, taskNotifyUrl)
}
f(ctx, w, r)
}
}
+104
View File
@@ -0,0 +1,104 @@
package options
import (
"fmt"
"yunion.io/x/jsonutils"
)
type DNSRecordOptions struct {
A []string `help:"DNS A record" metavar:"A_RECORD" positional:"false"`
AAAA []string `help:"DNS AAAA record" metavar:"AAAA_RECORD" positional:"false"`
CNAME string `help:"DNS CNAME record" metavar:"CNAME_RECORD" positional:"false"`
PTR string `help:"DNS PTR record" metavar:"PTR_RECORD" positional:"false"`
SRVHost string `help:"(deprecated) DNS SRV record, server of service" metavar:"SRV_RECORD_HOST" positional:"false"`
SRVPort int64 `help:"(deprecated) DNS SRV record, port of service" metavar:"SRV_RECORD_PORT" positional:"false"`
SRV []string `help:"DNS SRV record, in the format of host:port:weight:priority" metavar:"SRV_RECORD" positional:"false"`
}
func parseDNSRecords(opts *DNSRecordOptions, params *jsonutils.JSONDict) {
if len(opts.A) > 0 || len(opts.AAAA) > 0 {
for i, a := range opts.A {
params.Add(jsonutils.NewString(a), fmt.Sprintf("A.%d", i))
}
for i, a := range opts.AAAA {
params.Add(jsonutils.NewString(a), fmt.Sprintf("AAAA.%d", i))
}
} else if len(opts.CNAME) > 0 {
params.Add(jsonutils.NewString(opts.CNAME), "CNAME")
} else if len(opts.SRV) > 0 || (len(opts.SRVHost) > 0 && opts.SRVPort > 0) {
for i, s := range opts.SRV {
params.Set(fmt.Sprintf("SRV.%d", i), jsonutils.NewString(s))
}
// Keep using the original argument passing method in case a
// newer climc is used against old service
if len(opts.SRVHost) > 0 && opts.SRVPort > 0 {
params.Set("SRV_host", jsonutils.NewString(opts.SRVHost))
params.Set("SRV_port", jsonutils.NewInt(opts.SRVPort))
}
} else if len(opts.PTR) > 0 {
params.Add(jsonutils.NewString(opts.PTR), "PTR")
}
}
type DNSCreateOptions struct {
NAME string `help:"DNS name to create"`
TTL int64 `help:"TTL in seconds" positional:"false"`
Desc string `help:"Description" json:"description"`
IsPublic *bool `help:"Make the newly created record public to all"`
DNSRecordOptions
}
func (opts *DNSCreateOptions) Params() (*jsonutils.JSONDict, error) {
params, err := StructToParams(opts)
if err != nil {
return nil, err
}
parseDNSRecords(&opts.DNSRecordOptions, params)
return params, nil
}
type DNSUpdateOptions struct {
ID string `help:"ID of DNS record to update" json:"-"`
Name string `help:"Domain name"`
TTL int64 `help:"TTL in seconds" positional:"false"`
Desc string `help:"Description" json:"description"`
DNSRecordOptions
}
func (opts *DNSUpdateOptions) Params() (*jsonutils.JSONDict, error) {
params, err := StructToParams(opts)
if err != nil {
return nil, err
}
parseDNSRecords(&opts.DNSRecordOptions, params)
return params, nil
}
type DNSUpdateRecordsOptions struct {
ID string `help:"ID of dns record to modify" json:"-"`
DNSRecordOptions
}
func (opts *DNSUpdateRecordsOptions) Params() (*jsonutils.JSONDict, error) {
params := jsonutils.NewDict()
parseDNSRecords(&opts.DNSRecordOptions, params)
if params.Size() == 0 {
return nil, fmt.Errorf("Nothing to add")
}
return params, nil
}
type DNSListOptions struct {
BaseListOptions
IsPublic string `choices:"0|1"`
}
type DNSGetOptions struct {
ID string `help:"ID of DNS record to show" json:"-"`
}
@@ -4,6 +4,7 @@ import (
"fmt"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates/guest"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
@@ -19,11 +20,11 @@ func (p *HostStatusPredicate) Name() string {
return "host_status"
}
func (p *HostStatusPredicate) PreExecute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool {
func (p *HostStatusPredicate) PreExecute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool {
return true
}
func (p *HostStatusPredicate) Execute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
func (p *HostStatusPredicate) Execute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
if host.Status != guest.ExpectedStatus {
return false, fmt.Errorf("Host status is %s", host.Status)
}
+12 -5
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
)
@@ -16,14 +17,15 @@ func init() {
PredicatesManager.Register(
&HostStatusPredicate{},
&NetworkPredicate{},
&LocalVolumePredicate{},
)
}
type IPredicate interface {
Name() string
Clone() IPredicate
PreExecute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool
Execute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error)
PreExecute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool
Execute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error)
}
type SPredicatesManager struct {
@@ -58,13 +60,18 @@ func (man *SPredicatesManager) Has(newPre IPredicate) bool {
return false
}
func (man *SPredicatesManager) DoFilter(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
func (man *SPredicatesManager) DoFilter(
k8sCli *kubernetes.Clientset,
pod *v1.Pod,
node *v1.Node,
host *candidate.HostDesc,
) (bool, error) {
for _, pre := range man.predicates {
tmpPre := pre.Clone()
if !tmpPre.PreExecute(pod, node, host) {
if !tmpPre.PreExecute(k8sCli, pod, node, host) {
continue
}
fit, err := tmpPre.Execute(pod, node, host)
fit, err := tmpPre.Execute(k8sCli, pod, node, host)
if err != nil {
return false, err
}
@@ -4,6 +4,7 @@ import (
"fmt"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"yunion.io/x/pkg/util/errors"
@@ -30,7 +31,7 @@ func (p *NetworkPredicate) Name() string {
return "network"
}
func (p *NetworkPredicate) PreExecute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool {
func (p *NetworkPredicate) PreExecute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool {
net, netCont := pod.Annotations[YUNION_CNI_NETWORK_ANNOTATION]
ipAddr, ipCont := pod.Annotations[YUNION_CNI_IPADDR_ANNOTATION]
p.network = net
@@ -38,7 +39,7 @@ func (p *NetworkPredicate) PreExecute(pod *v1.Pod, node *v1.Node, host *candidat
return netCont || ipCont
}
func (p *NetworkPredicate) Execute(pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
func (p *NetworkPredicate) Execute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
hostNets := host.Networks
if p.network != "" {
err := p.checkByNetworks(hostNets)
@@ -0,0 +1,89 @@
package k8s
import (
"fmt"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
)
const (
YUNION_CSI_STORAGECLASS = "csi-yunion"
)
type LocalVolumePredicate struct {
pvcs []*v1.PersistentVolumeClaim
}
func (p *LocalVolumePredicate) Clone() IPredicate {
return &LocalVolumePredicate{}
}
func (p *LocalVolumePredicate) Name() string {
return "local-volume"
}
func (p *LocalVolumePredicate) PreExecute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) bool {
if cli == nil {
log.Errorf("k8s client is nil, not execute %s filter", p.Name())
return false
}
pvcs := make([]*v1.PersistentVolumeClaim, 0)
if pod.Spec.Volumes != nil && len(pod.Spec.Volumes) > 0 {
for _, v := range pod.Spec.Volumes {
if v.PersistentVolumeClaim == nil {
continue
}
pvcName := v.PersistentVolumeClaim.ClaimName
pvc, err := cli.CoreV1().PersistentVolumeClaims(pod.Namespace).Get(pvcName, metav1.GetOptions{})
if err != nil {
log.Warningf("Not found pvc %s for pod %s/%s", pvcName, pod.Namespace, pod.Name)
return false
}
// pvc's StorageClassName must "csi-yunion"
if pvc.Spec.StorageClassName != nil && *(pvc.Spec.StorageClassName) != YUNION_CSI_STORAGECLASS {
continue
}
pvcs = append(pvcs, pvc)
}
}
p.pvcs = pvcs
return len(pvcs) != 0
}
func (p *LocalVolumePredicate) getPvcRequestSize(pvc *v1.PersistentVolumeClaim) int64 {
req := pvc.Spec.Resources.Requests[v1.ResourceStorage]
return req.Value()
}
func (p *LocalVolumePredicate) Execute(cli *kubernetes.Clientset, pod *v1.Pod, node *v1.Node, host *candidate.HostDesc) (bool, error) {
var reqSize int64
for _, pvc := range p.pvcs {
pvName := pvc.Spec.VolumeName
if pvName != "" {
pv, _ := cli.CoreV1().PersistentVolumes().Get(pvName, metav1.GetOptions{})
if pv != nil {
// PersistentVolume already exists
log.V(10).Debugf("PV %s already exists", pv)
continue
}
}
reqSize += p.getPvcRequestSize(pvc)
}
reqSizeMB := reqSize / 1024 / 1024
return p.canHostStorageCreateVol(host, reqSizeMB)
}
func (p *LocalVolumePredicate) canHostStorageCreateVol(host *candidate.HostDesc, reqSize int64) (bool, error) {
freeSize := host.GetFreeStorageSizeOfType("local", false)
log.Debugf("[host %s] PVC request %dMB, free %dMB", host.Name, reqSize, freeSize)
if freeSize > reqSize {
return true, nil
}
return false, fmt.Errorf("Out of local storage for volume: %d/%d (request/free)MB", reqSize, freeSize)
}
+7 -1
View File
@@ -9,6 +9,8 @@ import (
"k8s.io/api/core/v1"
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api/v1"
"yunion.io/x/log"
k8spredicates "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates/k8s"
schedman "yunion.io/x/onecloud/pkg/scheduler/manager"
)
@@ -70,7 +72,11 @@ func doK8sPredicates(pod *v1.Pod, node *v1.Node) (bool, error) {
if len(hosts) == 0 {
return false, fmt.Errorf("Not found candidate host %s", node.Name)
}
return k8spredicates.PredicatesManager.DoFilter(pod, node, hosts[0])
k8sCli, err := schedman.GetK8sClient()
if err != nil {
log.Warningf("Get k8s client error: %v, some predicates will not execute", err)
}
return k8spredicates.PredicatesManager.DoFilter(k8sCli, pod, node, hosts[0])
}
func k8sPrioritizeHandler(c *gin.Context) {
+17 -1
View File
@@ -6,13 +6,18 @@ import (
"strings"
"time"
"k8s.io/client-go/kubernetes"
"yunion.io/x/log"
"yunion.io/x/pkg/utils"
o "yunion.io/x/onecloud/cmd/scheduler/options"
"yunion.io/x/onecloud/pkg/scheduler/api"
"yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
candidatecache "yunion.io/x/onecloud/pkg/scheduler/cache/candidate"
"yunion.io/x/onecloud/pkg/scheduler/core"
"yunion.io/x/onecloud/pkg/scheduler/data_manager"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/util/k8s"
)
const defaultIgnorePool = true
@@ -29,6 +34,7 @@ type SchedulerManager struct {
CandidateManager *data_manager.CandidateManager
//ReservedPoolManager *data_manager.ReservedPoolManager
//NetworkManager *data_manager.NetworkManager
KubeClusterManager *k8s.SKubeClusterManager
}
func NewSchedulerManager(stopCh <-chan struct{}) *SchedulerManager {
@@ -41,10 +47,19 @@ func NewSchedulerManager(stopCh <-chan struct{}) *SchedulerManager {
sm.TaskManager = NewTaskManager(stopCh)
//sm.ReservedPoolManager = data_manager.NewReservedPoolManager(stopCh)
//sm.NetworkManager = data_manager.NewNetworkManager(sm.DataManager, sm.ReservedPoolManager)
sm.KubeClusterManager = k8s.NewKubeClusterManager(o.GetOptions().Region, 30*time.Second)
return sm
}
func GetScheduleManager() *SchedulerManager {
return schedManager
}
func GetK8sClient() (*kubernetes.Clientset, error) {
return GetScheduleManager().KubeClusterManager.GetK8sClient()
}
func InitAndStart(stopCh <-chan struct{}) {
if schedManager != nil {
log.Warningf("Global scheduler already init.")
@@ -65,6 +80,7 @@ func (sm *SchedulerManager) start() {
sm.CandidateManager.Run,
//sm.ReservedPoolManager.Run,
//sm.NetworkManager.Run,
sm.KubeClusterManager.Start,
}
for _, f := range startFuncs {
go f()
-8
View File
@@ -51,14 +51,6 @@ func (self *SSnapshot) GetStatus() string {
}
}
func (self *SSnapshot) GetManagerId() string {
return self.region.client.providerId
}
func (self *SSnapshot) GetRegionId() string {
return self.region.GetId()
}
func (self *SSnapshot) GetSize() int32 {
return self.SourceDiskSize
}
+1 -1
View File
@@ -1,5 +1,5 @@
package ansible
const (
PUBLIC_CLOUD_ANSIBLE_USER = "yunionroot"
PUBLIC_CLOUD_ANSIBLE_USER = "cloudroot"
)
+116 -29
View File
@@ -106,8 +106,10 @@ func (self *SAzureClient) getDefaultClient() (*autorest.Client, error) {
return nil, err
}
client.Authorizer = authorizer
// client.RequestInspector = LogRequest()
// client.ResponseInspector = LogResponse()
if DEBUG {
client.RequestInspector = LogRequest()
client.ResponseInspector = LogResponse()
}
return &client, nil
}
@@ -116,7 +118,7 @@ func (self *SAzureClient) jsonRequest(method, url string, body string) (jsonutil
if err != nil {
return nil, err
}
return jsonRequest(cli, method, self.domain, url, body)
return jsonRequest(cli, method, self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) Get(resourceId string, params []string, retVal interface{}) error {
@@ -131,7 +133,7 @@ func (self *SAzureClient) Get(resourceId string, params []string, retVal interfa
if err != nil {
return err
}
body, err := jsonRequest(cli, "GET", self.domain, path, "")
body, err := jsonRequest(cli, "GET", self.domain, path, self.subscriptionId, "")
if err != nil {
return err
}
@@ -151,7 +153,7 @@ func (self *SAzureClient) ListVmSizes(location string) (jsonutils.JSONObject, er
return nil, fmt.Errorf("need subscription id")
}
url := fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Compute/locations/%s/vmSizes", self.subscriptionId, location)
return jsonRequest(cli, "GET", self.domain, url, "")
return jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
}
func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) {
@@ -163,7 +165,7 @@ func (self *SAzureClient) ListClassicDisks() (jsonutils.JSONObject, error) {
return nil, fmt.Errorf("need subscription id")
}
url := fmt.Sprintf("/subscriptions/%s/services/disks", self.subscriptionId)
return jsonRequest(cli, "GET", self.domain, url, "")
return jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
}
func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error {
@@ -178,7 +180,7 @@ func (self *SAzureClient) ListAll(resourceType string, retVal interface{}) error
if len(resourceType) > 0 {
url += fmt.Sprintf("/providers/%s", resourceType)
}
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -193,7 +195,7 @@ func (self *SAzureClient) ListSubscriptions() (jsonutils.JSONObject, error) {
if err != nil {
return nil, err
}
return jsonRequest(cli, "GET", self.domain, "/subscriptions", "")
return jsonRequest(cli, "GET", self.domain, "/subscriptions", self.subscriptionId, "")
}
func (self *SAzureClient) List(golbalResource string, retVal interface{}) error {
@@ -208,7 +210,7 @@ func (self *SAzureClient) List(golbalResource string, retVal interface{}) error
if len(self.subscriptionId) > 0 && len(golbalResource) > 0 {
url += fmt.Sprintf("/%s", golbalResource)
}
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -224,7 +226,7 @@ func (self *SAzureClient) ListByTypeWithResourceGroup(resourceGroupName string,
return fmt.Errorf("Missing subscription Info")
}
url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s", self.subscriptionId, resourceGroupName, Type)
body, err := jsonRequest(cli, "GET", self.domain, url, "")
body, err := jsonRequest(cli, "GET", self.domain, url, self.subscriptionId, "")
if err != nil {
return err
}
@@ -236,7 +238,7 @@ func (self *SAzureClient) Delete(resourceId string) error {
if err != nil {
return err
}
_, err = jsonRequest(cli, "DELETE", self.domain, resourceId, "")
_, err = jsonRequest(cli, "DELETE", self.domain, resourceId, self.subscriptionId, "")
return err
}
@@ -246,7 +248,7 @@ func (self *SAzureClient) PerformAction(resourceId string, action string, body s
return nil, err
}
url := fmt.Sprintf("%s/%s", resourceId, action)
return jsonRequest(cli, "POST", self.domain, url, body)
return jsonRequest(cli, "POST", self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) fetchResourceGroup(cli *autorest.Client, location string) error {
@@ -261,7 +263,7 @@ func (self *SAzureClient) fetchResourceGroup(cli *autorest.Client, location stri
if len(self.ressourceGroups) == 0 {
//Create Default resourceGroup
_url := fmt.Sprintf("/subscriptions/%s/resourcegroups/Default", self.subscriptionId)
body, err := jsonRequest(cli, "PUT", self.domain, _url, fmt.Sprintf(`{"name": "Default", "location": "%s"}`, location))
body, err := jsonRequest(cli, "PUT", self.domain, _url, self.subscriptionId, fmt.Sprintf(`{"name": "Default", "location": "%s"}`, location))
if err != nil {
return err
}
@@ -280,13 +282,25 @@ func (self *SAzureClient) checkParams(body jsonutils.JSONObject, params []string
for i := 0; i < len(params); i++ {
data, err := body.GetString(params[i])
if err != nil {
return nil, fmt.Errorf("Missing %s params")
return nil, fmt.Errorf("Missing %s params", params[i])
}
result[params[i]] = data
}
return result, nil
}
type AzureErrorDetail struct {
Code string `json:"code,omitempty"`
Message string `json:"message,omitempty"`
Target string `json:"target,omitempty"`
}
type AzureError struct {
Code string `json:"code,omitempty"`
Details []AzureErrorDetail `json:"details,omitempty"`
Message string `json:"message,omitempty"`
}
func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{}) error {
cli, err := self.getDefaultClient()
if err != nil {
@@ -307,11 +321,14 @@ func (self *SAzureClient) Create(body jsonutils.JSONObject, retVal interface{})
return fmt.Errorf("Create Default resourceGroup error?")
}
url := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/%s/%s", self.subscriptionId, self.ressourceGroups[0].Name, params["type"], params["name"])
result, err := jsonRequest(cli, "PUT", self.domain, url, body.String())
result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, body.String())
if err != nil {
return err
}
return result.Unmarshal(retVal)
if retVal != nil {
return result.Unmarshal(retVal)
}
return nil
}
func (self *SAzureClient) CheckNameAvailability(Type string, body string) (jsonutils.JSONObject, error) {
@@ -323,7 +340,7 @@ func (self *SAzureClient) CheckNameAvailability(Type string, body string) (jsonu
return nil, fmt.Errorf("Missing subscription ID")
}
url := fmt.Sprintf("/subscriptions/%s/providers/%s/checkNameAvailability", self.subscriptionId, Type)
return jsonRequest(cli, "POST", self.domain, url, body)
return jsonRequest(cli, "POST", self.domain, url, self.subscriptionId, body)
}
func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{}) error {
@@ -332,7 +349,7 @@ func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{})
return err
}
url, err := body.GetString("id")
result, err := jsonRequest(cli, "PUT", self.domain, url, body.String())
result, err := jsonRequest(cli, "PUT", self.domain, url, self.subscriptionId, body.String())
if err != nil {
return err
}
@@ -342,8 +359,86 @@ func (self *SAzureClient) Update(body jsonutils.JSONObject, retVal interface{})
return nil
}
func jsonRequest(client *autorest.Client, method, domain, baseUrl string, body string) (jsonutils.JSONObject, error) {
return _jsonRequest(client, method, domain, baseUrl, body)
func waitRegisterComplete(client *autorest.Client, domain, subscriptionId string, serviceType string) error {
for i := 1; i < 10; i++ {
result, err := _jsonRequest(client, "GET", domain, fmt.Sprintf("/subscriptions/%s/providers", subscriptionId), "")
if err != nil {
return err
}
value, err := result.GetArray("value")
if err != nil {
return err
}
for _, v := range value {
namespace, _ := v.GetString("namespace")
if namespace == serviceType {
state, _ := v.GetString("registrationState")
if state == "Registered" {
return nil
}
log.Debugf("service %s state %s waite %d second ...", serviceType, state, i*10)
}
}
time.Sleep(time.Second * time.Duration(i*10))
}
return fmt.Errorf("wait service %s register timeout", serviceType)
}
func registerService(client *autorest.Client, domain, subscriptionId string, serviceType string) error {
registryUrl := fmt.Sprintf("/subscriptions/%s/providers/%s/register", subscriptionId, serviceType)
result, err := _jsonRequest(client, "POST", domain, registryUrl, "")
if err != nil || result.Contains("error") {
return fmt.Errorf("failed to register %s service", serviceType)
}
if state, _ := result.GetString("registrationState"); state == "Registered" {
return nil
}
return waitRegisterComplete(client, domain, subscriptionId, serviceType)
}
func recoverFromError(client *autorest.Client, domain, subscriptionId string, azureErr AzureError) bool {
switch azureErr.Code {
case "SubscriptionNotRegistered":
services := []string{"Microsoft.Network"}
for _, service := range services {
if err := registerService(client, domain, subscriptionId, service); err != nil {
log.Errorf("register %s error: %v", service, err)
return false
}
}
return true
case "MissingSubscriptionRegistration":
for _, detail := range azureErr.Details {
log.Errorf("The subscription is not registered to use namespace '%s', try register it", detail.Target)
if err := registerService(client, domain, subscriptionId, detail.Target); err != nil {
log.Errorf("register %s error: %v", detail.Target, err)
return false
}
}
return true
default:
return false
}
return false
}
func jsonRequest(client *autorest.Client, method, domain, baseUrl string, subscriptionId string, body string) (jsonutils.JSONObject, error) {
result, err := _jsonRequest(client, method, domain, baseUrl, body)
if err != nil {
return nil, err
}
if result.Contains("error") {
azureError := AzureError{}
if err := result.Unmarshal(&azureError, "error"); err != nil {
return nil, fmt.Errorf(result.String())
}
if recoverFromError(client, domain, subscriptionId, azureError) {
return _jsonRequest(client, method, domain, baseUrl, body)
}
log.Errorf("Azure %s request: %s \nbody: %s error: %v", method, baseUrl, body, result.String())
return nil, fmt.Errorf(result.String())
}
return result, nil
}
func waitForComplatetion(client *autorest.Client, req *http.Request, resp *http.Response, timeout time.Duration) (jsonutils.JSONObject, error) {
@@ -470,15 +565,7 @@ func _jsonRequest(client *autorest.Client, method, domain, baseURL, body string)
return nil, err
}
_data := strings.Replace(string(data), "\r", "", -1)
result, err = jsonutils.Parse([]byte(_data))
if err != nil {
return nil, err
}
if result.Contains("error") {
log.Errorf("Azure %s request: %s \nbody: %s error: %v", req.Method, req.URL.String(), body, result.String())
return nil, fmt.Errorf(result.String())
}
return result, nil
return jsonutils.Parse([]byte(_data))
}
func (self *SAzureClient) UpdateAccount(tenantId, secret, envName string) error {
+2 -6
View File
@@ -13,10 +13,6 @@ type SClassicHost struct {
zone *SZone
}
const (
DEFAULT_USER = "yunion"
)
func (self *SClassicHost) GetMetadata() *jsonutils.JSONDict {
return nil
}
@@ -26,7 +22,7 @@ func (self *SClassicHost) GetId() string {
}
func (self *SClassicHost) GetName() string {
return fmt.Sprintf("%s-classic", self.zone.region.client.subscriptionId)
return fmt.Sprintf("%s/%s-classic", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
}
func (self *SClassicHost) GetGlobalId() string {
@@ -73,7 +69,7 @@ func (self *SClassicHost) GetMemSizeMB() int {
return 0
}
func (self *SClassicHost) GetEnabled() bool {
return false
return true
}
func (self *SClassicHost) GetHostStatus() string {
+4
View File
@@ -9,6 +9,10 @@ import (
"github.com/Azure/go-autorest/autorest"
)
const (
DEBUG = false
)
func LogRequest() autorest.PrepareDecorator {
return func(p autorest.Preparer) autorest.Preparer {
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
+43 -13
View File
@@ -8,6 +8,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/ansible"
)
type SHost struct {
@@ -23,7 +24,7 @@ func (self *SHost) GetId() string {
}
func (self *SHost) GetName() string {
return fmt.Sprintf("%s", self.zone.region.client.subscriptionId)
return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId)
}
func (self *SHost) GetGlobalId() string {
@@ -42,18 +43,47 @@ 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, userData string) (cloudprovider.ICloudVM, error) {
nicId := ""
if net := self.zone.getNetworkById(networkId); net == nil {
return nil, fmt.Errorf("invalid network ID %s", networkId)
} else if nic, err := self.zone.region.CreateNetworkInterface(fmt.Sprintf("%s-ipconfig", name), ipAddr, net.GetId(), secgroupId); err != nil {
return nil, err
} else {
nicId = nic.ID
}
vmId, err := self._createVM(name, imgId, int32(sysDiskSize), cpu, memMB, nicId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, userData)
func (self *SHost) searchNetorkInterface(IPAddr string, networkId string, secgroupId string) (*SInstanceNic, error) {
interfaces, err := self.zone.region.GetNetworkInterfaces()
if err != nil {
self.zone.region.DeleteNetworkInterface(nicId)
return nil, err
}
for i, nic := range interfaces {
for _, ipConf := range nic.Properties.IPConfigurations {
if ipConf.Properties.PrivateIPAddress == IPAddr && networkId == ipConf.Properties.Subnet.ID && ipConf.Properties.PrivateIPAllocationMethod == "Static" {
if nic.Properties.NetworkSecurityGroup == nil || nic.Properties.NetworkSecurityGroup.ID != secgroupId {
nic.Properties.NetworkSecurityGroup = &SSecurityGroup{ID: secgroupId}
if err := self.zone.region.client.Update(jsonutils.Marshal(nic), nil); err != nil {
log.Errorf("assign secgroup %s for nic %s failed %d")
return nil, err
}
}
return &interfaces[i], nil
}
}
}
return nil, cloudprovider.ErrNotFound
}
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) {
net := self.zone.getNetworkById(networkId)
if net == nil {
return nil, fmt.Errorf("invalid network ID %s", networkId)
}
nic, err := self.searchNetorkInterface(ipAddr, net.GetId(), secgroupId)
if err != nil {
if err == cloudprovider.ErrNotFound {
nic, err = self.zone.region.CreateNetworkInterface(fmt.Sprintf("%s-ipconfig", name), ipAddr, net.GetId(), secgroupId)
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
vmId, err := self._createVM(name, imgId, int32(sysDiskSize), cpu, memMB, nic.ID, ipAddr, desc, passwd, storageType, diskSizes, publicKey, userData)
if err != nil {
self.zone.region.DeleteNetworkInterface(nic.ID)
return nil, err
}
if vm, err := self.zone.region.GetInstance(vmId); err != nil {
@@ -89,7 +119,7 @@ func (self *SHost) _createVM(name string, imgId string, sysDiskSize int32, cpu i
},
OsProfile: OsProfile{
ComputerName: name,
AdminUsername: DEFAULT_USER,
AdminUsername: ansible.PUBLIC_CLOUD_ANSIBLE_USER,
AdminPassword: passwd,
CustomData: userData,
},
+55
View File
@@ -0,0 +1,55 @@
package azure
import (
"fmt"
)
type SServices struct {
Value []SService `json:"value,omitempty"`
}
type SService struct {
ID string `json:"id,omitempty"`
Namespace string `json:"namespace,omitempty"`
RegistrationState string `json:"registrationState,omitempty"`
ResourceTypes []ResourceType `json:"resourceTypes,omitempty"`
}
type ResourceType struct {
ApiVersions []string `json:"apiVersions,omitempty"`
Capabilities string `json:"capabilities,omitempty"`
Locations []string `json:"locations,omitempty"`
ResourceType string `json:"locations,omitempty"`
}
func (self *SRegion) ListServices() ([]SService, error) {
services := []SService{}
return services, self.client.List("providers", &services)
}
func (self *SRegion) SerciceShow(serviceType string) (*SService, error) {
service := SService{}
return &service, self.client.Get("providers/"+serviceType, []string{}, &service)
}
func (self *SRegion) serviceOperation(resourceType, operation string) error {
services, err := self.ListServices()
if err != nil {
return err
}
for _, service := range services {
if service.Namespace == resourceType {
_, err := self.client.jsonRequest("POST", fmt.Sprintf("%s/%s", service.ID, operation), "")
return err
}
}
return fmt.Errorf("failed to find namespace: %s", resourceType)
}
func (self *SRegion) ServiceRegister(resourceType string) error {
return self.serviceOperation(resourceType, "register")
}
func (self *SRegion) ServiceUnRegister(resourceType string) error {
return self.serviceOperation(resourceType, "unregister")
}
+41
View File
@@ -0,0 +1,41 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ServiceListOptions struct {
}
shellutils.R(&ServiceListOptions{}, "service-list", "List providers", func(cli *azure.SRegion, args *ServiceListOptions) error {
services, err := cli.ListServices()
if err != nil {
return err
}
printList(services, len(services), 0, 0, []string{})
return nil
})
type ServiceOptions struct {
NAME string `help:"Name for service register"`
}
shellutils.R(&ServiceOptions{}, "service-register", "Register service", func(cli *azure.SRegion, args *ServiceOptions) error {
return cli.ServiceRegister(args.NAME)
})
shellutils.R(&ServiceOptions{}, "service-unregister", "Unregister service", func(cli *azure.SRegion, args *ServiceOptions) error {
return cli.ServiceUnRegister(args.NAME)
})
shellutils.R(&ServiceOptions{}, "service-show", "Show service detail", func(cli *azure.SRegion, args *ServiceOptions) error {
service, err := cli.SerciceShow(args.NAME)
if err != nil {
return err
}
printObject(service)
return nil
})
}
+19
View File
@@ -32,4 +32,23 @@ func init() {
printObject(vpc)
return nil
})
shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *azure.SRegion, args *VpcOptions) error {
return cli.DeleteVpc(args.ID)
})
type VpcCreateOptions struct {
NAME string `help:"vpc Name"`
CIDR string `help:"vpc cidr"`
Desc string `help:"vpc description"`
}
shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *azure.SRegion, args *VpcCreateOptions) error {
vpc, err := cli.CreateIVpc(args.NAME, args.Desc, args.CIDR)
if err != nil {
return err
}
printObject(vpc)
return nil
})
}
+21 -10
View File
@@ -22,8 +22,9 @@ type SSnapshot struct {
Name string
Location string
ManagedBy string
Sku SnapshotSku
Sku *SnapshotSku
Properties DiskProperties
Type string
}
func (self *SSnapshot) GetId() string {
@@ -57,7 +58,23 @@ func (self *SSnapshot) IsEmulated() bool {
}
func (self *SRegion) CreateSnapshot(diskId, snapName, desc string) (*SSnapshot, error) {
snapshot := SSnapshot{}
disk, err := self.GetDisk(diskId)
if err != nil {
return nil, err
}
snapshot := SSnapshot{
region: self,
Name: snapName,
Location: self.Name,
Properties: DiskProperties{
CreationData: CreationData{
CreateOption: "Copy",
SourceResourceID: diskId,
},
DiskSizeGB: disk.Properties.DiskSizeGB,
},
Type: "Microsoft.Compute/snapshots",
}
return &snapshot, self.client.Create(jsonutils.Marshal(snapshot), &snapshot)
}
@@ -137,9 +154,11 @@ func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
classicSnapshots = append(classicSnapshots, _classicSnapshots...)
isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)+len(classicSnapshots))
for i := 0; i < len(snapshots); i++ {
snapshots[i].region = self
isnapshots[i] = &snapshots[i]
}
for i := 0; i < len(classicSnapshots); i++ {
classicSnapshots[i].region = self
isnapshots[len(snapshots)+i] = &classicSnapshots[i]
}
return isnapshots, nil
@@ -149,14 +168,6 @@ func (self *SSnapshot) GetDiskId() string {
return self.Properties.CreationData.SourceResourceID
}
func (self *SSnapshot) GetManagerId() string {
return self.region.client.providerId
}
func (self *SSnapshot) GetRegionId() string {
return self.region.GetId()
}
func (self *SSnapshot) GetDiskType() string {
return ""
}
+5 -1
View File
@@ -77,7 +77,11 @@ func (self *SVpc) GetCidrBlock() string {
}
func (self *SVpc) Delete() error {
return self.region.client.Delete(self.ID)
return self.region.DeleteVpc(self.ID)
}
func (self *SRegion) DeleteVpc(vpcId string) error {
return self.client.Delete(vpcId)
}
func (self *SVpc) getSecurityGroups() ([]SSecurityGroup, error) {
+103
View File
@@ -0,0 +1,103 @@
package k8s
import (
"sync"
"time"
"k8s.io/client-go/kubernetes"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/mcclient/auth"
kubeserver "yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
)
type SKubeClusterManager struct {
k8sConfigLock *sync.RWMutex
k8sConfig string
interval time.Duration
region string
}
func NewKubeClusterManager(region string, interval time.Duration) *SKubeClusterManager {
return &SKubeClusterManager{
k8sConfigLock: new(sync.RWMutex),
interval: interval,
region: region,
}
}
func (man *SKubeClusterManager) GetK8sConfig() string {
man.k8sConfigLock.RLock()
defer man.k8sConfigLock.RUnlock()
return man.k8sConfig
}
func (man *SKubeClusterManager) GetK8sClient() (*kubernetes.Clientset, error) {
cli, err := NewClientByContent([]byte(man.GetK8sConfig()), nil)
if err != nil {
log.Warningf("Init kubernetes client error: %v", err)
return nil, err
}
return cli, nil
}
func (man *SKubeClusterManager) Start() {
go man.startRefreshKubeConfig()
}
func (man *SKubeClusterManager) setK8sConfig(conf string) {
man.k8sConfigLock.Lock()
defer man.k8sConfigLock.Unlock()
man.k8sConfig = conf
}
func (man *SKubeClusterManager) isK8sHealthy() bool {
if man.GetK8sConfig() == "" {
return false
}
cli, err := man.GetK8sClient()
if err != nil {
return false
}
_, err = cli.Discovery().ServerVersion()
if err != nil {
log.Errorf("Discovery k8s version: %v", err)
return false
}
return true
}
func (man *SKubeClusterManager) startRefreshKubeConfig() {
man.refreshKubeConfig()
tick := time.Tick(man.interval)
for {
select {
case <-tick:
man.refreshKubeConfig()
}
}
}
func (man *SKubeClusterManager) refreshKubeConfig() {
if man.isK8sHealthy() {
return
}
kubeConfig, err := man.getKubeClusterConfig()
if err != nil {
log.Errorf("Get default k8s config from kube server error: %v", err)
}
man.setK8sConfig(kubeConfig)
}
func (man *SKubeClusterManager) getKubeClusterConfig() (string, error) {
session := auth.GetAdminSession(man.region, "v1")
params := jsonutils.NewDict()
params.Add(jsonutils.JSONTrue, "directly")
ret, err := kubeserver.Clusters.PerformAction(session, "default", "generate-kubeconfig", params)
if err != nil {
return "", err
}
return ret.GetString("kubeconfig")
}
+33 -23
View File
@@ -13,29 +13,29 @@ type TRbacResult string
const (
WILD_MATCH = "*"
Allow = TRbacResult("allow")
AdminAllow = TRbacResult("allow")
OwnerAllow = TRbacResult("owner")
UserAllow = TRbacResult("user")
GuestAllow = TRbacResult("guest")
Deny = TRbacResult("deny")
)
func (result TRbacResult) IsHigherPrivilege(r2 TRbacResult) bool {
switch result {
case Allow:
if r2 == Allow {
return false
} else {
return true
}
case OwnerAllow:
if r2 == Deny {
return true
} else {
return false
}
case Deny:
return false
var (
strictness = map[TRbacResult]int{
Deny: 0,
AdminAllow: 1,
OwnerAllow: 2,
UserAllow: 3,
GuestAllow: 4,
}
return false
)
func (r TRbacResult) Strictness() int {
return strictness[r]
}
func (r1 TRbacResult) StricterThan(r2 TRbacResult) bool {
return r1.Strictness() < r2.Strictness()
}
type SRbacPolicy struct {
@@ -79,6 +79,10 @@ func (rule *SRbacRule) contains(rule2 *SRbacRule) bool {
return true
}
func (rule *SRbacRule) stricterThan(r2 *SRbacRule) bool {
return rule.Result.StricterThan(r2.Result)
}
func (rule *SRbacRule) match(service string, resource string, action string, extra ...string) (bool, int, int) {
matched := 0
weight := 0
@@ -144,7 +148,9 @@ func (policy *SRbacPolicy) GetMatchRule(service string, resource string, action
var matchRule *SRbacRule
for i := 0; i < len(policy.Rules); i += 1 {
match, matchCnt, weight := policy.Rules[i].match(service, resource, action, extra...)
if match && (maxMatchCnt < matchCnt || (maxMatchCnt == matchCnt && minWeight > weight)) {
if match && (maxMatchCnt < matchCnt ||
(maxMatchCnt == matchCnt && minWeight > weight) ||
(maxMatchCnt == matchCnt && minWeight == weight && matchRule.stricterThan(&policy.Rules[i]))) {
maxMatchCnt = matchCnt
minWeight = weight
matchRule = &policy.Rules[i]
@@ -153,7 +159,7 @@ func (policy *SRbacPolicy) GetMatchRule(service string, resource string, action
return matchRule
}
func compactRules(rules []SRbacRule) []SRbacRule {
func CompactRules(rules []SRbacRule) []SRbacRule {
output := make([]SRbacRule, 1)
output[0] = rules[0]
for i := 1; i < len(rules); i += 1 {
@@ -190,7 +196,7 @@ func (policy *SRbacPolicy) Decode(policyJson jsonutils.JSONObject) error {
return err
}
policy.Rules = compactRules(rules)
policy.Rules = CompactRules(rules)
return nil
}
@@ -208,10 +214,14 @@ func decode(rules jsonutils.JSONObject, decodeRule SRbacRule, level int) ([]SRba
ruleJsonStr := rules.(*jsonutils.JSONString)
ruleStr, _ := ruleJsonStr.GetString()
switch ruleStr {
case string(Allow):
decodeRule.Result = Allow
case string(AdminAllow):
decodeRule.Result = AdminAllow
case string(OwnerAllow):
decodeRule.Result = OwnerAllow
case string(UserAllow):
decodeRule.Result = UserAllow
case string(GuestAllow):
decodeRule.Result = GuestAllow
case string(Deny):
decodeRule.Result = Deny
default:
+2 -2
View File
@@ -31,7 +31,7 @@ type SSHtoolSol struct {
func getCommand(ctx context.Context, userCred mcclient.TokenCredential, ip string) (string, *BaseCommand, error) {
cmd := NewBaseCommand(o.Options.SshToolPath)
s := auth.GetAdminSession(o.Options.Region, "v2")
key, err := modules.Sshkeypairs.GetById(s, userCred.GetProjectId(), jsonutils.NewDict())
key, err := modules.Sshkeypairs.GetById(s, userCred.GetProjectId(), jsonutils.Marshal(map[string]bool{"admin": true}))
if err != nil {
return "", nil, err
}
@@ -85,7 +85,7 @@ func NewSSHtoolSolCommand(ctx context.Context, userCred mcclient.TokenCredential
func (c *SSHtoolSol) GetCommand() *exec.Cmd {
if c.BaseCommand != nil {
cmd := c.BaseCommand.GetCommand()
cmd.Env = append(cmd.Env, "TERM=screen-256color")
cmd.Env = append(cmd.Env, "TERM=xterm-256color")
return cmd
}
return nil
+1 -1
View File
@@ -99,7 +99,7 @@ func initSocketHandler(so socketio.Socket, p *session.Pty) {
log.Infof("exec: %s", p.Command)
args := strings.Split(p.Command, " ")
cmd := exec.Command(args[0], args[1:]...)
cmd.Env = append(cmd.Env, "TERM=screen-256color")
cmd.Env = append(cmd.Env, "TERM=xterm-256color")
if _pty, err := pty.Start(cmd); err != nil {
so.Emit(OUTPUT_EVENT, err.Error()+"\r\n")
log.Errorf("exec error: %v", err)