Skip to content

Commit 1f7eaf3

Browse files
author
frank
committed
CloudStack CLOUDSTACK-774
Supporting kickstart in CloudStack baremetal merge baremetal feature to master
1 parent 867cb4a commit 1f7eaf3

58 files changed

Lines changed: 6678 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/com/cloud/event/EventTypes.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,10 @@ public class EventTypes {
313313
public static final String EVENT_AUTOSCALEVMGROUP_UPDATE = "AUTOSCALEVMGROUP.UPDATE";
314314
public static final String EVENT_AUTOSCALEVMGROUP_ENABLE = "AUTOSCALEVMGROUP.ENABLE";
315315
public static final String EVENT_AUTOSCALEVMGROUP_DISABLE = "AUTOSCALEVMGROUP.DISABLE";
316+
317+
public static final String EVENT_BAREMETAL_DHCP_SERVER_ADD = "PHYSICAL.DHCP.ADD";
318+
public static final String EVENT_BAREMETAL_DHCP_SERVER_DELETE = "PHYSICAL.DHCP.DELETE";
319+
320+
public static final String EVENT_BAREMETAL_PXE_SERVER_ADD = "PHYSICAL.PXE.ADD";
321+
public static final String EVENT_BAREMETAL_PXE_SERVER_DELETE = "PHYSICAL.PXE.DELETE";
316322
}

api/src/com/cloud/host/Host.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public enum Type {
3939
ExternalLoadBalancer(false),
4040
ExternalVirtualSwitchSupervisor(false),
4141
PxeServer(false),
42+
BaremetalPxe(false),
43+
BaremetalDhcp(false),
4244
TrafficMonitor(false),
4345

4446
ExternalDhcp(false),

api/src/org/apache/cloudstack/api/ApiConstants.java

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ public class ApiConstants {
427427
public static final String CONDITION_IDS = "conditionids";
428428
public static final String COUNTERPARAM_LIST = "counterparam";
429429
public static final String AUTOSCALE_USER_ID = "autoscaleuserid";
430+
public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
430431

431432
public enum HostDetails {
432433
all, capacity, events, stats, min;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF 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+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
<parent>
22+
<groupId>org.apache.cloudstack</groupId>
23+
<artifactId>cloudstack-plugins</artifactId>
24+
<version>4.1.0-SNAPSHOT</version>
25+
<relativePath>../../pom.xml</relativePath>
26+
</parent>
27+
<artifactId>cloud-plugin-hypervisor-baremetal</artifactId>
28+
<name>Apache CloudStack Plugin - Hypervisor Baremetal</name>
29+
<dependencies>
30+
<dependency>
31+
<groupId>commons-lang</groupId>
32+
<artifactId>commons-lang</artifactId>
33+
<version>2.6</version>
34+
</dependency>
35+
</dependencies>
36+
37+
</project>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/sh
2+
3+
# the following is chkconfig init header
4+
#
5+
# cs-sgagent: cloudStack baremetal sercurity group agent
6+
#
7+
# chkconfig: 345 97 03
8+
# description: This is a daemon instructed by CloudStack management server \
9+
# to perform baremetal security group related operations\
10+
#
11+
# processname: cs-sgagent
12+
# pidfile: /var/run/cssgagent.pid
13+
#
14+
15+
check_status() {
16+
pidfile='/var/run/cssgagent.pid'
17+
if [ ! -f $pidfile ]; then
18+
echo "cloudstack baremetal security group agent is stopped"
19+
exit 1
20+
else
21+
pid=`cat $pidfile`
22+
ps -p $pid > /dev/null
23+
if [ $? -eq 0 ]; then
24+
echo "cloudstack baremetal security group agent is running, pid is $pid"
25+
exit 0
26+
else
27+
echo "cloudstack baremetal security group agent is stopped, but pidfile at $pidfile is not cleaned. It may be caused by the agent crashed at last time, manually cleaning it would be ok"
28+
exit 1
29+
fi
30+
fi
31+
}
32+
33+
if [ $# -eq 0 ]; then
34+
echo "usage: $0
35+
[start|stop|restart|status]"
36+
exit 1
37+
fi
38+
39+
if [ "$@" = "status" ]; then
40+
check_status
41+
else
42+
python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" $@
43+
fi
44+
45+
if [ $? -eq 0 ]; then
46+
echo "$@ cloudstack baremetal security group agent .... SUCCESS"
47+
exit 0
48+
else
49+
echo "$@ cloudstack baremetal security group agent .... FAILED"
50+
exit 1
51+
fi
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
#
18+
# Automatically generated by addcopyright.py at 01/29/2013
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
#
18+
# Automatically generated by addcopyright.py at 01/29/2013
19+
'''
20+
Created on Jan 2, 2013
21+
22+
@author: frank
23+
'''
24+
import cherrypy
25+
import sglib
26+
import xmlobject
27+
import types
28+
import uuid
29+
import os.path
30+
import sys
31+
import os
32+
33+
class SGRule(object):
34+
def __init__(self):
35+
self.protocol = None
36+
self.start_port = None
37+
self.end_port = None
38+
self.allowed_ips = []
39+
40+
class IPSet(object):
41+
IPSET_TYPE = 'hash:ip'
42+
def __init__(self, setname, ips):
43+
self.ips = ips
44+
self.name = setname
45+
46+
def create(self):
47+
tmpname = str(uuid.uuid4()).replace('-', '')[0:30]
48+
sglib.ShellCmd('ipset -N %s %s' % (tmpname, self.IPSET_TYPE))()
49+
try:
50+
for ip in self.ips:
51+
sglib.ShellCmd('ipset -A %s %s' % (tmpname, ip))()
52+
53+
try:
54+
sglib.ShellCmd('ipset -N %s %s' % (self.name, self.IPSET_TYPE))()
55+
cherrypy.log('created new ipset: %s' % self.name)
56+
except Exception:
57+
cherrypy.log('%s already exists, no need to create new' % self.name)
58+
finally:
59+
sglib.ShellCmd('ipset -W %s %s' % (tmpname, self.name))()
60+
sglib.ShellCmd('ipset -F %s' % tmpname)()
61+
sglib.ShellCmd('ipset -X %s' % tmpname)()
62+
63+
@staticmethod
64+
def destroy_sets(sets_to_keep):
65+
sets = sglib.ShellCmd('ipset list')()
66+
for s in sets.split('\n'):
67+
if 'Name:' in s:
68+
set_name = s.split(':', 1)[1].strip()
69+
if not set_name in sets_to_keep:
70+
sglib.ShellCmd('ipset destroy %s' % set_name)()
71+
cherrypy.log('destroyed unused ipset: %s' % set_name)
72+
73+
class SGAgent(object):
74+
def __init__(self):
75+
pass
76+
77+
def _self_list(self, obj):
78+
if isinstance(obj, types.ListType):
79+
return obj
80+
else:
81+
return [obj]
82+
83+
def set_rules(self, req):
84+
body = req.body
85+
doc = xmlobject.loads(body)
86+
vm_name = doc.vmName.text_
87+
vm_id = doc.vmId.text_
88+
vm_ip = doc.vmIp.text_
89+
vm_mac = doc.vmMac.text_
90+
sig = doc.signature.text_
91+
seq = doc.sequenceNumber.text_
92+
93+
def parse_rules(rules, lst):
94+
for i in self._self_list(rules):
95+
r = SGRule()
96+
r.protocol = i.protocol.text_
97+
r.start_port = i.startPort.text_
98+
r.end_port = i.endPort.text_
99+
if hasattr(i, 'ip'):
100+
for ip in self._self_list(i.ip):
101+
r.allowed_ips.append(ip.text_)
102+
lst.append(r)
103+
104+
i_rules = []
105+
if hasattr(doc, 'ingressRules'):
106+
parse_rules(doc.ingressRules, i_rules)
107+
108+
e_rules = []
109+
if hasattr(doc, 'egressRules'):
110+
parse_rules(doc.egressRules, e_rules)
111+
112+
def create_chain(name):
113+
try:
114+
sglib.ShellCmd('iptables -F %s' % name)()
115+
except Exception:
116+
sglib.ShellCmd('iptables -N %s' % name)()
117+
118+
def apply_rules(rules, chainname, direction, action, current_set_names):
119+
create_chain(chainname)
120+
for r in i_rules:
121+
allow_any = False
122+
if '0.0.0.0/0' in r.allowed_ips:
123+
allow_any = True
124+
r.allowed_ips.remove('0.0.0.0/0')
125+
126+
if r.allowed_ips:
127+
setname = '_'.join([chainname, r.protocol, r.start_port, r.end_port])
128+
ipset = IPSet(setname, r.allowed_ips)
129+
ipset.create()
130+
current_set_names.append(setname)
131+
132+
if r.protocol == 'all':
133+
cmd = ['iptables -I', chainname, '-m state --state NEW -m set --set', setname, direction, '-j', action]
134+
sglib.ShellCmd(' '.join(cmd))()
135+
elif r.protocol != 'icmp':
136+
port_range = ":".join([r.start_port, r.end_port])
137+
cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m state --state NEW -m set --set', setname, direction, '-j', action]
138+
sglib.ShellCmd(' '.join(cmd))()
139+
else:
140+
port_range = "/".join([r.start_port, r.end_port])
141+
if r.start_port == "-1":
142+
port_range = "any"
143+
cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-m set --set', setname, direction, '-j', action]
144+
sglib.ShellCmd(' '.join(cmd))()
145+
146+
147+
if allow_any and r.protocol != 'all':
148+
if r.protocol != 'icmp':
149+
port_range = ":".join([r.start_port, r.end_port])
150+
cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m', 'state', '--state', 'NEW', '-j', action]
151+
sglib.ShellCmd(' '.join(cmd))()
152+
else:
153+
port_range = "/".join([r.start_port, r.end_port])
154+
if r.start_port == "-1":
155+
port_range = "any"
156+
cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-j', action]
157+
sglib.ShellCmd(' '.join(cmd))()
158+
159+
current_sets = []
160+
i_chain_name = vm_name + '-in'
161+
apply_rules(i_rules, i_chain_name, 'src', 'ACCEPT', current_sets)
162+
e_chain_name = vm_name + '-eg'
163+
apply_rules(e_rules, e_chain_name, 'dst', 'RETURN', current_sets)
164+
165+
if e_rules:
166+
sglib.ShellCmd('iptables -A %s -j RETURN' % e_chain_name)
167+
else:
168+
sglib.ShellCmd('iptables -A %s -j DROP' % e_chain_name)
169+
170+
sglib.ShellCmd('iptables -A %s -j DROP' % i_chain_name)
171+
IPSet.destroy_sets(current_sets)
172+
173+
174+
def echo(self, req):
175+
cherrypy.log("echo: I am alive")
176+
177+
def index(self):
178+
req = sglib.Request.from_cherrypy_request(cherrypy.request)
179+
cmd_name = req.headers['command']
180+
181+
if not hasattr(self, cmd_name):
182+
raise ValueError("SecurityGroupAgent doesn't have a method called '%s'" % cmd_name)
183+
method = getattr(self, cmd_name)
184+
185+
return method(req)
186+
index.exposed = True
187+
188+
@staticmethod
189+
def start():
190+
cherrypy.log.access_file = '/var/log/cs-securitygroup.log'
191+
cherrypy.log.error_file = '/var/log/cs-securitygroup.log'
192+
cherrypy.server.socket_host = '0.0.0.0'
193+
cherrypy.server.socket_port = 9988
194+
cherrypy.quickstart(SGAgent())
195+
196+
@staticmethod
197+
def stop():
198+
cherrypy.engine.exit()
199+
200+
PID_FILE = '/var/run/cssgagent.pid'
201+
class SGAgentDaemon(sglib.Daemon):
202+
def __init__(self):
203+
super(SGAgentDaemon, self).__init__(PID_FILE)
204+
self.is_stopped = False
205+
self.agent = SGAgent()
206+
sglib.Daemon.register_atexit_hook(self._do_stop)
207+
208+
def _do_stop(self):
209+
if self.is_stopped:
210+
return
211+
self.is_stopped = True
212+
self.agent.stop()
213+
214+
def run(self):
215+
self.agent.start()
216+
217+
def stop(self):
218+
self.agent.stop()
219+
super(SGAgentDaemon, self).stop()
220+
221+
def main():
222+
usage = 'usage: python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" start|stop|restart'
223+
if len(sys.argv) != 2 or not sys.argv[1] in ['start', 'stop', 'restart']:
224+
print usage
225+
sys.exit(1)
226+
227+
cmd = sys.argv[1]
228+
agentdaemon = SGAgentDaemon()
229+
if cmd == 'start':
230+
agentdaemon.start()
231+
elif cmd == 'stop':
232+
agentdaemon.stop()
233+
else:
234+
agentdaemon.restart()
235+
236+
sys.exit(0)
237+

0 commit comments

Comments
 (0)