elasticcache_instances.go 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159
  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. "regexp"
  20. "strings"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/tristate"
  27. bc "yunion.io/x/pkg/util/billing"
  28. "yunion.io/x/pkg/util/compare"
  29. "yunion.io/x/pkg/util/netutils"
  30. "yunion.io/x/pkg/util/rbacscope"
  31. "yunion.io/x/pkg/utils"
  32. "yunion.io/x/sqlchemy"
  33. "yunion.io/x/onecloud/pkg/apis"
  34. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  35. api "yunion.io/x/onecloud/pkg/apis/compute"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  39. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  40. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  41. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  42. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  43. "yunion.io/x/onecloud/pkg/compute/options"
  44. "yunion.io/x/onecloud/pkg/httperrors"
  45. "yunion.io/x/onecloud/pkg/mcclient"
  46. "yunion.io/x/onecloud/pkg/util/choices"
  47. "yunion.io/x/onecloud/pkg/util/logclient"
  48. "yunion.io/x/onecloud/pkg/util/rbacutils"
  49. "yunion.io/x/onecloud/pkg/util/seclib2"
  50. "yunion.io/x/onecloud/pkg/util/stringutils2"
  51. )
  52. type SElasticcacheManager struct {
  53. db.SVirtualResourceBaseManager
  54. db.SExternalizedResourceBaseManager
  55. SDeletePreventableResourceBaseManager
  56. SCloudregionResourceBaseManager
  57. SManagedResourceBaseManager
  58. SZoneResourceBaseManager
  59. SNetworkResourceBaseManager
  60. }
  61. var ElasticcacheManager *SElasticcacheManager
  62. func init() {
  63. ElasticcacheManager = &SElasticcacheManager{
  64. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  65. SElasticcache{},
  66. "elasticcacheinstances_tbl",
  67. "elasticcache",
  68. "elasticcaches",
  69. ),
  70. }
  71. ElasticcacheManager.SetVirtualObject(ElasticcacheManager)
  72. }
  73. type SElasticcache struct {
  74. db.SVirtualResourceBase
  75. db.SExternalizedResourceBase
  76. SCloudregionResourceBase
  77. SManagedResourceBase
  78. SBillingResourceBase
  79. SDeletePreventableResourceBase
  80. SZoneResourceBase
  81. VpcId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"vpc_id"`
  82. // 备可用区
  83. SlaveZones string `width:"512" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"slave_zones"`
  84. // 实例规格
  85. // example: redis.master.micro.default
  86. InstanceType string `width:"96" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"instance_type"`
  87. // 容量
  88. // example: 1024
  89. CapacityMB int `nullable:"false" list:"user" create:"optional" json:"capacity_mb"`
  90. // 对应Sku
  91. LocalCategory string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"local_category"`
  92. // 类型
  93. // single(单副本) | double(双副本) | readone (单可读) | readthree (3可读) | readfive(5只读)
  94. NodeType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"node_type"`
  95. // 后端存储引擎
  96. // Redis | Memcache
  97. // example: redis
  98. Engine string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine"`
  99. // 后端存储引擎版本
  100. // example: 4.0
  101. EngineVersion string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"required" json:"engine_version"`
  102. // VpcId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional"`
  103. // 网络类型, CLASSIC(经典网络) VPC(专有网络)
  104. // example: CLASSIC
  105. NetworkType string `width:"16" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"network_type"`
  106. // 所属网络ID
  107. NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"network_id"`
  108. // 带宽
  109. Bandwidth int `nullable:"true" list:"user" create:"optional"`
  110. // 内网DNS
  111. PrivateDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"private_dns"`
  112. // 内网IP地址
  113. PrivateIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional" json:"private_ip_addr"`
  114. // 内网访问端口
  115. PrivateConnectPort int `nullable:"true" list:"user" create:"optional" json:"private_connect_port"`
  116. // 公网DNS
  117. PublicDNS string `width:"256" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"public_dns"`
  118. // 公网IP地址
  119. PublicIpAddr string `width:"17" charset:"ascii" list:"user" create:"optional" json:"public_ip_addr"`
  120. // 外网访问端口
  121. PublicConnectPort int `nullable:"true" list:"user" create:"optional" json:"public_connect_port"`
  122. // 维护开始时间,格式为HH:mmZ
  123. // example: 02:00Z
  124. MaintainStartTime string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"maintain_start_time"`
  125. // 维护结束时间
  126. MaintainEndTime string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"maintain_end_time"`
  127. // 访问密码? on (开启密码)|off (免密码访问)
  128. AuthMode string `width:"8" charset:"ascii" nullable:"false" list:"user" create:"optional" json:"auth_mode"`
  129. // 最大连接数
  130. Connections int `nullable:"true" list:"user" create:"optional"`
  131. }
  132. // elastic cache 子资源获取owner id
  133. func elasticcacheSubResourceFetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
  134. parentId := jsonutils.GetAnyString(data, []string{"elasticcache_id", "elasticcache"})
  135. if len(parentId) > 0 {
  136. userCred := policy.FetchUserCredential(ctx)
  137. ec, err := db.FetchByIdOrName(ctx, ElasticcacheManager, userCred, parentId)
  138. if err != nil {
  139. log.Errorf("elasticcache sub resource FetchOwnerId %s", err)
  140. return nil, nil
  141. }
  142. return ec.(*SElasticcache).GetOwnerId(), nil
  143. }
  144. return db.FetchProjectInfo(ctx, data)
  145. }
  146. // elastic cache 子资源获取owner query
  147. func elasticcacheSubResourceFetchOwner(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  148. if userCred != nil {
  149. var subq *sqlchemy.SSubQuery
  150. q1 := ElasticcacheManager.Query()
  151. switch scope {
  152. case rbacscope.ScopeProject:
  153. subq = q1.Equals("tenant_id", userCred.GetProjectId()).SubQuery()
  154. case rbacscope.ScopeDomain:
  155. subq = q1.Equals("domain_id", userCred.GetProjectDomainId()).SubQuery()
  156. }
  157. if subq != nil {
  158. q = q.Join(subq, sqlchemy.Equals(q.Field("elasticcache_id"), subq.Field("id")))
  159. }
  160. }
  161. return q
  162. }
  163. func (manager *SElasticcacheManager) FetchCustomizeColumns(
  164. ctx context.Context,
  165. userCred mcclient.TokenCredential,
  166. query jsonutils.JSONObject,
  167. objs []interface{},
  168. fields stringutils2.SSortedStrings,
  169. isList bool,
  170. ) []api.ElasticcacheDetails {
  171. rows := make([]api.ElasticcacheDetails, len(objs))
  172. virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  173. manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  174. regRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  175. zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  176. netIds := make([]string, len(objs))
  177. cacheIds := make([]string, len(objs))
  178. vpcIds := make([]string, len(objs))
  179. zoneIds := []string{}
  180. for i := range rows {
  181. rows[i] = api.ElasticcacheDetails{
  182. VirtualResourceDetails: virtRows[i],
  183. ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase,
  184. }
  185. rows[i].ManagedResourceInfo = manRows[i]
  186. rows[i].CloudregionResourceInfo = regRows[i]
  187. cache := objs[i].(*SElasticcache)
  188. netIds[i] = cache.NetworkId
  189. cacheIds[i] = cache.Id
  190. vpcIds[i] = cache.VpcId
  191. sz := strings.Split(objs[i].(*SElasticcache).SlaveZones, ",")
  192. for j := range sz {
  193. if !utils.IsInStringArray(sz[j], zoneIds) {
  194. zoneIds = append(zoneIds, sz[j])
  195. }
  196. }
  197. }
  198. vpcs := make(map[string]SVpc)
  199. err := db.FetchStandaloneObjectsByIds(VpcManager, vpcIds, vpcs)
  200. if err != nil {
  201. log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
  202. return nil
  203. }
  204. networks := make(map[string]SNetwork)
  205. err = db.FetchStandaloneObjectsByIds(NetworkManager, netIds, &networks)
  206. if err != nil {
  207. log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
  208. return rows
  209. }
  210. for i := range rows {
  211. if net, ok := networks[netIds[i]]; ok {
  212. rows[i].Network = net.Name
  213. }
  214. if vpc, ok := vpcs[vpcIds[i]]; ok {
  215. rows[i].Vpc = vpc.Name
  216. rows[i].VpcExtId = vpc.ExternalId
  217. rows[i].IsDefaultVpc = vpc.IsDefault
  218. }
  219. }
  220. if len(fields) == 0 || fields.Contains("secgroups") || fields.Contains("secgroup") {
  221. gsgs := fetchElasticcacheSecgroups(cacheIds)
  222. if gsgs != nil {
  223. for i := range rows {
  224. if gsg, ok := gsgs[cacheIds[i]]; ok {
  225. if len(fields) == 0 || fields.Contains("secgroups") {
  226. rows[i].Secgroups = gsg
  227. }
  228. }
  229. }
  230. }
  231. }
  232. // zone ids
  233. if len(zoneIds) > 0 {
  234. zss := fetchElasticcacheSlaveZones(zoneIds)
  235. for i := range objs {
  236. if len(objs[i].(*SElasticcache).SlaveZones) > 0 {
  237. sz := strings.Split(objs[i].(*SElasticcache).SlaveZones, ",")
  238. szi := []apis.StandaloneShortDesc{}
  239. for j := range sz {
  240. if info, ok := zss[sz[j]]; ok {
  241. szi = append(szi, info)
  242. } else {
  243. szi = append(szi, apis.StandaloneShortDesc{Id: sz[j], Name: sz[j]})
  244. }
  245. }
  246. rows[i].SlaveZoneInfos = szi
  247. }
  248. }
  249. }
  250. return rows
  251. }
  252. func fetchElasticcacheSlaveZones(zoneIds []string) map[string]apis.StandaloneShortDesc {
  253. zones := []SZone{}
  254. err := ZoneManager.Query().In("id", zoneIds).All(&zones)
  255. if err != nil {
  256. log.Debugf("fetchElasticcacheSlaveZones.ZoneManager %s", err)
  257. return nil
  258. }
  259. ret := make(map[string]apis.StandaloneShortDesc)
  260. for i := range zones {
  261. zsd := apis.StandaloneShortDesc{
  262. Id: zones[i].Id,
  263. Name: zones[i].Name,
  264. }
  265. ret[zsd.Id] = zsd
  266. }
  267. return ret
  268. }
  269. func (self *SElasticcache) GetElasticcacheParameters() ([]SElasticcacheParameter, error) {
  270. ret := []SElasticcacheParameter{}
  271. q := ElasticcacheParameterManager.Query().Equals("elasticcache_id", self.Id)
  272. err := db.FetchModelObjects(ElasticcacheParameterManager, q, &ret)
  273. if err != nil {
  274. return nil, errors.Wrapf(err, "GetElasticcacheParameters.FetchModelObjects for elastic cache %s", self.Id)
  275. }
  276. return ret, nil
  277. }
  278. func (self *SElasticcache) GetElasticcacheAccounts() ([]SElasticcacheAccount, error) {
  279. ret := []SElasticcacheAccount{}
  280. q := ElasticcacheAccountManager.Query().Equals("elasticcache_id", self.Id)
  281. err := db.FetchModelObjects(ElasticcacheAccountManager, q, &ret)
  282. if err != nil {
  283. return nil, errors.Wrapf(err, "GetElasticcacheAccounts.FetchModelObjects for elastic cache %s", self.Id)
  284. }
  285. return ret, nil
  286. }
  287. func (self *SElasticcache) GetElasticcacheAcls() ([]SElasticcacheAcl, error) {
  288. ret := []SElasticcacheAcl{}
  289. q := ElasticcacheAclManager.Query().Equals("elasticcache_id", self.Id)
  290. err := db.FetchModelObjects(ElasticcacheAclManager, q, &ret)
  291. if err != nil {
  292. return nil, errors.Wrapf(err, "GetElasticcacheAcls.FetchModelObjects for elastic cache %s", self.Id)
  293. }
  294. return ret, nil
  295. }
  296. func (self *SElasticcache) GetElasticcacheBackups() ([]SElasticcacheBackup, error) {
  297. ret := []SElasticcacheBackup{}
  298. q := ElasticcacheBackupManager.Query().Equals("elasticcache_id", self.Id)
  299. err := db.FetchModelObjects(ElasticcacheBackupManager, q, &ret)
  300. if err != nil {
  301. return nil, errors.Wrapf(err, "GetElasticcacheBackups.FetchModelObjects for elastic cache %s", self.Id)
  302. }
  303. return ret, nil
  304. }
  305. func (self *SElasticcache) GetDetailsLoginInfo(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  306. account, err := self.GetAdminAccount()
  307. if err != nil {
  308. return nil, err
  309. }
  310. ret := jsonutils.NewDict()
  311. ret.Add(jsonutils.NewString(account.Id), "account_id")
  312. ret.Add(jsonutils.NewString(account.Name), "username")
  313. ret.Add(jsonutils.NewString(account.Password), "password")
  314. return ret, nil
  315. }
  316. func (manager *SElasticcacheManager) GetOwnerIdByElasticcacheId(elasticcacheId string) mcclient.IIdentityProvider {
  317. ec, err := db.FetchById(ElasticcacheManager, elasticcacheId)
  318. if err != nil {
  319. log.Errorf("SElasticcacheManager.GetOwnerIdByElasticcacheId %s", err)
  320. return nil
  321. }
  322. return ec.(*SElasticcache).GetOwnerId()
  323. }
  324. // 列出弹性缓存(redis等)
  325. func (manager *SElasticcacheManager) ListItemFilter(
  326. ctx context.Context,
  327. q *sqlchemy.SQuery,
  328. userCred mcclient.TokenCredential,
  329. query api.ElasticcacheListInput,
  330. ) (*sqlchemy.SQuery, error) {
  331. var err error
  332. q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
  333. if err != nil {
  334. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
  335. }
  336. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  337. if err != nil {
  338. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  339. }
  340. q, err = manager.SDeletePreventableResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DeletePreventableResourceBaseListInput)
  341. if err != nil {
  342. return nil, errors.Wrap(err, "SDeletePreventableResourceBaseManager.ListItemFilter")
  343. }
  344. q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
  345. if err != nil {
  346. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
  347. }
  348. zoneQuery := api.ZonalFilterListInput{
  349. ZonalFilterListBase: query.ZonalFilterListBase,
  350. }
  351. q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery)
  352. if err != nil {
  353. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter")
  354. }
  355. if len(query.SecgroupId) > 0 {
  356. _, err = validators.ValidateModel(ctx, userCred, SecurityGroupManager, &query.SecgroupId)
  357. if err != nil {
  358. return nil, err
  359. }
  360. sq := ElasticcachesecgroupManager.Query("elasticcache_id").Equals("secgroup_id", query.SecgroupId)
  361. q = q.In("id", sq.SubQuery())
  362. }
  363. if len(query.InstanceType) > 0 {
  364. q = q.In("instance_type", query.InstanceType)
  365. }
  366. if len(query.LocalCategory) > 0 {
  367. q = q.In("local_category", query.LocalCategory)
  368. }
  369. if len(query.NodeType) > 0 {
  370. q = q.In("node_type", query.NodeType)
  371. }
  372. if len(query.Engine) > 0 {
  373. q = q.In("engine", query.Engine)
  374. }
  375. if len(query.EngineVersion) > 0 {
  376. q = q.In("engine_version", query.EngineVersion)
  377. }
  378. if len(query.NetworkType) > 0 {
  379. q = q.In("network_type", query.NetworkType)
  380. }
  381. netQuery := api.NetworkFilterListInput{
  382. NetworkFilterListBase: query.NetworkFilterListBase,
  383. }
  384. q, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, netQuery)
  385. if err != nil {
  386. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter")
  387. }
  388. if len(query.PrivateDNS) > 0 {
  389. q = q.In("private_dns", query.PrivateDNS)
  390. }
  391. if len(query.PrivateIpAddr) > 0 {
  392. q = q.In("private_ip_addr", query.PrivateIpAddr)
  393. }
  394. if len(query.PrivateConnectPort) > 0 {
  395. q = q.In("private_connect_port", query.PrivateConnectPort)
  396. }
  397. if len(query.PublicDNS) > 0 {
  398. q = q.In("public_dns", query.PublicDNS)
  399. }
  400. if len(query.PublicIpAddr) > 0 {
  401. q = q.In("public_ip_addr", query.PublicIpAddr)
  402. }
  403. if len(query.PublicConnectPort) > 0 {
  404. q = q.In("public_connect_port", query.PublicConnectPort)
  405. }
  406. if len(query.AuthMode) > 0 {
  407. q = q.In("auth_mode", query.AuthMode)
  408. }
  409. return q, nil
  410. }
  411. func (manager *SElasticcacheManager) OrderByExtraFields(
  412. ctx context.Context,
  413. q *sqlchemy.SQuery,
  414. userCred mcclient.TokenCredential,
  415. query api.ElasticcacheListInput,
  416. ) (*sqlchemy.SQuery, error) {
  417. var err error
  418. q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
  419. if err != nil {
  420. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
  421. }
  422. q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
  423. if err != nil {
  424. return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
  425. }
  426. zoneQuery := api.ZonalFilterListInput{
  427. ZonalFilterListBase: query.ZonalFilterListBase,
  428. }
  429. q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery)
  430. if err != nil {
  431. return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields")
  432. }
  433. return q, nil
  434. }
  435. func (manager *SElasticcacheManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  436. var err error
  437. q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  438. if err == nil {
  439. return q, nil
  440. }
  441. q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  442. if err == nil {
  443. return q, nil
  444. }
  445. q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field)
  446. if err == nil {
  447. return q, nil
  448. }
  449. return q, httperrors.ErrNotFound
  450. }
  451. func (manager *SElasticcacheManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  452. var err error
  453. q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  454. if err == nil {
  455. return q, nil
  456. }
  457. return q, httperrors.ErrNotFound
  458. }
  459. func (self *SCloudregion) SyncElasticcaches(
  460. ctx context.Context,
  461. userCred mcclient.TokenCredential,
  462. syncOwnerId mcclient.IIdentityProvider,
  463. provider *SCloudprovider,
  464. cloudElasticcaches []cloudprovider.ICloudElasticcache,
  465. xor bool,
  466. ) ([]SElasticcache, []cloudprovider.ICloudElasticcache, compare.SyncResult) {
  467. lockman.LockRawObject(ctx, ElasticcacheManager.Keyword(), fmt.Sprintf("%s-%s", provider.Id, self.Id))
  468. defer lockman.ReleaseRawObject(ctx, ElasticcacheManager.Keyword(), fmt.Sprintf("%s-%s", provider.Id, self.Id))
  469. localElasticcaches := []SElasticcache{}
  470. remoteElasticcaches := []cloudprovider.ICloudElasticcache{}
  471. syncResult := compare.SyncResult{}
  472. dbInstances, err := self.GetElasticcaches(provider)
  473. if err != nil {
  474. syncResult.Error(err)
  475. return nil, nil, syncResult
  476. }
  477. for i := range dbInstances {
  478. if taskman.TaskManager.IsInTask(&dbInstances[i]) {
  479. syncResult.Error(fmt.Errorf("ElasticCacheInstance %s(%s)in task", dbInstances[i].Name, dbInstances[i].Id))
  480. return nil, nil, syncResult
  481. }
  482. }
  483. removed := make([]SElasticcache, 0)
  484. commondb := make([]SElasticcache, 0)
  485. commonext := make([]cloudprovider.ICloudElasticcache, 0)
  486. added := make([]cloudprovider.ICloudElasticcache, 0)
  487. if err := compare.CompareSets(dbInstances, cloudElasticcaches, &removed, &commondb, &commonext, &added); err != nil {
  488. syncResult.Error(err)
  489. return nil, nil, syncResult
  490. }
  491. for i := 0; i < len(removed); i++ {
  492. err := removed[i].syncRemoveCloudElasticcache(ctx, userCred)
  493. if err != nil {
  494. syncResult.DeleteError(err)
  495. } else {
  496. syncResult.Delete()
  497. }
  498. }
  499. if !xor {
  500. for i := 0; i < len(commondb); i++ {
  501. err := commondb[i].SyncWithCloudElasticcache(ctx, userCred, provider, commonext[i])
  502. if err != nil {
  503. syncResult.UpdateError(err)
  504. continue
  505. }
  506. localElasticcaches = append(localElasticcaches, commondb[i])
  507. remoteElasticcaches = append(remoteElasticcaches, commonext[i])
  508. syncResult.Update()
  509. }
  510. }
  511. for i := 0; i < len(added); i++ {
  512. instance, err := self.newFromCloudElasticcache(ctx, userCred, syncOwnerId, provider, added[i])
  513. if err != nil {
  514. syncResult.AddError(err)
  515. continue
  516. }
  517. localElasticcaches = append(localElasticcaches, *instance)
  518. remoteElasticcaches = append(remoteElasticcaches, added[i])
  519. syncResult.Add()
  520. }
  521. return localElasticcaches, remoteElasticcaches, syncResult
  522. }
  523. func (self *SElasticcache) syncRemoveCloudElasticcache(ctx context.Context, userCred mcclient.TokenCredential) error {
  524. lockman.LockObject(ctx, self)
  525. defer lockman.ReleaseObject(ctx, self)
  526. self.SetDisableDelete(userCred, false)
  527. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  528. Obj: self,
  529. Action: notifyclient.ActionSyncDelete,
  530. })
  531. return self.RealDelete(ctx, userCred)
  532. }
  533. func (self *SElasticcache) SyncWithCloudElasticcache(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extInstance cloudprovider.ICloudElasticcache) error {
  534. diff, err := db.UpdateWithLock(ctx, self, func() error {
  535. if options.Options.EnableSyncName {
  536. newName, _ := db.GenerateAlterName(self, extInstance.GetName())
  537. if len(newName) > 0 {
  538. self.Name = newName
  539. }
  540. }
  541. self.Status = extInstance.GetStatus()
  542. self.InstanceType = extInstance.GetInstanceType()
  543. self.CapacityMB = extInstance.GetCapacityMB()
  544. self.LocalCategory = extInstance.GetArchType()
  545. self.NodeType = extInstance.GetNodeType()
  546. self.Engine = extInstance.GetEngine()
  547. self.EngineVersion = extInstance.GetEngineVersion()
  548. self.NetworkType = extInstance.GetNetworkType()
  549. self.PrivateDNS = extInstance.GetPrivateDNS()
  550. self.PrivateIpAddr = extInstance.GetPrivateIpAddr()
  551. self.PrivateConnectPort = extInstance.GetPrivateConnectPort()
  552. self.PublicDNS = extInstance.GetPublicDNS()
  553. self.PublicIpAddr = extInstance.GetPublicIpAddr()
  554. self.PublicConnectPort = extInstance.GetPublicConnectPort()
  555. self.MaintainStartTime = extInstance.GetMaintainStartTime()
  556. self.MaintainEndTime = extInstance.GetMaintainEndTime()
  557. self.AuthMode = extInstance.GetAuthMode()
  558. if bw := extInstance.GetBandwidth(); bw > 0 {
  559. self.Bandwidth = bw
  560. }
  561. if cnns := extInstance.GetConnections(); cnns > 0 {
  562. self.Connections = cnns
  563. }
  564. self.BillingType = billing_api.TBillingType(extInstance.GetBillingType())
  565. self.ExpiredAt = time.Time{}
  566. self.AutoRenew = false
  567. if self.BillingType == billing_api.BILLING_TYPE_PREPAID {
  568. self.ExpiredAt = extInstance.GetExpiredAt()
  569. self.AutoRenew = extInstance.IsAutoRenew()
  570. }
  571. return nil
  572. })
  573. if err != nil {
  574. return errors.Wrapf(err, "syncWithCloudElasticcache.Update")
  575. }
  576. SyncCloudProject(ctx, userCred, self, provider.GetOwnerId(), extInstance, provider)
  577. if account := self.GetCloudaccount(); account != nil {
  578. syncVirtualResourceMetadata(ctx, userCred, self, extInstance, account.ReadOnly)
  579. }
  580. db.OpsLog.LogSyncUpdate(self, diff, userCred)
  581. if len(diff) > 0 {
  582. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  583. Obj: self,
  584. Action: notifyclient.ActionSyncUpdate,
  585. })
  586. }
  587. return nil
  588. }
  589. func (self *SCloudregion) newFromCloudElasticcache(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, provider *SCloudprovider, extInstance cloudprovider.ICloudElasticcache) (*SElasticcache, error) {
  590. instance := SElasticcache{}
  591. instance.SetModelManager(ElasticcacheManager, &instance)
  592. instance.ExternalId = extInstance.GetGlobalId()
  593. instance.CloudregionId = self.Id
  594. instance.ManagerId = provider.Id
  595. instance.IsEmulated = extInstance.IsEmulated()
  596. instance.Status = extInstance.GetStatus()
  597. instance.InstanceType = extInstance.GetInstanceType()
  598. instance.CapacityMB = extInstance.GetCapacityMB()
  599. instance.LocalCategory = extInstance.GetArchType()
  600. instance.NodeType = extInstance.GetNodeType()
  601. instance.Engine = extInstance.GetEngine()
  602. instance.EngineVersion = extInstance.GetEngineVersion()
  603. instance.PrivateDNS = extInstance.GetPrivateDNS()
  604. instance.PrivateIpAddr = extInstance.GetPrivateIpAddr()
  605. instance.PrivateConnectPort = extInstance.GetPrivateConnectPort()
  606. instance.PublicDNS = extInstance.GetPublicDNS()
  607. instance.PublicIpAddr = extInstance.GetPublicIpAddr()
  608. instance.PublicConnectPort = extInstance.GetPublicConnectPort()
  609. instance.MaintainStartTime = extInstance.GetMaintainStartTime()
  610. instance.MaintainEndTime = extInstance.GetMaintainEndTime()
  611. instance.AuthMode = extInstance.GetAuthMode()
  612. instance.Bandwidth = extInstance.GetBandwidth()
  613. instance.Connections = extInstance.GetConnections()
  614. var zone *SZone
  615. if zoneId := extInstance.GetZoneId(); len(zoneId) > 0 {
  616. _zone, err := db.FetchByExternalId(ZoneManager, zoneId)
  617. if err != nil {
  618. return nil, errors.Wrapf(err, "newFromCloudElasticcache.FetchZoneId")
  619. }
  620. instance.ZoneId = _zone.GetId()
  621. zone = _zone.(*SZone)
  622. }
  623. instance.NetworkType = extInstance.GetNetworkType()
  624. if instance.NetworkType == api.LB_NETWORK_TYPE_CLASSIC {
  625. vpc, err := VpcManager.GetOrCreateVpcForClassicNetwork(ctx, provider, self)
  626. if err != nil {
  627. return nil, errors.Wrap(err, "NewVpcForClassicNetwork")
  628. }
  629. instance.VpcId = vpc.GetId()
  630. wire, err := WireManager.GetOrCreateWireForClassicNetwork(ctx, vpc, zone)
  631. if err != nil {
  632. return nil, errors.Wrap(err, "NewWireForClassicNetwork")
  633. }
  634. network, err := NetworkManager.GetOrCreateClassicNetwork(ctx, wire)
  635. if err != nil {
  636. return nil, errors.Wrap(err, "GetOrCreateClassicNetwork")
  637. }
  638. instance.NetworkId = network.GetId()
  639. } else {
  640. if vpcId := extInstance.GetVpcId(); len(vpcId) > 0 {
  641. vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  642. return q.Equals("manager_id", provider.Id)
  643. })
  644. if err != nil {
  645. return nil, errors.Wrapf(err, "newFromCloudElasticcache.FetchVpcId %s", vpcId)
  646. }
  647. instance.VpcId = vpc.GetId()
  648. }
  649. if networkId := extInstance.GetNetworkId(); len(networkId) > 0 {
  650. network, err := db.FetchByExternalIdAndManagerId(NetworkManager, networkId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  651. wire := WireManager.Query().SubQuery()
  652. vpc := VpcManager.Query().SubQuery()
  653. return q.Join(wire, sqlchemy.Equals(wire.Field("id"), q.Field("wire_id"))).
  654. Join(vpc, sqlchemy.Equals(vpc.Field("id"), wire.Field("vpc_id"))).
  655. Filter(sqlchemy.Equals(vpc.Field("manager_id"), provider.Id))
  656. })
  657. if err != nil {
  658. return nil, errors.Wrapf(err, "newFromCloudElasticcache.FetchNetworkId %s", networkId)
  659. }
  660. instance.NetworkId = network.GetId()
  661. }
  662. }
  663. if createdAt := extInstance.GetCreatedAt(); !createdAt.IsZero() {
  664. instance.CreatedAt = createdAt
  665. }
  666. instance.BillingType = billing_api.TBillingType(extInstance.GetBillingType())
  667. instance.ExpiredAt = time.Time{}
  668. instance.AutoRenew = false
  669. if instance.BillingType == billing_api.BILLING_TYPE_PREPAID {
  670. instance.ExpiredAt = extInstance.GetExpiredAt()
  671. instance.AutoRenew = extInstance.IsAutoRenew()
  672. }
  673. err := func() error {
  674. lockman.LockRawObject(ctx, ElasticcacheManager.Keyword(), "name")
  675. defer lockman.ReleaseRawObject(ctx, ElasticcacheManager.Keyword(), "name")
  676. var err error
  677. instance.Name, err = db.GenerateName(ctx, ElasticcacheManager, ownerId, extInstance.GetName())
  678. if err != nil {
  679. return err
  680. }
  681. return ElasticcacheManager.TableSpec().Insert(ctx, &instance)
  682. }()
  683. if err != nil {
  684. return nil, errors.Wrapf(err, "newFromCloudElasticcache.Insert")
  685. }
  686. SyncCloudProject(ctx, userCred, &instance, provider.GetOwnerId(), extInstance, provider)
  687. syncVirtualResourceMetadata(ctx, userCred, &instance, extInstance, false)
  688. db.OpsLog.LogEvent(&instance, db.ACT_CREATE, instance.GetShortDesc(ctx), userCred)
  689. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  690. Obj: &instance,
  691. Action: notifyclient.ActionSyncCreate,
  692. })
  693. return &instance, nil
  694. }
  695. func (manager *SElasticcacheManager) getElasticcachesByProviderId(providerId string) ([]SElasticcache, error) {
  696. instances := []SElasticcache{}
  697. err := fetchByVpcManagerId(manager, providerId, &instances)
  698. if err != nil {
  699. return nil, errors.Wrapf(err, "getElasticcachesByProviderId.fetchByManagerId")
  700. }
  701. return instances, nil
  702. }
  703. func (manager *SElasticcacheManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.ElasticcacheCreateInput) (*api.ElasticcacheCreateInput, error) {
  704. var err error
  705. input, err = manager.validateCreateData(ctx, userCred, ownerId, query, input)
  706. if err != nil {
  707. return nil, errors.Wrap(err, "validateCreateData")
  708. }
  709. return input, nil
  710. }
  711. func (manager *SElasticcacheManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.ElasticcacheCreateInput) (*api.ElasticcacheCreateInput, error) {
  712. return manager.validateCreateData(ctx, userCred, ownerId, query, input)
  713. }
  714. func (manager *SElasticcacheManager) validateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.ElasticcacheCreateInput) (*api.ElasticcacheCreateInput, error) {
  715. if len(input.NetworkId) == 0 {
  716. return nil, httperrors.NewMissingParameterError("network_id")
  717. }
  718. networkObj, err := validators.ValidateModel(ctx, userCred, NetworkManager, &input.NetworkId)
  719. if err != nil {
  720. return nil, fmt.Errorf("getting network failed")
  721. }
  722. network := networkObj.(*SNetwork)
  723. wire, err := network.GetWire()
  724. if err != nil {
  725. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetWire"))
  726. }
  727. if len(wire.ZoneId) > 0 {
  728. input.ZoneId = wire.ZoneId
  729. }
  730. _, err = validators.ValidateModel(ctx, userCred, ZoneManager, &input.ZoneId)
  731. if err != nil {
  732. return nil, err
  733. }
  734. vpc, err := network.GetVpc()
  735. if err != nil {
  736. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetVpc"))
  737. }
  738. input.VpcId = vpc.Id
  739. region, err := vpc.GetRegion()
  740. if err != nil {
  741. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetRegion"))
  742. }
  743. input.CloudregionId = region.Id
  744. provider := vpc.GetCloudprovider()
  745. input.ManagerId = provider.Id
  746. skuObj, err := validators.ValidateModel(ctx, userCred, ElasticcacheSkuManager, &input.InstanceType)
  747. if err != nil {
  748. return nil, err
  749. }
  750. sku := skuObj.(*SElasticcacheSku)
  751. input.Engine = sku.Engine
  752. input.EngineVersion = sku.EngineVersion
  753. input.InstanceType = sku.InstanceSpec
  754. input.NodeType = sku.NodeType
  755. input.LocalCategory = sku.LocalCategory
  756. if len(input.PrivateIp) > 0 {
  757. _, err = netutils.NewIPV4Addr(input.PrivateIp)
  758. if err != nil {
  759. return nil, httperrors.NewInputParameterError("invalid private ip %s", input.PrivateIp)
  760. }
  761. }
  762. if len(input.SecgroupIds) == 0 {
  763. input.SecgroupIds = []string{api.SECGROUP_DEFAULT_ID}
  764. }
  765. for i := range input.SecgroupIds {
  766. _, err = validators.ValidateModel(ctx, userCred, SecurityGroupManager, &input.SecgroupIds[i])
  767. if err != nil {
  768. return nil, err
  769. }
  770. }
  771. if len(input.Duration) > 0 {
  772. cycle, err := bc.ParseBillingCycle(input.Duration)
  773. if err != nil {
  774. return nil, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
  775. }
  776. input.BillingCycle = cycle.String()
  777. if input.BillingType == billing_api.BILLING_TYPE_POSTPAID {
  778. input.ReleaseAt = cycle.EndAt(time.Now())
  779. }
  780. }
  781. // validate password
  782. if len(input.Password) > 0 {
  783. err := seclib2.ValidatePassword(input.Password)
  784. if err != nil {
  785. return nil, err
  786. }
  787. } else if input.ResetPassword {
  788. input.Password = seclib2.RandomPassword2(12)
  789. }
  790. input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  791. if err != nil {
  792. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ValidateCreateData")
  793. }
  794. ret, err := region.GetDriver().ValidateCreateElasticcacheData(ctx, userCred, nil, input)
  795. if err != nil {
  796. return nil, errors.Wrap(err, "region.GetDriver().ValidateCreateElasticcacheData")
  797. }
  798. cachePendingUsage := &SRegionQuota{Cache: 1}
  799. quotaKeys := fetchRegionalQuotaKeys(rbacscope.ScopeProject, ownerId, region, provider)
  800. cachePendingUsage.SetKeys(quotaKeys)
  801. if err = quotas.CheckSetPendingQuota(ctx, userCred, cachePendingUsage); err != nil {
  802. return nil, errors.Wrap(err, "quotas.CheckSetPendingQuota")
  803. }
  804. return ret, nil
  805. }
  806. func (self *SElasticcache) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  807. self.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  808. pendingUsage := SRegionQuota{Cache: 1}
  809. pendingUsage.SetKeys(self.GetQuotaKeys())
  810. err := quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  811. if err != nil {
  812. log.Errorf("CancelPendingUsage error %s", err)
  813. }
  814. input := &api.ElasticcacheCreateInput{}
  815. data.Unmarshal(input)
  816. self.StartElasticcacheCreateTask(ctx, userCred, input, "")
  817. }
  818. func (self *SElasticcache) StartElasticcacheCreateTask(ctx context.Context, userCred mcclient.TokenCredential, input *api.ElasticcacheCreateInput, parentTaskId string) {
  819. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_DEPLOYING, "")
  820. params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
  821. err := func() error {
  822. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheCreateTask", self, userCred, params, parentTaskId, "", nil)
  823. if err != nil {
  824. return errors.Wrapf(err, "NewTask")
  825. }
  826. return task.ScheduleRun(nil)
  827. }()
  828. if err != nil {
  829. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CREATE_FAILED, err.Error())
  830. }
  831. }
  832. func (self *SElasticcache) GetSlaveZones() ([]SZone, error) {
  833. zones := []SZone{}
  834. if len(self.SlaveZones) > 0 {
  835. sz := strings.Split(self.SlaveZones, ",")
  836. err := ZoneManager.Query().In("id", sz).All(&zones)
  837. if err != nil {
  838. return nil, errors.Wrap(err, "GetZones")
  839. }
  840. return zones, nil
  841. }
  842. return zones, nil
  843. }
  844. func (self *SElasticcache) PerformRestart(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  845. if utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING, api.ELASTIC_CACHE_STATUS_INACTIVE}) {
  846. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_RESTARTING, "")
  847. return nil, self.StartRestartTask(ctx, userCred, "", data)
  848. } else {
  849. return nil, httperrors.NewInvalidStatusError("Cannot do restart elasticcache instance in status %s", self.Status)
  850. }
  851. }
  852. func (self *SElasticcache) StartRestartTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, data jsonutils.JSONObject) error {
  853. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_RESTARTING, "")
  854. if task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheRestartTask", self, userCred, data.(*jsonutils.JSONDict), parentTaskId, "", nil); err != nil {
  855. log.Errorln(err)
  856. return err
  857. } else {
  858. task.ScheduleRun(nil)
  859. }
  860. return nil
  861. }
  862. func (self *SElasticcache) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  863. if self.DisableDelete.IsTrue() {
  864. return httperrors.NewInvalidStatusError("Elastic cache is locked, cannot delete")
  865. }
  866. if self.IsNotDeletablePrePaid() {
  867. return httperrors.NewInvalidStatusError("Elastic cache is not expired, cannot delete")
  868. }
  869. return self.SVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
  870. }
  871. func (self *SElasticcache) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  872. return self.StartDeleteElasticcacheTask(ctx, userCred, jsonutils.NewDict(), "")
  873. }
  874. func (self *SElasticcache) StartDeleteElasticcacheTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  875. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_RELEASING, "")
  876. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheDeleteTask", self, userCred, params, parentTaskId, "", nil)
  877. if err != nil {
  878. return err
  879. }
  880. task.ScheduleRun(nil)
  881. return nil
  882. }
  883. func (self *SElasticcache) ValidatorChangeSpecData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  884. skuV := validators.NewModelIdOrNameValidator("sku", "elasticcachesku", self.GetOwnerId())
  885. if err := skuV.Optional(false).Validate(ctx, data.(*jsonutils.JSONDict)); err != nil {
  886. return nil, err
  887. }
  888. sku := skuV.Model.(*SElasticcacheSku)
  889. region, _ := self.GetRegion()
  890. if sku.CloudregionId != region.Id {
  891. return nil, httperrors.NewInputParameterError("region mismatch: instance region %s, sku region %s", region.Id, sku.CloudregionId)
  892. }
  893. if sku.ZoneId != "" && sku.ZoneId != self.ZoneId {
  894. return nil, httperrors.NewInputParameterError("zone mismatch: instance zone %s, sku zone %s", self.ZoneId, sku.ZoneId)
  895. }
  896. if self.EngineVersion != "" && sku.EngineVersion != self.EngineVersion {
  897. return nil, httperrors.NewInputParameterError("engine version mismatch: instance version %s, sku version %s", self.EngineVersion, sku.EngineVersion)
  898. }
  899. data.(*jsonutils.JSONDict).Set("sku_ext_id", jsonutils.NewString(skuV.Model.(*SElasticcacheSku).GetName()))
  900. return data, nil
  901. }
  902. func (self *SElasticcache) PerformChangeSpec(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  903. if !utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING}) {
  904. return nil, httperrors.NewResourceNotReadyError("can not change specification in status %s", self.Status)
  905. }
  906. data, err := self.ValidatorChangeSpecData(ctx, userCred, query, data)
  907. if err != nil {
  908. return nil, err
  909. }
  910. params := jsonutils.NewDict()
  911. sku, _ := data.GetString("sku_ext_id")
  912. params.Set("sku_ext_id", jsonutils.NewString(sku))
  913. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  914. return nil, self.StartChangeSpecTask(ctx, userCred, params, "")
  915. }
  916. func (self *SElasticcache) StartChangeSpecTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  917. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheChangeSpecTask", self, userCred, params, parentTaskId, "", nil)
  918. if err != nil {
  919. return err
  920. }
  921. task.ScheduleRun(nil)
  922. return nil
  923. }
  924. func (self *SElasticcache) ValidatorUpdateAuthModeData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  925. region, _ := self.GetRegion()
  926. if region == nil {
  927. return nil, fmt.Errorf("fail to found region for elastic cache")
  928. }
  929. driver := region.GetDriver()
  930. if driver == nil {
  931. return nil, fmt.Errorf("fail to found driver for elastic cache")
  932. }
  933. err := driver.AllowUpdateElasticcacheAuthMode(ctx, userCred, self.GetOwnerId(), self)
  934. if err != nil {
  935. return nil, err
  936. }
  937. authModeV := validators.NewStringChoicesValidator("auth_mode", choices.NewChoices("on", "off"))
  938. if err := authModeV.Optional(false).Validate(ctx, data.(*jsonutils.JSONDict)); err != nil {
  939. return nil, err
  940. }
  941. if authModeV.Value == self.AuthMode {
  942. return nil, httperrors.NewConflictError("auth mode aready in status %s", self.AuthMode)
  943. }
  944. return data, nil
  945. }
  946. func (self *SElasticcache) PerformUpdateAuthMode(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  947. data, err := self.ValidatorUpdateAuthModeData(ctx, userCred, query, data)
  948. if err != nil {
  949. return nil, err
  950. }
  951. params := jsonutils.NewDict()
  952. authMode, _ := data.GetString("auth_mode")
  953. params.Set("auth_mode", jsonutils.NewString(authMode))
  954. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  955. return nil, self.StartUpdateAuthModeTask(ctx, userCred, params, "")
  956. }
  957. func (self *SElasticcache) StartUpdateAuthModeTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  958. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateAuthModeTask", self, userCred, params, parentTaskId, "", nil)
  959. if err != nil {
  960. return err
  961. }
  962. task.ScheduleRun(nil)
  963. return nil
  964. }
  965. func (self *SElasticcache) ValidatorResetPasswordData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  966. if reset, _ := data.Bool("reset_password"); reset {
  967. if _, err := data.GetString("password"); err != nil {
  968. randomPasswd := seclib2.RandomPassword2(12)
  969. data.(*jsonutils.JSONDict).Set("password", jsonutils.NewString(randomPasswd))
  970. }
  971. }
  972. if password, err := data.GetString("password"); err != nil || len(password) == 0 {
  973. return nil, httperrors.NewMissingParameterError("password")
  974. } else {
  975. err := seclib2.ValidatePassword(password)
  976. if err != nil {
  977. return nil, err
  978. }
  979. }
  980. return data, nil
  981. }
  982. func (self *SElasticcache) PerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  983. data, err := self.ValidatorResetPasswordData(ctx, userCred, query, data)
  984. if err != nil {
  985. return nil, err
  986. }
  987. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  988. return nil, self.StartResetPasswordTask(ctx, userCred, data.(*jsonutils.JSONDict), "")
  989. }
  990. func (self *SElasticcache) GetAdminAccount() (*SElasticcacheAccount, error) {
  991. accounts, err := self.GetElasticcacheAccounts()
  992. if err != nil {
  993. return nil, err
  994. }
  995. for i := range accounts {
  996. if accounts[i].AccountType == api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN {
  997. return &accounts[i], nil
  998. }
  999. }
  1000. return nil, httperrors.NewNotFoundError("no admin account found for elastic cache %s", self.Id)
  1001. }
  1002. func (self *SElasticcache) StartResetPasswordTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1003. account, err := self.GetAdminAccount()
  1004. if err != nil {
  1005. return err
  1006. }
  1007. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAccountResetPasswordTask", account, userCred, params, parentTaskId, "", nil)
  1008. if err != nil {
  1009. return err
  1010. }
  1011. task.ScheduleRun(nil)
  1012. return nil
  1013. }
  1014. func (self *SElasticcache) ValidatorSetMaintainTimeData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1015. timeReg, _ := regexp.Compile("^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z$")
  1016. startTimeV := validators.NewRegexpValidator("maintain_start_time", timeReg)
  1017. endTimeV := validators.NewRegexpValidator("maintain_end_time", timeReg)
  1018. keyV := map[string]validators.IValidator{
  1019. "maintain_start_time": startTimeV.Optional(false),
  1020. "maintain_end_time": endTimeV.Optional(false),
  1021. }
  1022. for _, v := range keyV {
  1023. if err := v.Validate(ctx, data.(*jsonutils.JSONDict)); err != nil {
  1024. return nil, err
  1025. }
  1026. }
  1027. if startTimeV.Value == self.MaintainStartTime && endTimeV.Value == self.MaintainEndTime {
  1028. return nil, httperrors.NewInputParameterError("maintain time has no change")
  1029. }
  1030. return data, nil
  1031. }
  1032. func (self *SElasticcache) PerformSetMaintainTime(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1033. data, err := self.ValidatorSetMaintainTimeData(ctx, userCred, query, data)
  1034. if err != nil {
  1035. return nil, err
  1036. }
  1037. params := jsonutils.NewDict()
  1038. startTime, _ := data.GetString("maintain_start_time")
  1039. endTime, _ := data.GetString("maintain_end_time")
  1040. params.Set("maintain_start_time", jsonutils.NewString(startTime))
  1041. params.Set("maintain_end_time", jsonutils.NewString(endTime))
  1042. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  1043. return nil, self.StartSetMaintainTimeTask(ctx, userCred, params, "")
  1044. }
  1045. func (self *SElasticcache) StartSetMaintainTimeTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1046. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSetMaintainTimeTask", self, userCred, params, parentTaskId, "", nil)
  1047. if err != nil {
  1048. return err
  1049. }
  1050. task.ScheduleRun(nil)
  1051. return nil
  1052. }
  1053. func (self *SElasticcache) ValidatorAllocatePublicConnectionData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1054. if self.PublicDNS != "" || self.PublicIpAddr != "" {
  1055. return nil, httperrors.NewConflictError("public connection aready allocated")
  1056. }
  1057. portV := validators.NewRangeValidator("port", 1024, 65535)
  1058. portV.Default(6379).Optional(true)
  1059. if err := portV.Validate(ctx, data.(*jsonutils.JSONDict)); err != nil {
  1060. return nil, err
  1061. }
  1062. return data, nil
  1063. }
  1064. func (self *SElasticcache) PerformAllocatePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1065. data, err := self.ValidatorAllocatePublicConnectionData(ctx, userCred, query, data)
  1066. if err != nil {
  1067. return nil, err
  1068. }
  1069. params := jsonutils.NewDict()
  1070. port, _ := data.Int("port")
  1071. params.Set("port", jsonutils.NewInt(port))
  1072. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING, "")
  1073. return nil, self.StartAllocatePublicConnectionTask(ctx, userCred, params, "")
  1074. }
  1075. func (self *SElasticcache) StartAllocatePublicConnectionTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1076. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheAllocatePublicConnectionTask", self, userCred, params, parentTaskId, "", nil)
  1077. if err != nil {
  1078. return err
  1079. }
  1080. task.ScheduleRun(nil)
  1081. return nil
  1082. }
  1083. func (self *SElasticcache) ValidatorReleasePublicConnectionData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1084. if self.PublicIpAddr == "" && self.PublicDNS == "" {
  1085. return nil, httperrors.NewConflictError("release public connection aready released")
  1086. }
  1087. return data, nil
  1088. }
  1089. func (self *SElasticcache) PerformReleasePublicConnection(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1090. data, err := self.ValidatorReleasePublicConnectionData(ctx, userCred, query, data)
  1091. if err != nil {
  1092. return nil, err
  1093. }
  1094. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING, "")
  1095. return nil, self.StartReleasePublicConnectionTask(ctx, userCred, jsonutils.NewDict(), "")
  1096. }
  1097. func (self *SElasticcache) StartReleasePublicConnectionTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1098. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheReleasePublicConnectionTask", self, userCred, params, parentTaskId, "", nil)
  1099. if err != nil {
  1100. return err
  1101. }
  1102. task.ScheduleRun(nil)
  1103. return nil
  1104. }
  1105. func (self *SElasticcache) PerformFlushInstance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1106. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_FLUSHING, "")
  1107. return nil, self.StartFlushInstanceTask(ctx, userCred, data.(*jsonutils.JSONDict), "")
  1108. }
  1109. func (self *SElasticcache) StartFlushInstanceTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1110. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheFlushInstanceTask", self, userCred, params, parentTaskId, "", nil)
  1111. if err != nil {
  1112. return err
  1113. }
  1114. task.ScheduleRun(nil)
  1115. return nil
  1116. }
  1117. func (self *SElasticcache) ValidatorUpdateInstanceParametersData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1118. parameters, err := data.Get("parameters")
  1119. if err != nil {
  1120. return nil, httperrors.NewMissingParameterError("parameters")
  1121. }
  1122. _, ok := parameters.(*jsonutils.JSONDict)
  1123. if !ok {
  1124. return nil, httperrors.NewInputParameterError("invalid parameter format. json dict required")
  1125. }
  1126. return data, nil
  1127. }
  1128. func (self *SElasticcache) PerformUpdateInstanceParameters(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1129. data, err := self.ValidatorUpdateInstanceParametersData(ctx, userCred, query, data)
  1130. if err != nil {
  1131. return nil, err
  1132. }
  1133. params := jsonutils.NewDict()
  1134. parameters, _ := data.Get("parameters")
  1135. params.Set("parameters", parameters)
  1136. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  1137. return nil, self.StartUpdateInstanceParametersTask(ctx, userCred, params, "")
  1138. }
  1139. func (self *SElasticcache) StartUpdateInstanceParametersTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1140. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateInstanceParametersTask", self, userCred, params, parentTaskId, "", nil)
  1141. if err != nil {
  1142. return err
  1143. }
  1144. task.ScheduleRun(nil)
  1145. return nil
  1146. }
  1147. func (self *SElasticcache) ValidatorUpdateBackupPolicyData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1148. timeReg, _ := regexp.Compile("^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z-(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]Z$")
  1149. backupTypeV := validators.NewStringChoicesValidator("backup_type", choices.NewChoices(api.BACKUP_MODE_AUTOMATED, api.ELASTIC_CACHE_BACKUP_MODE_MANUAL))
  1150. BackupReservedDaysV := validators.NewRangeValidator("backup_reserved_days", 1, 7).Default(7)
  1151. PreferredBackupPeriodV := validators.NewStringChoicesValidator("preferred_backup_period", choices.NewChoices("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
  1152. PreferredBackupTimeV := validators.NewRegexpValidator("preferred_backup_time", timeReg)
  1153. keyV := map[string]validators.IValidator{
  1154. "backup_type": backupTypeV.Optional(true),
  1155. "backup_reserved_days": BackupReservedDaysV.Optional(true),
  1156. "preferred_backup_period": PreferredBackupPeriodV.Optional(false),
  1157. "preferred_backup_time": PreferredBackupTimeV.Optional(false),
  1158. }
  1159. for _, v := range keyV {
  1160. if err := v.Validate(ctx, data.(*jsonutils.JSONDict)); err != nil {
  1161. return nil, err
  1162. }
  1163. }
  1164. return data, nil
  1165. }
  1166. func (self *SElasticcache) PerformUpdateBackupPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1167. data, err := self.ValidatorUpdateBackupPolicyData(ctx, userCred, query, data)
  1168. if err != nil {
  1169. return nil, err
  1170. }
  1171. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_CHANGING, "")
  1172. return nil, self.StartUpdateBackupPolicyTask(ctx, userCred, data.(*jsonutils.JSONDict), "")
  1173. }
  1174. func (self *SElasticcache) StartUpdateBackupPolicyTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1175. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheUpdateBackupPolicyTask", self, userCred, params, parentTaskId, "", nil)
  1176. if err != nil {
  1177. return err
  1178. }
  1179. task.ScheduleRun(nil)
  1180. return nil
  1181. }
  1182. // 同步弹性缓存状态
  1183. func (self *SElasticcache) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheSyncstatusInput) (jsonutils.JSONObject, error) {
  1184. var openTask = true
  1185. count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  1186. if err != nil {
  1187. return nil, err
  1188. }
  1189. if count > 0 {
  1190. return nil, httperrors.NewBadRequestError("Elasticcache has %d task active, can't sync status", count)
  1191. }
  1192. return nil, StartResourceSyncStatusTask(ctx, userCred, self, "ElasticcacheSyncstatusTask", "")
  1193. }
  1194. func (self *SElasticcache) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1195. return nil, self.StartSyncTask(ctx, userCred, data.(*jsonutils.JSONDict), "")
  1196. }
  1197. func (self *SElasticcache) StartSyncTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1198. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_SYNCING, "")
  1199. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSyncTask", self, userCred, params, parentTaskId, "", nil)
  1200. if err != nil {
  1201. return err
  1202. }
  1203. task.ScheduleRun(nil)
  1204. return nil
  1205. }
  1206. // 清理所有关联资源记录
  1207. func (self *SElasticcache) DeleteSubResources(ctx context.Context, userCred mcclient.TokenCredential) error {
  1208. ms := []db.IResourceModelManager{
  1209. ElasticcachesecgroupManager,
  1210. ElasticcacheAccountManager,
  1211. ElasticcacheAclManager,
  1212. ElasticcacheBackupManager,
  1213. ElasticcacheParameterManager,
  1214. }
  1215. ownerId := self.GetOwnerId()
  1216. delFunc := func(man db.IResourceModelManager) error {
  1217. lockman.LockClass(ctx, man, db.GetLockClassKey(man, ownerId))
  1218. defer lockman.ReleaseClass(ctx, man, db.GetLockClassKey(man, ownerId))
  1219. q := man.Query().IsFalse("deleted").Equals("elasticcache_id", self.GetId())
  1220. models := make([]interface{}, 0)
  1221. err := db.FetchModelObjects(man, q, &models)
  1222. if err != nil {
  1223. return errors.Wrapf(err, "db.FetchModelObjects")
  1224. }
  1225. for i := range models {
  1226. var imodel db.IModel
  1227. switch models[i].(type) {
  1228. case SElasticcachesecgroup:
  1229. _m := models[i].(SElasticcachesecgroup)
  1230. imodel = &_m
  1231. case SElasticcacheAccount:
  1232. _m := models[i].(SElasticcacheAccount)
  1233. imodel = &_m
  1234. case SElasticcacheAcl:
  1235. _m := models[i].(SElasticcacheAcl)
  1236. imodel = &_m
  1237. case SElasticcacheBackup:
  1238. _m := models[i].(SElasticcacheBackup)
  1239. imodel = &_m
  1240. case SElasticcacheParameter:
  1241. _m := models[i].(SElasticcacheParameter)
  1242. imodel = &_m
  1243. default:
  1244. log.Errorf("elasticcache.DeleteSubResources.UnknownModelType %s", models[i])
  1245. }
  1246. err = db.DeleteModel(ctx, userCred, imodel)
  1247. if err != nil {
  1248. return errors.Wrapf(err, "db.DeleteModel")
  1249. }
  1250. }
  1251. return nil
  1252. }
  1253. for i := range ms {
  1254. err := delFunc(ms[i])
  1255. if err != nil {
  1256. return errors.Wrapf(err, "delFunc")
  1257. }
  1258. }
  1259. return nil
  1260. }
  1261. func (man *SElasticcacheManager) TotalCount(
  1262. ctx context.Context,
  1263. scope rbacscope.TRbacScope,
  1264. ownerId mcclient.IIdentityProvider,
  1265. rangeObjs []db.IStandaloneModel,
  1266. providers []string, brands []string, cloudEnv string,
  1267. policyResult rbacutils.SPolicyResult,
  1268. ) (int, error) {
  1269. q := man.Query()
  1270. q = db.ObjectIdQueryWithPolicyResult(ctx, q, man, policyResult)
  1271. vpcs := VpcManager.Query().SubQuery()
  1272. q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id")))
  1273. q = scopeOwnerIdFilter(q, scope, ownerId)
  1274. q = CloudProviderFilter(q, vpcs.Field("manager_id"), providers, brands, cloudEnv)
  1275. q = RangeObjectsFilter(q, rangeObjs, vpcs.Field("cloudregion_id"), nil, vpcs.Field("manager_id"), nil, nil)
  1276. return q.CountWithError()
  1277. }
  1278. func (cache *SElasticcache) GetQuotaKeys() quotas.IQuotaKeys {
  1279. region, _ := cache.GetRegion()
  1280. return fetchRegionalQuotaKeys(
  1281. rbacscope.ScopeProject,
  1282. cache.GetOwnerId(),
  1283. region,
  1284. cache.GetCloudprovider(),
  1285. )
  1286. }
  1287. func (cache *SElasticcache) GetUsages() []db.IUsage {
  1288. if cache.PendingDeleted || cache.Deleted {
  1289. return nil
  1290. }
  1291. usage := SRegionQuota{Cache: 1}
  1292. keys := cache.GetQuotaKeys()
  1293. usage.SetKeys(keys)
  1294. return []db.IUsage{
  1295. &usage,
  1296. }
  1297. }
  1298. func (manager *SElasticcacheManager) ListItemExportKeys(ctx context.Context,
  1299. q *sqlchemy.SQuery,
  1300. userCred mcclient.TokenCredential,
  1301. keys stringutils2.SSortedStrings,
  1302. ) (*sqlchemy.SQuery, error) {
  1303. var err error
  1304. q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1305. if err != nil {
  1306. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
  1307. }
  1308. if keys.ContainsAny(manager.SVpcResourceBaseManager.GetExportKeys()...) {
  1309. q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1310. if err != nil {
  1311. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys")
  1312. }
  1313. }
  1314. if keys.Contains("zone") {
  1315. q, err = manager.SZoneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"zone"}))
  1316. if err != nil {
  1317. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemExportKeys")
  1318. }
  1319. }
  1320. if keys.ContainsAny("network", "wire") {
  1321. q, err = manager.SNetworkResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"network", "wire"}))
  1322. if err != nil {
  1323. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemExportKeys")
  1324. }
  1325. }
  1326. return q, nil
  1327. }
  1328. func (manager *SElasticcacheManager) getExpiredPostpaids() []SElasticcache {
  1329. q := ListExpiredPostpaidResources(manager.Query(), options.Options.ExpiredPrepaidMaxCleanBatchSize)
  1330. q = q.IsFalse("pending_deleted")
  1331. ecs := make([]SElasticcache, 0)
  1332. err := db.FetchModelObjects(ElasticcacheManager, q, &ecs)
  1333. if err != nil {
  1334. log.Errorf("fetch elasitc cache instances error %s", err)
  1335. return nil
  1336. }
  1337. return ecs
  1338. }
  1339. func (cache *SElasticcache) SetDisableDelete(userCred mcclient.TokenCredential, val bool) error {
  1340. diff, err := db.Update(cache, func() error {
  1341. if val {
  1342. cache.DisableDelete = tristate.True
  1343. } else {
  1344. cache.DisableDelete = tristate.False
  1345. }
  1346. return nil
  1347. })
  1348. if err != nil {
  1349. return err
  1350. }
  1351. db.OpsLog.LogEvent(cache, db.ACT_UPDATE, diff, userCred)
  1352. logclient.AddSimpleActionLog(cache, logclient.ACT_UPDATE, diff, userCred, true)
  1353. return err
  1354. }
  1355. func (self *SElasticcache) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  1356. region, err := self.GetRegion()
  1357. if err != nil {
  1358. return nil, err
  1359. }
  1360. provider, err := self.GetDriver(ctx)
  1361. if err != nil {
  1362. return nil, errors.Wrap(err, "self.GetDriver")
  1363. }
  1364. return provider.GetIRegionById(region.GetExternalId())
  1365. }
  1366. func (self *SElasticcache) doExternalSync(ctx context.Context, userCred mcclient.TokenCredential) error {
  1367. provider := self.GetCloudprovider()
  1368. if provider != nil {
  1369. return fmt.Errorf("no cloud provider???")
  1370. }
  1371. iregion, err := self.GetIRegion(ctx)
  1372. if err != nil || iregion == nil {
  1373. return fmt.Errorf("no cloud region??? %s", err)
  1374. }
  1375. iecs, err := iregion.GetIElasticcacheById(self.ExternalId)
  1376. if err != nil {
  1377. return err
  1378. }
  1379. return self.SyncWithCloudElasticcache(ctx, userCred, provider, iecs)
  1380. }
  1381. func (self *SElasticcache) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1382. return nil
  1383. }
  1384. func (self *SElasticcache) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  1385. err := self.DeleteSubResources(ctx, userCred)
  1386. if err != nil {
  1387. return err
  1388. }
  1389. return self.SVirtualResourceBase.Delete(ctx, userCred)
  1390. }
  1391. func (manager *SElasticcacheManager) DeleteExpiredPostpaids(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  1392. ecs := manager.getExpiredPostpaids()
  1393. if ecs == nil {
  1394. return
  1395. }
  1396. for i := 0; i < len(ecs); i += 1 {
  1397. if len(ecs[i].ExternalId) > 0 {
  1398. err := ecs[i].doExternalSync(ctx, userCred)
  1399. if err == nil && ecs[i].IsValidPrePaid() {
  1400. continue
  1401. }
  1402. }
  1403. ecs[i].SetDisableDelete(userCred, false)
  1404. ecs[i].StartDeleteElasticcacheTask(ctx, userCred, jsonutils.NewDict(), "")
  1405. }
  1406. }
  1407. func (self *SElasticcache) PerformPostpaidExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PostpaidExpireInput) (jsonutils.JSONObject, error) {
  1408. if self.BillingType != billing_api.BILLING_TYPE_POSTPAID {
  1409. return nil, httperrors.NewBadRequestError("elasticcache billing type is %s", self.BillingType)
  1410. }
  1411. releaseAt, err := input.GetReleaseAt()
  1412. if err != nil {
  1413. return nil, err
  1414. }
  1415. err = SaveReleaseAt(ctx, self, userCred, releaseAt)
  1416. return nil, err
  1417. }
  1418. func (self *SElasticcache) PerformCancelExpire(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1419. err := SaveReleaseAt(ctx, self, userCred, time.Time{})
  1420. if err != nil {
  1421. return nil, err
  1422. }
  1423. return nil, nil
  1424. }
  1425. func (self *SElasticcache) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheRemoteUpdateInput) (jsonutils.JSONObject, error) {
  1426. err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "")
  1427. if err != nil {
  1428. return nil, errors.Wrap(err, "StartRemoteUpdateTask")
  1429. }
  1430. return nil, nil
  1431. }
  1432. func (self *SElasticcache) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
  1433. data := jsonutils.NewDict()
  1434. if replaceTags {
  1435. data.Add(jsonutils.JSONTrue, "replace_tags")
  1436. }
  1437. if task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil); err != nil {
  1438. log.Errorln(err)
  1439. return errors.Wrap(err, "Start ElasticcacheRemoteUpdateTask")
  1440. } else {
  1441. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_UPDATE_TAGS, "StartRemoteUpdateTask")
  1442. task.ScheduleRun(nil)
  1443. }
  1444. return nil
  1445. }
  1446. func (self *SElasticcache) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  1447. if len(self.ExternalId) == 0 || options.Options.KeepTagLocalization {
  1448. return
  1449. }
  1450. if account := self.GetCloudaccount(); account != nil && account.ReadOnly {
  1451. return
  1452. }
  1453. err := self.StartRemoteUpdateTask(ctx, userCred, true, "")
  1454. if err != nil {
  1455. log.Errorf("StartRemoteUpdateTask fail: %s", err)
  1456. }
  1457. }
  1458. func (self *SElasticcache) GetVpc() (*SVpc, error) {
  1459. if len(self.VpcId) == 0 {
  1460. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty vpc id")
  1461. }
  1462. vpc, err := VpcManager.FetchById(self.VpcId)
  1463. if err != nil {
  1464. return nil, errors.Wrapf(err, "FetchById %s", self.VpcId)
  1465. }
  1466. return vpc.(*SVpc), nil
  1467. }
  1468. func (self *SElasticcache) getSecgroupsBySecgroupExternalIds(externalIds []string) ([]SSecurityGroup, error) {
  1469. vpc, err := self.GetVpc()
  1470. if err != nil {
  1471. return nil, errors.Wrapf(err, "GetVpc")
  1472. }
  1473. region, err := vpc.GetRegion()
  1474. if err != nil {
  1475. return nil, errors.Wrapf(err, "GetRegion")
  1476. }
  1477. filter, err := region.GetDriver().GetSecurityGroupFilter(vpc)
  1478. if err != nil {
  1479. return nil, errors.Wrapf(err, "GetSecurityGroupFilter")
  1480. }
  1481. q := SecurityGroupManager.Query().In("external_id", externalIds)
  1482. q = filter(q)
  1483. secgroups := []SSecurityGroup{}
  1484. err = db.FetchModelObjects(SecurityGroupManager, q, &secgroups)
  1485. if err != nil {
  1486. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1487. }
  1488. return secgroups, nil
  1489. }
  1490. func (self *SElasticcache) GetElasticcacheSecgroups() ([]SElasticcachesecgroup, error) {
  1491. ess := []SElasticcachesecgroup{}
  1492. q := ElasticcachesecgroupManager.Query().Equals("elasticcache_id", self.Id)
  1493. err := db.FetchModelObjects(ElasticcachesecgroupManager, q, &ess)
  1494. if err != nil {
  1495. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1496. }
  1497. return ess, nil
  1498. }
  1499. func (self *SElasticcache) GetSecgroups() ([]SSecurityGroup, error) {
  1500. ret := []SSecurityGroup{}
  1501. sq := ElasticcachesecgroupManager.Query("secgroup_id").Equals("elasticcache_id", self.Id)
  1502. q := SecurityGroupManager.Query().In("id", sq.SubQuery())
  1503. err := db.FetchModelObjects(SecurityGroupManager, q, &ret)
  1504. if err != nil {
  1505. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  1506. }
  1507. return ret, nil
  1508. }
  1509. func (self *SElasticcache) validateSecgroupInput(secgroups []string) error {
  1510. if !utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING, api.ELASTIC_CACHE_STATUS_DEPLOYING}) {
  1511. return httperrors.NewInputParameterError("Cannot add security groups in status %s", self.Status)
  1512. }
  1513. region, _ := self.GetRegion()
  1514. if region == nil {
  1515. return httperrors.NewNotFoundError("region")
  1516. }
  1517. driver := region.GetDriver()
  1518. if driver == nil {
  1519. return httperrors.NewNotFoundError("regiondriver")
  1520. }
  1521. maxCount := driver.GetMaxElasticcacheSecurityGroupCount()
  1522. if !driver.IsSupportedElasticcacheSecgroup() || maxCount == 0 {
  1523. return httperrors.NewNotSupportedError("not supported bind security group")
  1524. }
  1525. if len(secgroups) > maxCount {
  1526. return httperrors.NewOutOfLimitError("beyond security group quantity limit, max items %d.", maxCount)
  1527. }
  1528. return nil
  1529. }
  1530. func (self *SElasticcache) checkingSecgroupIds(ctx context.Context, userCred mcclient.TokenCredential, secgroupIds []string) ([]string, error) {
  1531. for i := range secgroupIds {
  1532. _, err := validators.ValidateModel(ctx, userCred, SecurityGroupManager, &secgroupIds[i])
  1533. if err != nil {
  1534. return nil, err
  1535. }
  1536. }
  1537. return secgroupIds, nil
  1538. }
  1539. // 返回 本次更新后secgroup id的全集、本次更增的secgroup id, 本次删除的secgroup id, error
  1540. func (self *SElasticcache) cleanSecgroupIds(action string, secgroupIds []string) ([]string, []string, []string, error) {
  1541. ess, err := self.GetElasticcacheSecgroups()
  1542. if err != nil {
  1543. return nil, nil, nil, errors.Wrap(err, "GetElasticcacheSecgroups")
  1544. }
  1545. currentIds := make([]string, len(ess))
  1546. for i := range ess {
  1547. currentIds[i] = ess[i].SecgroupId
  1548. }
  1549. all := []string{}
  1550. adds := []string{}
  1551. removes := []string{}
  1552. switch action {
  1553. case "add":
  1554. all = currentIds
  1555. for i := range secgroupIds {
  1556. if !utils.IsInStringArray(secgroupIds[i], currentIds) && !utils.IsInStringArray(secgroupIds[i], adds) {
  1557. adds = append(adds, secgroupIds[i])
  1558. all = append(all, secgroupIds[i])
  1559. }
  1560. }
  1561. case "revoke":
  1562. for i := range secgroupIds {
  1563. if utils.IsInStringArray(secgroupIds[i], currentIds) && !utils.IsInStringArray(secgroupIds[i], adds) {
  1564. removes = append(removes, secgroupIds[i])
  1565. }
  1566. }
  1567. for i := range currentIds {
  1568. if !utils.IsInStringArray(currentIds[i], removes) {
  1569. all = append(all, currentIds[i])
  1570. }
  1571. }
  1572. case "set":
  1573. for i := range secgroupIds {
  1574. if !utils.IsInStringArray(secgroupIds[i], all) {
  1575. all = append(all, secgroupIds[i])
  1576. }
  1577. }
  1578. for i := range currentIds {
  1579. if !utils.IsInStringArray(currentIds[i], all) {
  1580. removes = append(removes, currentIds[i])
  1581. }
  1582. }
  1583. for i := range all {
  1584. if !utils.IsInStringArray(all[i], currentIds) {
  1585. adds = append(adds, all[i])
  1586. }
  1587. }
  1588. default:
  1589. return nil, nil, nil, fmt.Errorf("not supported cleanSecgroupIds action %s", action)
  1590. }
  1591. return all, adds, removes, nil
  1592. }
  1593. func (self *SElasticcache) addSecgroup(ctx context.Context, userCred mcclient.TokenCredential, secgroupId string) error {
  1594. es := &SElasticcachesecgroup{}
  1595. es.SetModelManager(GuestsecgroupManager, es)
  1596. es.ElasticcacheId = self.Id
  1597. es.SecgroupId = secgroupId
  1598. err := ElasticcachesecgroupManager.TableSpec().Insert(ctx, es)
  1599. if err != nil {
  1600. return errors.Wrap(err, "ElasticcachesecgroupManager.Insert")
  1601. }
  1602. return nil
  1603. }
  1604. func (self *SElasticcache) removeSecgroup(ctx context.Context, userCred mcclient.TokenCredential, secgroupId string) error {
  1605. q := ElasticcachesecgroupManager.Query().Equals("secgroup_id", secgroupId).Equals("elasticcache_id", self.GetId())
  1606. ret := []SElasticcachesecgroup{}
  1607. err := db.FetchModelObjects(ElasticcachesecgroupManager, q, &ret)
  1608. if err != nil {
  1609. if errors.Cause(err) != sql.ErrNoRows {
  1610. return errors.Wrap(err, "FetchModelObjects")
  1611. } else {
  1612. return nil
  1613. }
  1614. }
  1615. for i := range ret {
  1616. err = ret[i].Delete(ctx, userCred)
  1617. if err != nil {
  1618. return errors.Wrapf(err, "Delete elasticcache %s secgroup %s", self.Name, secgroupId)
  1619. }
  1620. }
  1621. return nil
  1622. }
  1623. func (self *SElasticcache) saveSecgroups(ctx context.Context, userCred mcclient.TokenCredential, adds []string, removes []string) compare.SyncResult {
  1624. saveResult := compare.SyncResult{}
  1625. for i := range adds {
  1626. err := self.addSecgroup(ctx, userCred, adds[i])
  1627. if err != nil {
  1628. saveResult.Error(errors.Wrap(err, "addSecgroup"))
  1629. return saveResult
  1630. } else {
  1631. saveResult.Add()
  1632. }
  1633. }
  1634. for i := range removes {
  1635. err := self.removeSecgroup(ctx, userCred, removes[i])
  1636. if err != nil {
  1637. saveResult.Error(errors.Wrap(err, "removeSecgroup"))
  1638. return saveResult
  1639. } else {
  1640. saveResult.Delete()
  1641. }
  1642. }
  1643. return saveResult
  1644. }
  1645. func (self *SElasticcache) ProcessElasticcacheSecgroupsInput(ctx context.Context, userCred mcclient.TokenCredential, action string, input *api.ElasticcacheSecgroupsInput) ([]string, error) {
  1646. all, adds, removes, err := self.cleanSecgroupIds(action, input.SecgroupIds)
  1647. if err != nil {
  1648. return nil, httperrors.NewGeneralError(err)
  1649. }
  1650. if len(all) == 0 {
  1651. return nil, httperrors.NewInputParameterError("secgroups will be empty after update.")
  1652. }
  1653. switch action {
  1654. case "add":
  1655. input.SecgroupIds = adds
  1656. case "revoke":
  1657. input.SecgroupIds = removes
  1658. case "set":
  1659. input.SecgroupIds = all
  1660. }
  1661. err = self.validateSecgroupInput(all)
  1662. if err != nil {
  1663. return nil, err
  1664. }
  1665. names, err := self.checkingSecgroupIds(ctx, userCred, input.SecgroupIds)
  1666. if err != nil {
  1667. return nil, err
  1668. }
  1669. result := self.saveSecgroups(ctx, userCred, adds, removes)
  1670. if result.IsError() {
  1671. return nil, result.AllError()
  1672. }
  1673. return names, nil
  1674. }
  1675. func (self *SElasticcache) SyncSecgroup(ctx context.Context, userCred mcclient.TokenCredential, action string, input api.ElasticcacheSecgroupsInput) (jsonutils.JSONObject, error) {
  1676. names, err := self.ProcessElasticcacheSecgroupsInput(ctx, userCred, action, &input)
  1677. if err != nil {
  1678. return nil, err
  1679. }
  1680. logclient.AddActionLogWithContext(ctx, self, logclient.ACT_SYNC_CONF, names, userCred, true)
  1681. return nil, self.StartSyncSecgroupsTask(ctx, userCred, nil, "")
  1682. }
  1683. func (self *SElasticcache) PerformAddSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheSecgroupsInput) (jsonutils.JSONObject, error) {
  1684. return self.SyncSecgroup(ctx, userCred, "add", input)
  1685. }
  1686. func (self *SElasticcache) PerformRevokeSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheSecgroupsInput) (jsonutils.JSONObject, error) {
  1687. return self.SyncSecgroup(ctx, userCred, "revoke", input)
  1688. }
  1689. func (self *SElasticcache) PerformSetSecgroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ElasticcacheSecgroupsInput) (jsonutils.JSONObject, error) {
  1690. return self.SyncSecgroup(ctx, userCred, "set", input)
  1691. }
  1692. func (self *SElasticcache) SyncElasticcacheSecgroups(ctx context.Context, userCred mcclient.TokenCredential, externalIds []string) compare.SyncResult {
  1693. syncResult := compare.SyncResult{}
  1694. secgroups, err := self.getSecgroupsBySecgroupExternalIds(externalIds)
  1695. if err != nil {
  1696. syncResult.Error(err)
  1697. return syncResult
  1698. }
  1699. secgroupIds := []string{}
  1700. for _, secgroup := range secgroups {
  1701. secgroupIds = append(secgroupIds, secgroup.Id)
  1702. }
  1703. _, adds, removes, err := self.cleanSecgroupIds("set", secgroupIds)
  1704. if err != nil {
  1705. syncResult.Error(err)
  1706. return syncResult
  1707. }
  1708. return self.saveSecgroups(ctx, userCred, adds, removes)
  1709. }
  1710. func (self *SElasticcache) StartSyncSecgroupsTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  1711. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_STATUS_SYNCING, "")
  1712. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSyncsecgroupsTask", self, userCred, params, parentTaskId, "", nil)
  1713. if err != nil {
  1714. return err
  1715. }
  1716. task.ScheduleRun(nil)
  1717. return nil
  1718. }
  1719. func (self *SElasticcache) SetAutoRenew(autoRenew bool) error {
  1720. _, err := db.Update(self, func() error {
  1721. self.AutoRenew = autoRenew
  1722. return nil
  1723. })
  1724. return err
  1725. }
  1726. /*
  1727. 设置自动续费
  1728. 要求实例状态为running
  1729. 要求实例计费类型为包年包月(预付费)
  1730. */
  1731. func (self *SElasticcache) PerformSetAutoRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.GuestAutoRenewInput) (jsonutils.JSONObject, error) {
  1732. if !utils.IsInStringArray(self.Status, []string{api.ELASTIC_CACHE_STATUS_RUNNING}) {
  1733. return nil, httperrors.NewUnsupportOperationError("The elastic cache status need be %s, current is %s", api.ELASTIC_CACHE_STATUS_RUNNING, self.Status)
  1734. }
  1735. if self.BillingType != billing_api.BILLING_TYPE_PREPAID {
  1736. return nil, httperrors.NewUnsupportOperationError("Only %s elastic cache support set auto renew operation", billing_api.BILLING_TYPE_PREPAID)
  1737. }
  1738. if self.AutoRenew == input.AutoRenew {
  1739. return nil, nil
  1740. }
  1741. region, _ := self.GetRegion()
  1742. if region == nil {
  1743. return nil, httperrors.NewResourceNotFoundError("elastic cache no related region found")
  1744. }
  1745. if !region.GetDriver().IsSupportedElasticcacheAutoRenew() {
  1746. err := self.SetAutoRenew(input.AutoRenew)
  1747. if err != nil {
  1748. return nil, httperrors.NewGeneralError(err)
  1749. }
  1750. logclient.AddSimpleActionLog(self, logclient.ACT_SET_AUTO_RENEW, jsonutils.Marshal(input), userCred, true)
  1751. return nil, nil
  1752. }
  1753. return nil, self.StartSetAutoRenewTask(ctx, userCred, input.AutoRenew, "")
  1754. }
  1755. func (self *SElasticcache) StartSetAutoRenewTask(ctx context.Context, userCred mcclient.TokenCredential, autoRenew bool, parentTaskId string) error {
  1756. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_SET_AUTO_RENEW, "")
  1757. data := jsonutils.NewDict()
  1758. data.Set("auto_renew", jsonutils.NewBool(autoRenew))
  1759. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheSetAutoRenewTask", self, userCred, data, parentTaskId, "", nil)
  1760. if err != nil {
  1761. return errors.Wrap(err, "ElasticcacheSetAutoRenewTask")
  1762. }
  1763. task.ScheduleRun(nil)
  1764. return nil
  1765. }
  1766. func (self *SElasticcache) PerformRenew(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  1767. if self.BillingType != billing_api.BILLING_TYPE_PREPAID {
  1768. return nil, httperrors.NewUnsupportOperationError("Only %s elastic cache support renew operation", billing_api.BILLING_TYPE_PREPAID)
  1769. }
  1770. durationStr, _ := data.GetString("duration")
  1771. if len(durationStr) == 0 {
  1772. return nil, httperrors.NewInputParameterError("missong duration")
  1773. }
  1774. bc, err := bc.ParseBillingCycle(durationStr)
  1775. if err != nil {
  1776. return nil, httperrors.NewInputParameterError("invalid duration %s: %s", durationStr, err)
  1777. }
  1778. region, _ := self.GetRegion()
  1779. if region == nil {
  1780. return nil, httperrors.NewResourceNotFoundError("elastic cache no related region found")
  1781. }
  1782. if !region.GetDriver().IsSupportedBillingCycle(bc, self.KeywordPlural()) {
  1783. return nil, httperrors.NewInputParameterError("unsupported duration %s", durationStr)
  1784. }
  1785. err = self.startRenewTask(ctx, userCred, durationStr, "")
  1786. if err != nil {
  1787. return nil, err
  1788. }
  1789. return nil, nil
  1790. }
  1791. func (self *SElasticcache) startRenewTask(ctx context.Context, userCred mcclient.TokenCredential, duration string, parentTaskId string) error {
  1792. self.SetStatus(ctx, userCred, api.ELASTIC_CACHE_RENEWING, "")
  1793. data := jsonutils.NewDict()
  1794. data.Add(jsonutils.NewString(duration), "duration")
  1795. task, err := taskman.TaskManager.NewTask(ctx, "ElasticcacheRenewTask", self, userCred, data, parentTaskId, "", nil)
  1796. if err != nil {
  1797. log.Errorf("fail to crate ElasticcacheRenewTask %s", err)
  1798. return err
  1799. }
  1800. task.ScheduleRun(nil)
  1801. return nil
  1802. }
  1803. func (manager *SElasticcacheManager) GetExpiredModels(advanceDay int) ([]IBillingModel, error) {
  1804. return fetchExpiredModels(manager, advanceDay)
  1805. }
  1806. func (self *SElasticcache) GetExpiredAt() time.Time {
  1807. return self.ExpiredAt
  1808. }
  1809. func (cache *SElasticcache) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  1810. desc := cache.SVirtualResourceBase.GetShortDesc(ctx)
  1811. region, _ := cache.GetRegion()
  1812. provider := cache.GetCloudprovider()
  1813. info := MakeCloudProviderInfo(region, nil, provider)
  1814. desc.Set("engine", jsonutils.NewString(cache.Engine))
  1815. desc.Set("engine_version", jsonutils.NewString(cache.EngineVersion))
  1816. desc.Set("capacity_mb", jsonutils.NewInt(int64(cache.CapacityMB)))
  1817. desc.Set("instance_type", jsonutils.NewString(cache.InstanceType))
  1818. desc.Set("node_type", jsonutils.NewString(cache.NodeType))
  1819. desc.Set("network_type", jsonutils.NewString(cache.NetworkType))
  1820. desc.Set("bandwidth", jsonutils.NewInt(int64(cache.Bandwidth)))
  1821. desc.Set("connections", jsonutils.NewInt(int64(cache.Connections)))
  1822. desc.Update(jsonutils.Marshal(&info))
  1823. return desc
  1824. }
  1825. func (manager *SElasticcacheManager) InitializeData() error {
  1826. q := manager.Query().IsNotEmpty("vpc_id")
  1827. q = q.Filter(
  1828. sqlchemy.OR(
  1829. sqlchemy.IsNullOrEmpty(q.Field("cloudregion_id")),
  1830. sqlchemy.IsNullOrEmpty(q.Field("manager_id")),
  1831. ),
  1832. )
  1833. caches := []SElasticcache{}
  1834. err := db.FetchModelObjects(manager, q, &caches)
  1835. if err != nil {
  1836. return err
  1837. }
  1838. for i := range caches {
  1839. vpc, err := caches[i].GetVpc()
  1840. if err != nil {
  1841. return err
  1842. }
  1843. _, err = db.Update(&caches[i], func() error {
  1844. caches[i].CloudregionId = vpc.CloudregionId
  1845. caches[i].ManagerId = vpc.ManagerId
  1846. return nil
  1847. })
  1848. if err != nil {
  1849. return err
  1850. }
  1851. }
  1852. return nil
  1853. }