Merge "Improve server-side caching."
This commit is contained in:
commit
229645c468
6
.gitignore
vendored
6
.gitignore
vendored
@ -26,6 +26,9 @@ pip-log.txt
|
||||
.tox
|
||||
nosetests.xml
|
||||
|
||||
AUTHORS
|
||||
Changelog
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
@ -34,4 +37,5 @@ nosetests.xml
|
||||
.project
|
||||
.pydevproject
|
||||
.idea
|
||||
etc/murano-repository.conf
|
||||
|
||||
/etc/murano-repository.conf
|
||||
|
4
AUTHORS
4
AUTHORS
@ -1,4 +0,0 @@
|
||||
efedorova <efedorova@mirantis.com>
|
||||
Ekaterina Fedorova <efedorova@mirantis.com>
|
||||
EkaterinaFedorova <efedorova@mirantis.com>
|
||||
Timur Sufiev <tsufiev@mirantis.com>
|
189
ChangeLog
189
ChangeLog
@ -1,189 +0,0 @@
|
||||
commit 9cf280bdedc56a320ea60ca40b0bf54127aa0e4e
|
||||
Author: Ekaterina Fedorova <efedorova@mirantis.com>
|
||||
Date: Wed Oct 23 19:58:40 2013 +0400
|
||||
|
||||
Enable relative path for service manifest
|
||||
|
||||
Change-Id: I5fc5edd9abe0c4915d26282d5e71f6b80f437b28
|
||||
|
||||
commit c6a3f103ffc84aecca13ff2cc47274cbfdd464c1
|
||||
Author: Ekaterina Fedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 22 15:40:46 2013 +0400
|
||||
|
||||
Fix bugs
|
||||
|
||||
1) Handle hash_sum = None situation
|
||||
2) Add workflows to horizon archive
|
||||
|
||||
Change-Id: Ie44e43bdabab239fbdfdcaae90c533f663041dd3
|
||||
|
||||
commit d121a4195342fe3d9517a6f8f6176372d2e62ee9
|
||||
Author: Timur Sufiev <tsufiev@mirantis.com>
|
||||
Date: Mon Oct 21 20:48:28 2013 +0400
|
||||
|
||||
Implement server-side caching.
|
||||
|
||||
For the beginning, let's place server package cache into
|
||||
muranorepository/api dir (this path can be easily got with
|
||||
v1_api.root_path).
|
||||
|
||||
Change-Id: I7acbb174491f153eb340efb92ed3b0ce4c5f840f
|
||||
Implements-feature: MRN-1149
|
||||
|
||||
commit b6613f9ecb5b90baf070f5c581a218d503b47e19
|
||||
Author: Timur Sufiev <tsufiev@mirantis.com>
|
||||
Date: Mon Oct 21 16:36:13 2013 +0400
|
||||
|
||||
Add authentication against Keystone.
|
||||
|
||||
Change-Id: Ifb581cc809074354d7db1404c28561ec722cf0f0
|
||||
Implements-feature: MRN-1146.
|
||||
|
||||
commit 367d90f116d399754436060ddb221539911c2211
|
||||
Author: Ekaterina Fedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 21 11:45:08 2013 +0400
|
||||
|
||||
Add some unit tests
|
||||
|
||||
Refactor v1 api and archiver
|
||||
Change-Id: I193023dd8eca4f8cc665a29a6b86698bb38edc83
|
||||
|
||||
commit de388f5e64d887ff6b20790fb540c05ab43dacf7
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Thu Oct 17 19:18:08 2013 +0400
|
||||
|
||||
Refactoring API and Archiver module
|
||||
|
||||
* Set uo manifest.in and tox.ini
|
||||
* Add test module
|
||||
|
||||
Change-Id: I265401658922c75b50db4d1232af17215ee1b6fc
|
||||
|
||||
commit e4b9fe765e912a13ff02a394b329ecd117a0edb7
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 15 19:03:09 2013 +0400
|
||||
|
||||
Fix buf with manifests listing
|
||||
|
||||
commit b24d260524d16dce96a682fd32629951e2ac17ee
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 15 18:47:27 2013 +0400
|
||||
|
||||
Update api
|
||||
|
||||
commit ecb0c93b3077755192929fa8ddf045ef43d43112
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 14 16:54:00 2013 +0400
|
||||
|
||||
Fix typos
|
||||
|
||||
commit c46bfbde86728d689677a2d7d484b2db04893186
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 14 16:34:33 2013 +0400
|
||||
|
||||
Remove service to muranorepository
|
||||
|
||||
Add venv support
|
||||
Update requirements
|
||||
|
||||
commit 28cbd261871038cf1fc4fa67d36c26ae9e9a4747
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 14 13:27:09 2013 +0400
|
||||
|
||||
Fix bug with subfolder copying
|
||||
|
||||
Save path in manifest object in relative way, not in absolute
|
||||
|
||||
commit e98258043d9acbbf8f13d3017eebba9e04066cc9
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 14 11:07:48 2013 +0400
|
||||
|
||||
Add wsgi support.
|
||||
|
||||
Add config file
|
||||
Fix interacting with consts
|
||||
Change section names in manifests to correspond data_type
|
||||
|
||||
commit f40fe7372c220fbf6c29acd80186c34a515f9792
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Fri Oct 11 13:17:35 2013 +0400
|
||||
|
||||
Add api versioning
|
||||
|
||||
commit eb3b446a9f0535709c393620680f9c0c005a6eff
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Thu Oct 10 19:29:15 2013 +0400
|
||||
|
||||
Unite root_dir with data_type root_dir
|
||||
|
||||
commit 31472fb11b498b99d34b1d48a75643785729f451
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Thu Oct 10 18:14:56 2013 +0400
|
||||
|
||||
All api calls implemented
|
||||
|
||||
commit e1b704c61d76d204ce30c9822c9daa9fcda86c8c
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Thu Oct 10 14:40:17 2013 +0400
|
||||
|
||||
Add test.py with api calls
|
||||
|
||||
commit b0c04f614e04f02a36e4435ff8d9e27f42271828
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Thu Oct 10 14:33:57 2013 +0400
|
||||
|
||||
First version of murano Api added
|
||||
|
||||
commit ac04b4e1b74868ebb2b71ef22008e886e3be01fe
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Wed Oct 9 12:05:20 2013 +0400
|
||||
|
||||
Update the result archive structure
|
||||
|
||||
commit 63bd68cc2a87e961874eabf240be58912d6ec23a
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 8 20:09:29 2013 +0400
|
||||
|
||||
Add initial Archiver
|
||||
|
||||
commit 7266c3b98c5851db00c7207bbdff60bdd9e71350
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 8 16:29:06 2013 +0400
|
||||
|
||||
Fixed typos
|
||||
|
||||
Add full manifest class defenition
|
||||
|
||||
commit 8f18a1b75b68d8c97efd57673b160a9ceda608a3
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 8 16:25:07 2013 +0400
|
||||
|
||||
Add Manifest class
|
||||
|
||||
Add valid fields if all files specified in manifests exists
|
||||
|
||||
commit 77cefffbf829ed8b5de0db24d2d4479ec6ce1223
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 8 14:55:48 2013 +0400
|
||||
|
||||
Add new files
|
||||
|
||||
commit 20fafd31acfe062c1a06eeb299ef38ed27bbbbe7
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Tue Oct 8 12:12:37 2013 +0400
|
||||
|
||||
Update service manifests
|
||||
|
||||
Add parser.py
|
||||
|
||||
commit 3c2b1b65f16b93b7bd3c542844aa4c70f48c3ec3
|
||||
Author: efedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 7 15:30:11 2013 +0400
|
||||
|
||||
Initial commit
|
||||
|
||||
commit 87ce33fcf7b03e2722a636e641eb72ea87d9f38d
|
||||
Author: EkaterinaFedorova <efedorova@mirantis.com>
|
||||
Date: Mon Oct 7 04:10:43 2013 -0700
|
||||
|
||||
Initial commit
|
24
Services/demo-manifest.yaml
Normal file
24
Services/demo-manifest.yaml
Normal file
@ -0,0 +1,24 @@
|
||||
version: 0.1
|
||||
service_display_name: Demo Service
|
||||
|
||||
description: >-
|
||||
<strong> Demo Service </strong>
|
||||
shows how Murano is working.
|
||||
|
||||
full_service_name: demoService
|
||||
author: Mirantis Inc.
|
||||
service_version: 1.0
|
||||
enabled: True
|
||||
|
||||
ui:
|
||||
- Demo.yaml
|
||||
|
||||
workflows:
|
||||
- Demo.xml
|
||||
|
||||
heat:
|
||||
- Demo.template
|
||||
- Linux.template
|
||||
|
||||
agent:
|
||||
- Demo.template
|
127
Services/heat_templates/Linux.template
Normal file
127
Services/heat_templates/Linux.template
Normal file
@ -0,0 +1,127 @@
|
||||
{
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Parameters": {
|
||||
"KeyName": {
|
||||
"Description": "Key Pair name for Load Balancer",
|
||||
"Type": "String",
|
||||
"Default": "murano-lb-key"
|
||||
}
|
||||
},
|
||||
|
||||
"Resources": {
|
||||
"$instanceName": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
"Properties": {
|
||||
"InstanceType": "$instanceType",
|
||||
"ImageId": "$imageName",
|
||||
"AvailabilityZone": "$availabilityZone",
|
||||
"UserData": "$userData",
|
||||
"NetworkInterfaces": [ { "Ref": "$instancePort" } ]
|
||||
}
|
||||
},
|
||||
"$instancePort": {
|
||||
"Type": "OS::Quantum::Port",
|
||||
"Properties": {
|
||||
"network_id": {
|
||||
"Ref": "network"
|
||||
},
|
||||
"security_groups" : [ { "Ref" : "MuranoDefaultSecurityGroup"}],
|
||||
"fixed_ips": [
|
||||
{
|
||||
"subnet_id": {
|
||||
"Ref": "subnet"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"MuranoDefaultSecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"SecurityGroupIngress": [
|
||||
{
|
||||
"ToPort": "22",
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "22",
|
||||
"CidrIp": "0.0.0.0/0"
|
||||
},
|
||||
{
|
||||
"ToPort": "23",
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "23",
|
||||
"CidrIp": "0.0.0.0/0"
|
||||
},
|
||||
{
|
||||
"ToPort": "-1",
|
||||
"IpProtocol": "icmp",
|
||||
"FromPort": "-1",
|
||||
"CidrIp": "0.0.0.0/0"
|
||||
},
|
||||
{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort" : "1",
|
||||
"ToPort": "65535",
|
||||
"CidrIp": "10.0.0.0/24"
|
||||
},
|
||||
{
|
||||
"IpProtocol": "udp",
|
||||
"FromPort" : "1",
|
||||
"ToPort": "65535",
|
||||
"CidrIp": "10.0.0.0/24"
|
||||
}
|
||||
],
|
||||
"GroupDescription": "Default security group for Linux Murano Environments"
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"Type": "OS::Quantum::Net",
|
||||
"Properties": {
|
||||
"name": "$networkName"
|
||||
}
|
||||
},
|
||||
"subnet": {
|
||||
"Type": "OS::Quantum::Subnet",
|
||||
"Properties": {
|
||||
"network_id": {
|
||||
"Ref": "network"
|
||||
},
|
||||
"ip_version": 4,
|
||||
"cidr": "10.0.0.0/24",
|
||||
"dns_nameservers": ["8.8.8.8"],
|
||||
"allocation_pools": [
|
||||
{
|
||||
"start": "10.0.0.20",
|
||||
"end": "10.0.0.250"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"router": {
|
||||
"Type": "OS::Quantum::Router"
|
||||
},
|
||||
"router_interface": {
|
||||
"Type": "OS::Quantum::RouterInterface",
|
||||
"Properties": {
|
||||
"router_id": {
|
||||
"Ref": "router"
|
||||
},
|
||||
"subnet_id": {
|
||||
"Ref": "subnet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"router_gateway": {
|
||||
"Type": "OS::Quantum::RouterGateway",
|
||||
"Properties": {
|
||||
"router_id": {
|
||||
"Ref": "router"
|
||||
},
|
||||
"network_id": "$externalNetworkId"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"Outputs": {
|
||||
}
|
||||
}
|
74
Services/scripts/TelnetDeploy.sh
Normal file
74
Services/scripts/TelnetDeploy.sh
Normal file
@ -0,0 +1,74 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
#install app
|
||||
rpm -aq | grep $1 > /dev/null
|
||||
if [ $? -ne 0 ];then
|
||||
yum install $1 --assumeyes --quiet
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "Can't install $1, exiting..."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$1 already installed."
|
||||
fi
|
||||
#find iptables and add telnet rule
|
||||
iptcmd=$(which iptables)
|
||||
|
||||
if [ -n "$iptcmd" ]; then
|
||||
$iptcmd -nvL INPUT | grep "Telnet server access on TCP port 23" > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
$iptcmd -I INPUT 1 -p tcp -m tcp --dport 23 -j ACCEPT -m comment --comment "Telnet server access on TCP port 23"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "Can't set $1 access firewall rules, exiting..."
|
||||
exit 1
|
||||
else
|
||||
echo "$iptcmd rule for $1 set."
|
||||
fi
|
||||
else
|
||||
echo "$iptcmd rule for $1 exists."
|
||||
fi
|
||||
else
|
||||
echo "There's no iptables found..."
|
||||
fi
|
||||
|
||||
# check telnet start disabled
|
||||
xinetd_tlnt_cfg=/etc/xinetd.d/telnet
|
||||
if [ -f "$xinetd_tlnt_cfg" ]; then
|
||||
sed -i '/disable.*=/ s/yes/no/' $xinetd_tlnt_cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "can't modify $xinetd_tlnt_cfg"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$ serviec startup config not found under $xinetd_tlnt_cfg"
|
||||
fi
|
||||
#security tty for telnet
|
||||
setty=/etc/securetty
|
||||
lines=$(sed -ne '/^pts\/[0-9]/,/^pts\/[0-9]/ =' $setty)
|
||||
if [ -z "$lines" ]; then
|
||||
cat >> $setty << "EOF"
|
||||
pts/0
|
||||
pts/1
|
||||
pts/2
|
||||
pts/3
|
||||
pts/4
|
||||
pts/5
|
||||
pts/6
|
||||
pts/7
|
||||
pts/8
|
||||
pts/9
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error occured during $setty changing..."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$setty has pts/0-9 options..."
|
||||
fi
|
||||
#restart xinetd
|
||||
service xinetd restart
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error occured during xinetd restart..."
|
||||
exit 1
|
||||
fi
|
86
Services/ui_forms/LinuxTelnet.yaml
Normal file
86
Services/ui_forms/LinuxTelnet.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
name: Linux Telnet
|
||||
type: linuxTelnetService
|
||||
|
||||
description: >-
|
||||
<strong> Linux Telnet Service </strong>
|
||||
Demonstrates a simple linux agent, which installs Telnet if required.
|
||||
|
||||
unitTemplates:
|
||||
- {}
|
||||
|
||||
forms:
|
||||
- serviceConfiguration:
|
||||
fields:
|
||||
- name: title
|
||||
type: string
|
||||
required: false
|
||||
hidden: true
|
||||
attributeNames: false
|
||||
description: Telnet service that can be installed at linux
|
||||
- name: name
|
||||
type: string
|
||||
label: Service Name
|
||||
description: >-
|
||||
Enter a desired name for a service. Just A-Z, a-z, 0-9, dash and
|
||||
underline are allowed.
|
||||
minLength: 2
|
||||
maxLength: 64
|
||||
regexpValidator: '^[-\w]+$'
|
||||
errorMessages:
|
||||
invalid: Just letters, numbers, underscores and hyphens are allowed.
|
||||
helpText: Just letters, numbers, underscores and hyphens are allowed.
|
||||
- name: dcInstances
|
||||
type: instance
|
||||
hidden: true
|
||||
attributeNames: units
|
||||
initial: 1
|
||||
- name: deployTelnet
|
||||
type: boolean
|
||||
label: Deploy Telnet
|
||||
description: >-
|
||||
Indicates if the target machine has to get telnet deployed
|
||||
initial: true
|
||||
required: false
|
||||
widgetMedia:
|
||||
css: {all: [muranodashboard/css/checkbox.css]}
|
||||
- name: unitNamingPattern
|
||||
type: string
|
||||
label: Hostname
|
||||
description: >-
|
||||
For your convenience instance hostname can be specified.
|
||||
Enter a name or leave blank for random name generation.
|
||||
required: false
|
||||
regexpValidator: '^(([a-zA-Z0-9#][a-zA-Z0-9-#]*[a-zA-Z0-9#])\.)*([A-Za-z0-9#]|[A-Za-z0-9#][A-Za-z0-9-#]*[A-Za-z0-9#])$'
|
||||
helpText: Optional field for a machine hostname
|
||||
# temporaryHack
|
||||
widgetMedia:
|
||||
js: [muranodashboard/js/support_placeholder.js]
|
||||
css: {all: [muranodashboard/css/support_placeholder.css]}
|
||||
- instanceConfiguration:
|
||||
fields:
|
||||
- name: title
|
||||
type: string
|
||||
required: false
|
||||
hidden: true
|
||||
attributeNames: false
|
||||
descriptionTitle: Instance Configuration
|
||||
description: Specify some instance parameters on which service would be created.
|
||||
- name: flavor
|
||||
type: flavor
|
||||
label: Instance flavor
|
||||
description: >-
|
||||
Select registered in Openstack flavor. Consider that service performance
|
||||
depends on this parameter.
|
||||
required: false
|
||||
- name: osImage
|
||||
type: image
|
||||
imageType: linux
|
||||
label: Instance image
|
||||
description: >-
|
||||
Select valid image for a service. Image should already be prepared and
|
||||
registered in glance.
|
||||
- name: availabilityZone
|
||||
type: azone
|
||||
label: Availability zone
|
||||
description: Select availability zone where service would be installed.
|
||||
required: false
|
80
Services/workflows/LinuxTelnet.xml
Normal file
80
Services/workflows/LinuxTelnet.xml
Normal file
@ -0,0 +1,80 @@
|
||||
<workflow>
|
||||
|
||||
<rule match="$.services[?(@.type == 'linuxTelnetService')].units[?(@.state.hostname and not @.temp.instanceName)]"
|
||||
desc="Units of Linux Telnet service having hostname and image names assigned but without instances">
|
||||
<report entity="unit">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">Creating Linux instance <select path="state.hostname"/> (<select path="name"/>)</parameter>
|
||||
</report>
|
||||
<update-cf-stack template="Linux" error="exception">
|
||||
<parameter name="mappings">
|
||||
<map>
|
||||
<mapping name="instanceName"><select path="state.hostname"/></mapping>
|
||||
<mapping name="instancePort">port-<select path="state.hostname"/></mapping>
|
||||
<mapping name="networkName">network-<select path="/id"/></mapping>
|
||||
<mapping name="userData">
|
||||
<prepare-user-data template="Linux" initFile="linux_init.sh">
|
||||
<parameter name="hostname"><select path="state.hostname"/></parameter>
|
||||
<parameter name="unit"><select path="id"/></parameter>
|
||||
<parameter name="service"><select path="::id"/></parameter>
|
||||
</prepare-user-data>
|
||||
</mapping>
|
||||
<mapping name="instanceType"><select path="::flavor" default="m1.medium"/></mapping>
|
||||
<mapping name="imageName"><select path="::osImage.name"/></mapping>
|
||||
<mapping name="availabilityZone"><select path="::availabilityZone" default="nova"/></mapping>
|
||||
</map>
|
||||
</parameter>
|
||||
<success>
|
||||
<set path="temp.instanceName"><select path="name"/></set>
|
||||
<report entity="unit">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">Linux instance <select path="state.hostname"/> (<select path="name"/>) created</parameter>
|
||||
</report>
|
||||
</success>
|
||||
<failure>
|
||||
<report entity="unit" level="error">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">Unable to deploy Linux instance <select path="state.hostname"/> (<select path="name"/>) due to <format-error error="exception"/> </parameter>
|
||||
</report>
|
||||
<stop/>
|
||||
</failure>
|
||||
</update-cf-stack>
|
||||
</rule>
|
||||
|
||||
|
||||
<rule match="$.services[?(@.type == 'linuxTelnetService')].units[?(@.temp.instanceName and not @.state.TelnetInstalled)]"
|
||||
desc="Units of Linux Telnet service which have got an instance deployed but have not got telnet service installed">
|
||||
<report entity="unit">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">yum-ing telnet on unit <select path="state.hostname"/> (<select path="name"/>)</parameter>
|
||||
</report>
|
||||
<send-command template="DeployTelnet" error='exception'>
|
||||
<parameter name="unit">
|
||||
<select path="id"/>
|
||||
</parameter>
|
||||
<parameter name="service">
|
||||
<select path="::id"/>
|
||||
</parameter>
|
||||
<parameter name="mappings">
|
||||
<map>
|
||||
<mapping name="appName">telnet-server</mapping>
|
||||
</map>
|
||||
</parameter>
|
||||
<success>
|
||||
<set path="state.TelnetInstalled"><true/></set>
|
||||
<report entity="unit">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">Telnet deployed on <select path="state.hostname"/> (<select path="name"/>)</parameter>
|
||||
</report>
|
||||
</success>
|
||||
<failure>
|
||||
<report entity="unit" level="error">
|
||||
<parameter name="id"><select path="id"/></parameter>
|
||||
<parameter name="text">Unable to deploy Telnet on <select path="state.hostname"/> (<select path="name"/>) due to <format-error error="exception"/></parameter>
|
||||
</report>
|
||||
<stop/>
|
||||
</failure>
|
||||
</send-command>
|
||||
</rule>
|
||||
|
||||
</workflow>
|
@ -22,28 +22,57 @@ from werkzeug import secure_filename
|
||||
from muranorepository.utils.parser import ManifestParser
|
||||
from muranorepository.utils.archiver import Archiver
|
||||
from muranorepository.consts import DATA_TYPES, MANIFEST
|
||||
|
||||
from muranorepository.consts import CLIENTS_DICT
|
||||
from muranorepository.consts import ARCHIVE_PKG_NAME
|
||||
import logging as log
|
||||
from oslo.config import cfg
|
||||
CONF = cfg.CONF
|
||||
|
||||
v1_api = Blueprint('v1', __name__)
|
||||
CACHE_DIR = os.path.join(v1_api.root_path, 'cache')
|
||||
|
||||
if not os.path.exists(CACHE_DIR):
|
||||
os.mkdir(CACHE_DIR)
|
||||
|
||||
|
||||
def _update_hash(data_type):
|
||||
client = None
|
||||
for client_type, client_data_types in CLIENTS_DICT.iteritems():
|
||||
if data_type in client_data_types:
|
||||
client = client_type
|
||||
break
|
||||
if not client:
|
||||
abort(404)
|
||||
cache_dir = os.path.join(CACHE_DIR, client)
|
||||
if not os.path.exists(cache_dir):
|
||||
os.mkdir(cache_dir)
|
||||
manifests = ManifestParser(CONF.manifests).parse()
|
||||
archive_manager = Archiver()
|
||||
existing_hash = archive_manager.get_existing_hash(cache_dir)
|
||||
if existing_hash:
|
||||
archive_manager.remove_existing_hash(cache_dir, existing_hash)
|
||||
archive_manager.create(cache_dir, manifests, CLIENTS_DICT[client])
|
||||
|
||||
|
||||
def _get_archive(client, hash_sum):
|
||||
parser = ManifestParser(CONF.manifests)
|
||||
manifests = parser.parse()
|
||||
types = None
|
||||
if client == 'conductor':
|
||||
types = ('heat', 'agent', 'scripts', 'workflows')
|
||||
elif client == 'ui':
|
||||
types = ('ui',)
|
||||
else:
|
||||
types = CLIENTS_DICT.get(client)
|
||||
if not types:
|
||||
abort(404)
|
||||
return Archiver().create(client, CACHE_DIR, manifests, hash_sum, types)
|
||||
archive_manager = Archiver()
|
||||
cache_dir = os.path.join(CACHE_DIR, client)
|
||||
if not os.path.exists(cache_dir):
|
||||
os.mkdir(cache_dir)
|
||||
existing_hash = archive_manager.get_existing_hash(cache_dir)
|
||||
|
||||
if existing_hash and hash_sum is None:
|
||||
log.debug('Transfering existing archive')
|
||||
return os.path.join(cache_dir, existing_hash, ARCHIVE_PKG_NAME)
|
||||
|
||||
if archive_manager.hashes_match(cache_dir, existing_hash, hash_sum):
|
||||
return None
|
||||
|
||||
return archive_manager.create(cache_dir, manifests, types)
|
||||
|
||||
|
||||
def _get_locations(data_type, result_path):
|
||||
@ -64,11 +93,19 @@ def _get_locations(data_type, result_path):
|
||||
return jsonify({data_type: locations})
|
||||
|
||||
|
||||
def _save_file(request, result_path):
|
||||
def _save_file(request, data_type, path=None):
|
||||
if path:
|
||||
result_path = _compose_path(data_type, path)
|
||||
#subfolder should already exists
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
else:
|
||||
result_path = _compose_path(data_type)
|
||||
file_to_upload = request.files.get('file')
|
||||
if file_to_upload:
|
||||
filename = secure_filename(file_to_upload.filename)
|
||||
file_to_upload.save(os.path.join(result_path, filename))
|
||||
_update_hash(data_type)
|
||||
return jsonify(result='success')
|
||||
else:
|
||||
abort(400)
|
||||
@ -105,9 +142,8 @@ def get_data_type_locations(data_type):
|
||||
@v1_api.route('/admin/<data_type>', methods=['POST'])
|
||||
def upload_file(data_type):
|
||||
_check_data_type(data_type)
|
||||
result_path = _compose_path(data_type)
|
||||
try:
|
||||
return _save_file(request, result_path)
|
||||
return _save_file(request, data_type)
|
||||
except:
|
||||
abort(403)
|
||||
|
||||
@ -125,13 +161,10 @@ def _get_locations_in_nested_path_or_get_file(data_type, path):
|
||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['POST'])
|
||||
def upload_file_in_nested_path(data_type, path):
|
||||
_check_data_type(data_type)
|
||||
result_path = _compose_path(data_type, path)
|
||||
# it's forbidden to upload manifests to subfolder
|
||||
# it's forbidden to upload manifests to subfolders
|
||||
if data_type == MANIFEST:
|
||||
abort(403)
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
return _save_file(request, result_path)
|
||||
return _save_file(request, data_type, path)
|
||||
|
||||
|
||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['PUT'])
|
||||
@ -159,22 +192,13 @@ def delete_directory_or_file(data_type, path):
|
||||
if os.path.isfile(result_path):
|
||||
try:
|
||||
os.remove(result_path)
|
||||
_update_hash(data_type)
|
||||
except Exception:
|
||||
abort(404)
|
||||
else:
|
||||
try:
|
||||
# enable to delete only empty directories
|
||||
os.rmdir(result_path)
|
||||
except Exception:
|
||||
abort(403)
|
||||
return jsonify(result='success')
|
||||
|
||||
|
||||
@v1_api.route('/admin/services', methods=['GET'])
|
||||
def get_services_list():
|
||||
manifests = ManifestParser(CONF.manifests).parse()
|
||||
excluded_fields = set(DATA_TYPES) - set(MANIFEST)
|
||||
data = []
|
||||
for manifest in manifests:
|
||||
data.append(dict((k, v) for k, v in manifest.__dict__.iteritems()
|
||||
if not k in excluded_fields))
|
||||
return jsonify(tuple(data))
|
||||
|
@ -21,3 +21,7 @@ AGENT = 'agent'
|
||||
SCRIPTS = 'scripts'
|
||||
|
||||
DATA_TYPES = [UI, WORKFLOW, HEAT, AGENT, SCRIPTS, MANIFEST]
|
||||
CLIENTS_DICT = {'conductor': (WORKFLOW, HEAT, AGENT, SCRIPTS),
|
||||
'ui': (UI,)}
|
||||
|
||||
ARCHIVE_PKG_NAME = 'data.tar.gz'
|
||||
|
@ -18,10 +18,9 @@ import shutil
|
||||
import hashlib
|
||||
import logging as log
|
||||
from oslo.config import cfg
|
||||
from muranorepository.consts import DATA_TYPES
|
||||
from muranorepository.consts import DATA_TYPES, ARCHIVE_PKG_NAME
|
||||
CONF = cfg.CONF
|
||||
|
||||
ARCHIVE_PKG_NAME = 'data.tar.gz'
|
||||
CHUNK_SIZE = 1 << 20 # 1MB
|
||||
|
||||
|
||||
@ -75,49 +74,48 @@ class Archiver(object):
|
||||
shutil.rmtree(path, ignore_errors=True)
|
||||
except Exception as e:
|
||||
log.error("Unable to delete temp directory: {0}".format(e))
|
||||
hash_sum = self._get_hash(ARCHIVE_PKG_NAME)
|
||||
pkg_dir = os.path.join(cache_dir, hash_sum)
|
||||
if not os.path.exists(pkg_dir):
|
||||
os.mkdir(pkg_dir)
|
||||
shutil.move(ARCHIVE_PKG_NAME, os.path.join(pkg_dir, ARCHIVE_PKG_NAME))
|
||||
return os.path.abspath(os.path.join(pkg_dir, ARCHIVE_PKG_NAME))
|
||||
hash_folder = self._create_hash_folder(ARCHIVE_PKG_NAME, cache_dir)
|
||||
try:
|
||||
shutil.move(ARCHIVE_PKG_NAME, os.path.join(hash_folder,
|
||||
ARCHIVE_PKG_NAME))
|
||||
except Exception as e:
|
||||
log.error('Unable to move created archive {0}'
|
||||
' to hash folder {1} due to {2}'.format(ARCHIVE_PKG_NAME,
|
||||
hash_folder,
|
||||
e))
|
||||
return os.path.abspath(os.path.join(hash_folder, ARCHIVE_PKG_NAME))
|
||||
|
||||
def _is_data_cached(self, cache_dir, hash_sum):
|
||||
#ToDo: optimize archive creation: use existing cached version of
|
||||
# archive package when no hash sum is provided by client
|
||||
if not hash_sum:
|
||||
log.warning('Hash parameter was not found in request')
|
||||
return False
|
||||
def get_existing_hash(self, cache_dir):
|
||||
existing_caches = os.listdir(cache_dir)
|
||||
if len(existing_caches) == 1:
|
||||
if existing_caches[0] == hash_sum:
|
||||
path = os.path.join(cache_dir, hash_sum, ARCHIVE_PKG_NAME)
|
||||
if not os.path.exists(path):
|
||||
raise RuntimeError(
|
||||
'Archive package is missing at dir {0}'.format(
|
||||
os.path.join(cache_dir, hash_sum)))
|
||||
log.debug('Archive package already exists at {0} and it ' +
|
||||
'matches hash-sum {1}.'.format(path, hash_sum))
|
||||
return True
|
||||
else:
|
||||
path = os.path.join(cache_dir, hash_sum)
|
||||
log.info('Archive package already exists at {0}, but it '
|
||||
"doesn't match requested hash-sum {1}. "
|
||||
'Deleting it.'.format(path))
|
||||
shutil.rmtree(path)
|
||||
return False
|
||||
elif len(existing_caches) == 0:
|
||||
return False
|
||||
log.debug('Asserting there is just one archive in cache folder. Clear '
|
||||
'folder {0} in case of Assertion Error'.format(cache_dir))
|
||||
assert len(existing_caches) < 2
|
||||
if not len(existing_caches):
|
||||
return None
|
||||
else:
|
||||
raise RuntimeError('Too many cached archives at {0}'.format(
|
||||
cache_dir))
|
||||
path = os.path.join(cache_dir,
|
||||
existing_caches[0],
|
||||
ARCHIVE_PKG_NAME)
|
||||
if not os.path.exists(path):
|
||||
raise RuntimeError(
|
||||
'Archive package is missing at dir {0}'.format(
|
||||
os.path.join(cache_dir)))
|
||||
return existing_caches[0]
|
||||
|
||||
def create(self, client_type, cache_root, manifests, hash_sum, types):
|
||||
def hashes_match(self, cache_dir, existing_hash, hash_to_check):
|
||||
if hash_to_check is None or existing_hash is None:
|
||||
return False
|
||||
if existing_hash == hash_to_check:
|
||||
log.debug('Archive package matches hash-sum {0}.'.format(
|
||||
hash_to_check))
|
||||
return True
|
||||
else:
|
||||
self.remove_existing_hash(cache_dir, existing_hash)
|
||||
return False
|
||||
|
||||
def create(self, cache_dir, manifests, types):
|
||||
"""
|
||||
client_type -- client asked for metadata
|
||||
cache_root -- directory where cache is stored
|
||||
manifests -- list of Manifest objects
|
||||
hash_sum -- hash to compare to
|
||||
types -- desired data types to be added to archive
|
||||
return: absolute path to created archive
|
||||
"""
|
||||
@ -126,14 +124,6 @@ class Archiver(object):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
except:
|
||||
temp_dir = '/tmp'
|
||||
|
||||
cache_dir = os.path.join(cache_root, client_type)
|
||||
if not os.path.exists(cache_dir):
|
||||
os.mkdir(cache_dir)
|
||||
|
||||
if self._is_data_cached(cache_dir, hash_sum):
|
||||
return None
|
||||
|
||||
for data_type in types:
|
||||
if data_type not in DATA_TYPES:
|
||||
raise Exception("Please, specify one of the supported data "
|
||||
@ -157,3 +147,20 @@ class Archiver(object):
|
||||
"{1}".format(manifest.service_display_name, data_type))
|
||||
|
||||
return self._compose_archive(temp_dir, cache_dir)
|
||||
|
||||
def remove_existing_hash(self, cache_dir, hash):
|
||||
path = os.path.join(cache_dir, hash)
|
||||
log.info('Deleting archive package from {0}.'.format(path))
|
||||
shutil.rmtree(path, ignore_errors=True)
|
||||
|
||||
def _create_hash_folder(self, archive_name, cache_dir):
|
||||
"""
|
||||
Creates folder with data archive inside that has
|
||||
name equals to hash calculated from archive
|
||||
Return path to created hash folder
|
||||
"""
|
||||
hash_sum = self._get_hash(archive_name)
|
||||
pkg_dir = os.path.join(cache_dir, hash_sum)
|
||||
if not os.path.exists(pkg_dir):
|
||||
os.mkdir(pkg_dir)
|
||||
return pkg_dir
|
||||
|
Loading…
Reference in New Issue
Block a user