1 /**
2 * Licensed to jclouds, Inc. (jclouds) under one or more
3 * contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. jclouds licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.jclouds.cloudloadbalancers.domain.internal;
20
21 import static com.google.common.base.Preconditions.checkArgument;
22 import static com.google.common.base.Preconditions.checkNotNull;
23
24 /**
25 * The nodes defined by the load balancer are responsible for servicing the requests received
26 * through the load balancer's virtual IP. By default, the load balancer employs a basic health
27 * check that ensures the node is listening on its defined port. The node is checked at the time of
28 * addition and at regular intervals as defined by the load balancer health check configuration. If
29 * a back-end node is not listening on its port or does not meet the conditions of the defined
30 * active health check for the load balancer, then the load balancer will not forward connections
31 * and its status will be listed as OFFLINE. Only nodes that are in an ONLINE status will receive
32 * and be able to service traffic from the load balancer.
33 * <p/>
34 * All nodes have an associated status that indicates whether the node is ONLINE, OFFLINE, or
35 * DRAINING. Only nodes that are in ONLINE status will receive and be able to service traffic from
36 * the load balancer. The OFFLINE status represents a node that cannot accept or service traffic. A
37 * node in DRAINING status represents a node that stops the traffic manager from sending any
38 * additional new connections to the node, but honors established sessions. If the traffic manager
39 * receives a request and session persistence requires that the node is used, the traffic manager
40 * will use it. The status is determined by the passive or active health monitors.
41 * <p/>
42 * If the WEIGHTED_ROUND_ROBIN load balancer algorithm mode is selected, then the caller should
43 * assign the relevant weights to the node as part of the weight attribute of the node element. When
44 * the algorithm of the load balancer is changed to WEIGHTED_ROUND_ROBIN and the nodes do not
45 * already have an assigned weight, the service will automatically set the weight to "1" for all
46 * nodes.
47 *
48 * @author Adrian Cole
49 * @see <a href=
50 * "http://docs.rackspacecloud.com/loadbalancers/api/v1.0/clb-devguide/content/ch04s02.html" />
51 */
52 public class BaseNode<T extends BaseNode<T>> implements Comparable<BaseNode<T>> {
53
54 public static <T extends BaseNode<T>> Builder<T> builder() {
55 return new Builder<T>();
56 }
57
58 @SuppressWarnings("unchecked")
59 public Builder<T> toBuilder() {
60 return new Builder<T>().from((T) this);
61 }
62
63 public static class Builder<T extends BaseNode<T>> {
64 protected String address;
65 protected int port = -1;
66 protected Condition condition = Condition.ENABLED;
67 protected Integer weight;
68
69 public Builder<T> address(String address) {
70 this.address = address;
71 return this;
72 }
73
74 public Builder<T> port(int port) {
75 this.port = port;
76 return this;
77 }
78
79 public Builder<T> condition(Condition condition) {
80 this.condition = condition;
81 return this;
82 }
83
84 public Builder<T> weight(Integer weight) {
85 this.weight = weight;
86 return this;
87 }
88
89 public BaseNode<T> build() {
90 return new BaseNode<T>(address, port, condition, weight);
91 }
92
93 public Builder<T> from(T in) {
94 return address(in.getAddress()).port(in.getPort()).condition(in.getCondition()).weight(in.getWeight());
95 }
96 }
97
98 /**
99 * Virtual IP Conditions
100 */
101 public static enum Condition {
102 /**
103 * Node is permitted to accept new connections.
104 */
105 ENABLED,
106 /**
107 * Node is not permitted to accept any new connections regardless of session persistence
108 * configuration. Existing connections are forcibly terminated.
109 */
110 DISABLED,
111 /**
112 * Node is allowed to service existing established connections and connections that are being
113 * directed to it as a result of the session persistence configuration.
114 */
115 DRAINING,
116
117 UNRECOGNIZED;
118
119 public static Condition fromValue(String condition) {
120 try {
121 return valueOf(checkNotNull(condition, "condition"));
122 } catch (IllegalArgumentException e) {
123 return UNRECOGNIZED;
124 }
125 }
126
127 }
128
129 protected String address;
130 protected int port;
131 protected Condition condition;
132 protected Integer weight;
133
134 // for serialization only
135 protected BaseNode() {
136
137 }
138
139 public BaseNode(String address, int port, Condition condition, Integer weight) {
140 this.address = checkNotNull(address, "address");
141 checkArgument(port != -1, "port must be specified");
142 this.port = port;
143 this.condition = checkNotNull(condition, "condition");
144 this.weight = weight;
145 }
146
147 public String getAddress() {
148 return address;
149 }
150
151 public int getPort() {
152 return port;
153 }
154
155 public Condition getCondition() {
156 return condition;
157 }
158
159 /**
160 * the maximum weight of a node is 100.
161 */
162 public Integer getWeight() {
163 return weight;
164 }
165
166 @Override
167 public int compareTo(BaseNode<T> arg0) {
168 return address.compareTo(arg0.address);
169 }
170
171 @Override
172 public int hashCode() {
173 final int prime = 31;
174 int result = 1;
175 result = prime * result + ((address == null) ? 0 : address.hashCode());
176 result = prime * result + ((condition == null) ? 0 : condition.hashCode());
177 result = prime * result + port;
178 return result;
179 }
180
181 @Override
182 public boolean equals(Object obj) {
183 if (this == obj)
184 return true;
185 if (obj == null)
186 return false;
187 if (getClass() != obj.getClass())
188 return false;
189 BaseNode<?> other = (BaseNode<?>) obj;
190 if (address == null) {
191 if (other.address != null)
192 return false;
193 } else if (!address.equals(other.address))
194 return false;
195 if (condition == null) {
196 if (other.condition != null)
197 return false;
198 } else if (!condition.equals(other.condition))
199 return false;
200 if (port != other.port)
201 return false;
202 return true;
203 }
204
205 @Override
206 public String toString() {
207 return String.format("[address=%s, condition=%s, port=%s, weight=%s]", address, condition, port, weight);
208 }
209
210 }