| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package models
- import (
- "context"
- "database/sql"
- "fmt"
- "math"
- "math/big"
- "sort"
- "strings"
- "time"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/gotypes"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/billing"
- "yunion.io/x/pkg/util/compare"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/rand"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- billing_api "yunion.io/x/onecloud/pkg/apis/billing"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/cloudcommon/consts"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
- "yunion.io/x/onecloud/pkg/cloudcommon/policy"
- "yunion.io/x/onecloud/pkg/cloudcommon/types"
- "yunion.io/x/onecloud/pkg/cloudcommon/validators"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/rbacutils"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- type SNetworkManager struct {
- db.SSharableVirtualResourceBaseManager
- db.SExternalizedResourceBaseManager
- SWireResourceBaseManager
- }
- var NetworkManager *SNetworkManager
- func GetNetworkManager() *SNetworkManager {
- if NetworkManager != nil {
- return NetworkManager
- }
- NetworkManager = &SNetworkManager{
- SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
- SNetwork{},
- "networks_tbl",
- "network",
- "networks",
- ),
- }
- NetworkManager.SetVirtualObject(NetworkManager)
- return NetworkManager
- }
- func init() {
- GetNetworkManager()
- }
- type SNetwork struct {
- db.SSharableVirtualResourceBase
- db.SExternalizedResourceBase
- SWireResourceBase
- IfnameHint string `width:"9" charset:"ascii" nullable:"true" list:"user" create:"optional"`
- // 起始IP地址
- GuestIpStart string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // 结束IP地址
- GuestIpEnd string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // 掩码
- GuestIpMask int8 `nullable:"true" list:"user" update:"user" create:"optional"`
- // 网关地址
- GuestGateway string `width:"16" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // DNS, allow multiple dns, seperated by ","
- GuestDns string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // allow multiple dhcp, seperated by ","
- GuestDhcp string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // allow mutiple ntp, seperated by ","
- GuestNtp string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // search domain
- GuestDomain string `width:"128" charset:"ascii" nullable:"true" get:"user" update:"user"`
- // 起始IPv6地址
- GuestIp6Start string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // 结束IPv6地址
- GuestIp6End string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // IPv6子网掩码
- GuestIp6Mask uint8 `nullable:"true" list:"user" update:"user" create:"optional"`
- // IPv6网关
- GuestGateway6 string `width:"64" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // IPv6域名服务器
- // GuestDns6 string `width:"64" charset:"ascii" nullable:"true"`
- // GuestDomain6 string `width:"128" charset:"ascii" nullable:"true"`
- VlanId int `nullable:"false" default:"1" list:"user" update:"user" create:"optional"`
- // 服务器类型
- // example: server
- ServerType api.TNetworkType `width:"16" charset:"ascii" default:"guest" nullable:"true" list:"user" update:"admin" create:"optional"`
- // 分配策略
- AllocPolicy string `width:"16" charset:"ascii" nullable:"true" get:"user" update:"user" create:"optional"`
- AllocTimoutSeconds int `default:"0" nullable:"true" get:"admin"`
- // 该网段是否用于自动分配IP地址,如果为false,则用户需要明确选择该网段,才会使用该网段分配IP,
- // 如果为true,则用户不指定网段时,则自动从该值为true的网络中选择一个分配地址
- IsAutoAlloc tristate.TriState `list:"user" get:"user" update:"user" create:"optional"`
- // 线路类型
- BgpType string `width:"64" charset:"utf8" nullable:"false" list:"user" get:"user" update:"user" create:"optional"`
- }
- func (manager *SNetworkManager) GetContextManagers() [][]db.IModelManager {
- return [][]db.IModelManager{
- {WireManager},
- }
- }
- func (snet *SNetwork) getMtu(wire *SWire) int16 {
- baseMtu := options.Options.DefaultMtu
- if wire == nil {
- wire, _ = snet.GetWire()
- }
- if wire != nil {
- if IsOneCloudVpcResource(wire) {
- return int16(options.Options.OvnUnderlayMtu - api.VPC_OVN_ENCAP_COST)
- } else if wire.Mtu != 0 {
- return int16(wire.Mtu)
- } else {
- return int16(baseMtu)
- }
- }
- return int16(baseMtu)
- }
- func (snet *SNetwork) GetNetworkInterfaces() ([]SNetworkInterface, error) {
- sq := NetworkinterfacenetworkManager.Query().SubQuery()
- q := NetworkInterfaceManager.Query()
- q = q.Join(sq, sqlchemy.Equals(q.Field("id"), sq.Field("networkinterface_id"))).
- Filter(sqlchemy.Equals(sq.Field("network_id"), snet.Id))
- networkinterfaces := []SNetworkInterface{}
- err := db.FetchModelObjects(NetworkInterfaceManager, q, &networkinterfaces)
- if err != nil {
- return nil, err
- }
- return networkinterfaces, nil
- }
- func (snet *SNetwork) ValidateDeleteCondition(ctx context.Context, data *api.NetworkDetails) error {
- if data == nil {
- data = &api.NetworkDetails{}
- nics, err := NetworkManager.TotalNicCount([]string{snet.Id})
- if err != nil {
- return errors.Wrapf(err, "TotalNicCount")
- }
- if cnt, ok := nics[snet.Id]; ok {
- data.SNetworkNics = cnt
- }
- }
- if data.Total-data.ReserveVnics4-data.NetworkinterfaceVnics > 0 || data.Total6-data.ReserveVnics6 > 0 {
- return httperrors.NewNotEmptyError("not an empty network %s", jsonutils.Marshal(data.SNetworkNics).String())
- }
- return snet.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
- }
- func (snet *SNetwork) GetGuestnetworks() ([]SGuestnetwork, error) {
- q := GuestnetworkManager.Query().Equals("network_id", snet.Id)
- gns := []SGuestnetwork{}
- err := db.FetchModelObjects(GuestnetworkManager, q, &gns)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return gns, nil
- }
- func (snet *SNetwork) GetDBInstanceNetworks() ([]SDBInstanceNetwork, error) {
- q := DBInstanceNetworkManager.Query().Equals("network_id", snet.Id)
- networks := []SDBInstanceNetwork{}
- err := db.FetchModelObjects(DBInstanceNetworkManager, q, &networks)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return networks, nil
- }
- func (manager *SNetworkManager) GetOrCreateClassicNetwork(ctx context.Context, wire *SWire) (*SNetwork, error) {
- _network, err := db.FetchByExternalIdAndManagerId(manager, wire.Id, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- v, _ := wire.GetVpc()
- if v != nil {
- wire := WireManager.Query().SubQuery()
- vpc := VpcManager.Query().SubQuery()
- return q.Join(wire, sqlchemy.Equals(wire.Field("id"), q.Field("wire_id"))).
- Join(vpc, sqlchemy.Equals(vpc.Field("id"), wire.Field("vpc_id"))).
- Filter(sqlchemy.Equals(vpc.Field("manager_id"), v.ManagerId))
- }
- return q
- })
- if err == nil {
- return _network.(*SNetwork), nil
- }
- if errors.Cause(err) != sql.ErrNoRows {
- return nil, errors.Wrap(err, "db.FetchByExternalId")
- }
- network := SNetwork{
- GuestIpStart: "0.0.0.0",
- GuestIpEnd: "255.255.255.255",
- GuestIpMask: 0,
- GuestGateway: "0.0.0.0",
- ServerType: api.NETWORK_TYPE_GUEST,
- }
- network.WireId = wire.Id
- network.SetModelManager(manager, &network)
- network.Name = fmt.Sprintf("emulate network for classic network with wire %s", wire.Id)
- network.ExternalId = wire.Id
- network.IsEmulated = true
- network.IsPublic = true
- network.PublicScope = "system"
- admin := auth.AdminCredential()
- network.DomainId = admin.GetProjectDomainId()
- network.ProjectId = admin.GetProjectId()
- network.Status = api.NETWORK_STATUS_UNAVAILABLE
- err = manager.TableSpec().Insert(ctx, &network)
- if err != nil {
- return nil, errors.Wrap(err, "Insert classic network")
- }
- return &network, nil
- }
- func (snet *SNetwork) GetUsedAddresses(ctx context.Context) map[string]bool {
- used := make(map[string]bool)
- q := snet.getUsedAddressQuery(ctx, nil, nil, rbacscope.ScopeSystem, true)
- results, err := q.AllStringMap()
- if err != nil {
- log.Errorf("GetUsedAddresses fail %s", err)
- return used
- }
- for _, result := range results {
- used[result["ip_addr"]] = true
- }
- return used
- }
- func (snet *SNetwork) GetUsedAddresses6(ctx context.Context) map[string]bool {
- used := make(map[string]bool)
- q := snet.getUsedAddressQuery6(ctx, nil, nil, rbacscope.ScopeSystem, true)
- results, err := q.AllStringMap()
- if err != nil {
- log.Errorf("GetUsedAddresses fail %s", err)
- return used
- }
- for _, result := range results {
- used[result["ip6_addr"]] = true
- }
- return used
- }
- func (snet *SNetwork) GetIPRange() *netutils.IPV4AddrRange {
- return snet.getIPRange()
- }
- func (net *SNetwork) getIPRange() *netutils.IPV4AddrRange {
- if len(net.GuestIpStart) == 0 || len(net.GuestIpEnd) == 0 {
- return nil
- }
- start, _ := netutils.NewIPV4Addr(net.GuestIpStart)
- end, _ := netutils.NewIPV4Addr(net.GuestIpEnd)
- ipRange := netutils.NewIPV4AddrRange(start, end)
- return &ipRange
- }
- func (net *SNetwork) getIPRange6() *netutils.IPV6AddrRange {
- if len(net.GuestIp6Start) == 0 || len(net.GuestIp6End) == 0 {
- return nil
- }
- start, _ := netutils.NewIPV6Addr(net.GuestIp6Start)
- end, _ := netutils.NewIPV6Addr(net.GuestIp6End)
- ipRange := netutils.NewIPV6AddrRange(start, end)
- return &ipRange
- }
- func (net *SNetwork) getNetRange() netutils.IPV4AddrRange {
- start, _ := netutils.NewIPV4Addr(net.GuestIpStart)
- return netutils.NewIPV4AddrRange(start.NetAddr(net.GuestIpMask), start.BroadcastAddr(net.GuestIpMask))
- }
- func isIpUsed(ipstr string, addrTable map[string]bool, recentUsedAddrTable map[string]bool) bool {
- _, ok := addrTable[ipstr]
- if !ok {
- recentUsed := false
- if recentUsedAddrTable != nil {
- if _, ok := recentUsedAddrTable[ipstr]; ok {
- recentUsed = true
- }
- }
- return recentUsed
- } else {
- return true
- }
- }
- func (snet *SNetwork) getFreeIP6(addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string) (string, error) {
- if !snet.IsSupportIPv6() {
- return "", errors.Wrapf(cloudprovider.ErrNotSupported, "ipv6")
- }
- iprange := snet.getIPRange6()
- // Try candidate first
- if len(candidate) > 0 {
- candIP, err := netutils.NewIPV6Addr(candidate)
- if err != nil {
- return "", errors.Wrap(err, "NewIPV6Addr")
- }
- if !iprange.Contains(candIP) {
- return "", httperrors.NewInputParameterError("candidate %s out of range %s", candidate, iprange.String())
- }
- if _, ok := addrTable[candidate]; !ok {
- return candidate, nil
- }
- }
- // ipv6 support random address allocation only
- const MAX_TRIES = 5
- for i := 0; i < MAX_TRIES; i += 1 {
- ip := iprange.Random()
- if !isIpUsed(ip.String(), addrTable, recentUsedAddrTable) {
- return ip.String(), nil
- }
- }
- // failed, fallback to IPAllocationStepup
- return "", httperrors.NewInsufficientResourceError("Out of IP address")
- }
- func (snet *SNetwork) getFreeIP(addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string, allocDir api.IPAllocationDirection) (string, error) {
- iprange := snet.getIPRange()
- // Try candidate first
- if len(candidate) > 0 {
- candIP, err := netutils.NewIPV4Addr(candidate)
- if err != nil {
- return "", err
- }
- if !iprange.Contains(candIP) {
- return "", httperrors.NewInputParameterError("candidate %s out of range %s", candidate, iprange.String())
- }
- if _, ok := addrTable[candidate]; !ok {
- return candidate, nil
- }
- }
- // If network's alloc_policy is not none, then use network's alloc_policy
- if len(snet.AllocPolicy) > 0 && api.IPAllocationDirection(snet.AllocPolicy) != api.IPAllocationNone {
- allocDir = api.IPAllocationDirection(snet.AllocPolicy)
- }
- // if alloc_dir is not speicified, and network's alloc_policy is not either, use default
- if len(allocDir) == 0 {
- allocDir = api.IPAllocationDirection(options.Options.DefaultIPAllocationDirection)
- }
- if allocDir == api.IPAllocationStepdown {
- ip, _ := netutils.NewIPV4Addr(snet.GuestIpEnd)
- for iprange.Contains(ip) {
- if !isIpUsed(ip.String(), addrTable, recentUsedAddrTable) {
- return ip.String(), nil
- }
- ip = ip.StepDown()
- }
- } else {
- if allocDir == api.IPAllocationRandom {
- const MAX_TRIES = 5
- for i := 0; i < MAX_TRIES; i += 1 {
- ip := iprange.Random()
- if !isIpUsed(ip.String(), addrTable, recentUsedAddrTable) {
- return ip.String(), nil
- }
- }
- // failed, fallback to IPAllocationStepup
- }
- ip, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- for iprange.Contains(ip) {
- if !isIpUsed(ip.String(), addrTable, recentUsedAddrTable) {
- return ip.String(), nil
- }
- ip = ip.StepUp()
- }
- }
- return "", httperrors.NewInsufficientResourceError("Out of IP address")
- }
- func (snet *SNetwork) GetFreeIPWithLock(ctx context.Context, userCred mcclient.TokenCredential, addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string, allocDir api.IPAllocationDirection, reserved bool, addrType api.TAddressType) (string, error) {
- lockman.LockObject(ctx, snet)
- defer lockman.ReleaseObject(ctx, snet)
- return snet.GetFreeIP(ctx, userCred, addrTable, recentUsedAddrTable, candidate, allocDir, reserved, addrType)
- }
- func (snet *SNetwork) GetFreeIP(ctx context.Context, userCred mcclient.TokenCredential, addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string, allocDir api.IPAllocationDirection, reserved bool, addrType api.TAddressType) (string, error) {
- // if reserved true, first try find IP in reserved IP pool
- if reserved {
- rip := ReservedipManager.GetReservedIP(snet, candidate, addrType)
- if rip != nil {
- rip.Release(ctx, userCred, snet)
- return candidate, nil
- }
- // return "", httperrors.NewInsufficientResourceError("Reserved address %s not found", candidate)
- // if not find, warning, then fallback to normal procedure
- log.Warningf("Reserved address %s not found", candidate)
- }
- if addrType == api.AddressTypeIPv6 {
- if addrTable == nil {
- addrTable = snet.GetUsedAddresses6(ctx)
- }
- if recentUsedAddrTable == nil {
- recentUsedAddrTable = GuestnetworkManager.getRecentlyReleasedIPAddresses6(snet.Id, snet.getAllocTimoutDuration())
- }
- cand, err := snet.getFreeIP6(addrTable, recentUsedAddrTable, candidate)
- if err != nil {
- return "", errors.Wrap(err, "getFreeIP6")
- }
- return cand, nil
- } else {
- if addrTable == nil {
- addrTable = snet.GetUsedAddresses(ctx)
- }
- if recentUsedAddrTable == nil {
- recentUsedAddrTable = GuestnetworkManager.getRecentlyReleasedIPAddresses(snet.Id, snet.getAllocTimoutDuration())
- }
- cand, err := snet.getFreeIP(addrTable, recentUsedAddrTable, candidate, allocDir)
- if err != nil {
- return "", errors.Wrap(err, "getFreeIP")
- }
- return cand, nil
- }
- }
- func (snet *SNetwork) GetNetAddr() netutils.IPV4Addr {
- startIp, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- return startIp.NetAddr(snet.GuestIpMask)
- }
- func (snet *SNetwork) GetDNS(zoneName string) string {
- if len(snet.GuestDns) > 0 {
- return snet.GuestDns
- }
- if len(zoneName) == 0 {
- wire, _ := snet.GetWire()
- if wire != nil {
- zone, _ := wire.GetZone()
- if zone != nil {
- zoneName = zone.Name
- }
- }
- }
- srvs, _ := auth.GetDNSServers(options.Options.Region, zoneName)
- if len(srvs) > 0 {
- return strings.Join(srvs, ",")
- }
- if len(options.Options.DNSServer) > 0 {
- return options.Options.DNSServer
- }
- return ""
- }
- func (snet *SNetwork) GetNTP() string {
- if len(snet.GuestNtp) > 0 {
- return snet.GuestNtp
- } else {
- zoneName := ""
- wire, _ := snet.GetWire()
- if wire != nil {
- zone, _ := wire.GetZone()
- if zone != nil {
- zoneName = zone.Name
- }
- }
- srvs, _ := auth.GetNTPServers(options.Options.Region, zoneName)
- if len(srvs) > 0 {
- return strings.Join(srvs, ",")
- }
- return ""
- }
- }
- func (snet *SNetwork) GetDomain() string {
- if len(snet.GuestDomain) > 0 {
- return snet.GuestDomain
- } else if !apis.IsIllegalSearchDomain(options.Options.DNSDomain) {
- return options.Options.DNSDomain
- } else {
- return ""
- }
- }
- func (snet *SNetwork) GetRoutes() []types.SRoute {
- ret := make([]types.SRoute, 0)
- routes := snet.GetMetadataJson(context.Background(), "static_routes", nil)
- if routes != nil {
- routesMap, err := routes.GetMap()
- if err != nil {
- return nil
- }
- for net, routeJson := range routesMap {
- route, _ := routeJson.GetString()
- ret = append(ret, types.SRoute{net, route})
- }
- }
- return ret
- }
- func (snet *SNetwork) updateDnsRecord(nic *SGuestnetwork, isAdd bool) {
- guest := nic.GetGuest()
- if !gotypes.IsNil(guest) {
- snet._updateDnsRecord(guest.Name, nic.IpAddr, isAdd)
- }
- }
- func (snet *SNetwork) _updateDnsRecord(name string, ipAddr string, isAdd bool) {
- if len(snet.GuestDns) > 0 && len(snet.GuestDomain) > 0 && len(ipAddr) > 0 {
- keyName := snet.GetMetadata(context.Background(), "dns_update_key_name", nil)
- keySecret := snet.GetMetadata(context.Background(), "dns_update_key_secret", nil)
- dnsSrv := snet.GetMetadata(context.Background(), "dns_update_server", nil)
- if len(dnsSrv) == 0 || !regutils.MatchIPAddr(dnsSrv) {
- dnsSrv = snet.GuestDns
- }
- log.Infof("dns update %s %s isAdd=%t", ipAddr, dnsSrv, isAdd)
- if len(keyName) > 0 && len(keySecret) > 0 {
- /* netman.get_manager().dns_update(name,
- snet.guest_domain, ip_addr, None,
- dns_srv, snet.guest_dns6, key_name, key_secret,
- is_add) */
- }
- targets := snet.getDnsUpdateTargets()
- if targets != nil {
- for srv, keys := range targets {
- for _, key := range keys {
- log.Debugf("Register %s %s", srv, key)
- /*
- netman.get_manager().dns_update(name,
- snet.guest_domain, ip_addr, None,
- srv, None,
- key.get('key', None),
- key.get('secret', None),
- is_add)
- */
- }
- }
- }
- }
- }
- type DNSUpdateKeySecret struct {
- Key string
- Secret string
- }
- func (snet *SNetwork) getDnsUpdateTargets() map[string][]DNSUpdateKeySecret {
- targets := make(map[string][]DNSUpdateKeySecret)
- targetsJson := snet.GetMetadataJson(context.Background(), api.EXTRA_DNS_UPDATE_TARGETS, nil)
- if targetsJson == nil {
- return nil
- } else {
- err := targetsJson.Unmarshal(&targets)
- if err != nil {
- return nil
- }
- return targets
- }
- }
- func (snet *SNetwork) GetGuestIpv4StartAddress() netutils.IPV4Addr {
- addr, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- return addr
- }
- func (snet *SNetwork) IsExitNetwork() bool {
- if len(snet.GuestIpStart) == 0 {
- return false
- }
- return len(snet.ExternalId) == 0 && netutils.IsExitAddress(snet.GetGuestIpv4StartAddress())
- }
- func (manager *SNetworkManager) getNetworksByWire(ctx context.Context, wire *SWire) ([]SNetwork, error) {
- return wire.getNetworks(ctx, nil, nil, rbacscope.ScopeNone)
- }
- func (manager *SNetworkManager) SyncNetworks(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- wire *SWire,
- nets []cloudprovider.ICloudNetwork,
- provider *SCloudprovider,
- xor bool,
- ) ([]SNetwork, []cloudprovider.ICloudNetwork, compare.SyncResult) {
- syncOwnerId := provider.GetOwnerId()
- lockman.LockRawObject(ctx, manager.Keyword(), wire.Id)
- defer lockman.ReleaseRawObject(ctx, manager.Keyword(), wire.Id)
- localNets := make([]SNetwork, 0)
- remoteNets := make([]cloudprovider.ICloudNetwork, 0)
- syncResult := compare.SyncResult{}
- dbNets, err := manager.getNetworksByWire(ctx, wire)
- if err != nil {
- syncResult.Error(err)
- return nil, nil, syncResult
- }
- for i := range dbNets {
- if taskman.TaskManager.IsInTask(&dbNets[i]) {
- syncResult.Error(fmt.Errorf("object in task"))
- return nil, nil, syncResult
- }
- }
- removed := make([]SNetwork, 0)
- commondb := make([]SNetwork, 0)
- commonext := make([]cloudprovider.ICloudNetwork, 0)
- added := make([]cloudprovider.ICloudNetwork, 0)
- err = compare.CompareSets(dbNets, nets, &removed, &commondb, &commonext, &added)
- if err != nil {
- syncResult.Error(err)
- return nil, nil, syncResult
- }
- for i := 0; i < len(removed); i += 1 {
- err = removed[i].syncRemoveCloudNetwork(ctx, userCred)
- if err != nil {
- syncResult.DeleteError(err)
- } else {
- syncResult.Delete()
- }
- }
- if !xor {
- for i := 0; i < len(commondb); i += 1 {
- err = commondb[i].SyncWithCloudNetwork(ctx, userCred, commonext[i])
- if err != nil {
- syncResult.UpdateError(err)
- continue
- }
- localNets = append(localNets, commondb[i])
- remoteNets = append(remoteNets, commonext[i])
- syncResult.Update()
- }
- }
- for i := 0; i < len(added); i += 1 {
- new, err := manager.newFromCloudNetwork(ctx, userCred, added[i], wire, syncOwnerId, provider)
- if err != nil {
- syncResult.AddError(err)
- } else {
- localNets = append(localNets, *new)
- remoteNets = append(remoteNets, added[i])
- syncResult.Add()
- }
- }
- return localNets, remoteNets, syncResult
- }
- func (snet *SNetwork) syncRemoveCloudNetwork(ctx context.Context, userCred mcclient.TokenCredential) error {
- lockman.LockObject(ctx, snet)
- defer lockman.ReleaseObject(ctx, snet)
- if snet.ExternalId == snet.WireId {
- return nil
- }
- err := snet.ValidateDeleteCondition(ctx, nil)
- if err != nil { // cannot delete
- err = snet.SetStatus(ctx, userCred, api.NETWORK_STATUS_UNKNOWN, "Sync to remove")
- } else {
- err = snet.RealDelete(ctx, userCred)
- if err == nil {
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: snet,
- Action: notifyclient.ActionSyncDelete,
- })
- }
- }
- return err
- }
- func (snet *SNetwork) SyncWithCloudNetwork(ctx context.Context, userCred mcclient.TokenCredential, extNet cloudprovider.ICloudNetwork) error {
- diff, err := db.UpdateWithLock(ctx, snet, func() error {
- if options.Options.EnableSyncName {
- newName, _ := db.GenerateAlterName(snet, extNet.GetName())
- if len(newName) > 0 {
- snet.Name = newName
- }
- }
- snet.Status = extNet.GetStatus()
- snet.GuestIpStart = extNet.GetIpStart()
- snet.GuestIpEnd = extNet.GetIpEnd()
- snet.GuestIpMask = extNet.GetIpMask()
- snet.GuestGateway = extNet.GetGateway()
- snet.ServerType = api.TNetworkType(extNet.GetServerType())
- snet.GuestIp6Start = extNet.GetIp6Start()
- snet.GuestIp6End = extNet.GetIp6End()
- snet.GuestIp6Mask = extNet.GetIp6Mask()
- snet.GuestGateway6 = extNet.GetGateway6()
- snet.AllocTimoutSeconds = extNet.GetAllocTimeoutSeconds()
- if createdAt := extNet.GetCreatedAt(); !createdAt.IsZero() {
- snet.CreatedAt = createdAt
- }
- return nil
- })
- if err != nil {
- log.Errorf("syncWithCloudNetwork error %s", err)
- return err
- }
- db.OpsLog.LogSyncUpdate(snet, diff, userCred)
- if len(diff) > 0 {
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: snet,
- Action: notifyclient.ActionSyncUpdate,
- })
- }
- vpc, err := snet.GetVpc()
- if err != nil {
- return errors.Wrapf(err, "GetVpc")
- }
- provider := vpc.GetCloudprovider()
- if provider != nil {
- if account, _ := provider.GetCloudaccount(); account != nil {
- syncVirtualResourceMetadata(ctx, userCred, snet, extNet, account.ReadOnly)
- }
- SyncCloudProject(ctx, userCred, snet, provider.GetOwnerId(), extNet, provider)
- shareInfo := provider.getAccountShareInfo()
- if utils.IsInStringArray(provider.Provider, api.PRIVATE_CLOUD_PROVIDERS) && extNet.GetPublicScope() == rbacscope.ScopeNone {
- shareInfo = apis.SAccountShareInfo{
- IsPublic: false,
- PublicScope: rbacscope.ScopeNone,
- }
- }
- snet.SyncShareState(ctx, userCred, shareInfo)
- }
- return nil
- }
- func (manager *SNetworkManager) newFromCloudNetwork(ctx context.Context, userCred mcclient.TokenCredential, extNet cloudprovider.ICloudNetwork, wire *SWire, syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider) (*SNetwork, error) {
- net := &SNetwork{}
- net.SetModelManager(manager, net)
- net.Status = extNet.GetStatus()
- net.ExternalId = extNet.GetGlobalId()
- net.WireId = wire.Id
- net.GuestIpStart = extNet.GetIpStart()
- net.GuestIpEnd = extNet.GetIpEnd()
- net.GuestIpMask = extNet.GetIpMask()
- net.GuestGateway = extNet.GetGateway()
- net.ServerType = api.TNetworkType(extNet.GetServerType())
- net.GuestIp6Start = extNet.GetIp6Start()
- net.GuestIp6End = extNet.GetIp6End()
- net.GuestIp6Mask = extNet.GetIp6Mask()
- net.GuestGateway6 = extNet.GetGateway6()
- // net.IsPublic = extNet.GetIsPublic()
- // extScope := extNet.GetPublicScope()
- // if extScope == rbacutils.ScopeDomain && !consts.GetNonDefaultDomainProjects() {
- // extScope = rbacutils.ScopeSystem
- // }
- // net.PublicScope = string(extScope)
- net.AllocTimoutSeconds = extNet.GetAllocTimeoutSeconds()
- if createdAt := extNet.GetCreatedAt(); !createdAt.IsZero() {
- net.CreatedAt = createdAt
- }
- var err = func() error {
- lockman.LockRawObject(ctx, manager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
- newName, err := db.GenerateName(ctx, manager, syncOwnerId, extNet.GetName())
- if err != nil {
- return err
- }
- net.Name = newName
- return manager.TableSpec().Insert(ctx, net)
- }()
- if err != nil {
- return nil, errors.Wrapf(err, "Insert")
- }
- syncVirtualResourceMetadata(ctx, userCred, net, extNet, false)
- if provider != nil {
- SyncCloudProject(ctx, userCred, net, syncOwnerId, extNet, provider)
- shareInfo := provider.getAccountShareInfo()
- if utils.IsInStringArray(provider.Provider, api.PRIVATE_CLOUD_PROVIDERS) && extNet.GetPublicScope() == rbacscope.ScopeNone {
- shareInfo = apis.SAccountShareInfo{
- IsPublic: false,
- PublicScope: rbacscope.ScopeNone,
- }
- }
- net.SyncShareState(ctx, userCred, shareInfo)
- }
- db.OpsLog.LogEvent(net, db.ACT_CREATE, net.GetShortDesc(ctx), userCred)
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: net,
- Action: notifyclient.ActionSyncCreate,
- })
- return net, nil
- }
- func (net *SNetwork) IsAddressInRange(address netutils.IPV4Addr) bool {
- ipRange := net.getIPRange()
- if ipRange == nil {
- return false
- }
- return ipRange.Contains(address)
- }
- func (net *SNetwork) IsAddress6InRange(address netutils.IPV6Addr) bool {
- addrRange := net.getIPRange6()
- if addrRange == nil {
- return false
- }
- return addrRange.Contains(address)
- }
- func (net *SNetwork) IsAddressInNet(address netutils.IPV4Addr) bool {
- return net.getNetRange().Contains(address)
- }
- func (snet *SNetwork) isAddressUsed(ctx context.Context, address string) (bool, error) {
- q := snet.getUsedAddressQuery(ctx, nil, nil, rbacscope.ScopeSystem, true)
- q = q.Equals("ip_addr", address)
- count, err := q.CountWithError()
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return false, errors.Wrap(err, "Query")
- }
- if count > 0 {
- return true, nil
- } else {
- return false, nil
- }
- }
- func (snet *SNetwork) isAddress6Used(ctx context.Context, address string) (bool, error) {
- q := snet.getUsedAddressQuery6(ctx, nil, nil, rbacscope.ScopeSystem, true)
- q = q.Equals("ip6_addr", address)
- count, err := q.CountWithError()
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return false, errors.Wrap(err, "Query")
- }
- if count > 0 {
- return true, nil
- } else {
- return false, nil
- }
- }
- func (manager *SNetworkManager) fetchAllOnpremiseNetworks(serverType string, isPublic tristate.TriState) ([]SNetwork, error) {
- q := manager.Query()
- wires := WireManager.Query().SubQuery()
- q = q.Join(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id")))
- q = q.Filter(sqlchemy.Equals(wires.Field("vpc_id"), api.DEFAULT_VPC_ID))
- if len(serverType) > 0 {
- q = q.Filter(sqlchemy.Equals(q.Field("server_type"), serverType))
- }
- if isPublic.IsTrue() {
- q = q.Filter(sqlchemy.IsTrue(q.Field("is_public")))
- } else if isPublic.IsFalse() {
- q = q.Filter(sqlchemy.IsFalse(q.Field("is_public")))
- }
- nets := make([]SNetwork, 0)
- err := db.FetchModelObjects(manager, q, &nets)
- if err != nil {
- return nil, errors.Wrap(err, "FetchModelObjects")
- }
- return nets, nil
- }
- func (manager *SNetworkManager) GetOnPremiseNetworkOfIP(ipAddr string, serverType string, isPublic tristate.TriState) (*SNetwork, error) {
- var addr4 netutils.IPV4Addr
- var addr6 netutils.IPV6Addr
- var isIpv6Addr = false
- var err error
- if strings.Contains(ipAddr, ":") {
- isIpv6Addr = true
- }
- if isIpv6Addr {
- addr6, err = netutils.NewIPV6Addr(ipAddr)
- if err != nil {
- return nil, errors.Wrap(err, "NewIPV6Addr")
- }
- } else {
- addr4, err = netutils.NewIPV4Addr(ipAddr)
- if err != nil {
- return nil, errors.Wrap(err, "NewIPV4Addr")
- }
- }
- nets, err := manager.fetchAllOnpremiseNetworks(serverType, isPublic)
- if err != nil {
- return nil, errors.Wrap(err, "fetchAllOnpremiseNetworks")
- }
- for _, n := range nets {
- if isIpv6Addr {
- if n.IsAddress6InRange(addr6) {
- return &n, nil
- }
- } else {
- if n.IsAddressInRange(addr4) {
- return &n, nil
- }
- }
- }
- return nil, sql.ErrNoRows
- }
- func (manager *SNetworkManager) GetOnPremiseNetworkOfIP6(ip6Addr string, serverType string, isPublic tristate.TriState) (*SNetwork, error) {
- address, err := netutils.NewIPV6Addr(ip6Addr)
- if err != nil {
- return nil, errors.Wrap(err, "NewIPV6Addr")
- }
- nets, err := manager.fetchAllOnpremiseNetworks(serverType, isPublic)
- if err != nil {
- return nil, errors.Wrap(err, "fetchAllOnpremiseNetworks")
- }
- for _, n := range nets {
- if n.IsAddress6InRange(address) {
- return &n, nil
- }
- }
- return nil, sql.ErrNoRows
- }
- func (manager *SNetworkManager) allNetworksQ(providers []string, brands []string, cloudEnv string, rangeObjs []db.IStandaloneModel) *sqlchemy.SQuery {
- networks := manager.Query().SubQuery()
- wires := WireManager.Query().SubQuery()
- vpcs := VpcManager.Query().SubQuery()
- q := networks.Query(networks.Field("id"))
- q = q.Join(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id")))
- q = q.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id")))
- q = CloudProviderFilter(q, vpcs.Field("manager_id"), providers, brands, cloudEnv)
- q = RangeObjectsFilter(q, rangeObjs, vpcs.Field("cloudregion_id"), wires.Field("zone_id"), vpcs.Field("manager_id"), nil, nil)
- return q
- }
- func (manager *SNetworkManager) totalPortCountQ(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- userCred mcclient.IIdentityProvider,
- providers []string,
- brands []string,
- cloudEnv string,
- rangeObjs []db.IStandaloneModel,
- policyResult rbacutils.SPolicyResult,
- ) *sqlchemy.SQuery {
- q := manager.allNetworksQ(providers, brands, cloudEnv, rangeObjs)
- switch scope {
- case rbacscope.ScopeSystem:
- case rbacscope.ScopeDomain:
- q = q.Equals("domain_id", userCred.GetProjectDomainId())
- case rbacscope.ScopeProject:
- q = q.Equals("tenant_id", userCred.GetProjectId())
- }
- q = db.ObjectIdQueryWithPolicyResult(ctx, q, manager, policyResult)
- return manager.Query().In("id", q.Distinct().SubQuery())
- }
- type NetworkPortStat struct {
- Count int
- CountExt int
- }
- func (manager *SNetworkManager) TotalPortCount(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- userCred mcclient.IIdentityProvider,
- providers []string, brands []string, cloudEnv string,
- rangeObjs []db.IStandaloneModel,
- policyResult rbacutils.SPolicyResult,
- ) map[api.TNetworkType]NetworkPortStat {
- nets := make([]SNetwork, 0)
- err := manager.totalPortCountQ(
- ctx,
- scope,
- userCred,
- providers, brands, cloudEnv,
- rangeObjs,
- policyResult,
- ).All(&nets)
- if err != nil {
- log.Errorf("TotalPortCount: %v", err)
- }
- ret := make(map[api.TNetworkType]NetworkPortStat)
- for _, net := range nets {
- var stat NetworkPortStat
- var allStat NetworkPortStat
- if len(net.ServerType) > 0 {
- stat, _ = ret[net.ServerType]
- }
- allStat, _ = ret[""]
- count := net.GetTotalAddressCount()
- if net.IsExitNetwork() {
- if len(net.ServerType) > 0 {
- stat.CountExt += count
- }
- allStat.CountExt += count
- } else {
- if len(net.ServerType) > 0 {
- stat.Count += count
- }
- allStat.Count += count
- }
- if len(net.ServerType) > 0 {
- ret[net.ServerType] = stat
- }
- ret[""] = allStat
- }
- return ret
- }
- type SNicConfig struct {
- Mac string
- Index int
- Ifname string
- }
- func parseNetworkInfo(ctx context.Context, userCred mcclient.TokenCredential, info *api.NetworkConfig) (*api.NetworkConfig, error) {
- if info.Network != "" {
- netObj, err := NetworkManager.FetchByIdOrName(ctx, userCred, info.Network)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(NetworkManager.Keyword(), info.Network)
- } else {
- return nil, err
- }
- }
- net := netObj.(*SNetwork)
- if net.ProjectId == userCred.GetProjectId() ||
- (db.IsDomainAllowGet(ctx, userCred, net) && net.DomainId == userCred.GetProjectDomainId()) ||
- db.IsAdminAllowGet(ctx, userCred, net) ||
- net.IsSharable(userCred) {
- info.Network = netObj.GetId()
- } else {
- return nil, httperrors.NewForbiddenError("no allow to access network %s", info.Network)
- }
- }
- if info.BwLimit == 0 {
- info.BwLimit = options.Options.DefaultBandwidth
- }
- return info, nil
- }
- func (snet *SNetwork) GetFreeAddressCount() (int, error) {
- return snet.getFreeAddressCount()
- }
- func (snet *SNetwork) GetTotalAddressCount() int {
- ipRange := snet.getIPRange()
- if ipRange != nil {
- return ipRange.AddressCount()
- }
- ip6Range := snet.getIPRange6()
- if ip6Range == nil {
- return 0
- }
- cnt := ip6Range.AddressCount()
- if cnt.Cmp(big.NewInt(math.MaxInt32)) > 0 {
- return math.MaxInt32
- }
- return int(cnt.Int64())
- }
- func (snet *SNetwork) getFreeAddressCount() (int, error) {
- vnics, err := NetworkManager.TotalNicCount([]string{snet.Id})
- if err != nil {
- return -1, errors.Wrapf(err, "TotalNicCount")
- }
- used := 0
- if nics, ok := vnics[snet.Id]; ok {
- used = nics.Total
- }
- return snet.GetTotalAddressCount() - used, nil
- }
- func isValidNetworkInfo(ctx context.Context, userCred mcclient.TokenCredential, netConfig *api.NetworkConfig, reuseAddr, reuseAddr6 string) error {
- if len(netConfig.Network) > 0 {
- netObj, err := NetworkManager.FetchByIdOrName(ctx, userCred, netConfig.Network)
- if err != nil {
- return httperrors.NewResourceNotFoundError("Network %s not found: %v", netConfig.Network, err)
- }
- net := netObj.(*SNetwork)
- /*
- // scheduler do the check
- if !netConfig.Vip && !netConfig.Reserved && net.getFreeAddressCount() == 0 {
- return fmt.Errorf("Address exhausted in network %s")
- }*/
- if len(netConfig.Address) > 0 {
- ipAddr, err := netutils.NewIPV4Addr(netConfig.Address)
- if err != nil {
- return errors.Wrap(err, "NewIPV4Addr")
- }
- if !net.IsAddressInRange(ipAddr) {
- return httperrors.NewInputParameterError("Address %s not in range", netConfig.Address)
- }
- if netConfig.Reserved {
- // the privilege to access reserved ip
- if db.IsAdminAllowList(userCred, ReservedipManager).Result.IsDeny() {
- return httperrors.NewForbiddenError("Only system admin allowed to use reserved ip")
- }
- if ReservedipManager.GetReservedIP(net, netConfig.Address, api.AddressTypeIPv4) == nil {
- return httperrors.NewInputParameterError("Address %s not reserved", netConfig.Address)
- }
- } else {
- used, err := net.isAddressUsed(ctx, netConfig.Address)
- if err != nil {
- return httperrors.NewInternalServerError("isAddressUsed fail %s", err)
- }
- if used && netConfig.Address != reuseAddr {
- return httperrors.NewInputParameterError("Address %s has been used", netConfig.Address)
- }
- }
- }
- if len(netConfig.Address6) > 0 {
- if !net.IsSupportIPv6() {
- return errors.Wrap(httperrors.ErrNotSupported, "network not enable ipv6")
- }
- ipAddr, err := netutils.NewIPV6Addr(netConfig.Address6)
- if err != nil {
- return errors.Wrap(err, "NewIPV6Addr")
- }
- netConfig.Address6 = ipAddr.String()
- if !net.IsAddress6InRange(ipAddr) {
- return httperrors.NewInputParameterError("Address v6 %s not in range", netConfig.Address6)
- }
- if netConfig.Reserved {
- // the privilege to access reserved ip
- if db.IsAdminAllowList(userCred, ReservedipManager).Result.IsDeny() {
- return httperrors.NewForbiddenError("Only system admin allowed to use reserved ip")
- }
- if ReservedipManager.GetReservedIP(net, netConfig.Address6, api.AddressTypeIPv6) == nil {
- return httperrors.NewInputParameterError("Address v6 %s not reserved", netConfig.Address6)
- }
- } else {
- used, err := net.isAddress6Used(ctx, netConfig.Address6)
- if err != nil {
- return httperrors.NewInternalServerError("isAddress6Used fail %s", err)
- }
- if used && netConfig.Address6 != reuseAddr6 {
- return httperrors.NewInputParameterError("v6 address %s has been used", netConfig.Address6)
- }
- }
- }
- if netConfig.RequireIPv6 && !net.IsSupportIPv6() {
- return errors.Wrap(httperrors.ErrNotSupported, "network not enable ipv6")
- }
- if netConfig.BwLimit > api.MAX_BANDWIDTH {
- return httperrors.NewInputParameterError("Bandwidth limit cannot exceed %dMbps", api.MAX_BANDWIDTH)
- }
- if net.ServerType == api.NETWORK_TYPE_BAREMETAL {
- // not check baremetal network free address here
- // TODO: find better solution ?
- return nil
- }
- freeCnt, err := net.getFreeAddressCount()
- if err != nil {
- return httperrors.NewInternalServerError("getFreeAddressCount fail %s", err)
- }
- if reuseAddr != "" {
- freeCnt += 1
- }
- if freeCnt < 1 {
- return httperrors.NewInputParameterError("network %s(%s) has no free addresses", net.Name, net.Id)
- }
- }
- /* scheduler to the check
- else if ! netConfig.Vip {
- ct, ctExit := NetworkManager.to
- }
- */
- // billing update
- if netConfig.TxTrafficLimit > 0 || netConfig.RxTrafficLimit > 0 {
- if len(netConfig.BillingType) == 0 {
- netConfig.BillingType = billing_api.BILLING_TYPE_PREPAID
- } else if netConfig.BillingType != billing_api.BILLING_TYPE_PREPAID {
- return httperrors.NewInputParameterError("nic is limited by traffic, only support prepaid billing type")
- }
- if len(netConfig.ChargeType) == 0 {
- netConfig.ChargeType = billing_api.NET_CHARGE_TYPE_BY_TRAFFIC
- } else if netConfig.ChargeType != billing_api.NET_CHARGE_TYPE_BY_TRAFFIC {
- return httperrors.NewInputParameterError("nic is limited by traffic, only support charge traffic")
- }
- } else {
- if netConfig.BillingType == billing_api.BILLING_TYPE_PREPAID && netConfig.ChargeType == billing_api.NET_CHARGE_TYPE_BY_TRAFFIC {
- return httperrors.NewInputParameterError("nic traffic limited should be set for prepaid traffic billing type")
- }
- }
- if len(netConfig.PortMappings) != 0 {
- for i := range netConfig.PortMappings {
- if err := validatePortMapping(netConfig.PortMappings[i]); err != nil {
- return errors.Wrapf(err, "validate port mapping %s", jsonutils.Marshal(netConfig.PortMappings[i]))
- }
- }
- }
- return nil
- }
- func validatePortRange(portRange *api.GuestPortMappingPortRange) error {
- if portRange != nil {
- if portRange.Start > portRange.End {
- return httperrors.NewInputParameterError("port range start %d is large than %d", portRange.Start, portRange.End)
- }
- if portRange.Start <= api.GUEST_PORT_MAPPING_RANGE_START {
- return httperrors.NewInputParameterError("port range start %d <= %d", api.GUEST_PORT_MAPPING_RANGE_START, portRange.Start)
- }
- if portRange.End > api.GUEST_PORT_MAPPING_RANGE_END {
- return httperrors.NewInputParameterError("port range end %d > %d", api.GUEST_PORT_MAPPING_RANGE_END, portRange.End)
- }
- }
- return nil
- }
- func validatePort(port int, start int, end int) error {
- if port < start || port > end {
- return httperrors.NewInputParameterError("port number %d isn't within %d to %d", port, start, end)
- }
- return nil
- }
- func validatePortMapping(pm *api.GuestPortMapping) error {
- if err := validatePortRange(pm.HostPortRange); err != nil {
- return err
- }
- if pm.HostPort != nil {
- if err := validatePort(*pm.HostPort, api.GUEST_PORT_MAPPING_RANGE_START, api.GUEST_PORT_MAPPING_RANGE_END); err != nil {
- return errors.Wrap(err, "validate host_port")
- }
- }
- // -1 端口表示自动分配
- if pm.Port != -1 {
- if err := validatePort(pm.Port, 1, 65535); err != nil {
- return errors.Wrap(err, "validate port")
- }
- }
- if pm.Protocol == "" {
- pm.Protocol = api.GuestPortMappingProtocolTCP
- }
- if !sets.NewString(string(api.GuestPortMappingProtocolUDP), string(api.GuestPortMappingProtocolTCP)).Has(string(pm.Protocol)) {
- return httperrors.NewInputParameterError("unsupported protocol %s", pm.Protocol)
- }
- if len(pm.RemoteIps) != 0 {
- for _, ip := range pm.RemoteIps {
- if !regutils.MatchIPAddr(ip) && !regutils.MatchCIDR(ip) {
- return httperrors.NewInputParameterError("invalid ip or prefix %s", ip)
- }
- }
- }
- if pm.Rule != nil {
- if pm.Rule.FirstPortOffset != nil {
- if *pm.Rule.FirstPortOffset < 0 {
- return httperrors.NewInputParameterError("first port offset %d is less than 0", *pm.Rule.FirstPortOffset)
- }
- }
- }
- for _, env := range pm.Envs {
- if env.ValueFrom != api.GuestPortMappingEnvValueFromPort && env.ValueFrom != api.GuestPortMappingEnvValueFromHostPort {
- return httperrors.NewInputParameterError("invalid value from %s", env.ValueFrom)
- }
- }
- return nil
- }
- func IsExitNetworkInfo(ctx context.Context, userCred mcclient.TokenCredential, netConfig *api.NetworkConfig) bool {
- if len(netConfig.Network) > 0 {
- netObj, _ := NetworkManager.FetchByIdOrName(ctx, userCred, netConfig.Network)
- net := netObj.(*SNetwork)
- if net.IsExitNetwork() {
- return true
- }
- } else if netConfig.Exit {
- return true
- }
- return false
- }
- func (manager *SNetworkManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []api.NetworkDetails {
- rows := make([]api.NetworkDetails, len(objs))
- virtRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- wireRows := manager.SWireResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- netIds := make([]string, len(objs))
- for i := range rows {
- rows[i] = api.NetworkDetails{
- SharableVirtualResourceDetails: virtRows[i],
- WireResourceInfo: wireRows[i],
- }
- network := objs[i].(*SNetwork)
- rows[i].Exit = false
- if network.IsExitNetwork() {
- rows[i].Exit = true
- }
- if network.IsClassic() {
- rows[i].IsClassic = true
- }
- rows[i].Ports = network.GetTotalAddressCount()
- rows[i].Routes = network.GetRoutes()
- rows[i].Schedtags = GetSchedtagsDetailsToResourceV2(network, ctx)
- rows[i].Dns = network.GetDNS(rows[i].Zone)
- rows[i].AdditionalWires = network.fetchAdditionalWires()
- netIds[i] = network.Id
- }
- vnics, err := manager.TotalNicCount(netIds)
- if err != nil {
- return rows
- }
- for i := range rows {
- rows[i].SNetworkNics, _ = vnics[netIds[i]]
- }
- return rows
- }
- func (manager *SNetworkManager) GetTotalNicCount(netIds []string) (map[string]int, error) {
- vnics, err := manager.TotalNicCount(netIds)
- if err != nil {
- return nil, errors.Wrapf(err, "TotalNicCount")
- }
- result := map[string]int{}
- for _, id := range netIds {
- result[id] = 0
- if nics, ok := vnics[id]; ok {
- result[id] = nics.Total
- }
- }
- return result, nil
- }
- type SNetworkNics struct {
- Id string
- api.SNetworkNics
- }
- func (nm *SNetworkManager) query(manager db.IModelManager, field string, netIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
- q := manager.Query()
- if filter != nil {
- q = filter(q)
- }
- sq := q.SubQuery()
- return sq.Query(
- sq.Field("network_id"),
- sqlchemy.COUNT(field),
- ).In("network_id", netIds).GroupBy(sq.Field("network_id")).SubQuery()
- }
- func (nm *SNetworkManager) TotalNicCount(netIds []string) (map[string]api.SNetworkNics, error) {
- // guest vnic
- vnicSQ := nm.query(GuestnetworkManager, "vnic", netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsFalse("virtual")
- })
- vnic4SQ := nm.query(GuestnetworkManager, "vnic4", netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsNotEmpty("ip_addr")
- })
- vnic6SQ := nm.query(GuestnetworkManager, "vnic6", netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsNotEmpty("ip6_addr")
- })
- // bm vnic
- bmSQ := nm.query(HostnetworkManager, "bm_vnic", netIds, nil)
- // lb vnic
- lbSQ := nm.query(LoadbalancernetworkManager, "lb_vnic", netIds, nil)
- // eip vnic
- eipSQ := nm.query(ElasticipManager, "eip_vnic", netIds, nil)
- // group vnic
- groupSQ := nm.query(GroupnetworkManager, "group_vnic", netIds, nil)
- // reserved vnics
- reserve4SQ := nm.query(ReservedipManager, "reserve_vnic4", netIds, filterExpiredReservedIp4s)
- reserve6SQ := nm.query(ReservedipManager, "reserve_vnic6", netIds, filterExpiredReservedIp6s)
- // rds vnics
- rdsSQ := nm.query(DBInstanceNetworkManager, "rds_vnic", netIds, nil)
- // nat vnics
- natSQ := nm.query(NatGatewayManager, "nat_vnic", netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.IsNotEmpty("ip_addr")
- })
- // networkinterface vncis
- nisSQ := nm.query(NetworkinterfacenetworkManager, "networkinterface_vnic", netIds, nil)
- // bm reused vnics
- bmReusedSQ := nm.query(GuestnetworkManager, "bm_reused_vnic", netIds, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- guest := GuestManager.Query().SubQuery()
- bmn := HostnetworkManager.Query().SubQuery()
- return q.Join(guest, sqlchemy.Equals(guest.Field("id"), q.Field("guest_id"))).Join(bmn, sqlchemy.AND(
- sqlchemy.Equals(q.Field("ip_addr"), bmn.Field("ip_addr")),
- sqlchemy.Equals(guest.Field("host_id"), bmn.Field("baremetal_id")),
- ))
- })
- nets := nm.Query().SubQuery()
- netQ := nets.Query(
- sqlchemy.SUM("vnics", vnicSQ.Field("vnic")),
- sqlchemy.SUM("vnics4", vnic4SQ.Field("vnic4")),
- sqlchemy.SUM("vnics6", vnic6SQ.Field("vnic6")),
- sqlchemy.SUM("bm_vnics", bmSQ.Field("bm_vnic")),
- sqlchemy.SUM("lb_vnics", lbSQ.Field("lb_vnic")),
- sqlchemy.SUM("eip_vnics", eipSQ.Field("eip_vnic")),
- sqlchemy.SUM("group_vnics", groupSQ.Field("group_vnic")),
- sqlchemy.SUM("reserve_vnics4", reserve4SQ.Field("reserve_vnic4")),
- sqlchemy.SUM("reserve_vnics6", reserve6SQ.Field("reserve_vnic6")),
- sqlchemy.SUM("rds_vnics", rdsSQ.Field("rds_vnic")),
- sqlchemy.SUM("nat_vnics", natSQ.Field("nat_vnic")),
- sqlchemy.SUM("networkinterface_vnics", nisSQ.Field("networkinterface_vnic")),
- sqlchemy.SUM("bm_reused_vnics", bmReusedSQ.Field("bm_reused_vnic")),
- )
- netQ.AppendField(netQ.Field("id"))
- netQ = netQ.LeftJoin(vnicSQ, sqlchemy.Equals(netQ.Field("id"), vnicSQ.Field("network_id")))
- netQ = netQ.LeftJoin(vnic4SQ, sqlchemy.Equals(netQ.Field("id"), vnic4SQ.Field("network_id")))
- netQ = netQ.LeftJoin(vnic6SQ, sqlchemy.Equals(netQ.Field("id"), vnic6SQ.Field("network_id")))
- netQ = netQ.LeftJoin(bmSQ, sqlchemy.Equals(netQ.Field("id"), bmSQ.Field("network_id")))
- netQ = netQ.LeftJoin(lbSQ, sqlchemy.Equals(netQ.Field("id"), lbSQ.Field("network_id")))
- netQ = netQ.LeftJoin(eipSQ, sqlchemy.Equals(netQ.Field("id"), eipSQ.Field("network_id")))
- netQ = netQ.LeftJoin(groupSQ, sqlchemy.Equals(netQ.Field("id"), groupSQ.Field("network_id")))
- netQ = netQ.LeftJoin(reserve4SQ, sqlchemy.Equals(netQ.Field("id"), reserve4SQ.Field("network_id")))
- netQ = netQ.LeftJoin(reserve6SQ, sqlchemy.Equals(netQ.Field("id"), reserve6SQ.Field("network_id")))
- netQ = netQ.LeftJoin(rdsSQ, sqlchemy.Equals(netQ.Field("id"), rdsSQ.Field("network_id")))
- netQ = netQ.LeftJoin(natSQ, sqlchemy.Equals(netQ.Field("id"), natSQ.Field("network_id")))
- netQ = netQ.LeftJoin(nisSQ, sqlchemy.Equals(netQ.Field("id"), nisSQ.Field("network_id")))
- netQ = netQ.LeftJoin(bmReusedSQ, sqlchemy.Equals(netQ.Field("id"), bmReusedSQ.Field("network_id")))
- netQ = netQ.Filter(sqlchemy.In(netQ.Field("id"), netIds)).GroupBy(netQ.Field("id"))
- nics := []SNetworkNics{}
- err := netQ.All(&nics)
- if err != nil {
- return nil, errors.Wrapf(err, "netQ.All")
- }
- result := map[string]api.SNetworkNics{}
- for i := range nics {
- nics[i].SumTotal()
- result[nics[i].Id] = nics[i].SNetworkNics
- }
- return result, nil
- }
- // 预留IP
- // 预留的IP不会被调度使用
- func (snet *SNetwork) PerformReserveIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkReserveIpInput) (jsonutils.JSONObject, error) {
- if len(input.Ips) == 0 {
- return nil, httperrors.NewMissingParameterError("ips")
- }
- var duration time.Duration
- if len(input.Duration) > 0 {
- bc, err := billing.ParseBillingCycle(input.Duration)
- if err != nil {
- return nil, httperrors.NewInputParameterError("Duration %s invalid", input.Duration)
- }
- duration = bc.Duration()
- }
- errs := make([]error, 0)
- for _, ip := range input.Ips {
- err := snet.reserveIpWithDurationAndStatus(ctx, userCred, ip, input.Notes, duration, input.Status)
- if err != nil {
- errs = append(errs, errors.Wrap(err, "reserveIpWithDurationAndStatus"))
- }
- }
- if len(errs) > 0 {
- return nil, errors.NewAggregate(errs)
- }
- return nil, nil
- }
- func (net *SNetwork) reserveIpWithDuration(ctx context.Context, userCred mcclient.TokenCredential, ipstr string, notes string, duration time.Duration) error {
- return net.reserveIpWithDurationAndStatus(ctx, userCred, ipstr, notes, duration, "")
- }
- func (net *SNetwork) reserveIpWithDurationAndStatus(ctx context.Context, userCred mcclient.TokenCredential, ipstr string, notes string, duration time.Duration, status string) error {
- var used bool
- var addrType api.TAddressType
- if regutils.MatchIP6Addr(ipstr) {
- addr6, err := netutils.NewIPV6Addr(ipstr)
- if err != nil {
- return httperrors.NewInputParameterError("not a valid ipv6 address %s: %s", ipstr, err)
- }
- if !net.IsSupportIPv6() {
- return httperrors.NewInputParameterError("network is not ipv6 enabled")
- }
- if !net.IsAddress6InRange(addr6) {
- return httperrors.NewInputParameterError("Address %s not in network", ipstr)
- }
- used, err = net.isAddress6Used(ctx, addr6.String())
- if err != nil {
- return httperrors.NewInternalServerError("isAddress6Used fail %s", err)
- }
- addrType = api.AddressTypeIPv6
- ipstr = addr6.String()
- } else if regutils.MatchIP4Addr(ipstr) {
- ipAddr, err := netutils.NewIPV4Addr(ipstr)
- if err != nil {
- return httperrors.NewInputParameterError("not a valid ip address %s: %s", ipstr, err)
- }
- if !net.IsAddressInRange(ipAddr) {
- return httperrors.NewInputParameterError("Address %s not in network", ipstr)
- }
- used, err = net.isAddressUsed(ctx, ipstr)
- if err != nil {
- return httperrors.NewInternalServerError("isAddressUsed fail %s", err)
- }
- addrType = api.AddressTypeIPv4
- } else {
- return errors.Wrapf(httperrors.ErrInvalidFormat, "ip %s is neither ipv4 nor ipv6", ipstr)
- }
- if used {
- rip := ReservedipManager.getReservedIP(net, ipstr, addrType)
- if rip != nil {
- err := rip.extendWithDuration(notes, duration, status)
- if err != nil {
- return errors.Wrap(err, "extendWithDuration")
- }
- return nil
- }
- return httperrors.NewConflictError("Address %s has been used", ipstr)
- }
- err := ReservedipManager.ReserveIPWithDurationAndStatus(ctx, userCred, net, ipstr, notes, duration, status, addrType)
- if err != nil {
- return errors.Wrap(err, "ReservedipManager.ReserveIPWithDurationAndStatus")
- }
- return nil
- }
- // 释放预留IP
- func (snet *SNetwork) PerformReleaseReservedIp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkReleaseReservedIpInput) (jsonutils.JSONObject, error) {
- if len(input.Ip) == 0 {
- return nil, httperrors.NewMissingParameterError("ip")
- }
- addrType := api.AddressTypeIPv4
- if regutils.MatchIP6Addr(input.Ip) {
- addr, err := netutils.NewIPV6Addr(input.Ip)
- if err != nil {
- return nil, errors.Wrap(httperrors.ErrInvalidFormat, err.Error())
- }
- input.Ip = addr.String()
- }
- rip := ReservedipManager.getReservedIP(snet, input.Ip, addrType)
- if rip == nil {
- return nil, httperrors.NewInvalidStatusError("Address %s not reserved", input.Ip)
- }
- rip.Release(ctx, userCred, snet)
- return nil, nil
- }
- func (snet *SNetwork) GetDetailsReservedIps(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- rips := ReservedipManager.GetReservedIPs(snet)
- if rips == nil {
- return nil, httperrors.NewInternalServerError("get reserved ip error")
- }
- ripV4 := make([]string, 0)
- ripV6 := make([]string, 0)
- for i := 0; i < len(rips); i += 1 {
- if len(rips[i].IpAddr) > 0 {
- ripV4 = append(ripV4, rips[i].IpAddr)
- }
- if len(rips[i].Ip6Addr) > 0 {
- ripV6 = append(ripV6, rips[i].Ip6Addr)
- }
- }
- ret := jsonutils.NewDict()
- if len(ripV4) > 0 {
- ret.Add(jsonutils.Marshal(ripV4), "reserved_ips")
- }
- if len(ripV6) > 0 {
- ret.Add(jsonutils.Marshal(ripV6), "reserved_ip6s")
- }
- return ret, nil
- }
- func isValidIpv4MaskLen(maskLen int8) bool {
- if maskLen < 12 || maskLen > 30 {
- return false
- } else {
- return true
- }
- }
- func isValidIpv6MaskLen(maskLen uint8) bool {
- if maskLen < 48 || maskLen > 126 {
- return false
- } else {
- return true
- }
- }
- func (snet *SNetwork) ensureIfnameHint() {
- if snet.IfnameHint != "" {
- return
- }
- hint, err := NetworkManager.newIfnameHint(snet.Name)
- if err != nil {
- panic(errors.Wrap(err, "ensureIfnameHint: allocate hint"))
- }
- _, err = db.Update(snet, func() error {
- snet.IfnameHint = hint
- return nil
- })
- if err != nil {
- panic(errors.Wrap(err, "ensureIfnameHint: db update"))
- }
- log.Infof("network %s(%s): initialized ifname hint: %s", snet.Name, snet.Id, hint)
- }
- func (manager *SNetworkManager) NewIfnameHint(hint string) (string, error) {
- return manager.newIfnameHint(hint)
- }
- func (manager *SNetworkManager) newIfnameHint(hint string) (string, error) {
- isa := func(c byte) bool {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
- }
- isn := func(c byte) bool {
- return (c >= '0' && c <= '9')
- }
- sani := func(r string) string {
- if r != "" && !isa(r[0]) {
- r = "a" + r
- }
- if len(r) > MAX_HINT_LEN {
- r = r[:MAX_HINT_LEN]
- }
- return r
- }
- rand := func(base string) (string, error) {
- if len(base) > HINT_BASE_LEN {
- base = base[:HINT_BASE_LEN]
- }
- for i := 0; i < 3; i++ {
- r := sani(base + rand.String(HINT_RAND_LEN))
- cnt, err := manager.Query().Equals("ifname_hint", r).CountWithError()
- if err == nil && cnt == 0 {
- return r, nil
- }
- }
- /* generate ifname by ifname hint failed
- * try generate from rand string */
- for i := 0; i < 3; i++ {
- r := sani(rand.String(MAX_HINT_LEN))
- cnt, err := manager.Query().Equals("ifname_hint", r).CountWithError()
- if err == nil && cnt == 0 {
- return r, nil
- }
- }
- return "", fmt.Errorf("failed finding ifname hint")
- }
- r := ""
- for i := range hint {
- c := hint[i]
- if isa(c) || isn(c) || c == '_' {
- r += string(c)
- }
- }
- r = sani(r)
- if len(r) < 3 {
- return rand(r)
- }
- if cnt, err := manager.Query().Equals("ifname_hint", r).CountWithError(); err != nil {
- return "", err
- } else if cnt > 0 {
- return rand(r)
- }
- return r, nil
- }
- func (manager *SNetworkManager) validateEnsureWire(ctx context.Context, userCred mcclient.TokenCredential, input api.NetworkCreateInput) (w *SWire, v *SVpc, cr *SCloudregion, err error) {
- wObj, err := WireManager.FetchByIdOrName(ctx, userCred, input.Wire)
- if err != nil {
- err = errors.Wrapf(err, "wire %s", input.Wire)
- return
- }
- w = wObj.(*SWire)
- v, _ = w.GetVpc()
- crObj, err := CloudregionManager.FetchById(v.CloudregionId)
- if err != nil {
- err = errors.Wrapf(err, "cloudregion %s", v.CloudregionId)
- return
- }
- cr = crObj.(*SCloudregion)
- return
- }
- func (manager *SNetworkManager) validateEnsureZoneVpc(ctx context.Context, userCred mcclient.TokenCredential, input api.NetworkCreateInput) (*SWire, *SVpc, *SCloudregion, error) {
- zObj, err := validators.ValidateModel(ctx, userCred, ZoneManager, &input.Zone)
- if err != nil {
- return nil, nil, nil, err
- }
- z := zObj.(*SZone)
- vObj, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.Vpc)
- if err != nil {
- return nil, nil, nil, err
- }
- v := vObj.(*SVpc)
- cr, err := z.GetRegion()
- if err != nil {
- return nil, nil, nil, err
- }
- // 华为云,ucloud wire zone_id 为空
- var wires []SWire
- if utils.IsInStringArray(cr.Provider, api.REGIONAL_NETWORK_PROVIDERS) {
- wires, err = WireManager.getWiresByVpcAndZone(v, nil)
- } else {
- wires, err = WireManager.getWiresByVpcAndZone(v, z)
- }
- if err != nil {
- return nil, nil, nil, err
- }
- if len(wires) > 1 {
- return nil, nil, nil, httperrors.NewConflictError("found %d wires for zone %s and vpc %s", len(wires), input.Zone, input.Vpc)
- }
- if len(wires) == 1 {
- return &wires[0], v, cr, nil
- }
- externalId := ""
- if cr.Provider == api.CLOUD_PROVIDER_CLOUDPODS {
- iVpc, err := v.GetIVpc(ctx)
- if err != nil {
- return nil, nil, nil, err
- }
- iWire, err := iVpc.CreateIWire(&cloudprovider.SWireCreateOptions{
- Name: fmt.Sprintf("vpc-%s", v.Name),
- ZoneId: z.ExternalId,
- Bandwidth: 10000,
- Mtu: 1500,
- })
- if err != nil {
- return nil, nil, nil, errors.Wrapf(err, "CreateIWire")
- }
- externalId = iWire.GetGlobalId()
- }
- // wire not found. We auto create one for OneCloud vpc
- if cr.Provider == api.CLOUD_PROVIDER_ONECLOUD || cr.Provider == api.CLOUD_PROVIDER_CLOUDPODS {
- w, err := v.initWire(ctx, z, externalId)
- if err != nil {
- return nil, nil, nil, errors.Wrapf(err, "vpc %s init wire", v.Id)
- }
- return w, v, cr, nil
- }
- return nil, nil, nil, httperrors.NewNotFoundError("wire not found for zone %s and vpc %s", input.Zone, input.Vpc)
- }
- func (manager *SNetworkManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NetworkCreateInput) (api.NetworkCreateInput, error) {
- if input.ServerType == "" {
- input.ServerType = api.NETWORK_TYPE_GUEST
- } else if !api.IsInNetworkTypes(input.ServerType, api.ALL_NETWORK_TYPES) {
- return input, httperrors.NewInputParameterError("Invalid server_type: %s", input.ServerType)
- }
- var (
- wire *SWire
- vpc *SVpc
- region *SCloudregion
- err error
- )
- if input.WireId != "" {
- input.Wire = input.WireId
- }
- if input.Wire != "" {
- wire, vpc, region, err = manager.validateEnsureWire(ctx, userCred, input)
- if err != nil {
- return input, err
- }
- } else if input.Zone != "" && input.Vpc != "" {
- wire, vpc, region, err = manager.validateEnsureZoneVpc(ctx, userCred, input)
- if err != nil {
- return input, err
- }
- } else {
- return input, httperrors.NewInputParameterError("zone and vpc info required when wire is absent")
- }
- {
- if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID {
- input.ServerType = api.NETWORK_TYPE_HOSTLOCAL
- }
- }
- input.WireId = wire.Id
- if vpc.Status != api.VPC_STATUS_AVAILABLE {
- return input, httperrors.NewInvalidStatusError("VPC not ready")
- }
- if input.ServerType == api.NETWORK_TYPE_EIP && vpc.Id != api.DEFAULT_VPC_ID {
- return input, httperrors.NewInputParameterError("eip network can only exist in default vpc, got %s(%s)", vpc.Name, vpc.Id)
- }
- // if input.ServerType != api.NETWORK_TYPE_EIP {
- // input.BgpType = ""
- // }
- // check class metadata
- { // wire != nil
- var projectId string
- if len(input.ProjectId) > 0 {
- projectId = input.ProjectId
- } else {
- projectId = ownerId.GetProjectId()
- }
- project, err := db.TenantCacheManager.FetchTenantById(ctx, projectId)
- if err != nil {
- return input, errors.Wrapf(err, "unable to fetch tenant by id %s", projectId)
- }
- ok, err := db.IsInSameClass(ctx, wire, project)
- if err != nil {
- return input, errors.Wrapf(err, "unable to check if wire and project is in same class")
- }
- if !ok {
- return input, httperrors.NewForbiddenError("the wire %s and project %s has different class metadata", wire.GetName(), project.GetName())
- }
- }
- if vpc.Id != api.DEFAULT_VPC_ID {
- // require prefix
- if len(input.GuestIpPrefix) == 0 && len(input.GuestIp6Start) > 0 && len(input.GuestIp6End) > 0 {
- return input, errors.Wrap(httperrors.ErrInputParameter, "guest_ip_prefix is required")
- }
- if len(input.GuestIp6Prefix) == 0 && len(input.GuestIp6Start) > 0 && len(input.GuestIp6End) > 0 {
- return input, errors.Wrap(httperrors.ErrInputParameter, "guest_ip6_prefix is required")
- }
- }
- {
- defaultVlanId := 1
- if input.VlanId == nil {
- input.VlanId = &defaultVlanId
- } else if *input.VlanId < 1 {
- input.VlanId = &defaultVlanId
- }
- if *input.VlanId > 4095 {
- return input, httperrors.NewInputParameterError("valid vlan id")
- }
- }
- {
- if len(input.IfnameHint) == 0 {
- input.IfnameHint = input.Name
- }
- var err error
- input.IfnameHint, err = manager.newIfnameHint(input.IfnameHint)
- if err != nil {
- return input, httperrors.NewBadRequestError("cannot derive valid ifname hint: %v", err)
- }
- }
- var (
- ipRange *netutils.IPV4AddrRange
- masklen int8
- netAddr netutils.IPV4Addr
- )
- if len(input.GuestIpPrefix) > 0 {
- prefix, err := netutils.NewIPV4Prefix(input.GuestIpPrefix)
- if err != nil {
- return input, httperrors.NewInputParameterError("ip_prefix error: %s", err)
- }
- ipRangeTmp := prefix.ToIPRange()
- ipRange = &ipRangeTmp
- masklen = prefix.MaskLen
- netAddr = prefix.Address.NetAddr(masklen)
- input.GuestIpMask = prefix.MaskLen
- if !isValidIpv4MaskLen(masklen) {
- return input, httperrors.NewInputParameterError("subnet masklen should be smaller than 30")
- }
- // 根据掩码得到合法的GuestIpPrefix
- input.GuestIpPrefix = prefix.String()
- if region.Provider == api.CLOUD_PROVIDER_ONECLOUD && vpc.Id != api.DEFAULT_VPC_ID {
- // reserve addresses for onecloud vpc networks
- gateway := netAddr.StepUp()
- brdAddr := gateway.BroadcastAddr(masklen)
- // NOTE
- //
- // - reserve the 1st addr as gateway
- // - reserve the last ip for broadcasting
- // - reserve the 2nd-to-last for possible future use
- //
- // We do not allow split 192.168.1.0/24 into multiple ranges
- // like
- //
- // - 192.168.1.50-192.168.1.100,
- // - 192.168.1.100-192.168.1.200
- //
- // This could complicate gateway setting and topology
- // management without much benefit to end users
- ipStart := gateway.StepUp()
- ipEnd := brdAddr.StepDown().StepDown()
- ipRange.Set(ipStart, ipEnd)
- input.GuestGateway = gateway.String()
- }
- } else if len(input.GuestIpStart) > 0 && len(input.GuestIpEnd) > 0 {
- if !isValidIpv4MaskLen(input.GuestIpMask) {
- return input, httperrors.NewInputParameterError("Invalid masklen %d", input.GuestIpMask)
- }
- ipStart, err := netutils.NewIPV4Addr(input.GuestIpStart)
- if err != nil {
- return input, httperrors.NewInputParameterError("Invalid start ip: %s %s", input.GuestIpStart, err)
- }
- ipEnd, err := netutils.NewIPV4Addr(input.GuestIpEnd)
- if err != nil {
- return input, httperrors.NewInputParameterError("invalid end ip: %s %s", input.GuestIpEnd, err)
- }
- ipRangeTpm := netutils.NewIPV4AddrRange(ipStart, ipEnd)
- ipRange = &ipRangeTpm
- masklen = input.GuestIpMask
- netAddr = ipStart.NetAddr(masklen)
- if ipEnd.NetAddr(masklen) != netAddr {
- return input, httperrors.NewInputParameterError("start and end ip not in the same subnet")
- }
- if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID && len(input.GuestGateway) == 0 {
- return input, httperrors.NewInputParameterError("host local wire only support gateway ip")
- }
- }
- var (
- ipRange6 *netutils.IPV6AddrRange
- masklen6 uint8
- netAddr6 netutils.IPV6Addr
- )
- if len(input.GuestIp6Prefix) > 0 {
- prefix, err := netutils.NewIPV6Prefix(input.GuestIp6Prefix)
- if err != nil {
- return input, httperrors.NewInputParameterError("ip_prefix error: %s", err)
- }
- ipRange6tmp := prefix.ToIPRange()
- ipRange6 = &ipRange6tmp
- masklen6 = prefix.MaskLen
- netAddr6 = prefix.Address.NetAddr(masklen6)
- input.GuestIp6Mask = prefix.MaskLen
- if !isValidIpv6MaskLen(masklen6) {
- return input, httperrors.NewInputParameterError("ipv6 subnet masklen should be between 48~126")
- }
- // 根据掩码得到合法的GuestIp6Prefix
- input.GuestIp6Prefix = prefix.String()
- if region.Provider == api.CLOUD_PROVIDER_ONECLOUD && vpc.Id != api.DEFAULT_VPC_ID {
- // reserve addresses for onecloud vpc networks
- gateway := netAddr6.StepUp()
- brdAddr := gateway.BroadcastAddr(masklen6)
- // NOTE
- //
- // - reserve the 1st addr as gateway
- // - reserve the last ip for broadcasting
- // - reserve the 2nd-to-last for possible future use
- //
- // This could complicate gateway setting and topology
- // management without much benefit to end users
- ipStart := gateway.StepUp()
- ipEnd := brdAddr.StepDown().StepDown()
- ipRange6.Set(ipStart, ipEnd)
- input.GuestGateway6 = gateway.String()
- }
- } else if len(input.GuestIp6Start) > 0 && len(input.GuestIp6End) > 0 {
- if !isValidIpv6MaskLen(input.GuestIp6Mask) {
- return input, httperrors.NewInputParameterError("Invalid ipv6 masklen %d", input.GuestIp6Mask)
- }
- ip6Start, err := netutils.NewIPV6Addr(input.GuestIp6Start)
- if err != nil {
- return input, httperrors.NewInputParameterError("Invalid start v6 ip: %s %s", input.GuestIp6Start, err)
- }
- ip6End, err := netutils.NewIPV6Addr(input.GuestIp6End)
- if err != nil {
- return input, httperrors.NewInputParameterError("invalid end v6 ip: %s %s", input.GuestIp6End, err)
- }
- ipRange6tmp := netutils.NewIPV6AddrRange(ip6Start, ip6End)
- ipRange6 = &ipRange6tmp
- masklen6 = input.GuestIp6Mask
- netAddr6 = ip6Start.NetAddr(masklen6)
- if !ip6End.NetAddr(masklen6).Equals(netAddr6) {
- return input, httperrors.NewInputParameterError("v6 start and end ip not in the same subnet")
- }
- if wire.Id == api.DEFAULT_HOST_LOCAL_WIRE_ID && len(input.GuestGateway6) == 0 {
- return input, httperrors.NewInputParameterError("host local wire only support gateway v6 ip")
- }
- }
- if ipRange == nil && ipRange6 == nil {
- return input, httperrors.NewBadRequestError("No valid ipv4/ipv6 address input")
- }
- // do not set default dns
- // if len(input.GuestDns) == 0 {
- // input.GuestDns = options.Options.DNSServer
- // }
- for key, ipStr := range map[string]string{
- "guest_gateway": input.GuestGateway,
- "guest_dns": input.GuestDns,
- "guest_dhcp": input.GuestDHCP,
- "guest_ntp": input.GuestNtp,
- "guest_gateway6": input.GuestGateway6,
- } {
- if ipStr == "" {
- continue
- }
- if key == "guest_dhcp" || key == "guest_dns" {
- ipList := strings.Split(ipStr, ",")
- for _, ipstr := range ipList {
- if !regutils.MatchIPAddr(ipstr) {
- return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipstr)
- }
- }
- } else if key == "guest_ntp" {
- ipList := strings.Split(ipStr, ",")
- for _, ipstr := range ipList {
- if !regutils.MatchDomainName(ipstr) && !regutils.MatchIPAddr(ipstr) {
- return input, httperrors.NewInputParameterError("%s: Invalid domain name or IP address %s", key, ipstr)
- }
- }
- } else if !regutils.MatchIPAddr(ipStr) {
- return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipStr)
- }
- }
- if input.GuestGateway != "" {
- addr, err := netutils.NewIPV4Addr(input.GuestGateway)
- if err != nil {
- return input, httperrors.NewInputParameterError("bad gateway ip: %v", err)
- }
- if addr.NetAddr(masklen) != netAddr {
- return input, httperrors.NewInputParameterError("gateway ip must be in the same subnet as start, end ip")
- }
- }
- if input.GuestGateway6 != "" {
- addr, err := netutils.NewIPV6Addr(input.GuestGateway6)
- if err != nil {
- return input, httperrors.NewInputParameterError("bad v6 gateway ip: %v", err)
- }
- if !addr.NetAddr(masklen6).Equals(netAddr6) {
- return input, httperrors.NewInputParameterError("ipv6 gateway ip must be in the same subnet as start, end v6 ip")
- }
- }
- {
- if ipRange != nil && !vpc.containsIPV4Range(*ipRange) {
- return input, httperrors.NewInputParameterError("Network not in range of VPC cidrblock %s", vpc.CidrBlock)
- }
- if ipRange6 != nil {
- if !vpc.containsIPV6Range(*ipRange6) {
- return input, httperrors.NewInputParameterError("Network not in range of VPC ipv6 cidrblock %s", vpc.CidrBlock6)
- }
- }
- }
- {
- provider := wire.GetProviderName()
- nets, err := vpc.GetNetworksByProvider(provider)
- if err != nil {
- return input, httperrors.NewInternalServerError("fail to GetNetworks of vpc: %v", err)
- }
- if ipRange != nil && isOverlapNetworks(nets, *ipRange) {
- return input, httperrors.NewInputParameterError("Conflict address space with existing networks in vpc %q", vpc.GetName())
- }
- if ipRange6 != nil && isOverlapNetworks6(nets, *ipRange6) {
- return input, httperrors.NewInputParameterError("Conflict address space with existing networks in vpc %q", vpc.GetName())
- }
- }
- if ipRange != nil {
- input.GuestIpStart = ipRange.StartIp().String()
- input.GuestIpEnd = ipRange.EndIp().String()
- }
- if ipRange6 != nil {
- // validate v6 ip addr
- input.GuestIp6Start = ipRange6.StartIp().String()
- input.GuestIp6End = ipRange6.EndIp().String()
- }
- input.SharableVirtualResourceCreateInput, err = manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
- if err != nil {
- return input, err
- }
- return input, nil
- }
- func (snet *SNetwork) validateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.NetworkUpdateInput) (api.NetworkUpdateInput, error) {
- var (
- netAddr netutils.IPV4Addr
- masklen int8
- netAddr6 netutils.IPV6Addr
- masklen6 uint8
- err error
- )
- if input.GuestIpMask > 0 {
- if !snet.isManaged() && !isValidIpv4MaskLen(input.GuestIpMask) {
- return input, httperrors.NewInputParameterError("Invalid masklen %d", input.GuestIpMask)
- }
- masklen = input.GuestIpMask
- } else {
- masklen = snet.GuestIpMask
- }
- if input.GuestIp6Mask != nil && *input.GuestIp6Mask > 0 {
- if !snet.isManaged() && !isValidIpv6MaskLen(*input.GuestIp6Mask) {
- return input, httperrors.NewInputParameterError("Invalid ipv6 masklen %d", *input.GuestIp6Mask)
- }
- masklen6 = *input.GuestIp6Mask
- } else {
- masklen6 = snet.GuestIp6Mask
- }
- if input.GuestIpStart != "" || input.GuestIpEnd != "" {
- var (
- startIp netutils.IPV4Addr
- endIp netutils.IPV4Addr
- )
- if input.GuestIpStart != "" {
- startIp, err = netutils.NewIPV4Addr(input.GuestIpStart)
- if err != nil {
- return input, httperrors.NewInputParameterError("Invalid start ip: %s %s", input.GuestIpStart, err)
- }
- } else {
- startIp, _ = netutils.NewIPV4Addr(snet.GuestIpStart)
- }
- if input.GuestIpEnd != "" {
- endIp, err = netutils.NewIPV4Addr(input.GuestIpEnd)
- if err != nil {
- return input, httperrors.NewInputParameterError("invalid end ip: %s %s", input.GuestIpEnd, err)
- }
- } else {
- endIp, _ = netutils.NewIPV4Addr(snet.GuestIpEnd)
- }
- netRange := netutils.NewIPV4AddrRange(startIp, endIp)
- nets := NetworkManager.getAllNetworks(snet.WireId, snet.Id)
- if nets == nil {
- return input, httperrors.NewInternalServerError("query all networks fail")
- }
- if isOverlapNetworks(nets, netRange) {
- return input, httperrors.NewInputParameterError("Conflict address space with existing networks")
- }
- vpc, _ := snet.GetVpc()
- if !vpc.containsIPV4Range(netRange) {
- return input, httperrors.NewInputParameterError("Network not in range of VPC cidrblock %s", vpc.CidrBlock)
- }
- usedMap := snet.GetUsedAddresses(ctx)
- for usedIpStr := range usedMap {
- if usedIp, err := netutils.NewIPV4Addr(usedIpStr); err == nil && !netRange.Contains(usedIp) {
- return input, httperrors.NewInputParameterError("Address %s been assigned out of new range", usedIpStr)
- }
- }
- input.GuestIpStart = netRange.StartIp().String()
- input.GuestIpEnd = netRange.EndIp().String()
- netAddr = startIp.NetAddr(masklen)
- if endIp.NetAddr(masklen) != netAddr {
- return input, httperrors.NewInputParameterError("start, end ip must be in the same subnet")
- }
- if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.GuestGateway != nil && len(*input.GuestGateway) == 0 {
- return input, httperrors.NewInputParameterError("host local wire only support gateway ip")
- }
- } else {
- startIp, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- netAddr = startIp.NetAddr(masklen)
- }
- if (input.GuestIp6Start != nil && len(*input.GuestIp6Start) > 0) || (input.GuestIp6End != nil && len(*input.GuestIp6End) > 0) {
- var (
- startIp netutils.IPV6Addr
- endIp netutils.IPV6Addr
- )
- if input.GuestIp6Start != nil && len(*input.GuestIp6Start) > 0 {
- startIp, err = netutils.NewIPV6Addr(*input.GuestIp6Start)
- if err != nil {
- return input, httperrors.NewInputParameterError("Invalid start v6 ip: %s %s", *input.GuestIp6Start, err)
- }
- } else if len(snet.GuestIp6Start) > 0 {
- startIp, _ = netutils.NewIPV6Addr(snet.GuestIp6Start)
- } else {
- return input, httperrors.NewInputParameterError("no start v6 ip")
- }
- if input.GuestIp6End != nil && len(*input.GuestIp6End) > 0 {
- endIp, err = netutils.NewIPV6Addr(*input.GuestIp6End)
- if err != nil {
- return input, httperrors.NewInputParameterError("invalid end v6 ip: %s %s", *input.GuestIp6End, err)
- }
- } else if len(snet.GuestIp6End) > 0 {
- endIp, _ = netutils.NewIPV6Addr(snet.GuestIp6End)
- } else {
- return input, httperrors.NewInputParameterError("no end v6 ip")
- }
- netRange := netutils.NewIPV6AddrRange(startIp, endIp)
- nets := NetworkManager.getAllNetworks(snet.WireId, snet.Id)
- if nets == nil {
- return input, httperrors.NewInternalServerError("query all networks fail")
- }
- if isOverlapNetworks6(nets, netRange) {
- return input, httperrors.NewInputParameterError("Conflict v6 address space with existing networks")
- }
- vpc, _ := snet.GetVpc()
- if !vpc.containsIPV6Range(netRange) {
- return input, httperrors.NewInputParameterError("Network not in range of VPC v6 cidrblock %s", vpc.CidrBlock6)
- }
- usedMap := snet.GetUsedAddresses6(ctx)
- for usedIpStr := range usedMap {
- if usedIp, err := netutils.NewIPV6Addr(usedIpStr); err == nil && !netRange.Contains(usedIp) {
- return input, httperrors.NewInputParameterError("v6 address %s been assigned out of new range", usedIpStr)
- }
- }
- startIpStr := netRange.StartIp().String()
- endIpStr := netRange.EndIp().String()
- input.GuestIp6Start = &startIpStr
- input.GuestIp6End = &endIpStr
- netAddr6 = netRange.StartIp().NetAddr(masklen6)
- if !netRange.EndIp().NetAddr(masklen6).Equals(netAddr6) {
- return input, httperrors.NewInputParameterError("start, end v6 ip must be in the same subnet")
- }
- if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.GuestGateway6 != nil && len(*input.GuestGateway6) == 0 {
- return input, httperrors.NewInputParameterError("host local wire only support gateway ip")
- }
- } else if len(snet.GuestIp6Start) > 0 {
- startIp, _ := netutils.NewIPV6Addr(snet.GuestIp6Start)
- netAddr6 = startIp.NetAddr(masklen6)
- }
- for key, ipStr := range map[string]*string{
- "guest_gateway": input.GuestGateway,
- "guest_dns": input.GuestDns,
- "guest_dhcp": input.GuestDhcp,
- "guest_ntp": input.GuestNtp,
- "guest_gateway6": input.GuestGateway6,
- } {
- if ipStr == nil || len(*ipStr) == 0 {
- continue
- }
- if key == "guest_dhcp" || key == "guest_dns" {
- ipList := strings.Split(*ipStr, ",")
- for _, ipstr := range ipList {
- if !regutils.MatchIPAddr(ipstr) {
- return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, ipstr)
- }
- }
- } else if key == "guest_ntp" {
- ipList := strings.Split(*ipStr, ",")
- for _, ipstr := range ipList {
- if !regutils.MatchDomainName(ipstr) && !regutils.MatchIPAddr(ipstr) {
- return input, httperrors.NewInputParameterError("%s: Invalid domain name or IP address %s", key, ipstr)
- }
- }
- } else if !regutils.MatchIPAddr(*ipStr) {
- return input, httperrors.NewInputParameterError("%s: Invalid IP address %s", key, *ipStr)
- }
- }
- if input.GuestGateway != nil && len(*input.GuestGateway) > 0 {
- addr, err := netutils.NewIPV4Addr(*input.GuestGateway)
- if err != nil {
- return input, httperrors.NewInputParameterError("bad gateway ip: %v", err)
- }
- if addr.NetAddr(masklen) != netAddr {
- return input, httperrors.NewInputParameterError("gateway ip must be in the same subnet as start, end ip")
- }
- }
- if input.GuestGateway6 != nil && len(*input.GuestGateway6) > 0 {
- addr, err := netutils.NewIPV6Addr(*input.GuestGateway6)
- if err != nil {
- return input, httperrors.NewInputParameterError("bad ipv6 gateway ip: %v", err)
- }
- if !addr.NetAddr(masklen6).Equals(netAddr6) {
- return input, httperrors.NewInputParameterError("ipv6 gateway ip must be in the same subnet as start, end v6 ip")
- }
- }
- if input.IsAutoAlloc != nil && *input.IsAutoAlloc {
- if snet.ServerType != api.NETWORK_TYPE_GUEST && snet.ServerType != api.NETWORK_TYPE_HOSTLOCAL {
- return input, httperrors.NewInputParameterError("network server_type %s not support auto alloc", snet.ServerType)
- }
- }
- if len(input.ServerType) > 0 {
- if !api.IsInNetworkTypes(input.ServerType, api.ALL_NETWORK_TYPES) {
- return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid server_type %q", input.ServerType)
- }
- if snet.WireId == api.DEFAULT_HOST_LOCAL_WIRE_ID && input.ServerType != api.NETWORK_TYPE_HOSTLOCAL {
- return input, httperrors.NewInputParameterError("host local wire only support hostlocal server_type")
- }
- }
- return input, nil
- }
- func (snet *SNetwork) ValidateUpdateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.NetworkUpdateInput,
- ) (api.NetworkUpdateInput, error) {
- if snet.isManaged() {
- // managed network, not allow to update
- input.GuestIpStart = ""
- input.GuestIpEnd = ""
- input.GuestIpMask = 0
- input.GuestGateway = nil
- input.GuestDns = nil
- input.GuestDomain = nil
- input.GuestDhcp = nil
- input.GuestNtp = nil
- input.GuestIp6Start = nil
- input.GuestIp6End = nil
- input.GuestIp6Mask = nil
- input.GuestGateway6 = nil
- }
- var err error
- input, err = snet.validateUpdateData(ctx, userCred, query, input)
- if err != nil {
- return input, errors.Wrap(err, "validateUpdateData")
- }
- input.SharableVirtualResourceBaseUpdateInput, err = snet.SSharableVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.SharableVirtualResourceBaseUpdateInput)
- if err != nil {
- return input, errors.Wrap(err, "SSharableVirtualResourceBase.ValidateUpdateData")
- }
- return input, nil
- }
- func (manager *SNetworkManager) getAllNetworks(wireId, excludeId string) []SNetwork {
- nets := make([]SNetwork, 0)
- q := manager.Query().Equals("wire_id", wireId)
- if len(excludeId) > 0 {
- q = q.NotEquals("id", excludeId)
- }
- err := db.FetchModelObjects(manager, q, &nets)
- if err != nil {
- log.Errorf("getAllNetworks fail %s", err)
- return nil
- }
- return nets
- }
- func isOverlapNetworksAddr(nets []SNetwork, startIp, endIp netutils.IPV4Addr) bool {
- ipRange := netutils.NewIPV4AddrRange(startIp, endIp)
- for i := 0; i < len(nets); i += 1 {
- ipRange2 := nets[i].getIPRange()
- if ipRange2 != nil && ipRange2.IsOverlap(ipRange) {
- return true
- }
- }
- return false
- }
- func isOverlapNetworks(nets []SNetwork, ipRange netutils.IPV4AddrRange) bool {
- for i := 0; i < len(nets); i += 1 {
- ipRange2 := nets[i].getIPRange()
- if ipRange2 != nil && ipRange2.IsOverlap(ipRange) {
- return true
- }
- }
- return false
- }
- func isOverlapNetworks6(nets []SNetwork, ipRange netutils.IPV6AddrRange) bool {
- for i := 0; i < len(nets); i += 1 {
- ipRange2 := nets[i].getIPRange6()
- if ipRange2 != nil && ipRange2.IsOverlap(ipRange) {
- return true
- }
- }
- return false
- }
- func (snet *SNetwork) IsManaged() bool {
- wire, _ := snet.GetWire()
- if wire == nil {
- return false
- }
- return wire.IsManaged()
- }
- func (snet *SNetwork) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- if !data.Contains("public_scope") {
- if snet.ServerType == api.NETWORK_TYPE_GUEST && !snet.IsManaged() {
- wire, _ := snet.GetWire()
- if db.IsAdminAllowPerform(ctx, userCred, snet, "public") && ownerId.GetProjectDomainId() == userCred.GetProjectDomainId() && wire != nil && wire.IsPublic && wire.PublicScope == string(rbacscope.ScopeSystem) {
- snet.SetShare(rbacscope.ScopeSystem)
- } else if db.IsDomainAllowPerform(ctx, userCred, snet, "public") && ownerId.GetProjectId() == userCred.GetProjectId() && consts.GetNonDefaultDomainProjects() {
- // only if non_default_domain_projects turned on, share to domain
- snet.SetShare(rbacscope.ScopeDomain)
- } else {
- snet.SetShare(rbacscope.ScopeNone)
- }
- } else {
- snet.SetShare(rbacscope.ScopeNone)
- }
- data.(*jsonutils.JSONDict).Set("public_scope", jsonutils.NewString(snet.PublicScope))
- }
- return snet.SSharableVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
- }
- func (net *SNetwork) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- net.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
- vpc, _ := net.GetVpc()
- if vpc != nil && vpc.IsManaged() {
- task, err := taskman.TaskManager.NewTask(ctx, "NetworkCreateTask", net, userCred, data.(*jsonutils.JSONDict), "", "", nil)
- if err != nil {
- net.SetStatus(ctx, userCred, apis.STATUS_CREATE_FAILED, err.Error())
- return
- }
- task.ScheduleRun(nil)
- } else {
- {
- err := net.syncAdditionalWires(ctx, nil)
- if err != nil {
- log.Errorf("syncAdditionalWires error: %s", err)
- }
- }
- net.SetStatus(ctx, userCred, api.NETWORK_STATUS_AVAILABLE, "")
- if err := net.ClearSchedDescCache(); err != nil {
- log.Errorf("network post create clear schedcache error: %v", err)
- }
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: net,
- Action: notifyclient.ActionCreate,
- })
- }
- // reserve gateway IP
- {
- err := net.reserveGuestGateway(ctx, userCred)
- if err != nil {
- log.Errorf("reserveGuestGateway fail %s", err)
- }
- }
- }
- func (snet *SNetwork) reserveGuestGateway(ctx context.Context, userCred mcclient.TokenCredential) error {
- ipRange := snet.GetIPRange()
- if snet.GuestGateway != "" {
- gatewayIp, _ := netutils.NewIPV4Addr(snet.GuestGateway)
- if ipRange.Contains(gatewayIp) {
- err := snet.reserveIpWithDurationAndStatus(ctx, userCred, snet.GuestGateway, "Reserve GuestGateway IP", 0, api.RESERVEDIP_STATUS_ONLINE)
- if err != nil {
- return errors.Wrap(err, "reserveIpWithDurationAndStatus")
- }
- }
- }
- return nil
- }
- func (snet *SNetwork) GetPrefix() (netutils.IPV4Prefix, error) {
- addr, err := netutils.NewIPV4Addr(snet.GuestIpStart)
- if err != nil {
- return netutils.IPV4Prefix{}, err
- }
- addr = addr.NetAddr(snet.GuestIpMask)
- return netutils.IPV4Prefix{Address: addr, MaskLen: snet.GuestIpMask}, nil
- }
- func (snet *SNetwork) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- log.Infof("SNetwork delete do nothing")
- snet.SetStatus(ctx, userCred, api.NETWORK_STATUS_START_DELETE, "")
- return nil
- }
- func (snet *SNetwork) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- if len(snet.ExternalId) > 0 {
- return snet.StartDeleteNetworkTask(ctx, userCred)
- } else {
- return snet.RealDelete(ctx, userCred)
- }
- }
- func (snet *SNetwork) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- DeleteResourceJointSchedtags(snet, ctx, userCred)
- db.OpsLog.LogEvent(snet, db.ACT_DELOCATE, snet.GetShortDesc(ctx), userCred)
- snet.SetStatus(ctx, userCred, api.NETWORK_STATUS_DELETED, "real delete")
- networkinterfaces, err := snet.GetNetworkInterfaces()
- if err != nil {
- return errors.Wrap(err, "GetNetworkInterfaces")
- }
- for i := range networkinterfaces {
- err = networkinterfaces[i].purge(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "networkinterface.purge %s(%s)", networkinterfaces[i].Name, networkinterfaces[i].Id)
- }
- }
- reservedIps := ReservedipManager.GetReservedIPs(snet)
- for i := range reservedIps {
- err = reservedIps[i].Release(ctx, userCred, snet)
- if err != nil {
- return errors.Wrapf(err, "reservedIps.Release %s/%s(%d)", reservedIps[i].IpAddr, reservedIps[i].Ip6Addr, reservedIps[i].Id)
- }
- }
- gns, err := snet.GetGuestnetworks() // delete virtual nics
- if err != nil {
- return errors.Wrapf(err, "GetGuestnetworks")
- }
- for i := range gns {
- err = gns[i].Delete(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "delete virtual nic %s(%d)", gns[i].Ifname, gns[i].RowId)
- }
- }
- if err := snet.SSharableVirtualResourceBase.Delete(ctx, userCred); err != nil {
- return err
- }
- if err := NetworkAdditionalWireManager.DeleteNetwork(ctx, snet.Id); err != nil {
- return errors.Wrap(err, "NetworkAdditionalWireManager.DeleteNetwork")
- }
- snet.ClearSchedDescCache()
- return nil
- }
- func (snet *SNetwork) StartDeleteNetworkTask(ctx context.Context, userCred mcclient.TokenCredential) error {
- task, err := taskman.TaskManager.NewTask(ctx, "NetworkDeleteTask", snet, userCred, nil, "", "", nil)
- if err != nil {
- log.Errorf("Start NetworkDeleteTask fail %s", err)
- return err
- }
- task.ScheduleRun(nil)
- return nil
- }
- func (snet *SNetwork) GetINetwork(ctx context.Context) (cloudprovider.ICloudNetwork, error) {
- wire, err := snet.GetWire()
- if err != nil {
- return nil, errors.Wrapf(err, "GetWire")
- }
- iwire, err := wire.GetIWire(ctx)
- if err != nil {
- return nil, err
- }
- return iwire.GetINetworkById(snet.GetExternalId())
- }
- func (snet *SNetwork) isManaged() bool {
- if len(snet.ExternalId) > 0 {
- return true
- } else {
- return false
- }
- }
- func (snet *SNetwork) isOneCloudVpcNetwork() bool {
- return IsOneCloudVpcResource(snet)
- }
- /*func parseIpToIntArray(ip string) ([]int, error) {
- ipSp := strings.Split(strings.Trim(ip, "."), ".")
- if len(ipSp) > 4 {
- return nil, httperrors.NewInputParameterError("Parse Ip Failed")
- }
- ipIa := []int{}
- for i := 0; i < len(ipSp); i++ {
- val, err := strconv.Atoi(ipSp[i])
- if err != nil {
- return nil, httperrors.NewInputParameterError("Parse Ip Failed")
- }
- if val < 0 || val > 255 {
- return nil, httperrors.NewInputParameterError("Parse Ip Failed")
- }
- ipIa = append(ipIa, val)
- }
- return ipIa, nil
- }*/
- // IP子网列表
- func (manager *SNetworkManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- input api.NetworkListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.SharableVirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, input.ExternalizedResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
- }
- {
- wireFilter := input.WireResourceInput
- input.Wire = ""
- input.WireId = ""
- q, err = manager.SWireResourceBaseManager.ListItemFilter(ctx, q, userCred, input.WireFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemFilter")
- }
- if len(wireFilter.WireId) > 0 {
- wireObj, err := WireManager.FetchByIdOrName(ctx, userCred, wireFilter.WireId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), wireFilter.WireId)
- } else {
- return nil, errors.Wrapf(err, "WireManager.FetchByIdOrName %s", wireFilter.WireId)
- }
- }
- wireFilter.WireId = wireObj.GetId()
- wireFilter.Wire = wireObj.GetName()
- q = q.Filter(sqlchemy.OR(
- sqlchemy.Equals(q.Field("wire_id"), wireFilter.WireId),
- sqlchemy.In(q.Field("id"), NetworkAdditionalWireManager.networkIdQuery(wireFilter.WireId).SubQuery()),
- ))
- }
- input.WireResourceInput = wireFilter
- }
- if len(input.RouteTableId) > 0 {
- sq := RouteTableAssociationManager.Query("associated_resource_id").Equals("route_table_id", input.RouteTableId).Equals("association_type", string(cloudprovider.RouteTableAssociaToSubnet))
- q = q.In("id", sq.SubQuery())
- }
- if input.Usable != nil && *input.Usable {
- regions := CloudregionManager.Query("id").Equals("status", api.CLOUD_REGION_STATUS_INSERVER)
- zones := ZoneManager.Query("id").Equals("status", api.ZONE_ENABLE).In("cloudregion_id", regions)
- providerSQ := usableCloudProviders()
- _vpcs := VpcManager.Query("id").Equals("status", api.VPC_STATUS_AVAILABLE)
- vpcs := _vpcs.Filter(sqlchemy.OR(
- sqlchemy.In(_vpcs.Field("manager_id"), providerSQ),
- sqlchemy.IsNullOrEmpty(_vpcs.Field("manager_id")),
- ))
- wires := WireManager.Query("id")
- wires = wires.In("vpc_id", vpcs).
- Filter(sqlchemy.OR(sqlchemy.IsNullOrEmpty(wires.Field("zone_id")), sqlchemy.In(wires.Field("zone_id"), zones)))
- q = q.In("wire_id", wires).Equals("status", api.NETWORK_STATUS_AVAILABLE)
- }
- if len(input.HostType) > 0 || len(input.HostId) > 0 {
- classicWiresIdQ := WireManager.Query("id").Equals("vpc_id", api.DEFAULT_VPC_ID)
- netifs := NetInterfaceManager.Query("wire_id", "baremetal_id").SubQuery()
- classicWiresIdQ = classicWiresIdQ.Join(netifs, sqlchemy.Equals(netifs.Field("wire_id"), classicWiresIdQ.Field("id")))
- hosts := HostManager.Query("id")
- if len(input.HostType) > 0 {
- hosts = hosts.Equals("host_type", input.HostType)
- }
- if len(input.HostId) > 0 {
- hosts = hosts.In("id", input.HostId)
- }
- hostsQ := hosts.SubQuery()
- classicWiresIdQ = classicWiresIdQ.Join(hostsQ, sqlchemy.Equals(netifs.Field("baremetal_id"), hostsQ.Field("id")))
- wireIdQueries := []sqlchemy.IQuery{
- classicWiresIdQ,
- }
- if input.HostType == api.HOST_TYPE_HYPERVISOR || input.HostType == api.HOST_TYPE_CONTAINER {
- vpcHostQ := HostManager.Query().Equals("host_type", input.HostType)
- if len(input.HostId) > 0 {
- vpcHostQ = vpcHostQ.In("id", input.HostId)
- }
- hostCnt, err := vpcHostQ.CountWithError()
- if err != nil {
- return nil, errors.Wrap(err, "vpcHostQ.CountWithError")
- }
- if hostCnt > 0 {
- // should consider host local wire
- hostLocalWireQ := WireManager.Query("id").Equals("id", api.DEFAULT_HOST_LOCAL_WIRE_ID)
- wireIdQueries = append(wireIdQueries, hostLocalWireQ)
- }
- vpcHostQ = vpcHostQ.IsNotEmpty("ovn_version")
- vpcHostCnt, err := vpcHostQ.CountWithError()
- if err != nil {
- return nil, errors.Wrap(err, "vpcHostQ.CountWithError")
- }
- if vpcHostCnt > 0 {
- // should consider VPC network wire
- vpcWiresIdQ := WireManager.Query("id").NotEquals("vpc_id", api.DEFAULT_VPC_ID)
- wireIdQueries = append(wireIdQueries, vpcWiresIdQ)
- }
- }
- var wireIdQ *sqlchemy.SSubQuery
- if len(wireIdQueries) > 1 {
- wireIdQ = sqlchemy.Union(wireIdQueries...).Query().SubQuery()
- } else {
- wireIdQ = classicWiresIdQ.SubQuery()
- }
- additionalQ := NetworkAdditionalWireManager.Query("network_id")
- additionalQ = additionalQ.Join(wireIdQ, sqlchemy.Equals(wireIdQ.Field("id"), additionalQ.Field("wire_id")))
- q = q.Filter(sqlchemy.OR(
- sqlchemy.In(q.Field("wire_id"), wireIdQ),
- sqlchemy.In(q.Field("id"), additionalQ.SubQuery()),
- ))
- }
- storageStr := input.StorageId
- if len(storageStr) > 0 {
- storage, err := StorageManager.FetchByIdOrName(ctx, userCred, storageStr)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to fetch storage %q", storageStr)
- }
- hoststorages := HoststorageManager.Query("host_id").Equals("storage_id", storage.GetId()).SubQuery()
- hostSq := HostManager.Query("id").In("id", hoststorages).SubQuery()
- sq := NetInterfaceManager.Query("wire_id").In("baremetal_id", hostSq)
- ovnHosts := HostManager.Query().In("id", hoststorages).IsNotEmpty("ovn_version")
- if n, _ := ovnHosts.CountWithError(); n > 0 {
- wireQuery := WireManager.Query("id").IsNotNull("vpc_id")
- q = q.Filter(sqlchemy.OR(
- sqlchemy.In(q.Field("wire_id"), wireQuery.SubQuery()),
- sqlchemy.In(q.Field("wire_id"), sq.SubQuery())),
- )
- } else {
- q = q.Filter(sqlchemy.In(q.Field("wire_id"), sq.SubQuery()))
- }
- }
- ips := []string{}
- exactIpMatch := false
- if len(input.Ip) > 0 {
- exactIpMatch = true
- ips = input.Ip
- } else if len(input.IpMatch) > 0 {
- ips = input.IpMatch
- }
- if len(ips) > 0 {
- conditions := []sqlchemy.ICondition{}
- for _, ipstr := range ips {
- if len(ipstr) == 0 {
- continue
- }
- var ipCondtion sqlchemy.ICondition
- if ip4Addr, err := netutils.NewIPV4Addr(ipstr); err == nil {
- // ipv4 address, exactly
- ipStart := sqlchemy.INET_ATON(q.Field("guest_ip_start"))
- ipEnd := sqlchemy.INET_ATON(q.Field("guest_ip_end"))
- ipConst := sqlchemy.INET_ATON(q.StringField(ip4Addr.String()))
- ipCondtion = sqlchemy.AND(
- sqlchemy.IsNotNull(q.Field("guest_ip_start")),
- sqlchemy.IsNotNull(q.Field("guest_ip_end")),
- sqlchemy.IsNotEmpty(q.Field("guest_ip_start")),
- sqlchemy.IsNotEmpty(q.Field("guest_ip_end")),
- sqlchemy.GE(ipEnd, ipConst),
- sqlchemy.LE(ipStart, ipConst),
- )
- if !exactIpMatch {
- ipCondtion = sqlchemy.OR(
- ipCondtion,
- sqlchemy.Contains(q.Field("guest_ip_start"), ipstr),
- sqlchemy.Contains(q.Field("guest_ip_end"), ipstr),
- )
- }
- } else if ip6Addr, err := netutils.NewIPV6Addr(ipstr); err == nil {
- // ipv6 address, exactly
- ipStart := sqlchemy.INET6_ATON(q.Field("guest_ip6_start"))
- ipEnd := sqlchemy.INET6_ATON(q.Field("guest_ip6_end"))
- ipConst := sqlchemy.INET6_ATON(q.StringField(ip6Addr.String()))
- ipCondtion = sqlchemy.AND(
- sqlchemy.IsNotNull(q.Field("guest_ip6_start")),
- sqlchemy.IsNotNull(q.Field("guest_ip6_end")),
- sqlchemy.IsNotEmpty(q.Field("guest_ip6_start")),
- sqlchemy.IsNotEmpty(q.Field("guest_ip6_end")),
- sqlchemy.GE(ipEnd, ipConst),
- sqlchemy.LE(ipStart, ipConst),
- )
- if !exactIpMatch {
- ipCondtion = sqlchemy.OR(
- ipCondtion,
- sqlchemy.Contains(q.Field("guest_ip6_start"), ip6Addr.String()),
- sqlchemy.Contains(q.Field("guest_ip6_end"), ip6Addr.String()),
- )
- }
- } else {
- ipCondtion = sqlchemy.OR(
- sqlchemy.Contains(q.Field("guest_ip_start"), ipstr),
- sqlchemy.Contains(q.Field("guest_ip_end"), ipstr),
- sqlchemy.Contains(q.Field("guest_ip6_start"), ipstr),
- sqlchemy.Contains(q.Field("guest_ip6_end"), ipstr),
- )
- }
- conditions = append(conditions, ipCondtion)
- }
- q = q.Filter(sqlchemy.OR(conditions...))
- }
- if len(input.SchedtagId) > 0 {
- schedTag, err := SchedtagManager.FetchByIdOrName(ctx, nil, input.SchedtagId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(SchedtagManager.Keyword(), input.SchedtagId)
- }
- return nil, httperrors.NewGeneralError(err)
- }
- sq := NetworkschedtagManager.Query("network_id").Equals("schedtag_id", schedTag.GetId()).SubQuery()
- q = q.In("id", sq)
- }
- if len(input.IfnameHint) > 0 {
- q = q.In("ifname_hint", input.IfnameHint)
- }
- if len(input.GuestIpStart) > 0 {
- q = q.Filter(sqlchemy.ContainsAny(q.Field("guest_ip_start"), input.GuestIpStart))
- }
- if len(input.GuestIpEnd) > 0 {
- q = q.Filter(sqlchemy.ContainsAny(q.Field("guest_ip_end"), input.GuestIpEnd))
- }
- if len(input.GuestIpMask) > 0 {
- q = q.In("guest_ip_mask", input.GuestIpMask)
- }
- if len(input.GuestGateway) > 0 {
- q = q.In("guest_gateway", input.GuestGateway)
- }
- if len(input.GuestDns) > 0 {
- q = q.In("guest_dns", input.GuestDns)
- }
- if len(input.GuestDhcp) > 0 {
- q = q.In("guest_dhcp", input.GuestDhcp)
- }
- if len(input.GuestNtp) > 0 {
- q = q.In("guest_ntp", input.GuestNtp)
- }
- if len(input.GuestDomain) > 0 {
- q = q.In("guest_domain", input.GuestDomain)
- }
- if len(input.GuestIp6Start) > 0 {
- q = q.In("guest_ip6_start", input.GuestIp6Start)
- }
- if len(input.GuestIp6End) > 0 {
- q = q.In("guest_ip6_end", input.GuestIp6End)
- }
- if len(input.GuestIp6Mask) > 0 {
- q = q.In("guest_ip6_mask", input.GuestIp6Mask)
- }
- if len(input.GuestGateway6) > 0 {
- q = q.In("guest_gateway6", input.GuestGateway6)
- }
- if len(input.GuestDns6) > 0 {
- q = q.In("guest_dns6", input.GuestDns6)
- }
- if len(input.GuestDomain6) > 0 {
- q = q.In("guest_domain6", input.GuestDomain6)
- }
- if len(input.VlanId) > 0 {
- q = q.In("vlan_id", input.VlanId)
- }
- if len(input.ServerType) > 0 {
- q = q.In("server_type", input.ServerType)
- }
- if len(input.AllocPolicy) > 0 {
- q = q.In("alloc_policy", input.AllocPolicy)
- }
- if len(input.BgpType) > 0 {
- q = q.In("bgp_type", input.BgpType)
- }
- if input.IsAutoAlloc != nil {
- if *input.IsAutoAlloc {
- q = q.IsTrue("is_auto_alloc")
- } else {
- q = q.IsFalse("is_auto_alloc")
- }
- }
- if input.IsClassic != nil {
- subq := manager.Query("id")
- wires := WireManager.Query("id", "vpc_id").SubQuery()
- subq = subq.Join(wires, sqlchemy.Equals(wires.Field("id"), subq.Field("wire_id")))
- if *input.IsClassic {
- subq = subq.Filter(sqlchemy.Equals(wires.Field("vpc_id"), api.DEFAULT_VPC_ID))
- } else {
- subq = subq.Filter(sqlchemy.NotEquals(wires.Field("vpc_id"), api.DEFAULT_VPC_ID))
- }
- q = q.In("id", subq.SubQuery())
- }
- if len(input.HostSchedtagId) > 0 {
- schedTagObj, err := SchedtagManager.FetchByIdOrName(ctx, userCred, input.HostSchedtagId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", SchedtagManager.Keyword(), input.HostSchedtagId)
- } else {
- return nil, errors.Wrap(err, "SchedtagManager.FetchByIdOrName")
- }
- }
- subq := NetInterfaceManager.Query("wire_id")
- hostschedtags := HostschedtagManager.Query().Equals("schedtag_id", schedTagObj.GetId()).SubQuery()
- subq = subq.Join(hostschedtags, sqlchemy.Equals(hostschedtags.Field("host_id"), subq.Field("baremetal_id")))
- q = q.In("wire_id", subq.SubQuery())
- }
- return q, nil
- }
- func (manager *SNetworkManager) OrderByExtraFields(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- input api.NetworkListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.SharableVirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SWireResourceBaseManager.OrderByExtraFields(ctx, q, userCred, input.WireFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SWireResourceBaseManager.OrderByExtraFields")
- }
- if db.NeedOrderQuery([]string{input.OrderByIpStart}) {
- q = db.OrderByFields(q, []string{input.OrderByIpStart}, []sqlchemy.IQueryField{sqlchemy.INET_ATON(q.Field("guest_ip_start"))})
- }
- if db.NeedOrderQuery([]string{input.OrderByIpEnd}) {
- q = db.OrderByFields(q, []string{input.OrderByIpEnd}, []sqlchemy.IQueryField{sqlchemy.INET_ATON(q.Field("guest_ip_end"))})
- }
- return q, nil
- }
- func (manager *SNetworkManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SWireResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- func (manager *SNetworkManager) InitializeData() error {
- // set network status
- networks := make([]SNetwork, 0)
- q := manager.Query()
- err := db.FetchModelObjects(manager, q, &networks)
- if err != nil {
- return err
- }
- for _, n := range networks {
- if n.ExternalId != "" {
- var statusNew string
- if n.WireId != "" && n.Status == api.NETWORK_STATUS_INIT {
- statusNew = api.NETWORK_STATUS_AVAILABLE
- }
- db.Update(&n, func() error {
- if statusNew != "" {
- n.Status = statusNew
- }
- return nil
- })
- } else {
- var ifnameHintNew string
- if n.IfnameHint == "" {
- ifnameHintNew = n.Name
- }
- db.Update(&n, func() error {
- if ifnameHintNew != "" {
- n.IfnameHint = ifnameHintNew
- }
- return nil
- })
- }
- if n.IsAutoAlloc.IsNone() {
- db.Update(&n, func() error {
- if n.IsPublic && n.ServerType == api.NETWORK_TYPE_GUEST {
- n.IsAutoAlloc = tristate.True
- } else {
- n.IsAutoAlloc = tristate.False
- }
- return nil
- })
- }
- }
- return nil
- }
- func (snet *SNetwork) ValidateUpdateCondition(ctx context.Context) error {
- /*if len(snet.ExternalId) > 0 {
- return httperrors.NewConflictError("Cannot update external resource")
- }*/
- return snet.SSharableVirtualResourceBase.ValidateUpdateCondition(ctx)
- }
- func (net *SNetwork) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query, data jsonutils.JSONObject) {
- net.SSharableVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
- // reserve guest gateway IP
- {
- input := api.NetworkUpdateInput{}
- err := data.Unmarshal(&input)
- if err != nil {
- log.Errorf("Unmarshal NetworkUpdateInput fail %s", err)
- } else if input.GuestGateway != nil && len(*input.GuestGateway) > 0 {
- err := net.reserveGuestGateway(ctx, userCred)
- if err != nil {
- log.Errorf("reserveGuestGateway fail %s", err)
- }
- }
- }
- net.ClearSchedDescCache()
- if net.IsClassic() {
- err := net.syncAdditionalWires(ctx, nil)
- if err != nil {
- log.Errorf("syncAdditionalWires error %s", err)
- }
- }
- }
- // 清除IP子网数据
- // 要求IP子网内没有被分配IP,若清除接入云,要求接入云账号处于禁用状态
- func (snet *SNetwork) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkPurgeInput) (jsonutils.JSONObject, error) {
- err := snet.ValidateDeleteCondition(ctx, nil)
- if err != nil {
- return nil, err
- }
- wire, _ := snet.GetWire()
- if wire != nil && len(wire.ExternalId) > 0 {
- provider := wire.GetCloudprovider()
- if provider != nil && provider.GetEnabled() {
- return nil, httperrors.NewInvalidStatusError("Cannot purge network on enabled cloud provider")
- }
- }
- err = snet.RealDelete(ctx, userCred)
- return nil, err
- }
- func (manager *SNetworkManager) handleNetworkIdChange(ctx context.Context, args *networkIdChangeArgs) error {
- var handlers = []networkIdChangeHandler{
- GuestnetworkManager,
- HostnetworkManager,
- ReservedipManager,
- GroupnetworkManager,
- LoadbalancernetworkManager,
- LoadbalancerManager,
- }
- errs := []error{}
- for _, h := range handlers {
- if err := h.handleNetworkIdChange(ctx, args); err != nil {
- errs = append(errs, err)
- }
- }
- if len(errs) > 0 {
- err := errors.NewAggregate(errs)
- return httperrors.NewGeneralError(err)
- }
- return nil
- }
- // 合并IP子网
- // 将两个相连的IP子网合并成一个IP子网
- func (snet *SNetwork) PerformMerge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkMergeInput) (jsonutils.JSONObject, error) {
- if len(input.Target) == 0 {
- return nil, httperrors.NewMissingParameterError("target")
- }
- iNet, err := NetworkManager.FetchByIdOrName(ctx, userCred, input.Target)
- if err == sql.ErrNoRows {
- err = httperrors.NewNotFoundError("Network %s not found", input.Target)
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, err.Error(), userCred, false)
- return nil, err
- } else if err != nil {
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, err.Error(), userCred, false)
- return nil, err
- }
- net := iNet.(*SNetwork)
- if net == nil {
- err = fmt.Errorf("Network is nil")
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, err.Error(), userCred, false)
- return nil, err
- }
- startIp, endIp, err := snet.CheckInvalidToMerge(ctx, net, nil)
- if err != nil {
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, err.Error(), userCred, false)
- return nil, err
- }
- return nil, snet.MergeToNetworkAfterCheck(ctx, userCred, net, startIp, endIp)
- }
- func (snet *SNetwork) MergeToNetworkAfterCheck(ctx context.Context, userCred mcclient.TokenCredential, net *SNetwork, startIp string, endIp string) error {
- lockman.LockClass(ctx, NetworkManager, db.GetLockClassKey(NetworkManager, userCred))
- defer lockman.ReleaseClass(ctx, NetworkManager, db.GetLockClassKey(NetworkManager, userCred))
- _, err := db.Update(net, func() error {
- net.GuestIpStart = startIp
- net.GuestIpEnd = endIp
- return nil
- })
- if err != nil {
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, err.Error(), userCred, false)
- return err
- }
- if err := NetworkManager.handleNetworkIdChange(ctx, &networkIdChangeArgs{
- action: logclient.ACT_MERGE,
- oldNet: snet,
- newNet: net,
- userCred: userCred,
- }); err != nil {
- return err
- }
- note := map[string]string{"start_ip": startIp, "end_ip": endIp}
- db.OpsLog.LogEvent(snet, db.ACT_MERGE, note, userCred)
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_MERGE, note, userCred, true)
- if err = snet.RealDelete(ctx, userCred); err != nil {
- return err
- }
- note = map[string]string{"network": snet.Id}
- db.OpsLog.LogEvent(snet, db.ACT_DELETE, note, userCred)
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_DELOCATE, note, userCred, true)
- return nil
- }
- func (snet *SNetwork) CheckInvalidToMerge(ctx context.Context, net *SNetwork, allNets []*SNetwork) (string, string, error) {
- failReason := make([]string, 0)
- if snet.WireId != net.WireId {
- failReason = append(failReason, "wire_id")
- }
- if snet.GuestGateway != net.GuestGateway {
- failReason = append(failReason, "guest_gateway")
- }
- if snet.VlanId != net.VlanId {
- failReason = append(failReason, "vlan_id")
- }
- // Qiujian: allow merge networks of different server_type
- /*if snet.ServerType != net.ServerType {
- failReason = append(failReason, "server_type")
- }*/
- if len(failReason) > 0 {
- err := httperrors.NewInputParameterError("Invalid Target Network %s: inconsist %s", net.GetId(), strings.Join(failReason, ","))
- return "", "", err
- }
- var startIp, endIp string
- ipNE, _ := netutils.NewIPV4Addr(net.GuestIpEnd)
- ipNS, _ := netutils.NewIPV4Addr(net.GuestIpStart)
- ipSS, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- ipSE, _ := netutils.NewIPV4Addr(snet.GuestIpEnd)
- var wireNets []SNetwork
- if allNets == nil {
- wireSubq := WireManager.Query("vpc_id").Equals("id", snet.WireId).SubQuery()
- wiresQ := WireManager.Query("id")
- wiresSubQ := wiresQ.Join(wireSubq, sqlchemy.Equals(wiresQ.Field("vpc_id"), wireSubq.Field("vpc_id"))).SubQuery()
- q := NetworkManager.Query().In("wire_id", wiresSubQ).NotEquals("id", snet.Id).NotEquals("id", net.Id)
- err := db.FetchModelObjects(NetworkManager, q, &wireNets)
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return "", "", errors.Wrap(err, "Query nets of same wire")
- }
- } else {
- wireNets = make([]SNetwork, len(allNets))
- for i := range wireNets {
- wireNets[i] = *allNets[i]
- }
- }
- if ipNE.StepUp() == ipSS || (ipNE.StepUp() < ipSS && !isOverlapNetworksAddr(wireNets, ipNE.StepUp(), ipSS.StepDown())) {
- startIp, endIp = net.GuestIpStart, snet.GuestIpEnd
- } else if ipSE.StepUp() == ipNS || (ipSE.StepUp() < ipNS && !isOverlapNetworksAddr(wireNets, ipSE.StepUp(), ipNS.StepDown())) {
- startIp, endIp = snet.GuestIpStart, net.GuestIpEnd
- } else {
- note := "Incontinuity Network for %s and %s"
- return "", "", httperrors.NewBadRequestError(note, snet.Name, net.Name)
- }
- return startIp, endIp, nil
- }
- // 分割IP子网
- // 将一个IP子网分割成两个子网,仅本地IDC支持此操作
- func (snet *SNetwork) PerformSplit(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSplitInput) (jsonutils.JSONObject, error) {
- if len(snet.ExternalId) > 0 {
- return nil, httperrors.NewNotSupportedError("only on premise support this operation")
- }
- if !snet.IsClassic() {
- return nil, httperrors.NewNotSupportedError("only on premise classic network support this operation")
- }
- if snet.IsSupportIPv6() {
- return nil, httperrors.NewNotSupportedError("only on premise pure-ipv4 classic network support this operation")
- }
- if len(input.SplitIp) == 0 {
- return nil, httperrors.NewMissingParameterError("split_ip")
- }
- if !regutils.MatchIPAddr(input.SplitIp) {
- return nil, httperrors.NewInputParameterError("Invalid IP %s", input.SplitIp)
- }
- if input.SplitIp == snet.GuestIpStart {
- return nil, httperrors.NewInputParameterError("Split IP %s is the start ip", input.SplitIp)
- }
- iSplitIp, err := netutils.NewIPV4Addr(input.SplitIp)
- if err != nil {
- return nil, err
- }
- if !snet.IsAddressInRange(iSplitIp) {
- return nil, httperrors.NewInputParameterError("Split IP %s out of range", input.SplitIp)
- }
- network := &SNetwork{}
- network.GuestIpStart = input.SplitIp
- network.GuestIpEnd = snet.GuestIpEnd
- network.GuestIpMask = snet.GuestIpMask
- network.GuestGateway = snet.GuestGateway
- network.GuestDns = snet.GuestDns
- network.GuestDhcp = snet.GuestDhcp
- network.GuestNtp = snet.GuestNtp
- network.GuestDomain = snet.GuestDomain
- network.VlanId = snet.VlanId
- network.WireId = snet.WireId
- network.ServerType = snet.ServerType
- network.IsPublic = snet.IsPublic
- network.Status = snet.Status
- network.ProjectId = snet.ProjectId
- network.DomainId = snet.DomainId
- // network.UserId = snet.UserId
- network.IsSystem = snet.IsSystem
- network.Description = snet.Description
- network.IsAutoAlloc = snet.IsAutoAlloc
- err = func() error {
- lockman.LockRawObject(ctx, NetworkManager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, NetworkManager.Keyword(), "name")
- if len(input.Name) > 0 {
- if err := db.NewNameValidator(ctx, NetworkManager, userCred, input.Name, nil); err != nil {
- return httperrors.NewInputParameterError("Duplicate name %s", input.Name)
- }
- } else {
- input.Name, err = db.GenerateName(ctx, NetworkManager, userCred, fmt.Sprintf("%s#", snet.Name))
- if err != nil {
- return httperrors.NewInternalServerError("GenerateName fail %s", err)
- }
- }
- network.Name = input.Name
- network.IfnameHint, err = NetworkManager.newIfnameHint(input.Name)
- if err != nil {
- return httperrors.NewBadRequestError("Generate ifname hint failed %s", err)
- }
- return NetworkManager.TableSpec().Insert(ctx, network)
- }()
- if err != nil {
- return nil, err
- }
- network.SetModelManager(NetworkManager, network)
- db.Update(snet, func() error {
- snet.GuestIpEnd = iSplitIp.StepDown().String()
- return nil
- })
- if err := NetworkManager.handleNetworkIdChange(ctx, &networkIdChangeArgs{
- action: logclient.ACT_SPLIT,
- oldNet: snet,
- newNet: network,
- userCred: userCred,
- }); err != nil {
- return nil, err
- }
- note := map[string]string{"split_ip": input.SplitIp, "end_ip": network.GuestIpEnd}
- db.OpsLog.LogEvent(snet, db.ACT_SPLIT, note, userCred)
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_SPLIT, note, userCred, true)
- db.OpsLog.LogEvent(network, db.ACT_CREATE, map[string]string{"network": snet.Id}, userCred)
- return nil, nil
- }
- func (manager *SNetworkManager) PerformTryCreateNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkTryCreateNetworkInput) (jsonutils.JSONObject, error) {
- if len(input.Ip) == 0 {
- return nil, httperrors.NewMissingParameterError("ip")
- }
- var ipV4, ipV4NetAddr netutils.IPV4Addr
- var ipV6, ipV6NetAddr netutils.IPV6Addr
- var err error
- if input.Mask == 0 {
- return nil, httperrors.NewMissingParameterError("mask")
- }
- if regutils.MatchIP4Addr(input.Ip) {
- ipV4, err = netutils.NewIPV4Addr(input.Ip)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid ipv4 address %s", input.Ip)
- }
- if ipV4.IsZero() {
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "invalid ipv4 address %s", input.Ip)
- }
- ipV4NetAddr = ipV4.NetAddr(int8(input.Mask))
- } else if regutils.MatchIP6Addr(input.Ip) {
- ipV6, err = netutils.NewIPV6Addr(input.Ip)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid ipv6 address %s", input.Ip)
- }
- if ipV6.IsZero() {
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "invalid ipv6 address %s", input.Ip)
- }
- ipV6NetAddr = ipV6.NetAddr(uint8(input.Mask))
- } else {
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "invalid ip address %s", input.Ip)
- }
- if len(input.ServerType) == 0 {
- return nil, httperrors.NewMissingParameterError("server_type")
- }
- if input.ServerType != api.NETWORK_TYPE_BAREMETAL {
- return nil, httperrors.NewBadRequestError("Only support server type %s", api.NETWORK_TYPE_BAREMETAL)
- }
- if !input.IsOnPremise {
- return nil, httperrors.NewBadRequestError("Only support on premise network")
- }
- var (
- nm *SNetwork
- matched bool
- )
- q := NetworkManager.Query().Equals("server_type", input.ServerType)
- if !ipV4.IsZero() {
- q = q.Equals("guest_ip_mask", input.Mask)
- } else if !ipV6.IsZero() {
- q = q.Equals("guest_ip6_mask", input.Mask)
- }
- listQuery := api.NetworkListInput{}
- err = query.Unmarshal(&listQuery)
- if err != nil {
- return nil, errors.Wrap(err, "query.Unmarshal")
- }
- q, err = managedResourceFilterByAccount(ctx, q, listQuery.ManagedResourceListInput, "wire_id", func() *sqlchemy.SQuery {
- wires := WireManager.Query().SubQuery()
- vpcs := VpcManager.Query().SubQuery()
- subq := wires.Query(wires.Field("id"))
- subq = subq.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
- return subq
- })
- if err != nil {
- return nil, errors.Wrap(err, "managedResourceFilterByAccount")
- }
- rows, err := q.Rows()
- if err != nil {
- return nil, err
- }
- defer rows.Close()
- for rows.Next() {
- item, err := db.NewModelObject(NetworkManager)
- if err != nil {
- return nil, err
- }
- err = q.Row2Struct(rows, item)
- if err != nil {
- return nil, err
- }
- n := item.(*SNetwork)
- if !ipV4.IsZero() {
- if n.getIPRange().Contains(ipV4) {
- nm = n
- matched = true
- break
- } else if nIpV4, _ := netutils.NewIPV4Addr(n.GuestIpStart); nIpV4.NetAddr(n.GuestIpMask) == ipV4NetAddr {
- nm = n
- matched = false
- break
- }
- } else if !ipV6.IsZero() {
- if n.getIPRange6().Contains(ipV6) {
- nm = n
- matched = true
- break
- } else if nIpV6, _ := netutils.NewIPV6Addr(n.GuestIp6Start); nIpV6.NetAddr(n.GuestIp6Mask) == ipV6NetAddr {
- nm = n
- matched = false
- break
- }
- }
- }
- ret := jsonutils.NewDict()
- if nm == nil {
- ret.Set("find_matched", jsonutils.JSONFalse)
- return ret, nil
- }
- ret.Set("find_matched", jsonutils.JSONTrue)
- ret.Set("wire_id", jsonutils.NewString(nm.WireId))
- if !matched {
- log.Infof("Find same subnet network %s %s/%d %s/%d", nm.Name, nm.GuestGateway, nm.GuestIpMask, nm.GuestGateway6, nm.GuestIp6Mask)
- newNetwork := new(SNetwork)
- newNetwork.SetModelManager(NetworkManager, newNetwork)
- if !ipV4.IsZero() {
- newNetwork.GuestIpStart = ipV4.String()
- newNetwork.GuestIpEnd = ipV4.String()
- newNetwork.GuestGateway = nm.GuestGateway
- newNetwork.GuestIpMask = int8(input.Mask)
- } else if !ipV6.IsZero() {
- newNetwork.GuestIp6Start = ipV6.String()
- newNetwork.GuestIp6End = ipV6.String()
- newNetwork.GuestGateway6 = nm.GuestGateway6
- newNetwork.GuestIp6Mask = uint8(input.Mask)
- }
- newNetwork.GuestDns = nm.GuestDns
- newNetwork.GuestDhcp = nm.GuestDhcp
- newNetwork.GuestNtp = nm.GuestNtp
- newNetwork.WireId = nm.WireId
- newNetwork.ServerType = input.ServerType
- newNetwork.IsPublic = nm.IsPublic
- newNetwork.ProjectId = userCred.GetProjectId()
- newNetwork.DomainId = userCred.GetProjectDomainId()
- err = func() error {
- lockman.LockRawObject(ctx, NetworkManager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, NetworkManager.Keyword(), "name")
- newNetwork.Name, err = db.GenerateName(ctx, NetworkManager, userCred, fmt.Sprintf("%s#", nm.Name))
- if err != nil {
- return httperrors.NewInternalServerError("GenerateName fail %s", err)
- }
- return NetworkManager.TableSpec().Insert(ctx, newNetwork)
- }()
- if err != nil {
- return nil, err
- }
- err = newNetwork.CustomizeCreate(ctx, userCred, userCred, query, input.JSON(input))
- if err != nil {
- return nil, err
- }
- newNetwork.PostCreate(ctx, userCred, userCred, query, input.JSON(input))
- // inherit wire's class metadata
- wire, err := newNetwork.GetWire()
- if err != nil {
- return nil, errors.Wrap(err, "unable to get wire")
- }
- err = db.InheritFromTo(ctx, userCred, wire, newNetwork)
- if err != nil {
- return nil, errors.Wrap(err, "unable to inherit wire")
- }
- }
- return ret, nil
- }
- func (network *SNetwork) getAllocTimoutDuration() time.Duration {
- tos := network.AllocTimoutSeconds
- if tos < options.Options.MinimalIpAddrReusedIntervalSeconds {
- tos = options.Options.MinimalIpAddrReusedIntervalSeconds
- }
- return time.Duration(tos) * time.Second
- }
- func (network *SNetwork) GetSchedtags() []SSchedtag {
- return GetSchedtags(NetworkschedtagManager, network.Id)
- }
- func (network *SNetwork) GetDynamicConditionInput() *jsonutils.JSONDict {
- return jsonutils.Marshal(network).(*jsonutils.JSONDict)
- }
- func (network *SNetwork) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return PerformSetResourceSchedtag(network, ctx, userCred, query, data)
- }
- func (network *SNetwork) GetSchedtagJointManager() ISchedtagJointManager {
- return NetworkschedtagManager
- }
- func (network *SNetwork) ClearSchedDescCache() error {
- wire, _ := network.GetWire()
- if wire == nil {
- return nil
- }
- return wire.clearHostSchedDescCache()
- }
- func (network *SNetwork) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
- wire, err := network.GetWire()
- if err != nil {
- return nil, errors.Wrap(err, "unable to get wire")
- }
- project, err := db.TenantCacheManager.FetchTenantById(ctx, input.ProjectId)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to get project %s", input.ProjectId)
- }
- ok, err := db.IsInSameClass(ctx, wire, project)
- if err != nil {
- return nil, errors.Wrap(err, "unable to check if the wire and project is in same class")
- }
- if !ok {
- return nil, httperrors.NewForbiddenError("the wire %s and the project %s has different class metadata", wire.GetName(), project.GetName())
- }
- ret, err := network.SSharableVirtualResourceBase.PerformChangeOwner(ctx, userCred, query, input)
- if err != nil {
- return nil, err
- }
- network.ClearSchedDescCache()
- return ret, nil
- }
- func (network *SNetwork) getUsedAddressQuery(ctx context.Context, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope, addrOnly bool) *sqlchemy.SQuery {
- usedAddressQueryProviders := getUsedAddressQueryProviders()
- var (
- args = &usedAddressQueryArgs{
- network: network,
- userCred: userCred,
- owner: owner,
- scope: scope,
- addrOnly: addrOnly,
- addrType: api.AddressTypeIPv4,
- }
- queries = make([]sqlchemy.IQuery, 0, len(usedAddressQueryProviders))
- )
- for _, provider := range usedAddressQueryProviders {
- q := provider.usedAddressQuery(ctx, args)
- queries = append(queries, q)
- }
- return sqlchemy.Union(queries...).Query()
- }
- func (network *SNetwork) getUsedAddressQuery6(ctx context.Context, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope, addrOnly bool) *sqlchemy.SQuery {
- usedAddress6QueryProviders := getUsedAddress6QueryProviders()
- var (
- args = &usedAddressQueryArgs{
- network: network,
- userCred: userCred,
- owner: owner,
- scope: scope,
- addrOnly: addrOnly,
- addrType: api.AddressTypeIPv6,
- }
- queries = make([]sqlchemy.IQuery, 0, len(usedAddress6QueryProviders))
- )
- for _, provider := range usedAddress6QueryProviders {
- q := provider.usedAddressQuery(ctx, args)
- queries = append(queries, q)
- }
- return sqlchemy.Union(queries...).Query()
- }
- func (snet *SNetwork) Contains(ip string) bool {
- start, _ := netutils.NewIPV4Addr(snet.GuestIpStart)
- end, _ := netutils.NewIPV4Addr(snet.GuestIpEnd)
- addr, _ := netutils.NewIPV4Addr(ip)
- return netutils.NewIPV4AddrRange(start, end).Contains(addr)
- }
- type SNetworkUsedAddressList []api.SNetworkUsedAddress
- func (a SNetworkUsedAddressList) Len() int { return len(a) }
- func (a SNetworkUsedAddressList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
- func (a SNetworkUsedAddressList) Less(i, j int) bool {
- ipI, _ := netutils.NewIPV4Addr(a[i].IpAddr)
- ipJ, _ := netutils.NewIPV4Addr(a[j].IpAddr)
- return ipI < ipJ
- }
- type SNetworkUsedAddress6List []api.SNetworkUsedAddress
- func (a SNetworkUsedAddress6List) Len() int { return len(a) }
- func (a SNetworkUsedAddress6List) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
- func (a SNetworkUsedAddress6List) Less(i, j int) bool {
- ipI, _ := netutils.NewIPV6Addr(a[i].Ip6Addr)
- ipJ, _ := netutils.NewIPV6Addr(a[j].Ip6Addr)
- return ipI.Lt(ipJ)
- }
- func (network *SNetwork) GetDetailsAddresses(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- input api.GetNetworkAddressesInput,
- ) (api.GetNetworkAddressesOutput, error) {
- output := api.GetNetworkAddressesOutput{}
- allowScope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, network.KeywordPlural(), policy.PolicyActionGet, "addresses")
- scope := rbacscope.String2ScopeDefault(input.Scope, allowScope)
- if scope.HigherThan(allowScope) {
- return output, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", scope, allowScope)
- }
- output, err := network.fetchAddressDetails(ctx, userCred, userCred, scope)
- if err != nil {
- return output, errors.Wrap(err, "fetchAddressDetails")
- }
- return output, nil
- }
- func (network *SNetwork) GetUsedAddressDetails(ctx context.Context, addr string) (*api.SNetworkUsedAddress, error) {
- address, err := network.GetAddressDetails(ctx, nil, nil, rbacscope.ScopeSystem)
- if err != nil {
- return nil, errors.Wrapf(err, "GetAddressDetails")
- }
- for i := range address {
- if address[i].IpAddr == addr || address[i].Ip6Addr == addr {
- return &address[i], nil
- }
- }
- return nil, errors.Wrapf(errors.ErrNotFound, "%s", addr)
- }
- func (network *SNetwork) GetAddressDetails(ctx context.Context, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) ([]api.SNetworkUsedAddress, error) {
- netAddrs := make([]api.SNetworkUsedAddress, 0)
- q := network.getUsedAddressQuery(ctx, userCred, owner, scope, false)
- err := q.All(&netAddrs)
- if err != nil {
- return nil, httperrors.NewGeneralError(err)
- }
- sort.Sort(SNetworkUsedAddressList(netAddrs))
- return netAddrs, nil
- }
- func (network *SNetwork) fetchAddressDetails(ctx context.Context, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) (api.GetNetworkAddressesOutput, error) {
- output := api.GetNetworkAddressesOutput{}
- {
- var err error
- output.Addresses, err = network.GetAddressDetails(ctx, userCred, owner, scope)
- if err != nil {
- return output, err
- }
- }
- {
- netAddrs6 := make([]api.SNetworkUsedAddress, 0)
- q := network.getUsedAddressQuery6(ctx, userCred, owner, scope, false)
- err := q.All(&netAddrs6)
- if err != nil {
- return output, httperrors.NewGeneralError(err)
- }
- sort.Sort(SNetworkUsedAddress6List(netAddrs6))
- output.Addresses6 = netAddrs6
- }
- return output, nil
- }
- func (network *SNetwork) GetDetailsAvailableAddresses(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- input api.GetNetworkAvailableAddressesInput,
- ) (api.GetNetworkAvailableAddressesOutput, error) {
- const maxCount = 1024
- var availables []string
- var availables6 []string
- {
- addrTable := network.GetUsedAddresses(ctx)
- recentUsedAddrTable := GuestnetworkManager.getRecentlyReleasedIPAddresses(network.Id, network.getAllocTimoutDuration())
- addrRange := network.getIPRange()
- for addr := addrRange.StartIp(); addr <= addrRange.EndIp() && len(availables) < maxCount; addr = addr.StepUp() {
- addrStr := addr.String()
- if _, ok := addrTable[addrStr]; !ok {
- if _, ok := recentUsedAddrTable[addrStr]; !ok {
- availables = append(availables, addrStr)
- }
- }
- }
- }
- if network.IsSupportIPv6() {
- addrTable6 := network.GetUsedAddresses6(ctx)
- recentUsedAddrTable6 := GuestnetworkManager.getRecentlyReleasedIPAddresses6(network.Id, network.getAllocTimoutDuration())
- addrRange6 := network.getIPRange6()
- for addr6 := addrRange6.StartIp(); addr6.Le(addrRange6.EndIp()) && len(availables6) < maxCount; addr6 = addr6.StepUp() {
- addrStr6 := addr6.String()
- if _, ok := addrTable6[addrStr6]; !ok {
- if _, ok := recentUsedAddrTable6[addrStr6]; !ok {
- availables6 = append(availables6, addrStr6)
- }
- }
- }
- }
- return api.GetNetworkAvailableAddressesOutput{
- Addresses: availables,
- Addresses6: availables6,
- }, nil
- }
- // 同步接入云IP子网状态
- // 本地IDC不支持此操作
- func (net *SNetwork) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSyncInput) (jsonutils.JSONObject, error) {
- return net.PerformSync(ctx, userCred, query, input)
- }
- // 同步接入云IP子网状态
- // 本地IDC不支持此操作
- func (net *SNetwork) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSyncInput) (jsonutils.JSONObject, error) {
- vpc, _ := net.GetVpc()
- if vpc != nil && vpc.IsManaged() {
- return nil, net.StartSyncstatusTask(ctx, userCred, "")
- }
- return nil, httperrors.NewUnsupportOperationError("on-premise network cannot sync status")
- }
- func (net *SNetwork) StartSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- return StartResourceSyncStatusTask(ctx, userCred, net, "NetworkSyncstatusTask", parentTaskId)
- }
- // 更改IP子网状态
- func (net *SNetwork) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
- if len(input.Status) == 0 {
- return nil, httperrors.NewMissingParameterError("status")
- }
- vpc, _ := net.GetVpc()
- if vpc != nil && vpc.IsManaged() {
- return nil, httperrors.NewUnsupportOperationError("managed network cannot change status")
- }
- if !utils.IsInStringArray(input.Status, []string{api.NETWORK_STATUS_AVAILABLE, api.NETWORK_STATUS_UNAVAILABLE}) {
- return nil, httperrors.NewInputParameterError("invalid status %s", input.Status)
- }
- return net.SSharableVirtualResourceBase.PerformStatus(ctx, userCred, query, input)
- }
- func (net *SNetwork) GetChangeOwnerCandidateDomainIds() []string {
- candidates := [][]string{}
- wire, _ := net.GetWire()
- if wire != nil {
- vpc, _ := wire.GetVpc()
- if vpc != nil {
- candidates = append(candidates, vpc.GetChangeOwnerCandidateDomainIds())
- }
- candidates = append(candidates, db.ISharableChangeOwnerCandidateDomainIds(wire))
- }
- return db.ISharableMergeChangeOwnerCandidateDomainIds(net, candidates...)
- }
- func (manager *SNetworkManager) ListItemExportKeys(ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- keys stringutils2.SSortedStrings,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SSharableVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.ListItemExportKeys")
- }
- if keys.ContainsAny(manager.SWireResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SWireResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SWireResourceBaseManager.ListItemExportKeys")
- }
- }
- return q, nil
- }
- func (manager *SNetworkManager) AllowScope(userCred mcclient.TokenCredential) rbacscope.TRbacScope {
- scope, _ := policy.PolicyManager.AllowScope(userCred, api.SERVICE_TYPE, NetworkManager.KeywordPlural(), policy.PolicyActionGet)
- return scope
- }
- func (snet *SNetwork) PerformSetBgpType(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.NetworkSetBgpTypeInput) (jsonutils.JSONObject, error) {
- if snet.BgpType == input.BgpType {
- return nil, nil
- }
- if snet.ServerType != api.NETWORK_TYPE_EIP {
- return nil, httperrors.NewInputParameterError("BgpType attribute is only useful for eip network")
- }
- {
- var eips []SElasticip
- q := ElasticipManager.Query().
- Equals("network_id", snet.Id).
- NotEquals("bgp_type", input.BgpType)
- if err := db.FetchModelObjects(ElasticipManager, q, &eips); err != nil {
- return nil, err
- }
- for i := range eips {
- eip := &eips[i]
- if diff, err := db.UpdateWithLock(ctx, eip, func() error {
- eip.BgpType = input.BgpType
- return nil
- }); err != nil {
- // no need to retry/restore here. return error
- // and retry after user resolves the error
- return nil, err
- } else {
- db.OpsLog.LogEvent(eip, db.ACT_UPDATE, diff, userCred)
- }
- }
- }
- if diff, err := db.Update(snet, func() error {
- snet.BgpType = input.BgpType
- return nil
- }); err != nil {
- return nil, err
- } else {
- logclient.AddActionLogWithContext(ctx, snet, logclient.ACT_UPDATE, diff, userCred, true)
- db.OpsLog.LogEvent(snet, db.ACT_UPDATE, diff, userCred)
- }
- return nil, nil
- }
- func (net *SNetwork) IsClassic() bool {
- vpc, _ := net.GetVpc()
- if vpc != nil && vpc.Id == api.DEFAULT_VPC_ID {
- return true
- }
- return false
- }
- func (net *SNetwork) getAttachedHosts() ([]SHost, error) {
- guestsQ := GuestManager.Query()
- gnsQ := GuestnetworkManager.Query().Equals("network_id", net.Id).SubQuery()
- guestsQ = guestsQ.Join(gnsQ, sqlchemy.Equals(guestsQ.Field("id"), gnsQ.Field("guest_id")))
- guestsQ = guestsQ.IsNotEmpty("host_id")
- guestsQ = guestsQ.AppendField(guestsQ.Field("host_id"))
- guestsSubQ := guestsQ.SubQuery()
- // unionQ := sqlchemy.Union(hns, guestsQ).Query().SubQuery()
- q := HostManager.Query()
- q = q.Join(guestsSubQ, sqlchemy.Equals(q.Field("id"), guestsSubQ.Field("host_id")))
- q = q.Distinct()
- hosts := make([]SHost, 0)
- err := db.FetchModelObjects(HostManager, q, &hosts)
- if err != nil {
- return nil, errors.Wrap(err, "FetchModelObjects")
- }
- return hosts, nil
- }
- func (net *SNetwork) PerformSwitchWire(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input *api.NetworkSwitchWireInput,
- ) (jsonutils.JSONObject, error) {
- if !net.IsClassic() {
- return nil, errors.Wrap(httperrors.ErrNotSupported, "default vpc only")
- }
- wireObj, err := WireManager.FetchByIdOrName(ctx, userCred, input.WireId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), input.WireId)
- } else {
- return nil, errors.Wrapf(err, "WireManager.FetchByIdOrName %s", input.WireId)
- }
- }
- wire := wireObj.(*SWire)
- if net.WireId == wire.Id {
- return nil, nil
- }
- oldWire, _ := net.GetWire()
- if oldWire.VpcId != wire.VpcId {
- return nil, errors.Wrapf(httperrors.ErrConflict, "cannot switch wires of other vpc")
- }
- hosts, err := net.getAttachedHosts()
- if err != nil {
- return nil, errors.Wrap(err, "getAttachedHosts")
- }
- unreachedHost := make([]string, 0)
- for i := range hosts {
- if hosts[i].HostType == api.HOST_TYPE_ESXI {
- continue
- }
- if !hosts[i].IsAttach2Wire(wire.Id) {
- unreachedHost = append(unreachedHost, hosts[i].Name)
- }
- }
- if len(unreachedHost) > 0 {
- return nil, errors.Wrapf(httperrors.ErrConflict, "wire %s not reachable for hosts %s", wire.Name, strings.Join(unreachedHost, ","))
- }
- diff, err := db.Update(net, func() error {
- net.WireId = wire.Id
- return nil
- })
- if err != nil {
- return nil, errors.Wrap(err, "update wire_id")
- }
- {
- err := net.syncAdditionalWires(ctx, nil)
- if err != nil {
- log.Errorf("syncAdditionalWires fail %s", err)
- }
- }
- logclient.AddActionLogWithContext(ctx, net, logclient.ACT_UPDATE, diff, userCred, true)
- db.OpsLog.LogEvent(net, db.ACT_UPDATE, diff, userCred)
- // fix vmware hostnics wire
- hns, err := HostnetworkManager.fetchHostnetworksByNetwork(net.Id)
- if err != nil {
- return nil, errors.Wrap(err, "HostnetworkManager.fetchHostnetworksByNetwork")
- }
- for i := range hns {
- nic, err := hns[i].GetNetInterface()
- if err != nil {
- return nil, errors.Wrap(err, "Hostnetwork.GetNetInterface")
- }
- log.Errorf("PerformSwitchWire: change wireId for nic %s for hostnetwork %s", jsonutils.Marshal(nic), jsonutils.Marshal(hns[i]))
- if len(nic.Bridge) > 0 {
- log.Warningf("PerformSwitchWire: non-empty wireId %s for hostnetwork %s", jsonutils.Marshal(nic), jsonutils.Marshal(hns[i]))
- continue
- }
- if nic.WireId != wire.Id {
- _, err := db.Update(nic, func() error {
- nic.WireId = wire.Id
- return nil
- })
- if err != nil {
- return nil, errors.Wrap(err, "Update NetInterface")
- }
- }
- }
- return nil, nil
- }
- func (net *SNetwork) fetchAdditionalWires() []api.SSimpleWire {
- wires, err := NetworkAdditionalWireManager.FetchNetworkAdditionalWires(net.Id)
- if err != nil {
- log.Errorf("NetworkAdditionalWireManager.FetchNetworkAdditionalWires error %s", err)
- }
- return wires
- }
- func (net *SNetwork) PerformSyncAdditionalWires(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input *api.NetworSyncAdditionalWiresInput,
- ) (jsonutils.JSONObject, error) {
- if !net.IsClassic() {
- return nil, errors.Wrap(httperrors.ErrNotSupported, "default vpc only")
- }
- wireIds := make([]string, 0)
- errs := make([]error, 0)
- for _, wireId := range input.WireIds {
- wireObj, err := WireManager.FetchByIdOrName(ctx, userCred, wireId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- errs = append(errs, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), wireId))
- } else {
- errs = append(errs, errors.Wrapf(err, "WireManager.FetchByIdOrNam %s", wireId))
- }
- }
- wireIds = append(wireIds, wireObj.GetId())
- }
- if len(errs) > 0 {
- return nil, errors.NewAggregate(errs)
- }
- err := net.syncAdditionalWires(ctx, wireIds)
- if err != nil {
- return nil, errors.Wrap(err, "syncAdditionalWires")
- }
- return nil, nil
- }
- func (net *SNetwork) IsSupportIPv4() bool {
- return len(net.GuestIpStart) > 0 && len(net.GuestIpEnd) > 0
- }
- func (net *SNetwork) IsSupportIPv6() bool {
- return len(net.GuestIp6Start) > 0 && len(net.GuestIp6End) > 0
- }
- func (net *SNetwork) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
- if len(net.ExternalId) == 0 || options.Options.KeepTagLocalization {
- return
- }
- vpc, err := net.GetVpc()
- if err != nil {
- return
- }
- if account := vpc.GetCloudaccount(); account != nil && account.ReadOnly {
- return
- }
- err = net.StartRemoteUpdateTask(ctx, userCred, true, "")
- if err != nil {
- log.Errorf("StartRemoteUpdateTask fail: %s", err)
- }
- }
- func (net *SNetwork) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
- data := jsonutils.NewDict()
- if replaceTags {
- data.Add(jsonutils.JSONTrue, "replace_tags")
- }
- task, err := taskman.TaskManager.NewTask(ctx, "NetworkRemoteUpdateTask", net, userCred, data, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrap(err, "Start NetworkRemoteUpdateTask")
- }
- net.SetStatus(ctx, userCred, apis.STATUS_UPDATE_TAGS, "StartRemoteUpdateTask")
- return task.ScheduleRun(nil)
- }
- func (net SNetwork) HasIPv4Addr() bool {
- return len(net.GuestIpStart) > 0 && len(net.GuestIpEnd) > 0
- }
- func (net SNetwork) HasIPv6Addr() bool {
- return len(net.GuestIp6Start) > 0 && len(net.GuestIp6End) > 0
- }
- func (manager *SNetworkManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*db.CustomizeListFilters, error) {
- filters := db.NewCustomizeListFilters()
- if query.Contains("usable") {
- isUsable := jsonutils.QueryBoolean(query, "usable", false)
- addrCountFilter := func(obj jsonutils.JSONObject) (bool, error) {
- portsStats := struct {
- PortsUsed int
- Ports6Used int
- Ports int
- Ports6 int
- }{}
- err := obj.Unmarshal(&portsStats)
- if err != nil {
- return false, err
- }
- if portsStats.PortsUsed < portsStats.Ports || portsStats.Ports6Used < portsStats.Ports6 {
- return true, nil
- }
- return false, nil
- }
- if isUsable {
- filters.Append(addrCountFilter)
- }
- }
- return filters, nil
- }
|