1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17:
18: namespace OpenCloud\LoadBalancer\Resource;
19:
20: use OpenCloud\Common\Exceptions;
21: use OpenCloud\Common\Log\Logger;
22: use OpenCloud\Common\Resource\PersistentResource;
23: use OpenCloud\DNS\Resource\HasPtrRecordsInterface;
24: use OpenCloud\LoadBalancer\Enum\NodeCondition;
25: use OpenCloud\LoadBalancer\Enum\IpType;
26: use OpenCloud\LoadBalancer\Enum\NodeType;
27:
28: 29: 30: 31: 32:
33: class LoadBalancer extends PersistentResource implements HasPtrRecordsInterface
34: {
35: public $id;
36:
37: 38: 39: 40: 41: 42:
43: public $name;
44:
45: 46: 47: 48: 49:
50: public $port;
51:
52: 53: 54: 55: 56:
57: public $protocol;
58:
59: 60: 61: 62: 63:
64: public $virtualIps = array();
65:
66: 67: 68: 69: 70:
71: public $nodes = array();
72:
73: 74: 75: 76: 77: 78:
79: public $accessList;
80:
81: 82: 83: 84: 85:
86: public $algorithm;
87:
88:
89: 90: 91: 92: 93:
94: public $httpsRedirect;
95:
96: 97: 98: 99: 100:
101: public $connectionLogging;
102:
103: 104: 105: 106: 107: 108:
109: public $connectionThrottle;
110:
111: 112: 113: 114: 115: 116:
117: public $healthMonitor;
118:
119: 120: 121: 122: 123: 124:
125: public $sessionPersistence;
126:
127: 128: 129: 130: 131: 132:
133: public $metadata = array();
134:
135: 136: 137: 138: 139: 140:
141: public $timeout;
142:
143: public $created;
144: public $updated;
145: public $status;
146: public $nodeCount;
147: public $sourceAddresses;
148: public $cluster;
149:
150: protected static $json_name = 'loadBalancer';
151: protected static $url_resource = 'loadbalancers';
152:
153: protected $associatedResources = array(
154: 'certificateMapping' => 'CertificateMapping',
155: 'node' => 'Node',
156: 'virtualIp' => 'VirtualIp',
157: 'connectionLogging' => 'ConnectionLogging',
158: 'healthMonitor' => 'HealthMonitor',
159: 'sessionPersistance' => 'SessionPersistance'
160: );
161:
162: protected $associatedCollections = array(
163: 'certificateMappings' => 'CertificateMapping',
164: 'nodes' => 'Node',
165: 'virtualIps' => 'VirtualIp',
166: 'accessList' => 'Access'
167: );
168:
169: protected $createKeys = array(
170: 'name',
171: 'port',
172: 'protocol',
173: 'virtualIps',
174: 'nodes',
175: 'accessList',
176: 'algorithm',
177: 'connectionLogging',
178: 'connectionThrottle',
179: 'healthMonitor',
180: 'sessionPersistence',
181: 'httpsRedirect'
182: );
183:
184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201:
202: public function addNode(
203: $address,
204: $port,
205: $condition = NodeCondition::ENABLED,
206: $type = null,
207: $weight = null
208: ) {
209: $allowedConditions = array(
210: NodeCondition::ENABLED,
211: NodeCondition::DISABLED,
212: NodeCondition::DRAINING
213: );
214:
215: if (!in_array($condition, $allowedConditions)) {
216: throw new \InvalidArgumentException(sprintf(
217: "Invalid condition. It must one of the following: %s",
218: implode(', ', $allowedConditions)
219: ));
220: }
221:
222: $allowedTypes = array(NodeType::PRIMARY, NodeType::SECONDARY);
223: if ($type && !in_array($type, $allowedTypes)) {
224: throw new \InvalidArgumentException(sprintf(
225: "Invalid type. It must one of the following: %s",
226: implode(', ', $allowedTypes)
227: ));
228: }
229:
230: if ($weight && !is_numeric($weight)) {
231: throw new \InvalidArgumentException('Invalid weight. You must supply a numeric type');
232: }
233:
234:
235: $this->nodes[] = $this->node(array(
236: 'address' => $address,
237: 'port' => $port,
238: 'condition' => $condition,
239: 'type' => $type,
240: 'weight' => $weight
241: ));
242: }
243:
244: 245: 246: 247: 248: 249:
250: public function addNodes()
251: {
252: if (empty($this->nodes)) {
253: throw new Exceptions\MissingValueError(
254: 'Cannot add nodes; no nodes are defined'
255: );
256: }
257:
258: $requests = array();
259:
260: foreach ($this->nodes as $node) {
261:
262: if (null === $node->getId()) {
263: $json = json_encode($node->createJson());
264: $requests[] = $this->getClient()->post($node->getUrl(), self::getJsonHeader(), $json);
265: }
266: }
267:
268: return $this->getClient()->send($requests);
269: }
270:
271: 272: 273: 274: 275: 276:
277: public function removeNode($nodeId)
278: {
279: return $this->node($nodeId)->delete();
280: }
281:
282: 283: 284: 285: 286: 287: 288: 289: 290: 291:
292: public function addVirtualIp($type = IpType::PUBLIC_TYPE, $ipVersion = null)
293: {
294: $object = new \stdClass();
295:
296: switch (strtoupper($type)) {
297: case IpType::PUBLIC_TYPE:
298: case IpType::SERVICENET_TYPE:
299: $object->type = strtoupper($type);
300: break;
301: default:
302: $object->id = $type;
303: break;
304: }
305:
306: if ($ipVersion) {
307: switch ($ipVersion) {
308: case 4:
309: $object->ipVersion = IpType::IPv4;
310: break;
311: case 6:
312: $object->ipVersion = IpType::IPv6;
313: break;
314: default:
315: throw new Exceptions\DomainError(sprintf(
316: 'Value [%s] for ipVersion is not valid',
317: $ipVersion
318: ));
319: }
320: }
321:
322: 323: 324: 325: 326:
327: if ($this->Id()) {
328: $virtualIp = $this->virtualIp();
329: $virtualIp->type = $type;
330: $virtualIp->ipVersion = $object->ipVersion;
331: return $virtualIp->create();
332: } else {
333:
334: $this->virtualIps[] = $object;
335: }
336:
337: return true;
338: }
339:
340: 341: 342: 343: 344:
345: public function node($id = null)
346: {
347: return $this->getService()->resource('Node', $id, $this);
348: }
349:
350: 351: 352: 353: 354:
355: public function nodeList()
356: {
357: return $this->getService()->resourceList('Node', null, $this);
358: }
359:
360: 361: 362: 363: 364:
365: public function nodeEvent()
366: {
367: return $this->getService()->resource('NodeEvent', null, $this);
368: }
369:
370: 371: 372: 373: 374:
375: public function nodeEventList()
376: {
377: return $this->getService()->resourceList('NodeEvent', null, $this);
378: }
379:
380: 381: 382: 383: 384:
385: public function virtualIp($data = null)
386: {
387: return $this->getService()->resource('VirtualIp', $data, $this);
388: }
389:
390: 391: 392:
393: public function virtualIpList()
394: {
395: return $this->getService()->resourceList('VirtualIp', null, $this);
396: }
397:
398: 399: 400: 401: 402: 403: 404: 405:
406: public function certificateMapping($id = null)
407: {
408: return $this->getService()->resource('CertificateMapping', $id, $this);
409: }
410:
411: 412: 413: 414: 415:
416: public function certificateMappingList()
417: {
418: return $this->getService()->resourceList('CertificateMapping', null, $this);
419: }
420:
421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431:
432: public function addCertificateMapping(
433: $hostName,
434: $privateKey,
435: $certificate,
436: $intermediateCertificate = null
437: ) {
438: $certificateMapping = $this->certificateMapping(
439: array(
440: 'hostName' => $hostName,
441: 'privateKey' => $privateKey,
442: 'certificate' => $certificate,
443: 'intermediateCertificate' => $intermediateCertificate
444: )
445: );
446: $json = json_encode($certificateMapping->createJson());
447: $request = $this->getClient()->post($certificateMapping->getUrl(), self::getJsonHeader(), $json);
448:
449: return $this->getClient()->send($request);
450: }
451:
452: 453: 454: 455: 456: 457: 458: 459: 460: 461:
462: public function updateCertificateMapping(
463: $id,
464: $hostName = null,
465: $privateKey = null,
466: $certificate = null,
467: $intermediateCertificate = null
468: ) {
469: $certificateMapping = $this->certificateMapping($id);
470: return $certificateMapping->update(
471: array(
472: 'hostName' => $hostName,
473: 'privateKey' => $privateKey,
474: 'certificate' => $certificate,
475: 'intermediateCertificate' => $intermediateCertificate
476: )
477: );
478: }
479:
480: 481: 482: 483: 484: 485:
486: public function removeCertificateMapping($id)
487: {
488: return $this->certificateMapping($id)->delete();
489: }
490:
491: 492: 493: 494: 495:
496: public function sessionPersistence()
497: {
498: return $this->getService()->resource('SessionPersistence', null, $this);
499: }
500:
501: 502: 503: 504: 505:
506: public function errorPage()
507: {
508: return $this->getService()->resource('ErrorPage', null, $this);
509: }
510:
511: 512: 513: 514: 515:
516: public function healthMonitor()
517: {
518: return $this->getService()->resource('HealthMonitor', null, $this);
519: }
520:
521: 522: 523: 524: 525:
526: public function stats()
527: {
528: return $this->getService()->resource('Stats', null, $this);
529: }
530:
531: 532: 533:
534: public function usage()
535: {
536: return $this->getService()->resourceList('UsageRecord', null, $this);
537: }
538:
539: 540: 541: 542: 543:
544: public function access($data = null)
545: {
546: return $this->getService()->resource('Access', $data, $this);
547: }
548:
549: 550: 551: 552: 553: 554: 555: 556: 557: 558:
559: public function createAccessList(array $list)
560: {
561: $url = $this->getUrl();
562: $url->addPath('accesslist');
563:
564: $json = json_encode($list);
565: $this->checkJsonError();
566:
567: return $this->getClient()->post($url, self::getJsonHeader(), $json)->send();
568: }
569:
570: 571: 572:
573: public function accessList()
574: {
575: return $this->getService()->resourceList('Access', null, $this);
576: }
577:
578: 579: 580: 581: 582:
583: public function connectionThrottle()
584: {
585: return $this->getService()->resource('ConnectionThrottle', null, $this);
586: }
587:
588: 589: 590: 591: 592:
593: public function hasConnectionLogging()
594: {
595: $url = clone $this->getUrl();
596: $url->addPath('connectionlogging');
597:
598: $response = $this->getClient()->get($url)->send()->json();
599:
600: return isset($response['connectionLogging']['enabled'])
601: && $response['connectionLogging']['enabled'] === true;
602: }
603:
604: 605: 606: 607: 608: 609:
610: public function enableConnectionLogging($bool)
611: {
612: $url = clone $this->getUrl();
613: $url->addPath('connectionlogging');
614:
615: $body = array('connectionLogging' => (bool) $bool);
616:
617: return $this->getClient()->put($url, self::getJsonHeader(), $body)->send();
618: }
619:
620: 621: 622:
623: public function connectionLogging()
624: {
625: $this->getLogger()->warning(Logger::deprecated(__METHOD__, 'hasConnectionLogging or enableConnectionLogging'));
626: }
627:
628: 629: 630: 631: 632:
633: public function hasContentCaching()
634: {
635: $url = clone $this->getUrl();
636: $url->addPath('contentcaching');
637:
638: $response = $this->getClient()->get($url)->send()->json();
639:
640: return isset($response['contentCaching']['enabled'])
641: && $response['contentCaching']['enabled'] === true;
642: }
643:
644: 645: 646: 647: 648: 649:
650: public function enableContentCaching($bool)
651: {
652: $url = clone $this->getUrl();
653: $url->addPath('contentcaching');
654:
655: $body = array('contentCaching' => array('enabled' => (bool) $bool));
656: $body = json_encode($body);
657: $this->checkJsonError();
658:
659: return $this->getClient()->put($url, self::getJsonHeader(), $body)->send();
660: }
661:
662: 663: 664:
665: public function contentCaching()
666: {
667: $this->getLogger()->warning(sprintf(
668: 'The %s method is deprecated, please use %s instead', __METHOD__, 'hasContentCaching or setContentCaching'));
669: }
670:
671: 672: 673: 674: 675:
676: public function SSLTermination()
677: {
678: return $this->getService()->resource('SSLTermination', null, $this);
679: }
680:
681: 682: 683: 684: 685:
686: public function metadata($data = null)
687: {
688: return $this->getService()->resource('Metadata', $data, $this);
689: }
690:
691: 692: 693: 694: 695:
696: public function metadataList()
697: {
698: return $this->getService()->resourceList('Metadata', null, $this);
699: }
700:
701: protected function createJson()
702: {
703: $element = (object) array();
704:
705: foreach ($this->createKeys as $key) {
706: if ($key == 'nodes') {
707: foreach ($this->nodes as $node) {
708: $nodeObject = (object) array();
709: foreach ($node->createKeys as $key) {
710: if (!empty($node->$key)) {
711: $nodeObject->$key = $node->$key;
712: }
713: }
714: $element->nodes[] = (object) $nodeObject;
715: }
716: } elseif ($key == 'virtualIps') {
717: foreach ($this->virtualIps as $virtualIp) {
718: $element->virtualIps[] = $virtualIp;
719: }
720: } elseif (isset($this->$key)) {
721: $element->$key = $this->$key;
722: }
723: }
724:
725: $object = (object) array($this->jsonName() => $element);
726:
727: return $object;
728: }
729:
730: protected function updateJson($params = array())
731: {
732: $updatableFields = array('name', 'algorithm', 'protocol', 'port', 'timeout', 'halfClosed', 'httpsRedirect');
733:
734: $fields = array_keys($params);
735: foreach ($fields as $field) {
736: if (!in_array($field, $updatableFields)) {
737: throw new Exceptions\InvalidArgumentError("You cannot update $field.");
738: }
739: }
740:
741: $object = new \stdClass();
742: $object->loadBalancer = new \stdClass();
743: foreach ($params as $name => $value) {
744: $object->loadBalancer->$name = $this->$name;
745: }
746:
747: return $object;
748: }
749: }
750: