secgroups.go 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "strings"
  20. "time"
  21. "yunion.io/x/cloudmux/pkg/cloudprovider"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/gotypes"
  26. "yunion.io/x/pkg/util/compare"
  27. "yunion.io/x/pkg/util/rbacscope"
  28. "yunion.io/x/pkg/util/regutils"
  29. "yunion.io/x/pkg/util/secrules"
  30. "yunion.io/x/pkg/utils"
  31. "yunion.io/x/sqlchemy"
  32. "yunion.io/x/onecloud/pkg/apis"
  33. api "yunion.io/x/onecloud/pkg/apis/compute"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  39. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  40. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  41. "yunion.io/x/onecloud/pkg/compute/options"
  42. "yunion.io/x/onecloud/pkg/httperrors"
  43. "yunion.io/x/onecloud/pkg/mcclient"
  44. "yunion.io/x/onecloud/pkg/mcclient/auth"
  45. "yunion.io/x/onecloud/pkg/util/logclient"
  46. "yunion.io/x/onecloud/pkg/util/stringutils2"
  47. )
  48. // +onecloud:swagger-gen-model-singular=secgroup
  49. // +onecloud:swagger-gen-model-plural=secgroups
  50. type SSecurityGroupManager struct {
  51. db.SSharableVirtualResourceBaseManager
  52. db.SExternalizedResourceBaseManager
  53. SManagedResourceBaseManager
  54. SCloudregionResourceBaseManager
  55. SVpcResourceBaseManager
  56. SGlobalVpcResourceBaseManager
  57. }
  58. var SecurityGroupManager *SSecurityGroupManager
  59. func init() {
  60. SecurityGroupManager = &SSecurityGroupManager{
  61. SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
  62. SSecurityGroup{},
  63. "secgroups_tbl",
  64. "secgroup",
  65. "secgroups",
  66. ),
  67. }
  68. SecurityGroupManager.NameLength = 128
  69. SecurityGroupManager.SetVirtualObject(SecurityGroupManager)
  70. }
  71. const (
  72. SECURITY_GROUP_SEPARATOR = ";"
  73. )
  74. type SSecurityGroup struct {
  75. db.SSharableVirtualResourceBase
  76. db.SExternalizedResourceBase
  77. IsDirty bool `nullable:"false" default:"false"`
  78. SManagedResourceBase
  79. SCloudregionResourceBase `width:"36" charset:"ascii" nullable:"false" list:"domain" create:"domain_required" default:"default"`
  80. SGlobalVpcResourceBase `width:"36" charset:"ascii" list:"user" create:"domain_optional" json:"globalvpc_id"`
  81. SVpcResourceBase `wdith:"36" charset:"ascii" nullable:"true" list:"domain" create:"domain_optional" update:""`
  82. }
  83. func (self *SSecurityGroup) GetCloudproviderId() string {
  84. return self.ManagerId
  85. }
  86. // 安全组列表
  87. func (manager *SSecurityGroupManager) ListItemFilter(
  88. ctx context.Context,
  89. q *sqlchemy.SQuery,
  90. userCred mcclient.TokenCredential,
  91. input api.SecgroupListInput,
  92. ) (*sqlchemy.SQuery, error) {
  93. var err error
  94. q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput)
  95. if err != nil {
  96. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
  97. }
  98. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ExternalizedResourceBaseListInput)
  99. if err != nil {
  100. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  101. }
  102. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ManagedResourceListInput)
  103. if err != nil {
  104. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  105. }
  106. q, err = manager.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, input.RegionalFilterListInput)
  107. if err != nil {
  108. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  109. }
  110. if len(input.VpcId) > 0 {
  111. vpcObj, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcId)
  112. if err != nil {
  113. return nil, err
  114. }
  115. vpc := vpcObj.(*SVpc)
  116. region, err := vpc.GetRegion()
  117. if err != nil {
  118. return nil, err
  119. }
  120. filter, err := region.GetDriver().GetSecurityGroupFilter(vpc)
  121. if err != nil {
  122. return nil, err
  123. }
  124. q = filter(q)
  125. }
  126. serverStr := input.ServerId
  127. if len(serverStr) > 0 {
  128. guest, _, err := ValidateGuestResourceInput(ctx, userCred, input.ServerResourceInput)
  129. if err != nil {
  130. return nil, errors.Wrap(err, "ValidateGuestResourceInput")
  131. }
  132. serverId := guest.GetId()
  133. filters := []sqlchemy.ICondition{}
  134. filters = append(filters, sqlchemy.In(q.Field("id"), GuestManager.Query("secgrp_id").Equals("id", serverId).SubQuery()))
  135. filters = append(filters, sqlchemy.In(q.Field("id"), GuestsecgroupManager.Query("secgroup_id").Equals("guest_id", serverId).SubQuery()))
  136. isAdmin := false
  137. // admin := (input.Admin != nil && *input.Admin)
  138. allowScope, _ := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
  139. if allowScope == rbacscope.ScopeSystem || allowScope == rbacscope.ScopeDomain {
  140. isAdmin = true
  141. }
  142. if isAdmin {
  143. filters = append(filters, sqlchemy.In(q.Field("id"), GuestManager.Query("admin_secgrp_id").Equals("id", serverId).SubQuery()))
  144. }
  145. q = q.Filter(sqlchemy.OR(filters...))
  146. }
  147. if len(input.DBInstanceId) > 0 {
  148. _, err = validators.ValidateModel(ctx, userCred, DBInstanceManager, &input.DBInstanceId)
  149. if err != nil {
  150. return nil, err
  151. }
  152. sq := DBInstanceSecgroupManager.Query("secgroup_id").Equals("dbinstance_id", input.DBInstanceId)
  153. q = q.In("id", sq.SubQuery())
  154. }
  155. if len(input.LoadbalancerId) > 0 {
  156. _, err = validators.ValidateModel(ctx, userCred, LoadbalancerManager, &input.LoadbalancerId)
  157. if err != nil {
  158. return nil, err
  159. }
  160. sq := LoadbalancerSecurityGroupManager.Query("secgroup_id").Equals("loadbalancer_id", input.LoadbalancerId)
  161. q = q.In("id", sq.SubQuery())
  162. }
  163. if len(input.ElasticcacheId) > 0 {
  164. _, err = validators.ValidateModel(ctx, userCred, ElasticcacheManager, &input.ElasticcacheId)
  165. if err != nil {
  166. return nil, err
  167. }
  168. sq := ElasticcachesecgroupManager.Query("secgroup_id").Equals("elasticcache_id", input.ElasticcacheId).Distinct()
  169. q = q.In("id", sq.SubQuery())
  170. }
  171. if len(input.Ip) > 0 || len(input.Ports) > 0 {
  172. sq := SecurityGroupRuleManager.Query("secgroup_id")
  173. if len(input.Ip) > 0 {
  174. sq = sq.Like("cidr", input.Ip+"%")
  175. }
  176. if len(input.Ports) > 0 {
  177. sq = sq.Equals("ports", input.Ports)
  178. }
  179. if utils.IsInStringArray(input.Direction, []string{"in", "out"}) {
  180. sq = sq.Equals("direction", input.Direction)
  181. }
  182. q = q.In("id", sq.SubQuery())
  183. }
  184. if input.CloudEnv == "onpremise" {
  185. q = q.IsNullOrEmpty("manager_id")
  186. }
  187. return q, nil
  188. }
  189. func (manager *SSecurityGroupManager) OrderByExtraFields(
  190. ctx context.Context,
  191. q *sqlchemy.SQuery,
  192. userCred mcclient.TokenCredential,
  193. input api.SecgroupListInput,
  194. ) (*sqlchemy.SQuery, error) {
  195. var err error
  196. q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput)
  197. if err != nil {
  198. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
  199. }
  200. orderByGuest := input.OrderByGuestCnt
  201. if sqlchemy.SQL_ORDER_ASC.Equals(orderByGuest) || sqlchemy.SQL_ORDER_DESC.Equals(orderByGuest) {
  202. guests := GuestManager.Query().SubQuery()
  203. guestsecgroups := GuestsecgroupManager.Query().SubQuery()
  204. q1 := guests.Query(guests.Field("id").Label("guest_id"),
  205. guests.Field("secgrp_id").Label("secgroup_id"))
  206. q2 := guestsecgroups.Query(guestsecgroups.Field("guest_id"),
  207. guestsecgroups.Field("secgroup_id"))
  208. uq := sqlchemy.Union(q1, q2)
  209. uQ := uq.Query(
  210. uq.Field("secgroup_id"),
  211. sqlchemy.COUNT("guest_cnt", uq.Field("guest_id")),
  212. )
  213. sq := uQ.GroupBy(uq.Field("secgroup_id")).SubQuery()
  214. q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("id"), sq.Field("secgroup_id")))
  215. if sqlchemy.SQL_ORDER_ASC.Equals(orderByGuest) {
  216. q = q.Asc(sq.Field("guest_cnt"))
  217. } else {
  218. q = q.Desc(sq.Field("guest_cnt"))
  219. }
  220. }
  221. return q, nil
  222. }
  223. func (manager *SSecurityGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  224. var err error
  225. q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  226. if err == nil {
  227. return q, nil
  228. }
  229. q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  230. if err == nil {
  231. return q, nil
  232. }
  233. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  234. if err == nil {
  235. return q, nil
  236. }
  237. q, err = manager.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
  238. if err == nil {
  239. return q, nil
  240. }
  241. q, err = manager.SGlobalVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  242. if err == nil {
  243. return q, nil
  244. }
  245. return q, httperrors.ErrNotFound
  246. }
  247. func (manager *SSecurityGroupManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  248. var err error
  249. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  250. if err == nil {
  251. return q, nil
  252. }
  253. return q, httperrors.ErrNotFound
  254. }
  255. func (self *SSecurityGroup) GetChangeOwnerCandidateDomainIds() []string {
  256. candidates := [][]string{}
  257. vpc, _ := self.GetVpc()
  258. if vpc != nil {
  259. candidates = append(candidates, vpc.GetChangeOwnerCandidateDomainIds())
  260. }
  261. return db.ISharableMergeChangeOwnerCandidateDomainIds(self, candidates...)
  262. }
  263. func (self *SSecurityGroup) GetGuestsQuery() *sqlchemy.SQuery {
  264. guests := GuestManager.Query().SubQuery()
  265. return guests.Query().Filter(
  266. sqlchemy.OR(
  267. sqlchemy.Equals(guests.Field("secgrp_id"), self.Id),
  268. sqlchemy.Equals(guests.Field("admin_secgrp_id"), self.Id),
  269. sqlchemy.In(guests.Field("id"), GuestsecgroupManager.Query("guest_id").Equals("secgroup_id", self.Id).SubQuery()),
  270. ),
  271. ).Filter(sqlchemy.NotIn(guests.Field("hypervisor"), []string{api.HYPERVISOR_POD, api.HYPERVISOR_BAREMETAL, api.HYPERVISOR_ESXI}))
  272. }
  273. func (self *SSecurityGroup) GetGuestsCount() (int, error) {
  274. return self.GetGuestsQuery().CountWithError()
  275. }
  276. func (self *SSecurityGroup) GetGuests() []SGuest {
  277. guests := []SGuest{}
  278. q := self.GetGuestsQuery()
  279. err := db.FetchModelObjects(GuestManager, q, &guests)
  280. if err != nil {
  281. log.Errorf("GetGuests fail %s", err)
  282. return nil
  283. }
  284. return guests
  285. }
  286. func (self *SSecurityGroup) GetKvmGuests() ([]SGuest, error) {
  287. guests := []SGuest{}
  288. q := self.GetGuestsQuery().Equals("hypervisor", api.HYPERVISOR_KVM)
  289. err := db.FetchModelObjects(GuestManager, q, &guests)
  290. if err != nil {
  291. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  292. }
  293. return guests, nil
  294. }
  295. func (self *SSecurityGroup) getDesc() *api.SecgroupJsonDesc {
  296. return &api.SecgroupJsonDesc{
  297. Id: self.Id,
  298. Name: self.Name,
  299. }
  300. }
  301. func (self *SSecurityGroup) ClearRuleDirty() error {
  302. _, err := sqlchemy.GetDB().Exec(
  303. fmt.Sprintf(
  304. "update %s set is_dirty = false where secgroup_id = ?",
  305. SecurityGroupRuleManager.TableSpec().Name(),
  306. ), self.Id,
  307. )
  308. return err
  309. }
  310. func (manager *SSecurityGroupManager) FetchCustomizeColumns(
  311. ctx context.Context,
  312. userCred mcclient.TokenCredential,
  313. query jsonutils.JSONObject,
  314. objs []interface{},
  315. fields stringutils2.SSortedStrings,
  316. isList bool,
  317. ) []api.SecgroupDetails {
  318. rows := make([]api.SecgroupDetails, len(objs))
  319. virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  320. managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  321. regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  322. vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  323. globalVpcRows := manager.SGlobalVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  324. secgroupIds := make([]string, len(objs))
  325. secgroups := make([]*SSecurityGroup, len(objs))
  326. for i := range rows {
  327. rows[i] = api.SecgroupDetails{
  328. SharableVirtualResourceDetails: virtRows[i],
  329. VpcResourceInfo: vpcRows[i],
  330. GlobalVpcResourceInfo: globalVpcRows[i],
  331. }
  332. rows[i].ManagedResourceInfo = managerRows[i]
  333. rows[i].CloudregionResourceInfo = regionRows[i]
  334. secgroup := objs[i].(*SSecurityGroup)
  335. secgroupIds[i] = secgroup.Id
  336. secgroups[i] = secgroup
  337. }
  338. guests := []SGuest{}
  339. q := GuestManager.Query().IsFalse("pending_deleted")
  340. q = q.Filter(sqlchemy.OR(
  341. sqlchemy.In(q.Field("secgrp_id"), secgroupIds),
  342. sqlchemy.In(q.Field("admin_secgrp_id"), secgroupIds),
  343. ))
  344. ownerId, queryScope, err, _ := db.FetchCheckQueryOwnerScope(ctx, userCred, query, GuestManager, policy.PolicyActionList, true)
  345. if err != nil {
  346. log.Errorf("FetchCheckQueryOwnerScope error: %v", err)
  347. return rows
  348. }
  349. q = GuestManager.FilterByOwner(ctx, q, GuestManager, userCred, ownerId, queryScope)
  350. err = db.FetchModelObjects(GuestManager, q, &guests)
  351. if err != nil {
  352. log.Errorf("db.FetchModelObjects error: %v", err)
  353. return rows
  354. }
  355. adminGuestMaps := map[string]int{}
  356. systemGuestMaps := map[string]int{}
  357. normalGuestMaps := map[string]int{}
  358. guestNetworkMaps := map[string]int{}
  359. for i := range guests {
  360. if guests[i].IsSystem {
  361. if _, ok := systemGuestMaps[guests[i].SecgrpId]; !ok {
  362. systemGuestMaps[guests[i].SecgrpId] = 0
  363. }
  364. systemGuestMaps[guests[i].SecgrpId]++
  365. } else {
  366. if _, ok := normalGuestMaps[guests[i].SecgrpId]; !ok {
  367. normalGuestMaps[guests[i].SecgrpId] = 0
  368. }
  369. normalGuestMaps[guests[i].SecgrpId]++
  370. }
  371. if len(guests[i].AdminSecgrpId) > 0 {
  372. if _, ok := adminGuestMaps[guests[i].AdminSecgrpId]; !ok {
  373. adminGuestMaps[guests[i].AdminSecgrpId] = 0
  374. }
  375. adminGuestMaps[guests[i].AdminSecgrpId]++
  376. }
  377. }
  378. sq := GuestManager.Query("id").IsFalse("pending_deleted")
  379. sq = GuestManager.FilterByOwner(ctx, sq, GuestManager, userCred, ownerId, queryScope)
  380. guestSecgroups := []SGuestsecgroup{}
  381. q = GuestsecgroupManager.Query().In("secgroup_id", secgroupIds).In("guest_id", sq.SubQuery())
  382. err = db.FetchModelObjects(GuestsecgroupManager, q, &guestSecgroups)
  383. if err != nil {
  384. log.Errorf("db.FetchModelObjects error: %v", err)
  385. return rows
  386. }
  387. for i := range guestSecgroups {
  388. if _, ok := normalGuestMaps[guestSecgroups[i].SecgroupId]; !ok {
  389. normalGuestMaps[guestSecgroups[i].SecgroupId] = 0
  390. }
  391. normalGuestMaps[guestSecgroups[i].SecgroupId]++
  392. }
  393. rules := []SSecurityGroupRule{}
  394. q = SecurityGroupRuleManager.Query().In("secgroup_id", secgroupIds)
  395. err = db.FetchModelObjects(SecurityGroupRuleManager, q, &rules)
  396. if err != nil {
  397. log.Errorf("db.FetchModelObjects error: %v", err)
  398. return rows
  399. }
  400. gnq := GuestnetworksecgroupManager.Query()
  401. gq := GuestManager.Query().IsFalse("pending_deleted").SubQuery()
  402. gnq = gnq.Join(gq, sqlchemy.Equals(gnq.Field("guest_id"), gq.Field("id")))
  403. guestNetworkSecgroups := []SGuestnetworksecgroup{}
  404. err = db.FetchModelObjects(GuestnetworksecgroupManager, gnq, &guestNetworkSecgroups)
  405. if err != nil {
  406. log.Errorf("db.FetchModelObjects error: %v", err)
  407. return rows
  408. }
  409. for i := range guestNetworkSecgroups {
  410. if _, ok := guestNetworkMaps[guestNetworkSecgroups[i].SecgroupId]; !ok {
  411. guestNetworkMaps[guestNetworkSecgroups[i].SecgroupId] = 0
  412. }
  413. guestNetworkMaps[guestNetworkSecgroups[i].SecgroupId]++
  414. }
  415. totalCnt, err := manager.TotalCnt(secgroupIds)
  416. if err != nil {
  417. return rows
  418. }
  419. for i := range rows {
  420. rows[i].GuestCnt, _ = normalGuestMaps[secgroupIds[i]]
  421. rows[i].AdminGuestCnt, _ = adminGuestMaps[secgroupIds[i]]
  422. rows[i].SystemGuestCnt, _ = systemGuestMaps[secgroupIds[i]]
  423. rows[i].GuestNicCnt, _ = guestNetworkMaps[secgroupIds[i]]
  424. if cnt, ok := totalCnt[secgroupIds[i]]; ok {
  425. rows[i].TotalCnt = cnt.TotalCnt
  426. rows[i].LoadbalancerCnt = cnt.LoadbalancerCnt
  427. rows[i].RedisCnt = cnt.RedisCnt
  428. rows[i].RdsCnt = cnt.RdsCnt
  429. }
  430. }
  431. return rows
  432. }
  433. func (manager *SSecurityGroupManager) ValidateCreateData(
  434. ctx context.Context,
  435. userCred mcclient.TokenCredential,
  436. ownerId mcclient.IIdentityProvider,
  437. query jsonutils.JSONObject,
  438. input *api.SSecgroupCreateInput,
  439. ) (*api.SSecgroupCreateInput, error) {
  440. if len(input.VpcId) == 0 {
  441. input.VpcId = api.DEFAULT_VPC_ID
  442. }
  443. vpcObj, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcId)
  444. if err != nil {
  445. return nil, err
  446. }
  447. vpc := vpcObj.(*SVpc)
  448. input.CloudproviderId = vpc.ManagerId
  449. input.CloudregionId = vpc.CloudregionId
  450. input.GlobalvpcId = vpc.GlobalvpcId
  451. region, err := vpc.GetRegion()
  452. if err != nil {
  453. return nil, err
  454. }
  455. driver := region.GetDriver()
  456. input, err = driver.ValidateCreateSecurityGroupInput(ctx, userCred, input)
  457. if err != nil {
  458. return nil, err
  459. }
  460. input.SharableVirtualResourceCreateInput, err = manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
  461. if err != nil {
  462. return input, err
  463. }
  464. pendingUsage := SProjectQuota{Secgroup: 1}
  465. quotaKey := quotas.OwnerIdProjectQuotaKeys(rbacscope.ScopeProject, ownerId)
  466. pendingUsage.SetKeys(quotaKey)
  467. err = quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage)
  468. if err != nil {
  469. return input, httperrors.NewOutOfQuotaError("%s", err)
  470. }
  471. return input, nil
  472. }
  473. func (self *SSecurityGroup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  474. self.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  475. quota := &SProjectQuota{Secgroup: 1}
  476. quota.SetKeys(self.GetQuotaKeys())
  477. err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
  478. if err != nil {
  479. log.Errorf("Secgroup CancelPendingUsage fail %s", err)
  480. }
  481. input := &api.SSecgroupCreateInput{}
  482. data.Unmarshal(input)
  483. self.StartSecurityGroupCreateTask(ctx, userCred, input.Rules, "")
  484. }
  485. func (self *SSecurityGroup) StartSecurityGroupCreateTask(ctx context.Context, userCred mcclient.TokenCredential, rules []api.SSecgroupRuleCreateInput, parentTaskId string) error {
  486. params := jsonutils.NewDict()
  487. params.Set("rules", jsonutils.Marshal(rules))
  488. self.SetStatus(ctx, userCred, apis.STATUS_CREATING, "")
  489. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupCreateTask", self, userCred, params, parentTaskId, "", nil)
  490. if err != nil {
  491. return errors.Wrapf(err, "NewTask")
  492. }
  493. return task.ScheduleRun(nil)
  494. }
  495. func (manager *SSecurityGroupManager) FetchSecgroupById(secId string) (*SSecurityGroup, error) {
  496. secgrp, err := manager.FetchById(secId)
  497. if err != nil {
  498. return nil, errors.Wrapf(err, "FetchById(%s)", secId)
  499. }
  500. return secgrp.(*SSecurityGroup), nil
  501. }
  502. func (self *SSecurityGroup) GetSecurityRules() ([]SSecurityGroupRule, error) {
  503. q := SecurityGroupRuleManager.Query().Equals("secgroup_id", self.Id).Desc("priority")
  504. rules := []SSecurityGroupRule{}
  505. err := db.FetchModelObjects(SecurityGroupRuleManager, q, &rules)
  506. if err != nil {
  507. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  508. }
  509. return rules, nil
  510. }
  511. func (self *SSecurityGroup) getSecurityRuleString() (string, error) {
  512. secgrouprules, err := self.GetSecurityRules()
  513. if err != nil {
  514. return "", errors.Wrapf(err, "getSecurityRules()")
  515. }
  516. var rules []string
  517. for _, rule := range secgrouprules {
  518. rules = append(rules, rule.String())
  519. }
  520. return strings.Join(rules, SECURITY_GROUP_SEPARATOR), nil
  521. }
  522. func totalSecurityGroupCount(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider) (int, error) {
  523. q := SecurityGroupManager.Query()
  524. switch scope {
  525. case rbacscope.ScopeSystem:
  526. // do nothing
  527. case rbacscope.ScopeDomain:
  528. q = q.Equals("domain_id", ownerId.GetProjectDomainId())
  529. case rbacscope.ScopeProject:
  530. q = q.Equals("tenant_id", ownerId.GetProjectId())
  531. }
  532. return q.CountWithError()
  533. }
  534. func (self *SSecurityGroup) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.SecurityGroupSyncstatusInput) (jsonutils.JSONObject, error) {
  535. if !self.IsManaged() {
  536. return nil, self.SetStatus(ctx, userCred, api.SECGROUP_STATUS_READY, "")
  537. }
  538. return nil, self.StartSecurityGroupSyncTask(ctx, userCred, "")
  539. }
  540. func (self *SSecurityGroup) StartSecurityGroupSyncTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  541. params := jsonutils.NewDict()
  542. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  543. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupSyncTask", self, userCred, params, parentTaskId, "", nil)
  544. if err != nil {
  545. return errors.Wrapf(err, "NewTask")
  546. }
  547. return task.ScheduleRun(nil)
  548. }
  549. func (self *SSecurityGroup) StartSecurityGroupRuleCreateTask(ctx context.Context, userCred mcclient.TokenCredential, ruleId, parentTaskId string) error {
  550. params := jsonutils.NewDict()
  551. params.Set("rule_id", jsonutils.NewString(ruleId))
  552. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupRuleCreateTask", self, userCred, params, parentTaskId, "", nil)
  553. if err != nil {
  554. return errors.Wrapf(err, "NewTask")
  555. }
  556. return task.ScheduleRun(nil)
  557. }
  558. func (self *SSecurityGroup) StartSecurityGroupRuleDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, ruleId, parentTaskId string) error {
  559. params := jsonutils.NewDict()
  560. params.Set("rule_id", jsonutils.NewString(ruleId))
  561. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupRuleDeleteTask", self, userCred, params, parentTaskId, "", nil)
  562. if err != nil {
  563. return errors.Wrapf(err, "NewTask")
  564. }
  565. return task.ScheduleRun(nil)
  566. }
  567. func (self *SSecurityGroup) PerformAddRule(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  568. secgrouprule := &SSecurityGroupRule{}
  569. secgrouprule.SecgroupId = self.Id
  570. secgrouprule.SetModelManager(SecurityGroupRuleManager, secgrouprule)
  571. if err := data.Unmarshal(secgrouprule); err != nil {
  572. return nil, err
  573. }
  574. if len(secgrouprule.CIDR) > 0 {
  575. if !regutils.MatchCIDR(secgrouprule.CIDR) && !regutils.MatchIPAddr(secgrouprule.CIDR) {
  576. return nil, httperrors.NewInputParameterError("invalid ip address: %s", secgrouprule.CIDR)
  577. }
  578. } else {
  579. secgrouprule.CIDR = "0.0.0.0/0"
  580. }
  581. rule := secrules.SecurityRule{
  582. Priority: int(secgrouprule.Priority),
  583. Direction: secrules.TSecurityRuleDirection(secgrouprule.Direction),
  584. Action: secrules.TSecurityRuleAction(secgrouprule.Action),
  585. Protocol: secgrouprule.Protocol,
  586. Ports: []int{},
  587. PortStart: -1,
  588. PortEnd: -1,
  589. }
  590. if err := rule.ParsePorts(secgrouprule.Ports); err != nil {
  591. return nil, httperrors.NewInputParameterError("%v", err)
  592. }
  593. if err := rule.ValidateRule(); err != nil {
  594. return nil, httperrors.NewInputParameterError("%v", err)
  595. }
  596. if err := SecurityGroupRuleManager.TableSpec().Insert(ctx, secgrouprule); err != nil {
  597. return nil, httperrors.NewInputParameterError("%v", err)
  598. }
  599. self.DoSync(ctx, userCred)
  600. return nil, nil
  601. }
  602. func (self *SSecurityGroup) PerformClone(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SecurityGroupCloneInput) (api.SecurityGroupCloneInput, error) {
  603. if len(input.Name) == 0 {
  604. return input, httperrors.NewMissingParameterError("name")
  605. }
  606. ownerId := &db.SOwnerId{
  607. DomainId: userCred.GetProjectDomainId(),
  608. ProjectId: userCred.GetProjectId(),
  609. }
  610. pendingUsage := SProjectQuota{Secgroup: 1}
  611. quotaKey := quotas.OwnerIdProjectQuotaKeys(rbacscope.ScopeProject, ownerId)
  612. pendingUsage.SetKeys(quotaKey)
  613. err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage)
  614. if err != nil {
  615. return input, httperrors.NewOutOfQuotaError("%s", err)
  616. }
  617. secgroup := &SSecurityGroup{}
  618. secgroup.SetModelManager(SecurityGroupManager, secgroup)
  619. secgroup.Name = input.Name
  620. secgroup.Description = input.Description
  621. secgroup.Status = api.SECGROUP_STATUS_READY
  622. secgroup.ProjectId = userCred.GetProjectId()
  623. secgroup.DomainId = userCred.GetProjectDomainId()
  624. err = func() error {
  625. lockman.LockClass(ctx, SecurityGroupManager, "name")
  626. defer lockman.ReleaseClass(ctx, SecurityGroupManager, "name")
  627. input.Name, err = db.GenerateName(ctx, SecurityGroupManager, ownerId, input.Name)
  628. if err != nil {
  629. return err
  630. }
  631. return SecurityGroupManager.TableSpec().Insert(ctx, secgroup)
  632. }()
  633. if err != nil {
  634. return input, httperrors.NewGeneralError(errors.Wrapf(err, "Insert"))
  635. }
  636. secgrouprules, err := self.GetSecurityRules()
  637. if err != nil {
  638. return input, httperrors.NewGeneralError(errors.Wrapf(err, "getSecurityRules"))
  639. }
  640. for _, rule := range secgrouprules {
  641. secgrouprule := &SSecurityGroupRule{}
  642. secgrouprule.SetModelManager(SecurityGroupRuleManager, secgrouprule)
  643. secgrouprule.Priority = rule.Priority
  644. secgrouprule.Protocol = rule.Protocol
  645. secgrouprule.Ports = rule.Ports
  646. secgrouprule.Direction = rule.Direction
  647. secgrouprule.CIDR = rule.CIDR
  648. secgrouprule.Action = rule.Action
  649. secgrouprule.Description = rule.Description
  650. secgrouprule.SecgroupId = secgroup.Id
  651. if err := SecurityGroupRuleManager.TableSpec().Insert(ctx, secgrouprule); err != nil {
  652. return input, err
  653. }
  654. }
  655. quota := &SProjectQuota{Secgroup: 1}
  656. quota.SetKeys(secgroup.GetQuotaKeys())
  657. err = quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
  658. if err != nil {
  659. log.Errorf("Secgroup CancelPendingUsage fail %s", err)
  660. }
  661. logclient.AddActionLogWithContext(ctx, secgroup, logclient.ACT_CREATE, secgroup.GetShortDesc(ctx), userCred, true)
  662. return input, nil
  663. }
  664. /*func (self *SSecurityGroup) GetAllowList() (secrules.SecurityRuleSet, secrules.SecurityRuleSet, error) {
  665. in := secrules.SecurityRuleSet{}
  666. out := secrules.SecurityRuleSet{}
  667. rules, err := self.GetSecurityRules()
  668. if err != nil {
  669. return in, out, errors.Wrapf(err, "GetSecRules")
  670. }
  671. for i := range rules {
  672. r, _ := rules[i].toRule()
  673. if rules[i].Direction == secrules.DIR_IN {
  674. in = append(in, *r)
  675. } else {
  676. out = append(out, *r)
  677. }
  678. }
  679. in = append(in, *secrules.MustParseSecurityRule("in:deny any"))
  680. out = append(out, *secrules.MustParseSecurityRule("out:allow any"))
  681. return in.AllowList(), out.AllowList(), nil
  682. }*/
  683. func (self *SSecurityGroup) clearRules() error {
  684. _, err := sqlchemy.GetDB().Exec(
  685. fmt.Sprintf(
  686. "delete from %s where secgroup_id = ?",
  687. SecurityGroupRuleManager.TableSpec().Name(),
  688. ), self.Id,
  689. )
  690. return err
  691. }
  692. func (manager *SSecurityGroupManager) DelaySync(ctx context.Context, userCred mcclient.TokenCredential, idStr string) error {
  693. secgrp, err := manager.FetchSecgroupById(idStr)
  694. if err != nil {
  695. return errors.Wrapf(err, "FetchSecgroupById(%s)", idStr)
  696. }
  697. needSync := false
  698. func() {
  699. lockman.LockObject(ctx, secgrp)
  700. defer lockman.ReleaseObject(ctx, secgrp)
  701. if secgrp.IsDirty {
  702. if _, err := db.Update(secgrp, func() error {
  703. secgrp.IsDirty = false
  704. return nil
  705. }); err != nil {
  706. log.Errorf("Update Security Group error: %s", err.Error())
  707. }
  708. needSync = true
  709. }
  710. }()
  711. if needSync {
  712. guests, err := secgrp.GetKvmGuests()
  713. if err != nil {
  714. return errors.Wrapf(err, "GetKvmGuests")
  715. }
  716. for _, guest := range guests {
  717. guest.StartSyncTask(ctx, userCred, true, "")
  718. }
  719. }
  720. return nil
  721. }
  722. func (self *SSecurityGroup) DoSync(ctx context.Context, userCred mcclient.TokenCredential) {
  723. if _, err := db.Update(self, func() error {
  724. self.IsDirty = true
  725. return nil
  726. }); err != nil {
  727. log.Errorf("Update Security Group error: %s", err.Error())
  728. }
  729. time.AfterFunc(10*time.Second, func() {
  730. SecurityGroupManager.DelaySync(context.Background(), userCred, self.Id)
  731. })
  732. }
  733. func (manager *SSecurityGroupManager) InitializeData() error {
  734. _, err := manager.FetchById(api.SECGROUP_DEFAULT_ID)
  735. if err != nil && err != sql.ErrNoRows {
  736. return errors.Wrapf(err, `manager.FetchById("default")`)
  737. }
  738. if errors.Cause(err) == sql.ErrNoRows {
  739. log.Debugf("Init default secgroup")
  740. secGrp := &SSecurityGroup{}
  741. secGrp.SetModelManager(manager, secGrp)
  742. secGrp.Id = api.SECGROUP_DEFAULT_ID
  743. secGrp.Name = "Default"
  744. secGrp.Status = api.SECGROUP_STATUS_READY
  745. secGrp.ProjectId = auth.AdminCredential().GetProjectId()
  746. secGrp.DomainId = auth.AdminCredential().GetProjectDomainId()
  747. // secGrp.IsEmulated = false
  748. secGrp.IsPublic = true
  749. secGrp.Deleted = false
  750. secGrp.PublicScope = string(rbacscope.ScopeSystem)
  751. err = manager.TableSpec().InsertOrUpdate(context.TODO(), secGrp)
  752. if err != nil {
  753. return errors.Wrapf(err, "Insert default secgroup")
  754. }
  755. defRule := SSecurityGroupRule{}
  756. defRule.SetModelManager(SecurityGroupRuleManager, &defRule)
  757. defRule.Direction = secrules.DIR_IN
  758. defRule.Protocol = secrules.PROTO_ANY
  759. defRule.Priority = 1
  760. // empty CIDR means ::/0 or 0.0.0.0/0
  761. defRule.CIDR = "" // "0.0.0.0/0"
  762. defRule.Action = string(secrules.SecurityRuleAllow)
  763. defRule.SecgroupId = api.SECGROUP_DEFAULT_ID
  764. err = SecurityGroupRuleManager.TableSpec().Insert(context.TODO(), &defRule)
  765. if err != nil {
  766. return errors.Wrapf(err, "Insert default secgroup rule")
  767. }
  768. }
  769. guests := make([]SGuest, 0)
  770. q := GuestManager.Query().Equals("hypervisor", api.HYPERVISOR_KVM).IsNotEmpty("external_id").IsNullOrEmpty("secgrp_id")
  771. err = db.FetchModelObjects(GuestManager, q, &guests)
  772. if err != nil {
  773. log.Errorf("fetch guests without secgroup fail %s", err)
  774. return err
  775. }
  776. for i := 0; i < len(guests); i += 1 {
  777. db.Update(&guests[i], func() error {
  778. guests[i].SecgrpId = api.SECGROUP_DEFAULT_ID
  779. return nil
  780. })
  781. }
  782. return nil
  783. }
  784. func (manager *SSecurityGroupManager) PerformClean(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  785. q := SecurityGroupManager.Query()
  786. q = q.Filter(
  787. sqlchemy.AND(
  788. sqlchemy.Equals(q.Field("cloudregion_id"), api.DEFAULT_REGION_ID),
  789. sqlchemy.NotEquals(q.Field("id"), api.SECGROUP_DEFAULT_ID),
  790. sqlchemy.NotIn(q.Field("id"), GuestManager.Query("secgrp_id").IsNotNull("secgrp_id").SubQuery()),
  791. sqlchemy.NotIn(q.Field("id"), GuestManager.Query("admin_secgrp_id").IsNotNull("admin_secgrp_id").SubQuery()),
  792. sqlchemy.NotIn(q.Field("id"), GuestsecgroupManager.Query("secgroup_id").IsNotNull("secgroup_id").SubQuery()),
  793. sqlchemy.NotIn(q.Field("id"), GuestsecgroupManager.Query("secgroup_id").IsNotNull("secgroup_id").SubQuery()),
  794. sqlchemy.NotIn(q.Field("id"), DBInstanceSecgroupManager.Query("secgroup_id").IsNotNull("secgroup_id").SubQuery()),
  795. sqlchemy.NotIn(q.Field("id"), ElasticcachesecgroupManager.Query("secgroup_id").IsNotNull("secgroup_id").SubQuery()),
  796. sqlchemy.NotIn(q.Field("id"), LoadbalancerSecurityGroupManager.Query("secgroup_id").IsNotNull("secgroup_id").SubQuery()),
  797. ),
  798. )
  799. secgroups := []SSecurityGroup{}
  800. err := db.FetchModelObjects(SecurityGroupManager, q, &secgroups)
  801. if err != nil {
  802. return nil, errors.Wrapf(err, "FetchModelObjects")
  803. }
  804. for i := range secgroups {
  805. err = secgroups[i].RealDelete(ctx, userCred)
  806. if err != nil {
  807. return nil, errors.Wrapf(err, "delete %s", secgroups[i].Name)
  808. }
  809. }
  810. return nil, nil
  811. }
  812. func (self *SSecurityGroup) GetRegionDriver() (IRegionDriver, error) {
  813. if len(self.ManagerId) > 0 {
  814. manager, err := self.GetCloudprovider()
  815. if err != nil {
  816. return nil, errors.Wrapf(err, "GetCloudprovider")
  817. }
  818. return GetRegionDriver(manager.Provider), nil
  819. }
  820. return GetRegionDriver(api.CLOUD_PROVIDER_ONECLOUD), nil
  821. }
  822. func (self *SSecurityGroup) GetRegion() (*SCloudregion, error) {
  823. regionObj, err := CloudregionManager.FetchById(self.CloudregionId)
  824. if err != nil {
  825. return nil, errors.Wrapf(err, "FetchById")
  826. }
  827. return regionObj.(*SCloudregion), nil
  828. }
  829. func (self *SSecurityGroup) GetGlobalVpc() (*SGlobalVpc, error) {
  830. vpc, err := GlobalVpcManager.FetchById(self.GlobalvpcId)
  831. if err != nil {
  832. return nil, err
  833. }
  834. return vpc.(*SGlobalVpc), nil
  835. }
  836. func (self *SSecurityGroup) GetISecurityGroup(ctx context.Context) (cloudprovider.ICloudSecurityGroup, error) {
  837. if len(self.ExternalId) == 0 {
  838. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  839. }
  840. // google
  841. if len(self.GlobalvpcId) > 0 {
  842. vpc, err := self.GetGlobalVpc()
  843. if err != nil {
  844. return nil, errors.Wrapf(err, "GetGlobalVpc")
  845. }
  846. iVpc, err := vpc.GetICloudGlobalVpc(ctx)
  847. if err != nil {
  848. return nil, errors.Wrapf(err, "GetICloudGlobalVpc")
  849. }
  850. securityGroups, err := iVpc.GetISecurityGroups()
  851. if err != nil {
  852. return nil, errors.Wrapf(err, "GetISecurityGroups")
  853. }
  854. for i := range securityGroups {
  855. if securityGroups[i].GetGlobalId() == self.ExternalId {
  856. return securityGroups[i], nil
  857. }
  858. }
  859. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%v", self.ExternalId)
  860. }
  861. iRegion, err := self.GetIRegion(ctx)
  862. if err != nil {
  863. return nil, errors.Wrapf(err, "GetIRegion")
  864. }
  865. return iRegion.GetISecurityGroupById(self.ExternalId)
  866. }
  867. func (self *SSecurityGroup) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  868. region, err := self.GetRegion()
  869. if err != nil {
  870. return nil, errors.Wrapf(err, "GetRegion")
  871. }
  872. provider, err := self.GetProvider(ctx)
  873. if err != nil {
  874. return nil, errors.Wrapf(err, "GetProvider")
  875. }
  876. return provider.GetIRegionById(region.ExternalId)
  877. }
  878. func (self *SSecurityGroup) GetCloudprovider() (*SCloudprovider, error) {
  879. providerObj, err := CloudproviderManager.FetchById(self.ManagerId)
  880. if err != nil {
  881. return nil, errors.Wrapf(err, "FetchById")
  882. }
  883. return providerObj.(*SCloudprovider), nil
  884. }
  885. func (self *SSecurityGroup) GetProvider(ctx context.Context) (cloudprovider.ICloudProvider, error) {
  886. manager, err := self.GetCloudprovider()
  887. if err != nil {
  888. return nil, errors.Wrapf(err, "GetProvider")
  889. }
  890. return manager.GetProvider(ctx)
  891. }
  892. func (sm *SSecurityGroupManager) query(manager db.IModelManager, field, label string, secIds []string) *sqlchemy.SSubQuery {
  893. sq := manager.Query().SubQuery()
  894. return sq.Query(
  895. sq.Field(field),
  896. sqlchemy.COUNT(label),
  897. ).In(field, secIds).GroupBy(sq.Field(field)).SubQuery()
  898. }
  899. type sSecuriyGroupCnts struct {
  900. Id string
  901. Guest1Cnt int
  902. api.SSecurityGroupRef
  903. }
  904. func (sm *SSecurityGroupManager) TotalCnt(secIds []string) (map[string]api.SSecurityGroupRef, error) {
  905. g1SQ := sm.query(GuestsecgroupManager, "secgroup_id", "guest1", secIds)
  906. g2SQ := sm.query(GuestManager, "secgrp_id", "guest2", secIds)
  907. g3SQ := sm.query(GuestManager, "admin_secgrp_id", "guest3", secIds)
  908. g4SQ := sm.query(GuestnetworksecgroupManager, "secgroup_id", "guest4", secIds)
  909. rdsSQ := sm.query(DBInstanceSecgroupManager, "secgroup_id", "rds", secIds)
  910. redisSQ := sm.query(ElasticcachesecgroupManager, "secgroup_id", "redis", secIds)
  911. lbSQ := sm.query(LoadbalancerSecurityGroupManager, "secgroup_id", "loadbalancer", secIds)
  912. secs := sm.Query().SubQuery()
  913. secQ := secs.Query(
  914. sqlchemy.SUM("guest_cnt", g1SQ.Field("guest1")),
  915. sqlchemy.SUM("guest1_cnt", g2SQ.Field("guest2")),
  916. sqlchemy.SUM("admin_guest_cnt", g3SQ.Field("guest3")),
  917. sqlchemy.SUM("rds_cnt", rdsSQ.Field("rds")),
  918. sqlchemy.SUM("redis_cnt", redisSQ.Field("redis")),
  919. sqlchemy.SUM("loadbalancer_cnt", lbSQ.Field("loadbalancer")),
  920. sqlchemy.SUM("guest_nic_cnt", g4SQ.Field("guest4")),
  921. )
  922. secQ.AppendField(secQ.Field("id"))
  923. secQ = secQ.LeftJoin(g1SQ, sqlchemy.Equals(secQ.Field("id"), g1SQ.Field("secgroup_id")))
  924. secQ = secQ.LeftJoin(g2SQ, sqlchemy.Equals(secQ.Field("id"), g2SQ.Field("secgrp_id")))
  925. secQ = secQ.LeftJoin(g3SQ, sqlchemy.Equals(secQ.Field("id"), g3SQ.Field("admin_secgrp_id")))
  926. secQ = secQ.LeftJoin(rdsSQ, sqlchemy.Equals(secQ.Field("id"), rdsSQ.Field("secgroup_id")))
  927. secQ = secQ.LeftJoin(redisSQ, sqlchemy.Equals(secQ.Field("id"), redisSQ.Field("secgroup_id")))
  928. secQ = secQ.LeftJoin(lbSQ, sqlchemy.Equals(secQ.Field("id"), lbSQ.Field("secgroup_id")))
  929. secQ = secQ.LeftJoin(g4SQ, sqlchemy.Equals(secQ.Field("id"), g4SQ.Field("secgroup_id")))
  930. secQ = secQ.Filter(sqlchemy.In(secQ.Field("id"), secIds)).GroupBy(secQ.Field("id"))
  931. cnts := []sSecuriyGroupCnts{}
  932. err := secQ.All(&cnts)
  933. if err != nil {
  934. return nil, errors.Wrapf(err, "secQ.All")
  935. }
  936. result := map[string]api.SSecurityGroupRef{}
  937. for i := range cnts {
  938. cnts[i].GuestCnt += cnts[i].Guest1Cnt
  939. cnts[i].Sum()
  940. result[cnts[i].Id] = cnts[i].SSecurityGroupRef
  941. }
  942. return result, nil
  943. }
  944. func (self *SSecurityGroup) ValidateDeleteCondition(ctx context.Context, info api.SecgroupDetails) error {
  945. if self.Id == options.Options.DefaultSecurityGroupId {
  946. return httperrors.NewProtectedResourceError("not allow to delete default security group")
  947. }
  948. if self.Id == options.Options.DefaultSecurityGroupIdForKvm {
  949. return httperrors.NewProtectedResourceError("not allow to delete default security group for kvm")
  950. }
  951. if self.Id == options.Options.DefaultSecurityGroupIdForContainer {
  952. return httperrors.NewProtectedResourceError("not allow to delete default security group for container")
  953. }
  954. if self.Id == options.Options.DefaultAdminSecurityGroupId {
  955. return httperrors.NewProtectedResourceError("not allow to delete default admin security group")
  956. }
  957. if self.Id == options.Options.DefaultAdminSecurityGroupIdForKvm {
  958. return httperrors.NewProtectedResourceError("not allow to delete default admin security group for kvm")
  959. }
  960. if self.Id == options.Options.DefaultAdminSecurityGroupIdForContainer {
  961. return httperrors.NewProtectedResourceError("not allow to delete default admin security group for container")
  962. }
  963. if info.TotalCnt > 0 {
  964. return httperrors.NewNotEmptyError("the security group %s is in use cnt: %d", self.Id, info.TotalCnt)
  965. }
  966. return self.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
  967. }
  968. func (self *SSecurityGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  969. return self.StartDeleteSecurityGroupTask(ctx, userCred, "")
  970. }
  971. func (self *SSecurityGroup) StartDeleteSecurityGroupTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  972. params := jsonutils.NewDict()
  973. self.SetStatus(ctx, userCred, apis.STATUS_DELETING, "")
  974. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupDeleteTask", self, userCred, params, parentTaskId, "", nil)
  975. if err != nil {
  976. return errors.Wrapf(err, "NewTask")
  977. }
  978. return task.ScheduleRun(nil)
  979. }
  980. func (self *SSecurityGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  981. log.Infof("do nothing for delete secgroup")
  982. return nil
  983. }
  984. func (self *SSecurityGroup) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  985. if len(self.ExternalId) == 0 || options.Options.KeepTagLocalization {
  986. return
  987. }
  988. if account := self.GetCloudaccount(); account != nil && account.ReadOnly {
  989. return
  990. }
  991. err := self.StartRemoteUpdateTask(ctx, userCred, true, "")
  992. if err != nil {
  993. log.Errorf("StartRemoteUpdateTask fail: %s", err)
  994. }
  995. }
  996. func (self *SSecurityGroup) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
  997. data := jsonutils.NewDict()
  998. data.Set("replace_tags", jsonutils.NewBool(replaceTags))
  999. task, err := taskman.TaskManager.NewTask(ctx, "SecurityGroupRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil)
  1000. if err != nil {
  1001. return errors.Wrap(err, "RemoteUpdateTask")
  1002. }
  1003. self.SetStatus(ctx, userCred, apis.STATUS_UPDATE_TAGS, "StartRemoteUpdateTask")
  1004. return task.ScheduleRun(nil)
  1005. }
  1006. func (self *SSecurityGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1007. rules := []SSecurityGroupRule{}
  1008. q := SecurityGroupRuleManager.Query().Equals("secgroup_id", self.Id)
  1009. err := db.FetchModelObjects(SecurityGroupRuleManager, q, &rules)
  1010. if err != nil {
  1011. return errors.Wrap(err, "db.FetchModelObjects")
  1012. }
  1013. for i := 0; i < len(rules); i++ {
  1014. lockman.LockObject(ctx, &rules[i])
  1015. defer lockman.ReleaseObject(ctx, &rules[i])
  1016. err := rules[i].RealDelete(ctx, userCred)
  1017. if err != nil {
  1018. return errors.Wrap(err, "rules[i].Delete")
  1019. }
  1020. }
  1021. return self.SVirtualResourceBase.Delete(ctx, userCred)
  1022. }
  1023. func (sg *SSecurityGroup) GetQuotaKeys() quotas.IQuotaKeys {
  1024. return quotas.OwnerIdProjectQuotaKeys(rbacscope.ScopeProject, sg.GetOwnerId())
  1025. }
  1026. func (sg *SSecurityGroup) GetUsages() []db.IUsage {
  1027. if sg.PendingDeleted || sg.Deleted {
  1028. return nil
  1029. }
  1030. usage := SProjectQuota{Secgroup: 1}
  1031. keys := sg.GetQuotaKeys()
  1032. usage.SetKeys(keys)
  1033. return []db.IUsage{
  1034. &usage,
  1035. }
  1036. }
  1037. func (self *SSecurityGroup) PerformImportRules(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SecgroupImportRulesInput) (jsonutils.JSONObject, error) {
  1038. for i := range input.Rules {
  1039. if input.Rules[i].Priority == nil {
  1040. return nil, httperrors.NewMissingParameterError("priority")
  1041. }
  1042. err := input.Rules[i].Check()
  1043. if err != nil {
  1044. return nil, httperrors.NewInputParameterError("rule %d is invalid: %s", i+1, err)
  1045. }
  1046. }
  1047. for _, r := range input.Rules {
  1048. rule := &SSecurityGroupRule{
  1049. Priority: int(*r.Priority),
  1050. Protocol: r.Protocol,
  1051. Ports: r.Ports,
  1052. Direction: r.Direction,
  1053. CIDR: r.CIDR,
  1054. Action: r.Action,
  1055. Description: r.Description,
  1056. }
  1057. rule.SecgroupId = self.Id
  1058. err := SecurityGroupRuleManager.TableSpec().Insert(ctx, rule)
  1059. if err != nil {
  1060. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "Insert rule"))
  1061. }
  1062. }
  1063. return nil, nil
  1064. }
  1065. func (manager *SSecurityGroupManager) ListItemExportKeys(ctx context.Context,
  1066. q *sqlchemy.SQuery,
  1067. userCred mcclient.TokenCredential,
  1068. keys stringutils2.SSortedStrings,
  1069. ) (*sqlchemy.SQuery, error) {
  1070. q, err := manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1071. if err != nil {
  1072. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys")
  1073. }
  1074. if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
  1075. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1076. if err != nil {
  1077. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  1078. }
  1079. }
  1080. if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
  1081. q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1082. if err != nil {
  1083. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
  1084. }
  1085. }
  1086. if keys.ContainsAny(manager.SGlobalVpcResourceBaseManager.GetExportKeys()...) {
  1087. q, err = manager.SGlobalVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1088. if err != nil {
  1089. return nil, errors.Wrap(err, "SGlobalVpcResourceBaseManager.ListItemExportKeys")
  1090. }
  1091. }
  1092. if keys.ContainsAny(manager.SVpcResourceBaseManager.GetExportKeys()...) {
  1093. q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1094. if err != nil {
  1095. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys")
  1096. }
  1097. }
  1098. return q, nil
  1099. }
  1100. func (self *SCloudregion) GetSecgroups(managerId, vpcId string) ([]SSecurityGroup, error) {
  1101. q := SecurityGroupManager.Query().Equals("cloudregion_id", self.Id).Equals("manager_id", managerId)
  1102. if len(vpcId) > 0 {
  1103. q = q.Equals("vpc_id", vpcId)
  1104. }
  1105. ret := []SSecurityGroup{}
  1106. return ret, db.FetchModelObjects(SecurityGroupManager, q, &ret)
  1107. }
  1108. func (self *SCloudregion) SyncSecgroups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, vpc *SVpc, exts []cloudprovider.ICloudSecurityGroup, xor bool) compare.SyncResult {
  1109. vpcId := ""
  1110. if !gotypes.IsNil(vpc) {
  1111. vpcId = vpc.Id
  1112. }
  1113. key := fmt.Sprintf("%s-%s", self.Id, vpcId)
  1114. lockman.LockRawObject(ctx, SecurityGroupManager.Keyword(), key)
  1115. defer lockman.ReleaseRawObject(ctx, SecurityGroupManager.Keyword(), key)
  1116. result := compare.SyncResult{}
  1117. dbSecs, err := self.GetSecgroups(provider.Id, vpcId)
  1118. if err != nil {
  1119. result.Error(err)
  1120. return result
  1121. }
  1122. syncOwnerId := provider.GetOwnerId()
  1123. removed := make([]SSecurityGroup, 0)
  1124. commondb := make([]SSecurityGroup, 0)
  1125. commonext := make([]cloudprovider.ICloudSecurityGroup, 0)
  1126. added := make([]cloudprovider.ICloudSecurityGroup, 0)
  1127. err = compare.CompareSets(dbSecs, exts, &removed, &commondb, &commonext, &added)
  1128. if err != nil {
  1129. result.Error(err)
  1130. return result
  1131. }
  1132. for i := 0; i < len(removed); i += 1 {
  1133. err = removed[i].RealDelete(ctx, userCred)
  1134. if err != nil {
  1135. result.DeleteError(err)
  1136. continue
  1137. }
  1138. result.Delete()
  1139. }
  1140. for i := 0; i < len(commondb); i += 1 {
  1141. if !xor {
  1142. err = commondb[i].SyncWithCloudSecurityGroup(ctx, userCred, commonext[i], syncOwnerId, true)
  1143. if err != nil {
  1144. result.UpdateError(err)
  1145. continue
  1146. }
  1147. }
  1148. result.Update()
  1149. }
  1150. for i := 0; i < len(added); i += 1 {
  1151. err := self.newFromCloudSecurityGroup(ctx, userCred, provider, vpc, added[i], syncOwnerId)
  1152. if err != nil {
  1153. result.AddError(err)
  1154. continue
  1155. }
  1156. result.Add()
  1157. }
  1158. return result
  1159. }
  1160. func (self *SSecurityGroup) SyncWithCloudSecurityGroup(
  1161. ctx context.Context,
  1162. userCred mcclient.TokenCredential,
  1163. ext cloudprovider.ICloudSecurityGroup,
  1164. syncOwnerId mcclient.IIdentityProvider,
  1165. syncRule bool,
  1166. ) error {
  1167. _, err := db.Update(self, func() error {
  1168. self.Name = ext.GetName()
  1169. if len(self.Description) == 0 {
  1170. self.Description = ext.GetDescription()
  1171. }
  1172. return nil
  1173. })
  1174. if err != nil {
  1175. return errors.Wrapf(err, "db.Update")
  1176. }
  1177. if account := self.GetCloudaccount(); account != nil {
  1178. syncVirtualResourceMetadata(ctx, userCred, self, ext, account.ReadOnly)
  1179. }
  1180. if provider, _ := self.GetCloudprovider(); provider != nil {
  1181. SyncCloudProject(ctx, userCred, self, syncOwnerId, ext, provider)
  1182. }
  1183. if !syncRule {
  1184. return nil
  1185. }
  1186. rules, err := ext.GetRules()
  1187. if err != nil {
  1188. return errors.Wrapf(err, "GetRules")
  1189. }
  1190. result := self.SyncRules(ctx, userCred, rules)
  1191. if result.IsError() {
  1192. logclient.AddSimpleActionLog(self, logclient.ACT_CLOUD_SYNC, result, userCred, false)
  1193. }
  1194. return nil
  1195. }
  1196. func (self *SSecurityGroup) GetSecurityGroups(
  1197. ctx context.Context,
  1198. userCred mcclient.TokenCredential,
  1199. ownerId mcclient.IIdentityProvider,
  1200. filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery,
  1201. ) ([]SSecurityGroup, error) {
  1202. query := SecurityGroupManager.Query().Equals("status", api.SECGROUP_STATUS_READY).IsNotEmpty("external_id")
  1203. query = filter(query)
  1204. query = query.Filter(
  1205. sqlchemy.OR(
  1206. sqlchemy.AND(
  1207. sqlchemy.Equals(query.Field("public_scope"), "system"),
  1208. sqlchemy.Equals(query.Field("is_public"), true),
  1209. ),
  1210. sqlchemy.AND(
  1211. sqlchemy.Equals(query.Field("tenant_id"), ownerId.GetProjectId()),
  1212. sqlchemy.Equals(query.Field("domain_id"), ownerId.GetDomainId()),
  1213. ),
  1214. ),
  1215. )
  1216. ret := []SSecurityGroup{}
  1217. return ret, db.FetchModelObjects(SecurityGroupManager, query, &ret)
  1218. }
  1219. func (self *SCloudregion) newFromCloudSecurityGroup(
  1220. ctx context.Context,
  1221. userCred mcclient.TokenCredential,
  1222. provider *SCloudprovider,
  1223. vpc *SVpc,
  1224. ext cloudprovider.ICloudSecurityGroup,
  1225. syncOwnerId mcclient.IIdentityProvider,
  1226. ) error {
  1227. ret := &SSecurityGroup{}
  1228. ret.SetModelManager(SecurityGroupManager, ret)
  1229. ret.Name = ext.GetName()
  1230. ret.CloudregionId = self.Id
  1231. if vpc != nil {
  1232. ret.VpcId = vpc.Id
  1233. }
  1234. ret.Description = ext.GetDescription()
  1235. ret.ExternalId = ext.GetGlobalId()
  1236. ret.ManagerId = provider.Id
  1237. ret.Status = api.SECGROUP_STATUS_READY
  1238. err := SecurityGroupManager.TableSpec().Insert(ctx, ret)
  1239. if err != nil {
  1240. return errors.Wrapf(err, "Insert")
  1241. }
  1242. syncVirtualResourceMetadata(ctx, userCred, ret, ext, false)
  1243. SyncCloudProject(ctx, userCred, ret, syncOwnerId, ext, provider)
  1244. rules, err := ext.GetRules()
  1245. if err != nil {
  1246. return errors.Wrapf(err, "GetRules")
  1247. }
  1248. result := ret.SyncRules(ctx, userCred, rules)
  1249. if result.IsError() {
  1250. logclient.AddSimpleActionLog(ret, logclient.ACT_CLOUD_SYNC, result, userCred, false)
  1251. }
  1252. return nil
  1253. }