5 // Created by Michael Mayo on 2/9/11.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
9 #import "LoadBalancer.h"
11 #import "LoadBalancerNode.h"
12 #import "NSObject+NSCoding.h"
13 #import "LoadBalancerProtocol.h"
14 #import "LoadBalancerConnectionThrottle.h"
16 #import "NSString+Conveniences.h"
17 #import "OpenStackAccount.h"
18 #import "ASIHTTPRequest.h"
19 #import "LoadBalancerRequest.h"
22 @implementation LoadBalancer
24 @synthesize protocol, algorithm, status, virtualIPs, created, updated, maxConcurrentConnections,
25 connectionLoggingEnabled, nodes, connectionThrottle, clusterName, sessionPersistenceType, progress,
26 virtualIPType, region, usage;
27 //@synthesize cloudServerNodes;
29 #pragma mark - Constructors and Memory Management
34 self.nodes = [[[NSMutableArray alloc] init] autorelease];
35 // self.cloudServerNodes = [[[NSMutableArray alloc] init] autorelease];
48 [sessionPersistenceType release];
49 [clusterName release];
50 // [cloudServerNodes release];
51 [virtualIPType release];
54 [connectionThrottle release];
58 #pragma mark - Serialization
60 - (void)encodeWithCoder: (NSCoder *)coder {
61 [self autoEncodeWithCoder:coder];
64 - (id)initWithCoder:(NSCoder *)coder {
65 if ((self = [super initWithCoder:coder])) {
66 [self autoDecode:coder];
73 + (LoadBalancer *)fromJSON:(NSDictionary *)dict account:(OpenStackAccount *)account {
75 LoadBalancer *loadBalancer = [[[LoadBalancer alloc] initWithJSONDict:dict] autorelease];
77 LoadBalancerProtocol *p = [[[LoadBalancerProtocol alloc] init] autorelease];
78 p.name = [dict objectForKey:@"protocol"];
79 p.port = [[dict objectForKey:@"port"] intValue];
80 loadBalancer.protocol = p;
82 loadBalancer.algorithm = [dict objectForKey:@"algorithm"];
83 loadBalancer.status = [dict objectForKey:@"status"];
85 NSArray *virtualIpDicts = [dict objectForKey:@"virtualIps"];
86 loadBalancer.virtualIPs = [[[NSMutableArray alloc] initWithCapacity:[virtualIpDicts count]] autorelease];
87 for (NSDictionary *vipDict in virtualIpDicts) {
88 VirtualIP *ip = [VirtualIP fromJSON:vipDict];
89 [loadBalancer.virtualIPs addObject:ip];
90 loadBalancer.virtualIPType = ip.type;
93 loadBalancer.created = [loadBalancer dateForKey:@"time" inDict:[dict objectForKey:@"created"]];
94 loadBalancer.updated = [loadBalancer dateForKey:@"time" inDict:[dict objectForKey:@"updated"]];
96 if ([dict objectForKey:@"connectionLogging"]) {
97 loadBalancer.connectionLoggingEnabled = [[[dict objectForKey:@"connectionLogging"] objectForKey:@"enabled"] boolValue];
100 NSArray *nodeDicts = [dict objectForKey:@"nodes"];
101 loadBalancer.nodes = [[[NSMutableArray alloc] initWithCapacity:[nodeDicts count]] autorelease];
102 for (NSDictionary *nodeDict in nodeDicts) {
103 LoadBalancerNode *node = [LoadBalancerNode fromJSON:nodeDict];
104 Server *server = [account.serversByPublicIP objectForKey:node.address];
106 node.server = server;
108 [loadBalancer.nodes addObject:node];
111 if ([dict objectForKey:@"connectionThrottle"]) {
112 loadBalancer.connectionThrottle = [LoadBalancerConnectionThrottle fromJSON:[dict objectForKey:@"connectionThrottle"]];
115 loadBalancer.sessionPersistenceType = [[dict objectForKey:@"sessionPersistence"] objectForKey:@"persistenceType"];
116 loadBalancer.clusterName = [[dict objectForKey:@"cluster"] objectForKey:@"name"];
120 - (NSString *)toUpdateJSON {
122 = @"{ \"loadBalancer\": { "
123 " \"name\": \"<name>\","
124 " \"algorithm\": \"<algorithm>\","
125 " \"protocol\": \"<protocol>\","
126 " \"port\": \"<port>\""
128 json = [json replace:@"<name>" with:self.name];
129 json = [json replace:@"<algorithm>" with:self.algorithm];
130 json = [json replace:@"<protocol>" with:self.protocol.name];
131 json = [json replace:@"<port>" withInt:self.protocol.port];
135 - (NSString *)toJSON {
137 NSString *json = @"{ \"loadBalancer\": { ";
139 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"name\": \"%@\", ", self.name]];
140 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"protocol\": \"%@\", ", self.protocol.name]];
141 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"port\": \"%i\", ", self.protocol.port]];
142 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"algorithm\": \"%@\", ", self.algorithm]];
145 if ([self.virtualIPType isEqualToString:@"Public"]) {
146 json = [json stringByAppendingString:@"\"virtualIps\": [ { \"type\": \"PUBLIC\" } ], "];
147 } else if ([self.virtualIPType isEqualToString:@"ServiceNet"]) {
148 json = [json stringByAppendingString:@"\"virtualIps\": [ { \"type\": \"SERVICENET\" } ], "];
149 } else if ([self.virtualIPType isEqualToString:@"Shared Virtual IP"]) {
150 //json = [json stringByAppendingString:@"\"virtualIps\": [ { \"type\": \"PUBLIC\" } ], "];
151 json = [json stringByAppendingString:@"\"virtualIps\": [ "];
152 for (int i = 0; i < [self.virtualIPs count]; i++) {
153 VirtualIP *vip = [self.virtualIPs objectAtIndex:i];
154 json = [json stringByAppendingFormat:@"{ \"id\": \"%@\" }", vip.identifier];
155 if (i < [self.virtualIPs count] - 1) {
156 json = [json stringByAppendingString:@","];
159 json = [json stringByAppendingString:@"], "];
162 json = [json stringByAppendingString:@"\"nodes\": ["];
163 for (int i = 0; i < [self.nodes count]; i++) {
164 LoadBalancerNode *node = [self.nodes objectAtIndex:i];
166 Server *server = node.server;
167 json = [json stringByAppendingString:@"{"];
168 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"address\": \"%@\",", [[server.addresses objectForKey:@"public"] objectAtIndex:0]]];
169 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"port\": \"%i\",", self.protocol.port]];
170 json = [json stringByAppendingString:@"\"condition\": \"ENABLED\""];
172 LoadBalancerNode *lbNode = node;
173 json = [json stringByAppendingString:@"{"];
174 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"address\": \"%@\",", lbNode.address]];
175 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"port\": \"%@\",", lbNode.port]];
176 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"condition\": \"%@\"", lbNode.condition]];
179 if (i == [self.nodes count] - 1) {
180 json = [json stringByAppendingString:@"}"];
182 json = [json stringByAppendingString:@"}, "];
186 for (int i = 0; i < [self.cloudServerNodes count]; i++) {
187 Server *server = [self.cloudServerNodes objectAtIndex:i];
188 json = [json stringByAppendingString:@"{"];
189 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"address\": \"%@\",", [[server.addresses objectForKey:@"public"] objectAtIndex:0]]];
190 json = [json stringByAppendingString:[NSString stringWithFormat:@"\"port\": \"%i\",", self.protocol.port]];
191 json = [json stringByAppendingString:@"\"condition\": \"ENABLED\""];
192 json = [json stringByAppendingString:i == [self.cloudServerNodes count] - 1 ? @"}" : @"}, "];
195 json = [json stringByAppendingString:@"]"];
197 json = [json stringByAppendingString:@"}}"];
201 - (BOOL)shouldBePolled {
202 return ![self.status isEqualToString:@"ACTIVE"];
205 - (void)pollUntilActive:(OpenStackAccount *)account delegate:(id)delegate progressSelector:(SEL)progressSelector completeSelector:(SEL)completeSelector object:(id)object {
207 NSLog(@"polling. lb status = %@", self.status);
210 if ([self shouldBePolled]) {
211 NSString *endpoint = [account loadBalancerEndpointForRegion:self.region];
212 __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancerDetailsRequest:account loadBalancer:self endpoint:endpoint];
213 request.delegate = self;
214 [request setCompletionBlock:^{
215 if ([request isSuccess]) {
217 LoadBalancer *newLB = [request loadBalancer:account];
218 self.status = newLB.status;
219 self.progress = newLB.progress;
222 NSLog(@"lb poll status: %@", self.status);
224 if ([self shouldBePolled]) {
225 if (progressSelector && [delegate respondsToSelector:progressSelector]) {
226 [delegate performSelector:progressSelector];
228 [self pollUntilActive:account delegate:delegate progressSelector:progressSelector completeSelector:completeSelector object:object];
230 if ([delegate respondsToSelector:completeSelector]) {
231 [delegate performSelector:completeSelector withObject:object];
236 [request setFailedBlock:^{
237 [self pollUntilActive:account delegate:delegate progressSelector:progressSelector completeSelector:completeSelector object:object];
239 [request startAsynchronous];
241 if ([delegate respondsToSelector:completeSelector]) {
242 [delegate performSelector:completeSelector withObject:object];
247 - (void)pollUntilActive:(OpenStackAccount *)account delegate:(id)delegate completeSelector:(SEL)completeSelector object:(id)object {
248 [self pollUntilActive:account delegate:delegate progressSelector:nil completeSelector:completeSelector object:object];
251 - (void)pollUntilActive:(OpenStackAccount *)account withProgress:(ASIBasicBlock)progressBlock complete:(ASIBasicBlock)completeBlock {
253 if ([self shouldBePolled]) {
254 NSString *endpoint = [account loadBalancerEndpointForRegion:self.region];
255 __block LoadBalancerRequest *request = [LoadBalancerRequest getLoadBalancerDetailsRequest:account loadBalancer:self endpoint:endpoint];
256 request.delegate = self;
257 [request setCompletionBlock:^{
258 if ([request isSuccess]) {
260 LoadBalancer *newLB = [request loadBalancer:account];
261 self.status = newLB.status;
262 self.progress = newLB.progress;
265 NSLog(@"lb poll status: %@", self.status);
267 if ([self shouldBePolled]) {
271 [self pollUntilActive:account withProgress:nil complete:completeBlock];
277 [request setFailedBlock:^{
278 //[progressBlock retain];
279 //[completeBlock retain];
280 [self pollUntilActive:account withProgress:progressBlock complete:^{
285 [request startAsynchronous];
291 - (void)pollUntilActive:(OpenStackAccount *)account complete:(ASIBasicBlock)completeBlock {
292 // [self pollUntilActive:account withProgress:nil complete:[[completeBlock copy] autorelease]];
293 [self pollUntilActive:account withProgress:nil complete:completeBlock];
296 - (UIImage *)imageForStatus {
297 // load balancer statuses:
298 // ACTIVE BUILD PENDING_UPDATE PENDING_DELETE SUSPENDED ERROR DELETED
299 if ([self.status isEqualToString:@"ACTIVE"]) {
300 return [UIImage imageNamed:@"dot-green.png"];
301 } else if ([self.status isEqualToString:@"BUILD"] || [self.status isEqualToString:@"PENDING_UPDATE"]) {
302 return [UIImage imageNamed:@"dot-orange.png"];
304 return [UIImage imageNamed:@"dot-red.png"];