net_tap_services.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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. "sort"
  19. "strings"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/tristate"
  24. "yunion.io/x/pkg/util/netutils"
  25. "yunion.io/x/sqlchemy"
  26. "yunion.io/x/onecloud/pkg/apis"
  27. api "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  30. "yunion.io/x/onecloud/pkg/httperrors"
  31. "yunion.io/x/onecloud/pkg/mcclient"
  32. "yunion.io/x/onecloud/pkg/util/seclib2"
  33. "yunion.io/x/onecloud/pkg/util/stringutils2"
  34. )
  35. // +onecloud:swagger-gen-model-singular=tap_service
  36. // +onecloud:swagger-gen-model-plural=tap_services
  37. type SNetTapServiceManager struct {
  38. db.SEnabledStatusStandaloneResourceBaseManager
  39. }
  40. var NetTapServiceManager *SNetTapServiceManager
  41. func init() {
  42. NetTapServiceManager = &SNetTapServiceManager{
  43. SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
  44. SNetTapService{},
  45. "net_tap_services_tbl",
  46. "tap_service",
  47. "tap_services",
  48. ),
  49. }
  50. NetTapServiceManager.SetVirtualObject(NetTapServiceManager)
  51. NetTapServiceManager.TableSpec().AddIndex(false, "mac_addr", "deleted")
  52. }
  53. type SNetTapService struct {
  54. db.SEnabledStatusStandaloneResourceBase
  55. // 流量采集端类型,虚拟机(guest)还是宿主机(host)
  56. Type string `width:"10" charset:"ascii" list:"admin" create:"admin_required"`
  57. // 接受流量的目标ID,如果type=host,是hostId,如果type=guest,是guestId
  58. TargetId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
  59. // 接受流量的Mac地址
  60. MacAddr string `width:"18" charset:"ascii" list:"admin" create:"admin_optional"`
  61. // 网卡名称
  62. Ifname string `width:"16" charset:"ascii" nullable:"true" list:"admin"`
  63. }
  64. func (man *SNetTapServiceManager) ListItemFilter(
  65. ctx context.Context,
  66. q *sqlchemy.SQuery,
  67. userCred mcclient.TokenCredential,
  68. query api.NetTapServiceListInput,
  69. ) (*sqlchemy.SQuery, error) {
  70. q, err := man.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  71. if err != nil {
  72. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
  73. }
  74. if len(query.HostId) > 0 {
  75. hostObj, err := HostManager.FetchByIdOrName(ctx, userCred, query.HostId)
  76. if err != nil {
  77. if errors.Cause(err) == sql.ErrNoRows {
  78. return nil, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), query.HostId)
  79. } else {
  80. return nil, errors.Wrap(err, "HostManager.FetchHostById")
  81. }
  82. }
  83. q = man.filterByHostId(q, hostObj.GetId())
  84. }
  85. return q, nil
  86. }
  87. func (man *SNetTapServiceManager) filterByHostId(q *sqlchemy.SQuery, hostId string) *sqlchemy.SQuery {
  88. guestIdQ := GuestManager.Query("id").Equals("host_id", hostId).SubQuery()
  89. q = q.Filter(sqlchemy.OR(
  90. sqlchemy.AND(
  91. sqlchemy.Equals(q.Field("type"), api.TapServiceHost),
  92. sqlchemy.Equals(q.Field("target_id"), hostId),
  93. ),
  94. sqlchemy.AND(
  95. sqlchemy.Equals(q.Field("type"), api.TapServiceGuest),
  96. sqlchemy.In(q.Field("target_id"), guestIdQ),
  97. ),
  98. ))
  99. return q
  100. }
  101. func (man *SNetTapServiceManager) getEnabledTapServiceOnHost(hostId string) ([]SNetTapService, error) {
  102. q := man.Query().IsTrue("enabled")
  103. q = man.filterByHostId(q, hostId)
  104. srvs := make([]SNetTapService, 0)
  105. err := db.FetchModelObjects(man, q, &srvs)
  106. if err != nil {
  107. return nil, errors.Wrap(err, "FetchModelObjects")
  108. }
  109. return srvs, nil
  110. }
  111. func (man *SNetTapServiceManager) OrderByExtraFields(
  112. ctx context.Context,
  113. q *sqlchemy.SQuery,
  114. userCred mcclient.TokenCredential,
  115. query api.NetTapServiceListInput,
  116. ) (*sqlchemy.SQuery, error) {
  117. q, err := man.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
  118. if err != nil {
  119. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
  120. }
  121. if db.NeedOrderQuery([]string{query.OrderByIp}) {
  122. hSQ := HostManager.Query("id", "access_ip").SubQuery()
  123. q = q.LeftJoin(hSQ, sqlchemy.Equals(q.Field("target_id"), hSQ.Field("id")))
  124. q = q.AppendField(q.QueryFields()...)
  125. q = q.AppendField(hSQ.Field("access_ip"))
  126. db.OrderByFields(q, []string{query.OrderByIp}, []sqlchemy.IQueryField{q.Field("access_ip")})
  127. }
  128. if db.NeedOrderQuery([]string{query.OrderByFlowCount}) {
  129. ntfQ := NetTapFlowManager.Query()
  130. ntfQ = ntfQ.AppendField(ntfQ.Field("tap_id"), sqlchemy.COUNT("flow_count", ntfQ.Field("tap_id")))
  131. ntfQ = ntfQ.GroupBy("tap_id")
  132. ntfSQ := ntfQ.SubQuery()
  133. q = q.LeftJoin(ntfSQ, sqlchemy.Equals(q.Field("id"), ntfSQ.Field("tap_id")))
  134. q = q.AppendField(q.QueryFields()...)
  135. q = q.AppendField(ntfSQ.Field("flow_count"))
  136. db.OrderByFields(q, []string{query.OrderByFlowCount}, []sqlchemy.IQueryField{q.Field("flow_count")})
  137. }
  138. return q, nil
  139. }
  140. func (man *SNetTapServiceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  141. var err error
  142. q, err = man.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  143. if err == nil {
  144. return q, nil
  145. }
  146. return q, httperrors.ErrNotFound
  147. }
  148. func (manager *SNetTapServiceManager) FetchCustomizeColumns(
  149. ctx context.Context,
  150. userCred mcclient.TokenCredential,
  151. query jsonutils.JSONObject,
  152. objs []interface{},
  153. fields stringutils2.SSortedStrings,
  154. isList bool,
  155. ) []api.NetTapServiceDetails {
  156. rows := make([]api.NetTapServiceDetails, len(objs))
  157. stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  158. for i := range rows {
  159. rows[i] = api.NetTapServiceDetails{
  160. EnabledStatusStandaloneResourceDetails: stdRows[i],
  161. }
  162. rows[i] = objs[i].(*SNetTapService).getMoreDetails(ctx, rows[i])
  163. }
  164. return rows
  165. }
  166. func (srv *SNetTapService) getMoreDetails(ctx context.Context, details api.NetTapServiceDetails) api.NetTapServiceDetails {
  167. var err error
  168. switch srv.Type {
  169. case api.TapServiceHost:
  170. host := HostManager.FetchHostById(srv.TargetId)
  171. details.Target = host.Name
  172. details.TargetIps = host.AccessIp
  173. case api.TapServiceGuest:
  174. guest := GuestManager.FetchGuestById(srv.TargetId)
  175. details.Target = guest.Name
  176. ret := fetchGuestIPs([]string{srv.TargetId}, tristate.False)
  177. details.TargetIps = strings.Join(ret[srv.TargetId], ",")
  178. }
  179. details.FlowCount, err = srv.getFlowsCount()
  180. if err != nil {
  181. log.Errorf("getFlowsCount %s", err)
  182. }
  183. return details
  184. }
  185. func (srv *SNetTapService) getFlowsQuery() *sqlchemy.SQuery {
  186. return NetTapFlowManager.Query().Equals("tap_id", srv.Id)
  187. }
  188. func (srv *SNetTapService) getFlowsCount() (int, error) {
  189. return srv.getFlowsQuery().CountWithError()
  190. }
  191. func (srv *SNetTapService) getFlows() ([]SNetTapFlow, error) {
  192. flows := make([]SNetTapFlow, 0)
  193. q := srv.getFlowsQuery()
  194. err := db.FetchModelObjects(NetTapFlowManager, q, &flows)
  195. if err != nil {
  196. return nil, errors.Wrap(err, "FetchModelObjects")
  197. }
  198. return flows, nil
  199. }
  200. func (srv *SNetTapService) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  201. cnt, err := srv.getFlowsCount()
  202. if err != nil {
  203. return errors.Wrap(err, "getFlowCount")
  204. }
  205. if cnt > 0 {
  206. return httperrors.NewNotEmptyError("Tap service has associated flows")
  207. }
  208. return srv.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, info)
  209. }
  210. func (manager *SNetTapServiceManager) ValidateCreateData(
  211. ctx context.Context,
  212. userCred mcclient.TokenCredential,
  213. ownerId mcclient.IIdentityProvider,
  214. query jsonutils.JSONObject,
  215. input api.NetTapServiceCreateInput,
  216. ) (api.NetTapServiceCreateInput, error) {
  217. var err error
  218. input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput)
  219. if err != nil {
  220. return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(")
  221. }
  222. switch input.Type {
  223. case api.TapServiceHost:
  224. hostObj, err := HostManager.FetchByIdOrName(ctx, userCred, input.TargetId)
  225. if err != nil {
  226. if errors.Cause(err) == sql.ErrNoRows {
  227. return input, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", HostManager.Keyword(), input.TargetId)
  228. } else {
  229. return input, errors.Wrap(err, "HostManager.FetchByIdOrName")
  230. }
  231. }
  232. host := hostObj.(*SHost)
  233. if host.HostType != api.HOST_TYPE_HYPERVISOR {
  234. return input, errors.Wrapf(httperrors.ErrNotSupported, "host type %s not supported", host.HostType)
  235. }
  236. if len(input.MacAddr) > 0 {
  237. input.MacAddr = netutils.FormatMacAddr(input.MacAddr)
  238. nic := host.GetNetInterface(input.MacAddr, 1)
  239. if nic == nil {
  240. return input, errors.Wrap(errors.ErrNotFound, "host.GetNetInterface")
  241. }
  242. if len(nic.WireId) > 0 {
  243. return input, errors.Wrap(httperrors.ErrNotEmpty, "interface has been used")
  244. }
  245. }
  246. _, err = manager.fetchByHostIdMac(hostObj.GetId(), input.MacAddr)
  247. if err == nil {
  248. return input, errors.Wrapf(httperrors.ErrNotEmpty, "host %s(%s) has been attached to tap service", input.TargetId, input.MacAddr)
  249. } else if errors.Cause(err) != sql.ErrNoRows {
  250. return input, errors.Wrap(err, "fetchGuestById")
  251. }
  252. input.TargetId = hostObj.GetId()
  253. case api.TapServiceGuest:
  254. guestObj, err := GuestManager.FetchByIdOrName(ctx, userCred, input.TargetId)
  255. if err != nil {
  256. if errors.Cause(err) == sql.ErrNoRows {
  257. return input, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", GuestManager.Keyword(), input.TargetId)
  258. } else {
  259. return input, errors.Wrap(err, "GuestManager.FetchByIdOrName")
  260. }
  261. }
  262. guest := guestObj.(*SGuest)
  263. if guest.Hypervisor != api.HYPERVISOR_KVM {
  264. return input, errors.Wrapf(httperrors.ErrNotSupported, "hypervisor %s not supported", guest.Hypervisor)
  265. }
  266. // check the guest attach to tap
  267. _, err = manager.fetchByGuestId(guestObj.GetId())
  268. if err == nil {
  269. return input, errors.Wrapf(httperrors.ErrNotEmpty, "guest %s has been attached to tap service", input.TargetId)
  270. } else if errors.Cause(err) != sql.ErrNoRows {
  271. return input, errors.Wrap(err, "fetchGuestById")
  272. }
  273. input.TargetId = guestObj.GetId()
  274. default:
  275. return input, errors.Wrapf(httperrors.ErrNotSupported, "unsupported type %s", input.Type)
  276. }
  277. return input, nil
  278. }
  279. func (man *SNetTapServiceManager) fetchByGuestId(guestId string) (*SNetTapService, error) {
  280. return man.fetchByTargetMac(api.TapServiceGuest, guestId, "")
  281. }
  282. func (man *SNetTapServiceManager) fetchByHostIdMac(hostId, mac string) (*SNetTapService, error) {
  283. return man.fetchByTargetMac(api.TapServiceHost, hostId, mac)
  284. }
  285. func (man *SNetTapServiceManager) fetchByTargetMac(tapTyep, targetId, mac string) (*SNetTapService, error) {
  286. q := man.Query().Equals("type", api.TapServiceGuest).Equals("target_id", targetId)
  287. if len(mac) > 0 {
  288. q = q.Equals("mac_addr", mac)
  289. }
  290. tapObj, err := db.NewModelObject(man)
  291. if err != nil {
  292. return nil, errors.Wrap(err, "NewModelObject")
  293. }
  294. err = q.First(tapObj)
  295. if err != nil {
  296. return nil, errors.Wrap(err, "First")
  297. }
  298. return tapObj.(*SNetTapService), nil
  299. }
  300. func (tap *SNetTapService) CustomizeCreate(
  301. ctx context.Context,
  302. userCred mcclient.TokenCredential,
  303. ownerId mcclient.IIdentityProvider,
  304. query jsonutils.JSONObject,
  305. data jsonutils.JSONObject,
  306. ) error {
  307. input := api.NetTapServiceCreateInput{}
  308. err := data.Unmarshal(&input)
  309. if err != nil {
  310. return errors.Wrap(err, "Unmarshal NetTapServiceCreateInput")
  311. }
  312. switch input.Type {
  313. case api.TapServiceGuest:
  314. err := func() error {
  315. lockman.LockClass(ctx, NetTapServiceManager, "")
  316. defer lockman.ReleaseClass(ctx, NetTapServiceManager, "")
  317. // generate mac
  318. mac, err := NetTapServiceManager.GenerateMac(input.MacAddr)
  319. if err != nil {
  320. return errors.Wrap(err, "GenerateMac")
  321. }
  322. ifname, err := NetTapServiceManager.generateIfname(mac)
  323. if err != nil {
  324. return errors.Wrap(err, "generateIfname")
  325. }
  326. tap.Ifname = ifname
  327. tap.MacAddr = mac
  328. return nil
  329. }()
  330. if err != nil {
  331. return errors.Wrap(err, "generate mac and ifname")
  332. }
  333. }
  334. return tap.SEnabledStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  335. }
  336. func (manager *SNetTapServiceManager) generateIfname(seed string) (string, error) {
  337. for tried := 0; tried < maxMacTries; tried++ {
  338. ifname := "tap" + seclib2.HashId(seed, byte(tried), 6)
  339. cnt, err := manager.Query().Equals("ifname", ifname).CountWithError()
  340. if err != nil {
  341. return "", errors.Wrap(err, "CountWithError")
  342. }
  343. if cnt == 0 {
  344. return ifname, nil
  345. }
  346. }
  347. return "", errors.Wrap(httperrors.ErrTooManyAttempts, "maximal retry reached")
  348. }
  349. func (manager *SNetTapServiceManager) GenerateMac(suggestion string) (string, error) {
  350. return generateMac(suggestion)
  351. }
  352. func (manager *SNetTapServiceManager) FilterByMac(mac string) *sqlchemy.SQuery {
  353. return manager.Query().Equals("mac_addr", mac)
  354. }
  355. func (srv *SNetTapService) getTapHostIp() string {
  356. var hostId string
  357. if srv.Type == api.TapServiceGuest {
  358. guest := GuestManager.FetchGuestById(srv.TargetId)
  359. hostId = guest.HostId
  360. } else {
  361. hostId = srv.TargetId
  362. }
  363. host := HostManager.FetchHostById(hostId)
  364. return host.AccessIp
  365. }
  366. func (srv *SNetTapService) getConfig() (api.STapServiceConfig, error) {
  367. conf := api.STapServiceConfig{}
  368. flows, err := NetTapFlowManager.getEnabledTapFlowsOfTap(srv.Id)
  369. if err != nil {
  370. return conf, errors.Wrap(err, "NetTapFlowManager.getEnabledTapFlows")
  371. }
  372. mirrors := make([]api.SMirrorConfig, 0)
  373. for _, flow := range flows {
  374. mc, err := flow.getMirrorConfig(false)
  375. if err != nil {
  376. log.Errorf("getMirrorConfig fail: %s", err)
  377. } else {
  378. mirrors = append(mirrors, mc)
  379. }
  380. }
  381. sort.Sort(sMirrorConfigs(mirrors))
  382. conf.Mirrors = mirrors // groupMirrorConfig(mirrors)
  383. conf.TapHostIp = srv.getTapHostIp()
  384. conf.MacAddr = srv.MacAddr
  385. conf.Ifname = srv.Ifname
  386. return conf, nil
  387. }
  388. type sMirrorConfigs []api.SMirrorConfig
  389. func (a sMirrorConfigs) Len() int { return len(a) }
  390. func (a sMirrorConfigs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  391. func (a sMirrorConfigs) Less(i, j int) bool {
  392. if a[i].TapHostIp != a[j].TapHostIp {
  393. return a[i].TapHostIp < a[j].TapHostIp
  394. }
  395. if a[i].HostIp != a[j].HostIp {
  396. return a[i].HostIp < a[j].HostIp
  397. }
  398. if a[i].Bridge != a[j].Bridge {
  399. return a[i].Bridge < a[j].Bridge
  400. }
  401. if a[i].Direction != a[j].Direction {
  402. return a[i].Direction < a[j].Direction
  403. }
  404. if a[i].VlanId != a[j].VlanId {
  405. return a[i].VlanId < a[j].VlanId
  406. }
  407. if a[i].Port != a[j].Port {
  408. return a[i].Port < a[j].Port
  409. }
  410. return a[i].FlowId < a[j].FlowId
  411. }
  412. /*
  413. func groupMirrorConfig(mirrors []api.SMirrorConfig) []api.SHostBridgeMirrorConfig {
  414. sort.Sort(sMirrorConfigs(mirrors))
  415. ret := make([]api.SHostBridgeMirrorConfig, 0)
  416. var mc *api.SHostBridgeMirrorConfig
  417. for _, m := range mirrors {
  418. if mc != nil && (mc.TapHostIp != m.TapHostIp || mc.HostIp != m.HostIp || mc.Bridge != m.Bridge || mc.Direction != m.Direction) {
  419. ret = append(ret, *mc)
  420. mc = nil
  421. }
  422. if mc == nil {
  423. mc = &api.SHostBridgeMirrorConfig{
  424. TapHostIp: m.TapHostIp,
  425. HostIp: m.HostIp,
  426. Bridge: m.Bridge,
  427. Direction: m.Direction,
  428. FlowId: m.FlowId,
  429. }
  430. }
  431. if m.VlanId > 0 {
  432. mc.VlanId = append(mc.VlanId, m.VlanId)
  433. }
  434. if len(m.Port) > 0 {
  435. mc.Port = append(mc.Port, m.Port)
  436. }
  437. }
  438. if mc != nil {
  439. ret = append(ret, *mc)
  440. }
  441. return ret
  442. }
  443. */
  444. func (manager *SNetTapServiceManager) getEnabledTapServiceByGuestId(guestId string) *SNetTapService {
  445. srvs, err := manager.getTapServicesByGuestId(guestId, true)
  446. if err != nil {
  447. log.Errorf("getTapServicesByGuestId fail %s", err)
  448. return nil
  449. }
  450. if len(srvs) == 0 {
  451. return nil
  452. }
  453. return &srvs[0]
  454. }
  455. func (manager *SNetTapServiceManager) getTapServicesByGuestId(guestId string, enabled bool) ([]SNetTapService, error) {
  456. return manager.getTapServices(api.TapServiceGuest, guestId, enabled)
  457. }
  458. func (manager *SNetTapServiceManager) getTapServicesByHostId(hostId string, enabled bool) ([]SNetTapService, error) {
  459. return manager.getTapServices(api.TapServiceHost, hostId, enabled)
  460. }
  461. func (manager *SNetTapServiceManager) getTapServices(typeStr string, guestId string, enabled bool) ([]SNetTapService, error) {
  462. q := manager.Query().Equals("type", typeStr).Equals("target_id", guestId)
  463. if enabled {
  464. q = q.IsTrue("enabled")
  465. }
  466. srvs := make([]SNetTapService, 0)
  467. err := db.FetchModelObjects(manager, q, &srvs)
  468. if err != nil {
  469. return nil, errors.Wrap(err, "FetchModelObjects")
  470. }
  471. return srvs, nil
  472. }
  473. func (srv *SNetTapService) PerformEnable(
  474. ctx context.Context,
  475. userCred mcclient.TokenCredential,
  476. query jsonutils.JSONObject,
  477. input apis.PerformEnableInput,
  478. ) (jsonutils.JSONObject, error) {
  479. ret, err := srv.SEnabledStatusStandaloneResourceBase.PerformEnable(ctx, userCred, query, input)
  480. if err != nil {
  481. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformEnable")
  482. }
  483. if srv.Type == api.TapServiceGuest {
  484. // need to sync config
  485. guest := GuestManager.FetchGuestById(srv.TargetId)
  486. guest.StartSyncTask(ctx, userCred, false, "")
  487. }
  488. return ret, nil
  489. }
  490. func (srv *SNetTapService) PerformDisable(
  491. ctx context.Context,
  492. userCred mcclient.TokenCredential,
  493. query jsonutils.JSONObject,
  494. input apis.PerformDisableInput,
  495. ) (jsonutils.JSONObject, error) {
  496. ret, err := srv.SEnabledStatusStandaloneResourceBase.PerformDisable(ctx, userCred, query, input)
  497. if err != nil {
  498. return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBase.PerformEnable")
  499. }
  500. if srv.Type == api.TapServiceGuest {
  501. // need to sync config
  502. guest := GuestManager.FetchGuestById(srv.TargetId)
  503. guest.StartSyncTask(ctx, userCred, false, "")
  504. }
  505. return ret, nil
  506. }
  507. func (srv *SNetTapService) cleanup(ctx context.Context, userCred mcclient.TokenCredential) error {
  508. flows, err := srv.getFlows()
  509. if err != nil {
  510. return errors.Wrap(err, "getFlows")
  511. }
  512. for _, flow := range flows {
  513. err := flow.Delete(ctx, userCred)
  514. if err != nil {
  515. return errors.Wrap(err, "flow.Delete")
  516. }
  517. }
  518. err = srv.Delete(ctx, userCred)
  519. if err != nil {
  520. return errors.Wrap(err, "srv.Delete")
  521. }
  522. return nil
  523. }
  524. func (manager *SNetTapServiceManager) removeTapServicesByGuestId(ctx context.Context, userCred mcclient.TokenCredential, targetId string) error {
  525. return manager.removeTapServices(ctx, userCred, api.TapServiceGuest, targetId)
  526. }
  527. func (manager *SNetTapServiceManager) removeTapServicesByHostId(ctx context.Context, userCred mcclient.TokenCredential, targetId string) error {
  528. return manager.removeTapServices(ctx, userCred, api.TapServiceHost, targetId)
  529. }
  530. func (manager *SNetTapServiceManager) removeTapServices(ctx context.Context, userCred mcclient.TokenCredential, srvType string, targetId string) error {
  531. srvs, err := manager.getTapServices(srvType, targetId, false)
  532. if err != nil {
  533. return errors.Wrap(err, "getTapServicesByHostId")
  534. }
  535. for i := range srvs {
  536. err := srvs[i].cleanup(ctx, userCred)
  537. if err != nil {
  538. return errors.Wrap(err, "cleanup")
  539. }
  540. }
  541. return nil
  542. }