GoogleCloud.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <?php
  2. namespace MGModule\DNSManager2\mgLibs\custom\dns\submodules;
  3. use \MGModule\DNSManager2\mgLibs\custom\dns;
  4. use \MGModule\DNSManager2\mgLibs\custom\dns\exceptions;
  5. use \MGModule\DNSManager2\mgLibs\custom\dns\interfaces;
  6. use \MGModule\DNSManager2\mgLibs\custom\dns\utils\Patterns;
  7. class GoogleCloud extends dns\SubmoduleAbstract implements
  8. interfaces\SubmoduleIPInterface, interfaces\SubmoduleRDNSInterface, interfaces\SubmoduleTTLInterface, interfaces\SubmoduleImportInterface
  9. {
  10. public $configFields = array(
  11. 'configContent' => array(
  12. 'friendlyName' => 'Config Content',
  13. 'type' => 'textarea',
  14. 'validators' => array(
  15. 'required' => 'required',
  16. )
  17. ),
  18. );
  19. public $availableTypes = array('A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NAPTR', 'NS', 'PTR', 'TXT', 'SPF', 'SRV');
  20. public function testConnection()
  21. {
  22. try
  23. {
  24. $domainRelations = new GoogleCloud\DomainRelations();
  25. $domainRelations->createTableIfNotExists();
  26. $this->apiTestConnection();
  27. return true;
  28. }
  29. catch (\Exception $e)
  30. {
  31. throw new exceptions\DNSSubmoduleException($e->getMessage(), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  32. }
  33. }
  34. public function getRecords($recordType = false)
  35. {
  36. try
  37. {
  38. $client = $this->getGoogleClient();
  39. $service = new \Google_Service_Dns($client);
  40. $results = $service->resourceRecordSets->listResourceRecordSets($this->getProjectID(), $this->getDomainName());
  41. $return = [];
  42. if (!empty($results->rrsets))
  43. {
  44. foreach ($results->rrsets as $key => $r)
  45. {
  46. $i = 0;
  47. foreach ($r->rrdatas as $rdata)
  48. {
  49. $record = new dns\record\Record();
  50. $record->line = $key . '-' . $i++;
  51. $record->name = $r->name;
  52. $record->type = $r->type;
  53. $record->ttl = $r->ttl;
  54. $record->createRDATAObject();
  55. if( $record->type === 'TXT' )
  56. {
  57. $record->rdata->txtdata = $rdata;
  58. }
  59. else
  60. {
  61. $record->rdata = $this->assignValuesToFields($record->rdata, $rdata);
  62. }
  63. $return[] = $record;
  64. }
  65. }
  66. }
  67. return $return;
  68. }
  69. catch (\Exception $ex)
  70. {
  71. throw new exceptions\DNSSubmoduleException($ex->getMessage(), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  72. }
  73. }
  74. public function addRecord(dns\record\Record $record)
  75. {
  76. try
  77. {
  78. $client = $this->getGoogleClient();
  79. $service = new \Google_Service_Dns($client);
  80. if( $record->type === 'TXT' )
  81. {
  82. $record->rdata->txtdata = htmlspecialchars_decode($record->rdata->txtdata);
  83. }
  84. $model = new \Google_Service_Dns_ResourceRecordSet();
  85. $model->setName($record->nameToAbsolute($this->domain));
  86. $model->setType($record->type);
  87. $model->setTtl($record->ttl);
  88. $model->setRrdatas([implode(' ', $this->preapareArray($record->rdata))]);
  89. $additions = new \Google_Service_Dns_Change();
  90. $additions->setAdditions([$model]);
  91. $service->changes->create($this->getProjectID(), $this->getDomainName(), $additions);
  92. return true;
  93. }
  94. catch (\Exception $ex)
  95. {
  96. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  97. }
  98. }
  99. public function editRecord(dns\record\Record $record)
  100. {
  101. try
  102. {
  103. $lines = $this->getLines($record);
  104. $newLines = $this->getNewLines($record);
  105. if( $record->type === 'TXT' )
  106. {
  107. $record->rdata->txtdata = htmlspecialchars_decode($record->rdata->txtdata);
  108. }
  109. if (count($lines) > 1)
  110. {
  111. $rData = $this->getRDataForLines($lines);
  112. $newRData = $this->getRDataForLines($newLines);
  113. }
  114. else
  115. {
  116. $rData = [implode(' ', $this->preapareArray($lines[0]->rdata))];
  117. $newRData = [implode(' ', $this->preapareArray($record->rdata))];
  118. }
  119. $client = $this->getGoogleClient();
  120. $service = new \Google_Service_Dns($client);
  121. $removeModel = new \Google_Service_Dns_ResourceRecordSet();
  122. $removeModel->setName($lines[0]->name);
  123. $removeModel->setType($lines[0]->type);
  124. $removeModel->setTtl($lines[0]->ttl);
  125. $removeModel->setRrdatas(array_values($rData));
  126. $addModel = new \Google_Service_Dns_ResourceRecordSet();
  127. $addModel->setName($record->nameToAbsolute($this->domain));
  128. $addModel->setType($record->type);
  129. $addModel->setTtl($record->ttl);
  130. $addModel->setRrdatas(array_values($newRData));
  131. $additions = new \Google_Service_Dns_Change();
  132. $additions->setDeletions([$removeModel]);
  133. $additions->setAdditions([$addModel]);
  134. $service->changes->create($this->getProjectID(), $this->getDomainName(), $additions);
  135. return true;
  136. }
  137. catch (\Exception $ex)
  138. {
  139. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  140. }
  141. }
  142. public function getNewLines(dns\record\Record $record)
  143. {
  144. $lines = $this->getLines($record);
  145. foreach ($lines as $line)
  146. {
  147. if ($line->line == $record->line)
  148. {
  149. $line->rdata = $record->rdata;
  150. }
  151. }
  152. return $lines;
  153. }
  154. public function customDeleteRecord($records, $toRemove)
  155. {
  156. try
  157. {
  158. $newRData = $this->getRDataForLines($records);
  159. $client = $this->getGoogleClient();
  160. $service = new \Google_Service_Dns($client);
  161. $removeModel = new \Google_Service_Dns_ResourceRecordSet();
  162. $removeModel->setName($toRemove->nameToAbsolute($this->domain));
  163. $removeModel->setType($toRemove->type);
  164. $removeModel->setTtl($toRemove->ttl);
  165. $removeModel->setRrdatas(array_values($newRData));
  166. unset($newRData[$this->preapareArray($toRemove->rdata)[0]]);
  167. $addModel = new \Google_Service_Dns_ResourceRecordSet();
  168. $addModel->setName($toRemove->nameToAbsolute($this->domain));
  169. $addModel->setType($toRemove->type);
  170. $addModel->setTtl($toRemove->ttl);
  171. $addModel->setRrdatas(array_values($newRData));
  172. $additions = new \Google_Service_Dns_Change();
  173. $additions->setDeletions([$removeModel]);
  174. $additions->setAdditions([$addModel]);
  175. $service->changes->create($this->getProjectID(), $this->getDomainName(), $additions);
  176. return true;
  177. }
  178. catch (\Exception $ex)
  179. {
  180. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  181. }
  182. }
  183. public function getRDataForLines($lines)
  184. {
  185. $newRData = [];
  186. foreach ($lines as $row)
  187. {
  188. $rData = $this->preapareArray($row->rdata)[0];
  189. $newRData[$rData] = $rData;
  190. }
  191. return $newRData;
  192. }
  193. public function deleteRecord(dns\record\Record $record)
  194. {
  195. try
  196. {
  197. $lines = $this->getLines($record);
  198. if( $record->type === 'TXT' )
  199. {
  200. $record->rdata->txtdata = htmlspecialchars_decode($record->rdata->txtdata);
  201. }
  202. if (count($lines) > 1)
  203. {
  204. $this->customDeleteRecord($lines, $record);
  205. }
  206. else
  207. {
  208. $client = $this->getGoogleClient();
  209. $service = new \Google_Service_Dns($client);
  210. $model = new \Google_Service_Dns_ResourceRecordSet();
  211. $model->setName($record->nameToAbsolute($this->domain));
  212. $model->setType($record->type);
  213. $model->setTtl($record->ttl);
  214. $model->setRrdatas([implode(' ', $this->preapareArray($record->rdata))]);
  215. $additions = new \Google_Service_Dns_Change();
  216. $additions->setDeletions([$model]);
  217. $service->changes->create($this->getProjectID(), $this->getDomainName(), $additions);
  218. }
  219. }
  220. catch (\Exception $ex)
  221. {
  222. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  223. }
  224. }
  225. public function getLines(dns\record\Record $record)
  226. {
  227. $records = $this->getRecords();
  228. if (empty($records))
  229. {
  230. return false;
  231. }
  232. $lines = [];
  233. foreach ($records as $r)
  234. {
  235. if (explode('-', $r->line)[0] == explode('-', $record->line)[0])
  236. {
  237. $lines[] = $r;
  238. }
  239. }
  240. return $lines;
  241. }
  242. public function zoneExists()
  243. {
  244. try
  245. {
  246. $client = $this->getGoogleClient();
  247. $service = new \Google_Service_Dns($client);
  248. $service->managedZones->get($this->getProjectID(), $this->getDomainName());
  249. return true;
  250. }
  251. catch( \Exception $ex )
  252. {
  253. if( $ex->getErrors() && $ex->getErrors()[0]['reason'] === 'notFound' )
  254. {
  255. return false;
  256. }
  257. throw $ex;
  258. }
  259. }
  260. public function activateZone()
  261. {
  262. if ($this->ip != '')
  263. {
  264. if (!filter_var($this->ip, FILTER_VALIDATE_IP))
  265. {
  266. throw new exceptions\DNSSubmoduleException('IP is not valid!', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  267. }
  268. }
  269. try
  270. {
  271. $model = new \Google_Service_Dns_ManagedZone();
  272. $model->setName($this->getDomainName());
  273. $model->setDnsName($this->getDNSName());
  274. $model->setDescription($this->ip);
  275. $client = $this->getGoogleClient();
  276. $service = new \Google_Service_Dns($client);
  277. $service->managedZones->create($this->getProjectID(), $model);
  278. }
  279. catch (\Exception $ex)
  280. {
  281. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  282. }
  283. }
  284. public function terminateZone()
  285. {
  286. try
  287. {
  288. $this->clearRecords();
  289. $client = $this->getGoogleClient();
  290. $service = new \Google_Service_Dns($client);
  291. $service->managedZones->delete($this->getProjectID(), $this->getDomainName());
  292. return true;
  293. }
  294. catch (\Exception $ex)
  295. {
  296. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  297. }
  298. }
  299. private function clearRecords(){
  300. foreach ($this->getRecords() as $record) {
  301. try{
  302. $this->deleteRecord($record);
  303. } catch(\Exception $e) {
  304. continue;
  305. }
  306. }
  307. }
  308. public function getZones()
  309. {
  310. try
  311. {
  312. $client = $this->getGoogleClient();
  313. $service = new \Google_Service_Dns($client);
  314. $results = $service->managedZones->listManagedZones($this->getProjectID());
  315. $out = [];
  316. foreach ($results->managedZones as $zone)
  317. {
  318. $domainName = rtrim($zone->dnsName, ".");
  319. $domainRelations = GoogleCloud\DomainRelations::WhereName($domainName)->first();
  320. if (is_null($domainRelations))
  321. {
  322. $model = new GoogleCloud\DomainRelations([
  323. 'domain' => $domainName,
  324. 'name' => $zone->name
  325. ]);
  326. $model->save();
  327. }
  328. $out[$domainName] = '';
  329. }
  330. }
  331. catch (\Exception $ex)
  332. {
  333. throw new exceptions\DNSSubmoduleException($this->getErrorMessage($ex), dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  334. }
  335. return $out;
  336. }
  337. /*
  338. * Google API
  339. *
  340. */
  341. private function apiTestConnection()
  342. {
  343. $client = $this->getGoogleClient();
  344. $service = new \Google_Service_Dns($client);
  345. $results = $service->managedZones->listManagedZones($this->getProjectID());
  346. return $results;
  347. }
  348. private function assignValuesToFields($object, $values)
  349. {
  350. $fields = get_object_vars($object);
  351. $values = explode(' ', $values);
  352. $i = 0;
  353. foreach ($fields as $field => $v)
  354. {
  355. $object->{$field} = $values[$i++];
  356. }
  357. return $object;
  358. }
  359. private function preapareArray($object)
  360. {
  361. $return = [];
  362. foreach ($object as $option)
  363. {
  364. $return[] = $option;
  365. }
  366. return $return;
  367. }
  368. private function getDomainName()
  369. {
  370. $domainRelations = GoogleCloud\DomainRelations::WhereDomain($this->domain)->first();
  371. if ($domainRelations->name)
  372. {
  373. return $domainRelations->name;
  374. }
  375. $name = str_replace('.', '-', strtolower($this->domain)) . time();
  376. $model = new GoogleCloud\DomainRelations([
  377. 'domain' => $this->domain,
  378. 'name' => $name
  379. ]);
  380. $model->save();
  381. return $name;
  382. }
  383. private function getDNSName()
  384. {
  385. return $this->domain . '.';
  386. }
  387. private function getConfigArray()
  388. {
  389. if (!$config = json_decode(htmlspecialchars_decode($this->config['configContent']), true))
  390. {
  391. throw new \Exception('Invalid json for auth config');
  392. }
  393. return $config;
  394. }
  395. private function getProjectID()
  396. {
  397. return $this->getConfigArray()['project_id'];
  398. }
  399. private function getErrorMessage(\Exception $ex)
  400. {
  401. $object = \json_decode($ex->getMessage(), true);
  402. return $object['error']['message'];
  403. }
  404. private function getGoogleClient()
  405. {
  406. $googleClient = new \Google_Client();
  407. $googleClient->setAuthConfig($this->getConfigArray());
  408. $googleClient->addScope(\Google_Service_Dns::CLOUD_PLATFORM);
  409. return $googleClient;
  410. }
  411. }