Expanded open file functionality to use available apps.
[pithos-ios] / Classes / LoadBalancer.m
1 //
2 //  LoadBalancer.m
3 //  OpenStack
4 //
5 //  Created by Michael Mayo on 2/9/11.
6 //  Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "LoadBalancer.h"
10 #import "VirtualIP.h"
11 #import "LoadBalancerNode.h"
12 #import "NSObject+NSCoding.h"
13 #import "LoadBalancerProtocol.h"
14 #import "LoadBalancerConnectionThrottle.h"
15 #import "Server.h"
16 #import "NSString+Conveniences.h"
17 #import "OpenStackAccount.h"
18 #import "ASIHTTPRequest.h"
19 #import "LoadBalancerRequest.h"
20
21
22 @implementation LoadBalancer
23
24 @synthesize protocol, algorithm, status, virtualIPs, created, updated, maxConcurrentConnections,
25             connectionLoggingEnabled, nodes, connectionThrottle, clusterName, sessionPersistenceType, progress,
26             virtualIPType, region, usage;
27 //@synthesize cloudServerNodes;
28
29 #pragma mark - Constructors and Memory Management
30
31 - (id)init {
32     self = [super init];
33     if (self) {
34         self.nodes = [[[NSMutableArray alloc] init] autorelease];
35 //        self.cloudServerNodes = [[[NSMutableArray alloc] init] autorelease];
36     }
37     return self;
38 }
39
40 - (void)dealloc {
41     [protocol release];
42     [algorithm release];
43     [status release];
44     [virtualIPs release];
45     [created release];
46     [updated release];
47     [nodes release];
48     [sessionPersistenceType release];
49     [clusterName release];
50 //    [cloudServerNodes release];
51     [virtualIPType release];
52     [region release];
53     [usage release];
54     [connectionThrottle release];
55     [super dealloc];
56 }
57
58 #pragma mark - Serialization
59
60 - (void)encodeWithCoder: (NSCoder *)coder {
61     [self autoEncodeWithCoder:coder];    
62 }
63
64 - (id)initWithCoder:(NSCoder *)coder {
65     if ((self = [super initWithCoder:coder])) {
66         [self autoDecode:coder];
67     }
68     return self;
69 }
70
71 #pragma mark - JSON
72
73 + (LoadBalancer *)fromJSON:(NSDictionary *)dict account:(OpenStackAccount *)account {
74     
75     LoadBalancer *loadBalancer = [[[LoadBalancer alloc] initWithJSONDict:dict] autorelease];
76     
77     LoadBalancerProtocol *p = [[[LoadBalancerProtocol alloc] init] autorelease];
78     p.name = [dict objectForKey:@"protocol"];
79     p.port = [[dict objectForKey:@"port"] intValue];
80     loadBalancer.protocol = p;
81     
82     loadBalancer.algorithm = [dict objectForKey:@"algorithm"];
83     loadBalancer.status = [dict objectForKey:@"status"];
84     
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;
91     }
92     
93     loadBalancer.created = [loadBalancer dateForKey:@"time" inDict:[dict objectForKey:@"created"]];
94     loadBalancer.updated = [loadBalancer dateForKey:@"time" inDict:[dict objectForKey:@"updated"]];
95
96     if ([dict objectForKey:@"connectionLogging"]) {
97         loadBalancer.connectionLoggingEnabled = [[[dict objectForKey:@"connectionLogging"] objectForKey:@"enabled"] boolValue];
98     }
99
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];
105         if (server) {
106             node.server = server;
107         }
108         [loadBalancer.nodes addObject:node];        
109     }
110
111     if ([dict objectForKey:@"connectionThrottle"]) {
112         loadBalancer.connectionThrottle = [LoadBalancerConnectionThrottle fromJSON:[dict objectForKey:@"connectionThrottle"]];
113     }
114     
115     loadBalancer.sessionPersistenceType = [[dict objectForKey:@"sessionPersistence"] objectForKey:@"persistenceType"];
116     loadBalancer.clusterName = [[dict objectForKey:@"cluster"] objectForKey:@"name"];
117     return loadBalancer;
118 }
119
120 - (NSString *)toUpdateJSON {
121     NSString *json
122         = @"{ \"loadBalancer\": { "
123            "        \"name\": \"<name>\","
124            "        \"algorithm\": \"<algorithm>\","
125            "        \"protocol\": \"<protocol>\","
126            "        \"port\": \"<port>\""
127            "  }}";
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];
132     return json;
133 }
134
135 - (NSString *)toJSON {
136     
137     NSString *json = @"{ \"loadBalancer\": { ";
138
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]];
143     
144     // virtualIPType
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:@","];
157             }
158         }
159         json = [json stringByAppendingString:@"], "];
160     }
161     
162     json = [json stringByAppendingString:@"\"nodes\": ["];
163     for (int i = 0; i < [self.nodes count]; i++) {
164         LoadBalancerNode *node = [self.nodes objectAtIndex:i];
165         if (node.server) {
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\""];
171         } else {
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]];
177         }
178         
179         if (i == [self.nodes count] - 1) {
180             json = [json stringByAppendingString:@"}"];
181         } else {
182             json = [json stringByAppendingString:@"}, "];
183         }
184     }
185     /*
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 ? @"}" : @"}, "];
193     }
194      */
195     json = [json stringByAppendingString:@"]"];
196     
197     json = [json stringByAppendingString:@"}}"];
198     return json;
199 }
200
201 - (BOOL)shouldBePolled {
202     return ![self.status isEqualToString:@"ACTIVE"];
203 }
204
205 - (void)pollUntilActive:(OpenStackAccount *)account delegate:(id)delegate progressSelector:(SEL)progressSelector completeSelector:(SEL)completeSelector object:(id)object {
206     
207     NSLog(@"polling.  lb status = %@", self.status);
208     
209     
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]) {
216                 
217                 LoadBalancer *newLB = [request loadBalancer:account];                
218                 self.status = newLB.status;
219                 self.progress = newLB.progress;
220                 // load LB stuff                
221                 
222                 NSLog(@"lb poll status: %@", self.status);
223                 
224                 if ([self shouldBePolled]) {
225                     if (progressSelector && [delegate respondsToSelector:progressSelector]) {
226                         [delegate performSelector:progressSelector];
227                     }
228                     [self pollUntilActive:account delegate:delegate progressSelector:progressSelector completeSelector:completeSelector object:object];
229                 } else {
230                     if ([delegate respondsToSelector:completeSelector]) {
231                         [delegate performSelector:completeSelector withObject:object];
232                     }
233                 }
234             }
235         }];
236         [request setFailedBlock:^{
237             [self pollUntilActive:account delegate:delegate progressSelector:progressSelector completeSelector:completeSelector object:object];
238         }];
239         [request startAsynchronous];
240     } else {
241         if ([delegate respondsToSelector:completeSelector]) {
242             [delegate performSelector:completeSelector withObject:object];
243         }
244     }
245 }
246
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];
249 }
250
251 - (void)pollUntilActive:(OpenStackAccount *)account withProgress:(ASIBasicBlock)progressBlock complete:(ASIBasicBlock)completeBlock {
252     
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]) {
259                 
260                 LoadBalancer *newLB = [request loadBalancer:account];                
261                 self.status = newLB.status;
262                 self.progress = newLB.progress;
263                 // load LB stuff                
264                 
265                 NSLog(@"lb poll status: %@", self.status);
266                 
267                 if ([self shouldBePolled]) {
268                     if (progressBlock) {
269                         progressBlock();
270                     }
271                     [self pollUntilActive:account withProgress:nil complete:completeBlock];
272                 } else {
273                     completeBlock();
274                 }
275             }
276         }];
277         [request setFailedBlock:^{
278             //[progressBlock retain];
279             //[completeBlock retain];
280             [self pollUntilActive:account withProgress:progressBlock complete:^{ 
281                 completeBlock();
282             }];
283
284         }];
285         [request startAsynchronous];
286     } else {
287         completeBlock();
288     }
289 }
290
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];
294 }
295
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"];
303     } else {
304         return [UIImage imageNamed:@"dot-red.png"];
305     }
306 }
307
308 @end