/* Ċ Ġ* ĠCopyright Ġ 2 0 0 0 - 2 0 2 1 ĠJetBrains Ġs . r . o . Ċ Ġ* Ċ Ġ* Ġ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 Ġjet brains . build Server . clouds . azure . arm Ċ Ċ import Ġcom . intellij . openapi . diagnostic . Logger Ċ import Ġjet brains . build Server . clouds . Cloud Exception Ċ import Ġjet brains . build Server . clouds . Cloud Instance UserData Ċ import Ġjet brains . build Server . clouds . Instance Status Ċ import Ġjet brains . build Server . clouds . Quota Exception Ċ import Ġjet brains . build Server . clouds . azure . Azure Utils Ċ import Ġjet brains . build Server . clouds . azure . arm . connector . Azure Api Connector Ċ import Ġjet brains . build Server . clouds . azure . arm . connector . Azure Instance Ċ import Ġjet brains . build Server . clouds . azure . arm . types .* Ċ import Ġjet brains . build Server . clouds . base . Abstract Cloud Image Ċ import Ġjet brains . build Server . clouds . base . connector . Abstract Instance Ċ import Ġjet brains . build Server . clouds . base . errors . Typed Cloud Error Info Ċ import Ġjet brains . build Server . server Side . Team City Properties Ċ import Ġkotlinx . coroutines .* Ċ import Ġjava . lang . StringBuilder Ċ import Ġjava . util .* Ċ import Ġjava . util . concurrent . atomic . Atomic Reference Ċ Ċ /** Ċ Ġ* ĠAzure Ġcloud Ġimage . Ċ Ġ*/ Ċ class ĠAzure Cloud Image ( private Ġval Ġmy Image Details : ĠAzure Cloud Image Details , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġmy Api Connector : ĠAzure Api Connector , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġmy Scope : ĠCor outine Scope ) ĊĠĠĠ Ġ: ĠAbstract Cloud Image < Azure Cloud Instance , ĠAzure Cloud Image Details >( my Image Details . source Id , Ġmy Image Details . source Id ) Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġmy Image Handlers Ġ= Ġmap Of ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAzure Cloud ImageType . V hd Ġto ĠAzure V hd Handler ( my Api Connector ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAzure Cloud ImageType . Image Ġto ĠAzure Image Handler ( my Api Connector ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAzure Cloud ImageType . Gallery Image Ġto ĠAzure Image Handler ( my Api Connector ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAzure Cloud ImageType . Template Ġto ĠAzure Template Handler ( my Api Connector ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAzure Cloud ImageType . Container Ġto ĠAzure Container Handler ( my Api Connector ) ĊĠĠĠ Ġ) ĊĠĠĠ Ġprivate Ġval Ġmy Instance Handler Ġ= ĠAzure Instance Handler ( my Api Connector ) ĊĊĠĠĠ Ġprivate Ġval Ġmy Active Statuses Ġ= Ġset Of ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . SCHEDUL ED _ TO _ START , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . START ING , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . RUNNING , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . RE START ING , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . SCHEDUL ED _ TO _ STOP , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . STOP PING , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠInstance Status . ERROR ĊĠĠĠ Ġ) ĊĊĠĠĠ Ġprivate Ġvar Ġazure Cpu Quota Exceeded : ĠSet < String >? Ġ= Ġnull ĊĊĠĠĠ Ġprivate Ġval Ġover limit Instance ToDelete Ġ= ĠAtomic Reference < Azure Cloud Instance ? >( null ) ĊĊĠĠĠ Ġoverride Ġfun ĠgetImage Details (): ĠAzure Cloud Image Details Ġ= Ġmy Image Details ĊĊĠĠĠ Ġoverride Ġfun Ġcreate Instance From Real ( real Instance : ĠAbstract Instance ): ĠAzure Cloud Instance Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn ĠAzure Cloud Instance ( this , Ġreal Instance . name ). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġproperties Ġ= Ġreal Instance . properties ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġdetect New Instances ( real Instances : ĠMutable Map < String , Ġout ĠAbstract Instance > ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . detect New Instances ( real Instances ) ĊĠĠĠĠĠĠĠ Ġif Ġ( real Instances Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠUpdate Ġproperties ĊĠĠĠĠĠĠĠ Ġinstances . forEach Ġ{ Ġinstance Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreal Instances [ instance . instanceId ]?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . properties Ġ= Ġit . properties ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġcan Start New Instance (): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( active Instances . size Ġ>= Ġmy Image Details . max Instances ) Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġ// ĠCheck ĠAzure ĠCPU Ġquota Ġstate ĊĠĠĠĠĠĠĠ Ġazure Cpu Quota Exceeded ?. let Ġ{ Ġinstances Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( instances Ġ== ĠgetInstance Ids ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġazure Cpu Quota Exceeded Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Azure ĠCPU Ġquota Ġlimit Ġhas Ġbeen Ġreset Ġdue Ġto Ġchange Ġin Ġthe Ġnumber Ġof Ġactive Ġinstances Ġfor Ġimage Ġ${ image Details . source Id }. ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( image Details . deploy Target Ġ== ĠAzure Cloud Deploy Target . Instance Ġ&& Ġstopped Instances . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġstart New Instance ( userData : ĠCloud Instance UserData ) Ġ= Ġrun Blocking Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! can Start New Instance ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠQu ota Exception (" Unable Ġto Ġstart Ġmore Ġinstances . ĠLimit Ġhas Ġreached ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġinstance Ġ= Ġif Ġ( my Image Details . deploy Target Ġ== ĠAzure Cloud Deploy Target . Instance ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġstart Stopped Instance () ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry To Start Stopped Instance ( userData ) Ġ?: Ġcreate Instance ( userData ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġinstance . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġset StartDate ( Date ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠCreates Ġa Ġnew Ġvirtual Ġmachine . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ param ĠuserData Ġinfo Ġabout Ġserver . ĊĠĠĠĠ Ġ* Ġ@ return Ġcreated Ġinstance . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġcreate Instance ( userData : ĠCloud Instance UserData ): ĠAzure Cloud Instance Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinstance Ġ= Ġcreate Azure Cloud Instance () ĊĠĠĠĠĠĠĠ Ġval Ġdata Ġ= ĠAzure Utils . set Vm Name For Tag ( userData , Ġinstance . name ) ĊĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġthis ĊĊĠĠĠĠĠĠĠ Ġmy Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġhash Ġ= Ġhandler !!. getImage Hash ( image Details ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . properties [ Azure Constants . TAG _ PROFILE ] Ġ= ĠuserData . profile Id ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . properties [ Azure Constants . TAG _ SOURCE ] Ġ= Ġimage Details . source Id ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . properties [ Azure Constants . TAG _ DATA _ HASH ] Ġ= ĠgetData Hash ( data ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . properties [ Azure Constants . TAG _ IMAGE _ HASH ] Ġ= Ġhash ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . START ING ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Creating Ġnew Ġvirtual Ġmachine Ġ${ instance . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . create Instance ( instance , Ġdata ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Instance Status ( image , Ġinstance ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Deployment Error ( e ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( Team City Properties . getBoolean Or True ( Azure Constants . PROP _ DEPLOY MENT _ DELETE _ FAILED )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Removing Ġallocated Ġresources Ġfor Ġvirtual Ġmachine Ġ${ instance . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . delete Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Allocated Ġresources Ġfor Ġvirtual Ġmachine Ġ${ instance . name } Ġhave Ġbeen Ġremoved ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmessage Ġ= Ġ" Failed Ġto Ġdelete Ġallocated Ġresources Ġfor Ġvirtual Ġmachine Ġ${ instance . name }: Ġ${ e . message }" ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Allocated Ġresources Ġfor Ġvirtual Ġmachine Ġ${ instance . name } Ġwould Ġnot Ġbe Ġdeleted . ĠCleanup Ġthem Ġmanually .") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġinstance ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcreate Azure Cloud Instance (): ĠAzure Cloud Instance Ġ{ ĊĠĠĠĠĠĠĠ Ġdo Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinstance Ġ= ĠAzure Cloud Instance ( this , ĠgetInstance Name ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . SCHEDUL ED _ TO _ START ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( add Instance If Absent ( instance )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile ( active Instances . size Ġ> Ġmy Image Details . max Instances ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlast Starting Instance Ġ= Ġinstances . filter Ġ{ Ġit . status Ġ== ĠInstance Status . SCHEDUL ED _ TO _ START Ġ}. sorted By Ġ{ Ġit . name Ġ}. last OrNull () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( last Starting Instance Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠQu ota Exception (" Unable Ġto Ġstart Ġmore Ġinstances . ĠLimit Ġhas Ġreached ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( over limit Instance ToDelete . compare AndSet ( null , Ġinstance )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremove Instance ( instance . instanceId ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġover limit Instance ToDelete . set ( null ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠQu ota Exception (" Unable Ġto Ġstart Ġmore Ġinstances . ĠLimit Ġhas Ġreached ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġinstance ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}; ĊĠĠĠĠĠĠĠ Ġ} Ġwhile Ġ( true ); ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠT ries Ġto Ġfind Ġand Ġstart Ġstopped Ġinstance . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ return Ġinstance Ġif Ġit Ġfound . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġtry To Start Stopped Instance ( userData : ĠCloud Instance UserData ): ĠAzure Cloud Instance ? Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġthis ĊĠĠĠĠĠĠĠ Ġreturn Ġcoroutine Scope Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( my Image Details . be haviour . is Delete After Stop ) Ġreturn @ coroutine Scope Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( stopped Instances . isEmpty ()) Ġreturn @ coroutine Scope Ġnull ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinstances Ġ= Ġstopped Instances ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġvalid Instances Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstances . filter Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! is Same Image Instance ( it )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Will Ġremove Ġvirtual Ġmachine Ġ${ it . name } Ġdue Ġto Ġchanges Ġin Ġimage Ġsource ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ filter Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdata Ġ= ĠAzure Utils . set Vm Name For Tag ( userData , Ġit . name ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . properties [ Azure Constants . TAG _ DATA _ HASH ] Ġ!= ĠgetData Hash ( data )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Will Ġremove Ġvirtual Ġmachine Ġ${ it . name } Ġdue Ġto Ġchanges Ġin Ġcloud Ġprofile ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ filter Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ filter Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinvalid Instances Ġ= Ġinstances Ġ- Ġvalid Instances ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinstance Ġ= Ġvalid Instances . first OrNull () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance ?. status Ġ= ĠInstance Status . SCHEDUL ED _ TO _ START ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġmy Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinvalid Instances . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġinstance ToRemove Ġ= Ġremove Instance ( it . instanceId ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( instance ToRemove Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Removing Ġvirtual Ġmachine Ġ${ it . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . delete Instance ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġadd Instance ( instance ToRemove ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . status Ġ= ĠInstance Status . START ING ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Starting Ġstopped Ġvirtual Ġmachine Ġ${ it . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . start Instance ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Instance Status ( image , Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Deployment Error ( e ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ coroutine Scope Ġinstance ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠStarts Ġstopped Ġinstance . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ return Ġinstance . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġstart Stopped Instance (): ĠAzure Cloud Instance Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinstance Ġ= Ġstopped Instances . single OrNull () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ?: Ġthrow ĠCloud Exception (" Instance Ġ${ image Details . vm Name Prefix Ġ?: Ġimage Details . source Id } Ġwas Ġnot Ġfound ") ĊĊĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . SCHEDUL ED _ TO _ START ĊĊĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġthis ĊĠĠĠĠĠĠĠ Ġmy Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . START ING ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Starting Ġvirtual Ġmachine Ġ${ instance . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . start Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Instance Status ( image , Ġinstance ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Deployment Error ( e ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġinstance ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġupdate Instance Status ( image : ĠAzure Cloud Image , Ġinstance : ĠAzure Cloud Instance ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġinstances Ġ= Ġmy Api Connector . fetch Instances < Azure Instance >( image ) ĊĠĠĠĠĠĠĠ Ġinstances . get ( instance . name )?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . startDate ?. let Ġ{ Ġinstance . set StartDate ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . ipAddress ?. let Ġ{ Ġinstance . set Network Ident ify ( it ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= Ġit . instance Status ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġis Same Image Instance ( instance : ĠAzure Cloud Instance ) Ġ= Ġcoroutine Scope Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( image Details . deploy Target Ġ== ĠAzure Cloud Deploy Target . Instance ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ coroutine Scope Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġhandler ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġhash Ġ= Ġit . getImage Hash ( image Details ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ coroutine Scope Ġhash Ġ== Ġinstance . properties [ Azure Constants . TAG _ IMAGE _ HASH ] ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġfalse ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠgetData Hash ( userData : ĠCloud Instance UserData ): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġdata Hash Ġ= ĠStringBuilder ( userData . agent Name ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. append ( userData . profile Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. append ( userData . server Address ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toString () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. hashCode () ĊĠĠĠĠĠĠĠ Ġreturn ĠInteger . to HexString ( data Hash ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġrestart Instance ( instance : ĠAzure Cloud Instance ) Ġ{ ĊĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . RE START ING ĊĊĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġthis ĊĠĠĠĠĠĠĠ Ġmy Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . START ING ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Re starting Ġvirtual Ġmachine Ġ${ instance . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . restart Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Instance Status ( image , Ġinstance ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġterminate Instance ( instance : ĠAzure Cloud Instance ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( instance . properties . containsKey ( Azure Constants . TAG _ IN VE ST IG ATION )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Could Ġnot Ġstop Ġvirtual Ġmachine Ġ${ instance . name } Ġunder Ġinvestigation . ĠTo Ġdo Ġthat Ġremove Ġ${ Azure Constants . TAG _ IN VE ST IG ATION } Ġtag Ġfrom Ġit .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġimage Ġ= Ġthis ĊĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . SCHEDUL ED _ TO _ STOP ĊĊĠĠĠĠĠĠĠ Ġmy Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . STOP PING ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsame V hd Image Ġ= Ġis Same Image Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( my Image Details . be haviour . is Delete After Stop ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Removing Ġvirtual Ġmachine Ġ${ instance . name } Ġdue Ġto Ġcloud Ġimage Ġsettings ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . delete Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . STOP PED ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ(! same V hd Image ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Removing Ġvirtual Ġmachine Ġ${ instance . name } Ġdue Ġto Ġcloud Ġimage Ġretention Ġpolicy ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . delete Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . STOP PED ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Stopping Ġvirtual Ġmachine Ġ${ instance . name }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmy Api Connector . stop Instance ( instance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Instance Status ( image , Ġinstance ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Virtual Ġmachine Ġ${ instance . name } Ġhas Ġbeen Ġsuccessfully Ġterminated ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn And Debug Details ( e . message , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ= ĠInstance Status . ERROR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . update Errors ( Typed Cloud Error Info . from Exception ( e )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . provisioning InProgress Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġget Agent Pool Id (): ĠInt ? Ġ= Ġmy Image Details . agent Pool Id ĊĊĠĠĠ Ġval Ġhandler : ĠAzure Handler ? ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġif Ġ( image Details . deploy Target Ġ== ĠAzure Cloud Deploy Target . Instance ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmy Instance Handler ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmy Image Handlers [ image Details . type ] ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠgetInstance Name (): ĠString Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġkeys Ġ= Ġinstances . map Ġ{ Ġit . instanceId . toLowerCase () Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġsource Name Ġ= Ġmy Image Details . source Id . toLowerCase () ĊĠĠĠĠĠĠĠ Ġvar Ġi Ġ= Ġ 1 ĊĊĠĠĠĠĠĠĠ Ġwhile Ġ( keys . contains ( source Name Ġ+ Ġi )) Ġi ++ ĊĊĠĠĠĠĠĠĠ Ġreturn Ġsource Name Ġ+ Ġi ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠReturns Ġactive Ġinstances . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ return Ġinstances . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġval Ġactive Instances : ĠList < Azure Cloud Instance > ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġinstances . filter Ġ{ Ġinstance Ġ-> Ġmy Active Statuses . contains ( instance . status ) Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠReturns Ġstopped Ġinstances . ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* Ġ@ return Ġinstances . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġval Ġstopped Instances : ĠList < Azure Cloud Instance > ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġinstances . filter Ġ{ Ġinstance Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinstance . status Ġ== ĠInstance Status . STOP PED Ġ&& ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ! instance . properties . containsKey ( Azure Constants . TAG _ IN VE ST IG ATION ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġhandle Deployment Error ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( AZURE _ CPU _ QUOT A _ EX CE EDED . contains Match In ( e . message !! )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġazure Cpu Quota Exceeded Ġ= ĠgetInstance Ids () ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Exceeded ĠAzure ĠCPU Ġquota Ġlimit Ġfor Ġimage Ġ${ image Details . source Id }. ĠWould Ġnot Ġstart Ġnew Ġcloud Ġinstances Ġuntil Ġactive Ġinstances Ġtermination .") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠgetInstance Ids () Ġ= Ġactive Instances . as Sequence (). map Ġ{ Ġit . instanceId Ġ}. to Sorted Set () ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠLOG Ġ= ĠLogger . getInstance ( Azure Cloud Image :: class . java . name ) ĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠAZ URE _ CPU _ QUOT A _ EX CE EDED Ġ= ĠRegex (" Operation Ġresults Ġin Ġexceed ing Ġquota Ġlimits Ġof ĠCore \\. ĠMaximum Ġallowed : Ġ\\ d +, ĠCurrent Ġin Ġuse : Ġ\\ d +, ĠAdditional Ġrequested : Ġ\\ d + \\ .") ĊĠĠĠ Ġ} Ċ } Ċ