mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Fix pylint (again)
This commit is contained in:
commit
48b498bb2f
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
||||
Salt - Remote execution system
|
||||
Salt - Remote execution system
|
||||
|
||||
Copyright 2014 SaltStack Team
|
||||
|
||||
|
@ -2,7 +2,9 @@ include AUTHORS
|
||||
include HACKING.rst
|
||||
include LICENSE
|
||||
include README.rst
|
||||
include requirements.txt
|
||||
include _requirements.txt
|
||||
include raet-requirements.txt
|
||||
include zeromq-requirements.txt
|
||||
include tests/*.py
|
||||
recursive-include tests *
|
||||
include tests/integration/modules/files/*
|
||||
|
6
_requirements.txt
Normal file
6
_requirements.txt
Normal file
@ -0,0 +1,6 @@
|
||||
Jinja2
|
||||
msgpack-python > 0.1.13
|
||||
PyYAML
|
||||
MarkupSafe
|
||||
apache-libcloud >= 0.14.0
|
||||
requests
|
@ -160,7 +160,7 @@
|
||||
# Works like autosign_file, but instead allows you to specify minion IDs for
|
||||
# which keys will automatically be rejected. Will override both membership in
|
||||
# the autosign_file and the auto_accept setting.
|
||||
#autoreject_file: /etc/salt/autosign.conf
|
||||
#autoreject_file: /etc/salt/autoreject.conf
|
||||
|
||||
# Enable permissive access to the salt keys. This allows you to run the
|
||||
# master or minion as root, but have a non-root group be given access to
|
||||
|
5
doc/_themes/saltstack/layout.html
vendored
5
doc/_themes/saltstack/layout.html
vendored
@ -92,7 +92,6 @@
|
||||
{% endif %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/basic.css', 1) }}">
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ pathto('_static/css/bootstrap.css', 1) }}">
|
||||
<style>
|
||||
body { padding-top: 20px; }
|
||||
@ -118,6 +117,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="google-site-verification" content="1Y-ojT3ndjxA9coB77iUDyXPWxeuQ3T4_r0j-QG6QHg" />
|
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,600,700,800,300' rel='stylesheet' type='text/css'>
|
||||
{{ css() }}
|
||||
|
||||
{%- if not embedded %}
|
||||
@ -159,7 +159,6 @@
|
||||
{%- endblock %}
|
||||
|
||||
{%- block extrahead %} {% endblock %}
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,800italic,300,800' rel='stylesheet' type='text/css'>
|
||||
<script src="{{ pathto('_static/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js', 1) }}"></script>
|
||||
|
||||
{%- block analytics %}
|
||||
@ -262,7 +261,7 @@
|
||||
<script src="{{ pathto('_static/js/main.js', 1) }}"></script>
|
||||
|
||||
{% if on_saltstack %}
|
||||
<script type="text/javascript" language="javascript">llactid=23943</script>
|
||||
<script type="text/javascript" language="javascript">llactid=23943</script>
|
||||
<script type="text/javascript" language="javascript" src="http://t6.trackalyzer.com/trackalyze.js"></script>
|
||||
|
||||
<script>
|
||||
|
427
doc/_themes/saltstack/static/css/main.css
vendored
427
doc/_themes/saltstack/static/css/main.css
vendored
@ -1,321 +1,347 @@
|
||||
|
||||
|
||||
/* ==========================================================================
|
||||
Author's custom styles
|
||||
========================================================================== */
|
||||
Author's custom styles
|
||||
========================================================================== */
|
||||
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
-ms-transition: all 0.2s ease;
|
||||
-o-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
-ms-transition: all 0.2s ease;
|
||||
-o-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.navbar .nav {
|
||||
float:right;
|
||||
margin: 0;
|
||||
padding-top: 18px;
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
.navbar .nav {
|
||||
float:right;
|
||||
margin: 0;
|
||||
padding-top: 18px;
|
||||
}
|
||||
.navbar-inverse .brand, .navbar-inverse .nav > li > a {
|
||||
color: #484c51;
|
||||
font: 14px/24px 'Open Sans Light';
|
||||
color: #484c51;
|
||||
font: 14px/24px 'Open Sans';
|
||||
font-weight: 200;
|
||||
}
|
||||
.navbar .nav li.currentNav {
|
||||
background: url(../img/navCurrentArrow.png) center 32px no-repeat;
|
||||
background: url(../img/navCurrentArrow.png) center 32px no-repeat;
|
||||
}
|
||||
.hero-unit {
|
||||
margin-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.shaded {
|
||||
background: #f7f9f8;
|
||||
background: #f7f9f8;
|
||||
}
|
||||
.shaded img {
|
||||
margin: 8px 12px;
|
||||
margin: 8px 12px;
|
||||
}
|
||||
.articleCredits {
|
||||
padding-left: 12px;
|
||||
font: 12px/24px 'Open Sans Light';
|
||||
white-space: pre;
|
||||
padding-left: 12px;
|
||||
font: 12px/24px 'Open Sans';
|
||||
font-weight: 100;
|
||||
white-space: pre;
|
||||
}
|
||||
.fullwidth {
|
||||
padding: 30px;
|
||||
padding: 30px;
|
||||
}
|
||||
body.contact .shaded img {
|
||||
margin: 0;
|
||||
body.contact .shaded img {
|
||||
margin: 0;
|
||||
}
|
||||
.map img {
|
||||
margin-top: 30px;
|
||||
float: left;
|
||||
margin-top: 30px;
|
||||
float: left;
|
||||
}
|
||||
body.index .success, body.index .clients {
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
.success h2 {
|
||||
margin-top: 25px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
.testimonialAuthor {
|
||||
display: block;
|
||||
margin-bottom: 30px;
|
||||
font: 12px/24px 'Open Sans Extrabold';
|
||||
color: #aa2b39;
|
||||
text-transform: uppercase;
|
||||
display: block;
|
||||
margin-bottom: 30px;
|
||||
font: 12px/24px 'Open Sans';
|
||||
color: #aa2b39;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.success hr, .events hr, .productnews hr {
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
.clients {
|
||||
background-color: #415a72;
|
||||
background-color: #415a72;
|
||||
}
|
||||
.clients img {
|
||||
margin: 15px 21px;
|
||||
margin: 15px 21px;
|
||||
}
|
||||
.news {
|
||||
margin-bottom: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
h2.homeSecTitles {
|
||||
color: #8d9caa;
|
||||
font-family: 'Open Sans Extrabold Italic';
|
||||
text-transform: capitalize;
|
||||
margin-bottom: 0;
|
||||
color: #8d9caa;
|
||||
font-style: italic;
|
||||
font-family: 'Open Sans';
|
||||
font-weight: 800;
|
||||
text-transform: capitalize;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.success h3 {
|
||||
font: 18px/30px 'Open Sans Light Italic'; color: #4f575b; margin: 25px 0;
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font: 18px/30px 'Open Sans';
|
||||
color: #4f575b; margin: 25px 0;
|
||||
}
|
||||
.success img {
|
||||
margin: 30px 10px 10px 80px;
|
||||
margin: 30px 10px 10px 80px;
|
||||
}
|
||||
.about img {
|
||||
margin-bottom: 21px;
|
||||
margin-bottom: 21px;
|
||||
}
|
||||
.carousel-inner {
|
||||
max-height: 387px;
|
||||
.carousel-inner {
|
||||
max-height: 387px;
|
||||
}
|
||||
.carousel-control {
|
||||
opacity: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
opacity: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.carousel-caption h1 {
|
||||
text-transform:uppercase;
|
||||
margin-top: 20px;
|
||||
display:none;
|
||||
text-transform:uppercase;
|
||||
margin-top: 20px;
|
||||
display:none;
|
||||
}
|
||||
.carousel-caption p {
|
||||
margin-top: 25px;
|
||||
font: 16px/24px 'Open Sans Light';
|
||||
color: #000;
|
||||
display: none;
|
||||
margin-top: 25px;
|
||||
font-weight: 100;
|
||||
font: 16px/24px 'Open Sans';
|
||||
color: #000;
|
||||
display: none;
|
||||
}
|
||||
.carousel-caption img {
|
||||
margin-top: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
#myCarousel img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
#myCarousel .carousel-control img {
|
||||
width: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Open Sans Light';
|
||||
font-weight: 100;
|
||||
font-family: 'Open Sans';
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: 18px/28px 'Open Sans Extrabold';
|
||||
text-transform: uppercase;
|
||||
color: #373e4b;
|
||||
margin-bottom: 0;
|
||||
font: 18px/28px 'Open Sans';
|
||||
text-transform: uppercase;
|
||||
font-weight: 800;
|
||||
color: #373e4b;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 16px; line-height:26px;
|
||||
font-size: 16px; line-height:26px;
|
||||
}
|
||||
p {
|
||||
font-size: 14px; line-height: 24px; color: #313131;
|
||||
font-size: 14px; line-height: 24px; color: #313131;
|
||||
}
|
||||
.lede {
|
||||
text-align: center;
|
||||
margin-bottom:20px;
|
||||
max-width: 80%;
|
||||
margin-left: 10%;
|
||||
text-align: center;
|
||||
margin-bottom:20px;
|
||||
max-width: 80%;
|
||||
margin-left: 10%;
|
||||
}
|
||||
body.services .lede {
|
||||
max-width: 95%;
|
||||
margin-left: 2.5%;
|
||||
margin-top: 30px;
|
||||
max-width: 95%;
|
||||
margin-left: 2.5%;
|
||||
margin-top: 30px;
|
||||
}
|
||||
body.products .lede {
|
||||
margin-top: 30px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.lede h3 {
|
||||
font: 24px/30px 'Open Sans Light';
|
||||
color: #aa2b39;
|
||||
font-weight: 100;
|
||||
font: 24px/30px 'Open Sans';
|
||||
color: #aa2b39;
|
||||
}
|
||||
.lede h4 {
|
||||
font: 20px/30px 'Open Sans Light Italic';
|
||||
color: #373e4b;
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font: 20px/30px 'Open Sans';
|
||||
color: #373e4b;
|
||||
}
|
||||
body.services .lede h4 {
|
||||
font-size: 16px;
|
||||
line-height: 150%;
|
||||
font-size: 16px;
|
||||
line-height: 150%;
|
||||
}
|
||||
body.services .lede {
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
body.about h1, body.services h1, body.contact h1 {
|
||||
font: 20px/30px 'Open Sans Extrabold Italic';
|
||||
color: #4f575b;
|
||||
margin-top: 0;
|
||||
font: 20px/30px 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
color: #4f575b;
|
||||
margin-top: 0;
|
||||
}
|
||||
.row-fluid {
|
||||
margin-top: 50px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
body.about h6 {
|
||||
margin: 0;
|
||||
font-family: 'Open Sans Light Italic';
|
||||
text-transform: uppercase;
|
||||
line-height: 80%;
|
||||
margin-bottom: 10px;
|
||||
color: #AA2B39;
|
||||
margin: 0;
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-family: 'Open Sans';
|
||||
text-transform: uppercase;
|
||||
line-height: 80%;
|
||||
margin-bottom: 10px;
|
||||
color: #AA2B39;
|
||||
}
|
||||
body.services table {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
table-layout: fixed;
|
||||
body.services table {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
table-layout: fixed;
|
||||
}
|
||||
body.services table th, body.services table td {
|
||||
padding: 10px 0;
|
||||
text-align: left;
|
||||
padding: 10px 0;
|
||||
text-align: left;
|
||||
}
|
||||
body.services table td {
|
||||
color: #373e4b;
|
||||
font-family: 'Open Sans Light Italic';
|
||||
width: 206px;
|
||||
body.services table td {
|
||||
color: #373e4b;
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-family: 'Open Sans';
|
||||
width: 206px;
|
||||
}
|
||||
body.services table tr:last-child th, body.services table tr:last-child td {
|
||||
border-bottom: none;
|
||||
body.services table tr:last-child th, body.services table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
body.services table tr:nth-child(even) {
|
||||
background: #eff3f1;
|
||||
}
|
||||
body.services table td:first-child {
|
||||
padding-left: 30px;
|
||||
body.services table tr:nth-child(even) {
|
||||
background: #eff3f1;
|
||||
}
|
||||
body.services table td:first-child {
|
||||
padding-left: 30px;
|
||||
}
|
||||
body.services table td.tableCenter {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
.singleProduct ul {
|
||||
margin-left: 15px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
.singleProduct li {
|
||||
padding: 5px 0;
|
||||
padding: 5px 0;
|
||||
}
|
||||
.btn-red {
|
||||
display:block;
|
||||
padding: 5px 0;
|
||||
background: #aa2b39;
|
||||
color: #FFF;
|
||||
font-family: 'Open Sans Light';
|
||||
text-shadow: none;
|
||||
font-weight: normal;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
width: 100px;
|
||||
margin-left: 75px;
|
||||
display:block;
|
||||
padding: 5px 0;
|
||||
background: #aa2b39;
|
||||
color: #FFF;
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-family: 'Open Sans';
|
||||
text-shadow: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
width: 100px;
|
||||
margin-left: 75px;
|
||||
}
|
||||
.btn-red:hover, .bth-red:focus {
|
||||
background-color: #9B1C2E;
|
||||
color: white;
|
||||
background-color: #9B1C2E;
|
||||
color: white;
|
||||
}
|
||||
body.contact .btn-red {
|
||||
margin-left: 0; margin-top: 5px;
|
||||
margin-left: 0; margin-top: 5px;
|
||||
}
|
||||
#myCarousel .btn-red {
|
||||
margin-left: 12px; margin-top:-7px;
|
||||
margin-left: 12px; margin-top:-7px;
|
||||
}
|
||||
.map {
|
||||
border: 0; border-right: 1px solid #eee;
|
||||
.map {
|
||||
border: 0; border-right: 1px solid #eee;
|
||||
}
|
||||
.map h2, .connect h2 {
|
||||
margin: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.map img {
|
||||
padding-right: 30px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
.connect a {
|
||||
margin: 0 8px 0 0; display: block; float: left;
|
||||
margin: 0 8px 0 0; display: block; float: left;
|
||||
}
|
||||
.connect a img:hover {
|
||||
margin-top: -5px;
|
||||
-webkit-transition: margin 0.2s ease-out;
|
||||
-moz-transition: margin 0.2s ease-out;
|
||||
-o-transition: margin 0.2s ease-out;
|
||||
transition: margin 0.2s ease-out;
|
||||
margin-top: -5px;
|
||||
-webkit-transition: margin 0.2s ease-out;
|
||||
-moz-transition: margin 0.2s ease-out;
|
||||
-o-transition: margin 0.2s ease-out;
|
||||
transition: margin 0.2s ease-out;
|
||||
}
|
||||
|
||||
footer {
|
||||
background: url(../images/footerBG.jpg) 50% 0 no-repeat;
|
||||
min-height: 340px;
|
||||
margin-top: 50px;
|
||||
position:relative;
|
||||
-webkit-background-size: cover; /*for webKit*/
|
||||
-moz-background-size: cover; /*Mozilla*/
|
||||
-o-background-size: cover; /*opera*/
|
||||
background-size: cover; /*generic*/
|
||||
background: url(../images/footerBG.jpg) 50% 0 no-repeat;
|
||||
min-height: 340px;
|
||||
margin-top: 50px;
|
||||
position:relative;
|
||||
-webkit-background-size: cover; /*for webKit*/
|
||||
-moz-background-size: cover; /*Mozilla*/
|
||||
-o-background-size: cover; /*opera*/
|
||||
background-size: cover; /*generic*/
|
||||
}
|
||||
footer p, footer a {
|
||||
color: #FFF;
|
||||
font: 12px 'Open Sans Light';
|
||||
color: #FFF;
|
||||
font-weight: 100;
|
||||
font: 12px 'Open Sans';
|
||||
}
|
||||
footer a {
|
||||
display:block;
|
||||
float: left;
|
||||
margin: 0 0 6px 0;
|
||||
clear: left;
|
||||
display:block;
|
||||
float: left;
|
||||
margin: 0 0 6px 0;
|
||||
clear: left;
|
||||
}
|
||||
footer .row-fluid {
|
||||
margin-top: 30px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.footerCol {
|
||||
width: 20%;
|
||||
float:left;
|
||||
width: 20%;
|
||||
float:left;
|
||||
}
|
||||
.footerCol h4 {
|
||||
color: #FFF;
|
||||
font: 14px/24px 'Open Sans Extrabold';
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0;
|
||||
color: #FFF;
|
||||
font-weight: 800;
|
||||
font: 14px/24px 'Open Sans';
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
footer .social a {
|
||||
clear: none;
|
||||
margin: 0 4px;
|
||||
clear: none;
|
||||
margin: 0 4px;
|
||||
}
|
||||
footer .social img:hover {
|
||||
margin-top: -5px;
|
||||
-webkit-transition: margin 0.2s ease-out;
|
||||
-moz-transition: margin 0.2s ease-out;
|
||||
-o-transition: margin 0.2s ease-out;
|
||||
transition: margin 0.2s ease-out;
|
||||
margin-top: -5px;
|
||||
-webkit-transition: margin 0.2s ease-out;
|
||||
-moz-transition: margin 0.2s ease-out;
|
||||
-o-transition: margin 0.2s ease-out;
|
||||
transition: margin 0.2s ease-out;
|
||||
}
|
||||
body.contact footer, body.index footer {
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
.news img {
|
||||
max-width: 275px;
|
||||
height: auto;
|
||||
max-width: 275px;
|
||||
height: auto;
|
||||
}
|
||||
.news h2, .news p, .events hr {
|
||||
max-width: 275px;
|
||||
max-width: 275px;
|
||||
}
|
||||
.productnews hr {
|
||||
max-width: 595px;
|
||||
max-width: 595px;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Sphinx custom styles
|
||||
========================================================================== */
|
||||
Sphinx custom styles
|
||||
========================================================================== */
|
||||
|
||||
h1:hover > .headerlink,
|
||||
h2:hover > .headerlink,
|
||||
@ -326,53 +352,50 @@ h6:hover > .headerlink,
|
||||
dt:hover > .headerlink { visibility: visible; }
|
||||
|
||||
.sidebar .toctree-l1.current a {
|
||||
border-right: 5px solid #fcaf3e; }
|
||||
|
||||
border-right: 5px solid #fcaf3e;
|
||||
}
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
div.header div.rel a {
|
||||
color: #fcaf3e;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
color: #fcaf3e;
|
||||
letter-spacing: .1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.descname {
|
||||
font-weight: bold; }
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
.literal {
|
||||
background-color: #eeeeec; }
|
||||
|
||||
background-color: #eeeeec;
|
||||
}
|
||||
blockquote {
|
||||
margin: 1em; }
|
||||
|
||||
margin: 1em;
|
||||
}
|
||||
.footer, .footer a {
|
||||
color: #888a85; }
|
||||
|
||||
color: #888a85;
|
||||
}
|
||||
div.admonition {
|
||||
font-size: 0.9em;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.5em 1em 0.5em 1em;
|
||||
border: 1px solid #ddd; }
|
||||
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
div.admonition p.admonition-title {
|
||||
font-weight: bold; color: #3465a4; }
|
||||
|
||||
font-weight: bold; color: #3465a4;
|
||||
}
|
||||
div.warning {
|
||||
border-color: #940000; }
|
||||
|
||||
border-color: #940000;
|
||||
}
|
||||
div.warning p.admonition-title {
|
||||
color: #940000; }
|
||||
|
||||
color: #940000;
|
||||
}
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
@ -380,8 +403,8 @@ div.viewcode-block:target {
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
SaltStack custom styles
|
||||
========================================================================== */
|
||||
SaltStack custom styles
|
||||
========================================================================== */
|
||||
|
||||
.lit-docs {
|
||||
list-style-type: none;
|
||||
@ -407,6 +430,7 @@ div.viewcode-block:target {
|
||||
}
|
||||
|
||||
/* Override a few Bootstrap-isms */
|
||||
|
||||
.lit-annotation pre,
|
||||
.lit-content pre {
|
||||
word-break: normal;
|
||||
@ -441,8 +465,9 @@ div.viewcode-block:target {
|
||||
}
|
||||
|
||||
/* rST automatically puts the .container class on ``.. container`` directives
|
||||
* which conflicts with the bootstrap class of the same name. >.<
|
||||
*/
|
||||
* which conflicts with the bootstrap class of the same name. >.<
|
||||
*/
|
||||
|
||||
.scrollable.container {
|
||||
width: auto;
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ copyright = '2014 SaltStack, Inc.'
|
||||
|
||||
version = salt.version.__version__
|
||||
#release = '.'.join(map(str, salt.version.__version_info__))
|
||||
release = '2014.1.4'
|
||||
release = '2014.1.5'
|
||||
|
||||
language = 'en'
|
||||
locale_dirs = [
|
||||
|
@ -109,23 +109,30 @@ arbitrary commands on remote hosts.
|
||||
Targeting
|
||||
---------
|
||||
|
||||
:doc:`Targeting </topics/targeting/index>` is specifying which minions
|
||||
should execute commands or manage server configuration.
|
||||
:ref:`Targeting <targeting>` is the method of specifying which minions should
|
||||
execute commands or manage server configuration.
|
||||
|
||||
:doc:`Globbing and regex </topics/targeting/globbing>`
|
||||
:ref:`Globbing and regex <targeting-glob>`
|
||||
Match minions using globbing and regular expressions.
|
||||
|
||||
:doc:`Grains </topics/targeting/grains>`
|
||||
:ref:`Grains <targeting-grains>`
|
||||
Match minions using bits of static information about the minion such as
|
||||
OS, software versions, virtualization, CPU, memory, and much more.
|
||||
|
||||
:doc:`Node groups </topics/targeting/nodegroups>`
|
||||
Statically define groups of minions.
|
||||
:ref:`Pillar <targeting-pillar>`
|
||||
Match minions using user-defined variables.
|
||||
|
||||
:doc:`Compound matchers </topics/targeting/compound>`
|
||||
Combine the above matchers as a single target.
|
||||
:ref:`Subnet/IP Address <targeting-ipcidr>`
|
||||
Match minions by Subnet or IP address (currently IPv4 only).
|
||||
|
||||
:doc:`Batching execution </topics/targeting/batch>`
|
||||
:ref:`Compound matching <targeting-compound>`
|
||||
Combine any of the above matchers into a single expression.
|
||||
|
||||
:ref:`Node groups <targeting-nodegroups>`
|
||||
Statically define groups of minions in the master config file using the
|
||||
:ref:`compound <targeting-compound>` matching syntax.
|
||||
|
||||
:ref:`Batching execution <targeting-batch>`
|
||||
Loop through all matching minions so that only a subset are executing a
|
||||
command at one time.
|
||||
|
||||
|
@ -15,6 +15,7 @@ Full list of builtin pillar modules
|
||||
cobbler
|
||||
django_orm
|
||||
etcd_pillar
|
||||
foreman
|
||||
git_pillar
|
||||
hiera
|
||||
libvirt
|
||||
|
6
doc/ref/pillar/all/salt.pillar.foreman.rst
Normal file
6
doc/ref/pillar/all/salt.pillar.foreman.rst
Normal file
@ -0,0 +1,6 @@
|
||||
===================
|
||||
salt.pillar.foreman
|
||||
===================
|
||||
|
||||
.. automodule:: salt.pillar.foreman
|
||||
:members:
|
@ -5,6 +5,14 @@ Troubleshooting Salt Cloud
|
||||
This page describes various steps for troubleshooting problems that may arise
|
||||
while using Salt Cloud.
|
||||
|
||||
Virtual Machines Are Created, But Do Not Respond
|
||||
================================================
|
||||
|
||||
Are TCP ports 4505 and 4506 open on the master? This is easy to overlook on new
|
||||
masters. Information on how to open firewall ports on various platforms can be
|
||||
found :doc:`here </topics/tutorials/firewall>`.
|
||||
|
||||
|
||||
Generic Troubleshooting Steps
|
||||
=============================
|
||||
This section describes a set of instructions that are useful to a large number
|
||||
|
@ -44,21 +44,46 @@ Dependencies
|
||||
Salt should run on any Unix-like platform so long as the dependencies are met.
|
||||
|
||||
* `Python 2.6`_ >= 2.6 <3.0
|
||||
* `ZeroMQ`_ >= 3.2.0
|
||||
* `pyzmq`_ >= 2.2.0 - ZeroMQ Python bindings
|
||||
* `PyCrypto`_ - The Python cryptography toolkit
|
||||
* `M2Crypto`_ - "Me Too Crypto" - Python OpenSSL wrapper
|
||||
* `msgpack-python`_ - High-performance message interchange format
|
||||
* `YAML`_ - Python YAML bindings
|
||||
* `Jinja2`_ - parsing Salt States (configurable in the master settings)
|
||||
* `MarkupSafe`_ - Implements a XML/HTML/XHTML Markup safe string for Python
|
||||
* `apache-libcloud`_ - Python lib for interacting with many of the popular
|
||||
cloud service providers using a unified API
|
||||
|
||||
The upcoming feature release will include a new dependency:
|
||||
|
||||
* `Requests`_ - HTTP library
|
||||
|
||||
Depending on the chosen Salt transport, `ZeroMQ`_ or `RAET`_, dependencies
|
||||
vary:
|
||||
|
||||
* ZeroMQ:
|
||||
* `ZeroMQ`_ >= 3.2.0
|
||||
* `pyzmq`_ >= 2.2.0 - ZeroMQ Python bindings
|
||||
* `PyCrypto`_ - The Python cryptography toolkit
|
||||
* `M2Crypto`_ - "Me Too Crypto" - Python OpenSSL wrapper
|
||||
|
||||
* RAET:
|
||||
* `libnacl`_ - Python bindings to `libsodium`_
|
||||
* `ioflo`_ - The flo programming interface raet and salt-raet is built on
|
||||
* `RAET`_ - The worlds most awesome UDP protocol
|
||||
|
||||
Salt defaults to the `ZeroMQ`_ transport, and the choice can be made at install
|
||||
time, for example:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py --salt-transport=raet install
|
||||
|
||||
This way, only the required dependencies are pulled by the setup script if need
|
||||
be.
|
||||
|
||||
If installing using pip, the ``--salt-transport`` global option can be provided
|
||||
like:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
pip install --global-option="--salt-transport=raet" salt
|
||||
|
||||
|
||||
Optional Dependencies
|
||||
---------------------
|
||||
|
||||
@ -79,6 +104,10 @@ Optional Dependencies
|
||||
.. _`Cython`: http://cython.org/
|
||||
.. _`apache-libcloud`: http://libcloud.apache.org
|
||||
.. _`Requests`: http://docs.python-requests.org/en/latest
|
||||
.. _`libnacl`: https://github.com/saltstack/libnacl
|
||||
.. _`ioflo`: https://github.com/ioflo/ioflo
|
||||
.. _`RAET`: https://github.com/saltstack/raet
|
||||
.. _`libsodium`: https://github.com/jedisct1/libsodium
|
||||
|
||||
|
||||
Upgrading Salt
|
||||
|
@ -236,6 +236,8 @@ locally. This is done with the ``saltutil.refresh_pillar`` function.
|
||||
This function triggers the minion to asynchronously refresh the pillar and will
|
||||
always return ``None``.
|
||||
|
||||
.. _targeting-pillar:
|
||||
|
||||
Targeting with Pillar
|
||||
=====================
|
||||
|
||||
|
48
doc/topics/releases/2014.1.5.rst
Normal file
48
doc/topics/releases/2014.1.5.rst
Normal file
@ -0,0 +1,48 @@
|
||||
===========================
|
||||
Salt 2014.1.5 Release Notes
|
||||
===========================
|
||||
|
||||
:release: 2014-06-11
|
||||
|
||||
Version 2014.1.5 is another bugfix release for :doc:`2014.1.0
|
||||
</topics/releases/2014.1.0>`. Changes include:
|
||||
|
||||
- Add function for finding cached job on the minion
|
||||
- Fix iptables save file location for Debian (:issue:`11730`)
|
||||
- Fix for minion caching jobs when master is down
|
||||
- Bump default ``syndic_wait`` to 5 to fix syndic-related problems
|
||||
(:issue:`12262`)
|
||||
- Add OpenBSD, FreeBSD, and NetBSD support for ``network.netstat``
|
||||
(:issue:`12121`)
|
||||
- Fix false positive error in logs for ``makeconf`` state (:issue:`9762`)
|
||||
- Fix for yum ``fromrepo`` package installs when repo is disabled by default
|
||||
(:issue:`12466`)
|
||||
- Fix for extra blank lines in ``file.blockreplace`` (:issue:`12422`)
|
||||
- Fix grain detection for OpenVZ guests (:issue:`11877`)
|
||||
- Fix ``get_dns_servers`` function for Windows ``win_dns_client``
|
||||
- Use system locale for ports package installations
|
||||
- Use correct stop/restart procedure for Debian networking in ``debian_ip``
|
||||
(:issue:`12614`)
|
||||
- Fix for ``cmd_iter``/``cmd_iter_no_block`` blocking issues (:issue:`12617`)
|
||||
- Fix traceback when syncing custom types (:issue:`12883`)
|
||||
- Fix cleaning directory symlinks in ``file.directory``
|
||||
- Add performance optimizations for ``saltutil.sync_all`` and
|
||||
``state.highstate``
|
||||
- Fix possible error in ``saltutil.running``
|
||||
- Fix for kmod modules with dashes (:issue:`13239`)
|
||||
- Fix possible race condition for Windows minions in state module reloading
|
||||
(:issue:`12370`)
|
||||
- Fix bug with roster for ``passwd``s that are loaded as non-string objects
|
||||
(:issue:`13249`)
|
||||
- Keep duplicate version numbers from showing up in ``pkg.list_pkgs`` output
|
||||
- Fixes for Jinja renderer, timezone :mod:`module
|
||||
<salt.modules.timezone>`/:mod:`state <salt.states.timezone>` (:issue:`12724`)
|
||||
- Fix timedatectl parsing for systemd>=210 (:issue:`12728`)
|
||||
- Fix ``saltenv`` being written to YUM repo config files (:issue:`12887`)
|
||||
- Removed the deprecated external nodes classifier (originally accessible by
|
||||
setting a value for external_nodes in the master configuration file). Note
|
||||
that this functionality has been marked deprecated for some time and was
|
||||
replaced by the more general :doc:`master tops <topics/master_tops>` system.
|
||||
- More robust escaping of ldap filter strings.
|
||||
- Fix trailing slash in :conf_master:`gitfs_root` causing files not to be
|
||||
available (:issue:`13185`)
|
95
doc/topics/sdb/index.rst
Normal file
95
doc/topics/sdb/index.rst
Normal file
@ -0,0 +1,95 @@
|
||||
.. _sdb:
|
||||
|
||||
===============================
|
||||
Storing Data in Other Databases
|
||||
===============================
|
||||
The SDB interface is designed to store and retrieve data that, unlike pillars
|
||||
and grains, is not necessarily minion-specific. The initial design goal was to
|
||||
allow passwords to be stored in a secure database, such as one managed by the
|
||||
keyring package, rather than as plain-text files. However, as a generic database
|
||||
interface, it could conceptually be used for a number of other purposes.
|
||||
|
||||
SDB was added to Salt in version Helium. SDB is currently experimental, and
|
||||
should probably not be used in production.
|
||||
|
||||
|
||||
SDB Configuration
|
||||
================
|
||||
In order to use the SDB interface, a configuration profile must be set up in
|
||||
either the master or minion configuration file. The configuration stanza
|
||||
includes the name/ID that the profile will be referred to as, a ``driver``
|
||||
setting, and any other arguments that are necessary for the SDB module that will
|
||||
be used. For instance, a profile called ``mykeyring``, which uses the
|
||||
``system`` service in the ``keyring`` module would look like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
mykeyring:
|
||||
driver: keyring
|
||||
service: system
|
||||
|
||||
It is recommended to keep the name of the profile simple, as it is used in the
|
||||
SDB URI as well.
|
||||
|
||||
|
||||
SDB URIs
|
||||
========
|
||||
SDB is designed to make small database queries (hence the name, SDB) using a
|
||||
compact URL. This allows users to reference a database value quickly inside
|
||||
a number of Salt configuration areas, without a lot of overhead. The basic
|
||||
format of an SDB URI is:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sdb://<profile>/<args>
|
||||
|
||||
The profile refers to the configuration profile defined in either the master or
|
||||
the minion configuration file. The args are specific to the module referred to
|
||||
in the profile, but will typically only need to refer to the key of a
|
||||
key/value pair inside the database. This is because the profile itself should
|
||||
define as many other parameters as possible.
|
||||
|
||||
For example, a profile might be set up to reference credentials for a specific
|
||||
OpenStack account. The profile might look like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
kevinopenstack:
|
||||
driver: keyring
|
||||
service salt.cloud.openstack.kevin
|
||||
|
||||
And the URI used to reference the password might look like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sdb://kevinopenstack/password
|
||||
|
||||
|
||||
Writing SDB Modules
|
||||
===================
|
||||
There is currently one function that MUST exist in any SDB module (``get()``)
|
||||
and one that MAY exist (``set_()``). If using a (``set_()``) function, a
|
||||
``__func_alias__`` dictionary MUST be declared in the module as well:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
__func_alias__ = {
|
||||
'set_': 'set',
|
||||
}
|
||||
|
||||
This is because ``set`` is a Python built-in, and therefore functions should not
|
||||
be created which are called ``set()``. The ``__func_alias__`` functionality is
|
||||
provided via Salt's loader interfaces, and allows legally-named functions to be
|
||||
referred to using names that would otherwise be unwise to use.
|
||||
|
||||
The ``get()`` function is required, as it will be called via functions in other
|
||||
areas of the code which make use of the ``sdb://`` URI. For example, the
|
||||
``config.get`` function in the ``config`` execution module uses this function.
|
||||
|
||||
The ``set_()`` function may be provided, but is not required, as some sources
|
||||
may be read-only, or may be otherwise unwise to access via a URI (for instance,
|
||||
because of SQL injection attacks).
|
||||
|
||||
A simple example of an SDB module is ``salt/sdb/keyring_db.py``, as it provides
|
||||
basic examples of most, if not all, of the types of functionality that are
|
||||
available not only for SDB modules, but for Salt modules in general.
|
@ -1,3 +1,5 @@
|
||||
.. _targeting-batch:
|
||||
|
||||
Batch Size
|
||||
----------
|
||||
|
||||
|
@ -28,6 +28,7 @@ There are many ways to target individual minions or groups of minions in Salt:
|
||||
|
||||
globbing
|
||||
grains
|
||||
nodegroups
|
||||
ipcidr
|
||||
compound
|
||||
nodegroups
|
||||
batch
|
||||
|
19
doc/topics/targeting/ipcidr.rst
Normal file
19
doc/topics/targeting/ipcidr.rst
Normal file
@ -0,0 +1,19 @@
|
||||
.. _targeting-ipcidr:
|
||||
|
||||
==========================
|
||||
Subnet/IP Address Matching
|
||||
==========================
|
||||
|
||||
Minions can easily be matched based on IP address, or by subnet (using CIDR_
|
||||
notation).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt -S 192.168.40.20 test.ping
|
||||
salt -S 10.0.0.0/24 test.ping
|
||||
|
||||
.. _CIDR: http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
|
||||
|
||||
.. note::
|
||||
|
||||
Only IPv4 matching is supported at this time.
|
@ -90,11 +90,10 @@ master:
|
||||
gitfs_remotes:
|
||||
- https://github.com/saltstack-formulas/salt-formula.git
|
||||
|
||||
3. *Restart the master* so that the git repository cache on the master
|
||||
is updated, and
|
||||
new ``salt://`` requests will send the latest files from
|
||||
the remote git repository.
|
||||
This step is not necessary with a standalone minion configuration.
|
||||
3. Restart the master so that the git repository cache on the master is
|
||||
updated, and new ``salt://`` requests will send the latest files from the
|
||||
remote git repository. This step is not necessary with a standalone minion
|
||||
configuration.
|
||||
|
||||
.. note::
|
||||
|
||||
|
5
raet-requirements.txt
Normal file
5
raet-requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
-r _requirements.txt
|
||||
|
||||
libnacl
|
||||
ioflo
|
||||
raet
|
@ -1,9 +0,0 @@
|
||||
Jinja2
|
||||
M2Crypto
|
||||
msgpack-python > 0.1.13
|
||||
pycrypto
|
||||
PyYAML
|
||||
pyzmq >= 2.2.0
|
||||
MarkupSafe
|
||||
apache-libcloud >= 0.14.0
|
||||
requests
|
@ -52,10 +52,12 @@ class LocalClient(salt.client.LocalClient):
|
||||
timeout=timeout,
|
||||
**kwargs)
|
||||
yid = salt.utils.gen_jid()
|
||||
basedirpath = os.path.join(self.opts['cachedir'], 'raet')
|
||||
stack = LaneStack(
|
||||
name=('client' + yid),
|
||||
yid=yid,
|
||||
lanename='master',
|
||||
basedirpath=basedirpath,
|
||||
sockdirpath=self.opts['sock_dir'])
|
||||
stack.Pk = raeting.packKinds.pack
|
||||
router_yard = RemoteYard(
|
||||
|
@ -281,6 +281,12 @@ def create(vm_):
|
||||
)
|
||||
)
|
||||
|
||||
if key_filename is None:
|
||||
raise SaltCloudConfigError(
|
||||
'The Digital Ocean driver requires a ssh_key_file because it does not supply a root password '
|
||||
'upon building the server'
|
||||
)
|
||||
|
||||
private_networking = config.get_cloud_config_value(
|
||||
'private_networking', vm_, __opts__, search_global=False, default=None,
|
||||
)
|
||||
|
@ -1438,6 +1438,7 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
break
|
||||
|
||||
providers = {}
|
||||
ext_count = 0
|
||||
for key, val in config.items():
|
||||
if key in ('conf_file', 'include', 'default_include', 'user'):
|
||||
continue
|
||||
@ -1473,21 +1474,14 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
|
||||
for entry in val:
|
||||
if 'provider' not in entry:
|
||||
entry['provider'] = '-only-extendable-'
|
||||
entry['provider'] = '-only-extendable-{0}'.format(ext_count)
|
||||
ext_count += 1
|
||||
|
||||
if key not in providers:
|
||||
providers[key] = {}
|
||||
|
||||
provider = entry['provider']
|
||||
if provider in providers[key] and provider == '-only-extendable-':
|
||||
raise salt.cloud.exceptions.SaltCloudConfigError(
|
||||
'There\'s multiple entries under {0!r} which do not set '
|
||||
'a provider setting. This is most likely just a holder '
|
||||
'for data to be extended from, however, there can be '
|
||||
'only one entry which does not define it\'s \'provider\' '
|
||||
'setting.'.format(key)
|
||||
)
|
||||
elif provider not in providers[key]:
|
||||
if provider not in providers[key]:
|
||||
providers[key][provider] = entry
|
||||
|
||||
# Is any provider extending data!?
|
||||
@ -1530,6 +1524,8 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
)
|
||||
)
|
||||
details['extends'] = '{0}:{1}'.format(alias, provider)
|
||||
# # change provider details '-only-extendable-' to extended provider name
|
||||
details['provider'] = provider
|
||||
elif providers.get(extends) and len(providers[extends]) > 1:
|
||||
raise salt.cloud.exceptions.SaltCloudConfigError(
|
||||
'The {0!r} cloud provider entry in {1!r} is trying '
|
||||
@ -1549,12 +1545,11 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
)
|
||||
)
|
||||
else:
|
||||
provider = providers.get(extends)
|
||||
if driver in providers.get(extends):
|
||||
details['extends'] = '{0}:{1}'.format(extends, driver)
|
||||
elif '-only-extendable-' in providers.get(extends):
|
||||
elif providers.get(extends).startswith('-only-extendable-'):
|
||||
details['extends'] = '{0}:{1}'.format(
|
||||
extends, '-only-extendable-'
|
||||
extends, '-only-extendable-{0}'.format(ext_count)
|
||||
)
|
||||
else:
|
||||
# We're still not aware of what we're trying to extend
|
||||
@ -1590,6 +1585,11 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
extended.update(details)
|
||||
# Update the providers dictionary with the merged data
|
||||
providers[alias][driver] = extended
|
||||
# Update name of the driver, now that it's populated with extended information
|
||||
if driver.startswith('-only-extendable-'):
|
||||
providers[alias][ext_driver] = providers[alias][driver]
|
||||
# Delete driver with old name to maintain dictionary size
|
||||
del providers[alias][driver]
|
||||
|
||||
if not keep_looping:
|
||||
break
|
||||
@ -1598,7 +1598,7 @@ def apply_cloud_providers_config(overrides, defaults=None):
|
||||
# extend from
|
||||
for provider_alias, entries in providers.copy().items():
|
||||
for driver, details in entries.copy().iteritems():
|
||||
if driver != '-only-extendable-':
|
||||
if not driver.startswith('-only-extendable-'):
|
||||
continue
|
||||
|
||||
log.info(
|
||||
|
@ -111,11 +111,12 @@ class SaltRaetRoadStack(ioflo.base.deeding.Deed):
|
||||
localname=localname,
|
||||
auto=auto,
|
||||
main=main,
|
||||
dirpath=dirpath,
|
||||
basedirpath=dirpath,
|
||||
safe=safe,
|
||||
txMsgs=txMsgs,
|
||||
rxMsgs=rxMsgs)
|
||||
self.stack.value.Bk = raeting.bodyKinds.msgpack
|
||||
self.stack.value.JoinentTimeout = 0.0
|
||||
|
||||
|
||||
class SaltRaetRoadStackCloser(ioflo.base.deeding.Deed): # pylint: disable=W0232
|
||||
@ -162,7 +163,7 @@ class SaltRaetRoadStackJoiner(ioflo.base.deeding.Deed):
|
||||
'''
|
||||
stack = self.stack.value
|
||||
if stack and isinstance(stack, RoadStack):
|
||||
stack.join(mha=self.mha, timeout=0.0)
|
||||
stack.join(ha=self.mha, timeout=0.0)
|
||||
|
||||
|
||||
class SaltRaetRoadStackJoined(ioflo.base.deeding.Deed):
|
||||
@ -721,13 +722,13 @@ class NixExecutor(ioflo.base.deeding.Deed):
|
||||
Send the return data back via the uxd socket
|
||||
'''
|
||||
stackname = self.opts['id'] + ret['jid']
|
||||
dirpath = os.path.join(self.opts['cachedir'], stackname)
|
||||
dirpath = os.path.join(self.opts['cachedir'], 'raet')
|
||||
ret_stack = LaneStack(
|
||||
name=stackname,
|
||||
lanename=self.opts['id'],
|
||||
yid=ret['jid'],
|
||||
sockdirpath=self.opts['sock_dir'],
|
||||
dirpath=dirpath)
|
||||
basedirpath=dirpath)
|
||||
|
||||
ret_stack.Pk = raeting.packKinds.pack
|
||||
main_yard = RemoteYard(
|
||||
|
@ -14,7 +14,7 @@ from ioflo.base.odicting import odict
|
||||
from ioflo.base.consoling import getConsole
|
||||
console = getConsole()
|
||||
|
||||
from raet import raeting, nacling, keeping
|
||||
from raet import raeting, nacling
|
||||
from raet.road.keeping import RoadKeep
|
||||
|
||||
from salt.key import RaetKey
|
||||
@ -134,10 +134,16 @@ class SaltSafe(object):
|
||||
Load and Return the data from the remote estate file
|
||||
Override this in sub class to change uid
|
||||
'''
|
||||
status='accepted'
|
||||
#status = raeting.ACCEPTANCE_NAMES.get(remote.acceptance, 'accepted')
|
||||
#status='accepted'
|
||||
|
||||
mid = remote.name
|
||||
keydata = self.saltRaetKey.read_remote(mid, status)
|
||||
statae = raeting.ACCEPTANCES.keys()
|
||||
for status in statae:
|
||||
keydata = self.saltRaetKey.read_remote(mid, status)
|
||||
if keydata:
|
||||
break
|
||||
|
||||
if not keydata:
|
||||
return None
|
||||
|
||||
@ -152,12 +158,25 @@ class SaltSafe(object):
|
||||
|
||||
def clearRemote(self, remote):
|
||||
'''
|
||||
Clear the remote estate file
|
||||
Override this in sub class to change uid
|
||||
Salt level keys should not be auto removed with cache changes
|
||||
'''
|
||||
#mid = str(remote.eid)
|
||||
mid = remote.name
|
||||
self.saltRaetKey.delete_key(mid)
|
||||
pass
|
||||
|
||||
def replaceRemote(self, remote, old):
|
||||
'''
|
||||
Replace the safe keep key file at old name given remote.name has changed
|
||||
Assumes name uniqueness already taken care of
|
||||
'''
|
||||
new = remote.name
|
||||
if new != old:
|
||||
self.dumpRemote(remote) #will be pending by default unless autoaccept
|
||||
# manually fix up acceptance if not pending
|
||||
if remote.acceptance == raeting.acceptances.accepted:
|
||||
self.acceptRemote(remote)
|
||||
elif remote.acceptance == raeting.acceptances.rejected:
|
||||
self.rejectRemote(remote)
|
||||
|
||||
self.saltRaetKey.delete_key(old) #now delete old key file
|
||||
|
||||
def statusRemote(self, remote, verhex, pubhex, main=True):
|
||||
'''
|
||||
|
@ -903,6 +903,14 @@ class RemoteClient(Client):
|
||||
else:
|
||||
self.auth = ''
|
||||
|
||||
def _get_channel(self):
|
||||
'''
|
||||
Return the right channel
|
||||
'''
|
||||
if self.auth:
|
||||
return self.channel
|
||||
return salt.transport.Channel.factory(self.opts)
|
||||
|
||||
def get_file(self,
|
||||
path,
|
||||
dest='',
|
||||
@ -976,7 +984,8 @@ class RemoteClient(Client):
|
||||
else:
|
||||
load['loc'] = fn_.tell()
|
||||
try:
|
||||
data = self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
data = channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
if not data:
|
||||
@ -1045,7 +1054,8 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1067,7 +1077,8 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_file_list_emptydirs'}
|
||||
try:
|
||||
self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1089,7 +1100,8 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_dir_list'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1101,7 +1113,8 @@ class RemoteClient(Client):
|
||||
'prefix': prefix,
|
||||
'cmd': '_symlink_list'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1139,7 +1152,8 @@ class RemoteClient(Client):
|
||||
'saltenv': saltenv,
|
||||
'cmd': '_file_hash'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1160,7 +1174,8 @@ class RemoteClient(Client):
|
||||
load = {'saltenv': saltenv,
|
||||
'cmd': '_file_list'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1170,7 +1185,8 @@ class RemoteClient(Client):
|
||||
'''
|
||||
load = {'cmd': '_master_opts'}
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
||||
@ -1182,8 +1198,10 @@ class RemoteClient(Client):
|
||||
load = {'cmd': '_ext_nodes',
|
||||
'id': self.opts['id'],
|
||||
'opts': self.opts}
|
||||
load['tok'] = self.auth.gen_token('salt')
|
||||
if self.auth:
|
||||
load['tok'] = self.auth.gen_token('salt')
|
||||
try:
|
||||
return self.channel.send(load)
|
||||
channel = self._get_channel()
|
||||
return channel.send(load)
|
||||
except SaltReqTimeoutError:
|
||||
return ''
|
||||
|
@ -1150,6 +1150,8 @@ def file_hash(load, fnd):
|
||||
'{0}.hash.{1}'.format(relpath,
|
||||
__opts__['hash_type']))
|
||||
if not os.path.isfile(hashdest):
|
||||
if not os.path.exists(os.path.dirname(hashdest)):
|
||||
os.makedirs(os.path.dirname(hashdest))
|
||||
with salt.utils.fopen(path, 'rb') as fp_:
|
||||
ret['hsum'] = getattr(hashlib, __opts__['hash_type'])(
|
||||
fp_.read()).hexdigest()
|
||||
|
@ -370,8 +370,7 @@ def grains(opts, force_refresh=False):
|
||||
opts['grains'] = {}
|
||||
else:
|
||||
opts['grains'] = {}
|
||||
|
||||
load = _create_loader(opts, 'grains', 'grain')
|
||||
load = _create_loader(opts, 'grains', 'grain', ext_type_dirs='grains_dirs')
|
||||
grains_info = load.gen_grains(force_refresh)
|
||||
grains_info.update(opts['grains'])
|
||||
return grains_info
|
||||
@ -408,6 +407,20 @@ def queues(opts):
|
||||
return load.gen_functions()
|
||||
|
||||
|
||||
def sdb(opts, functions=None, whitelist=None):
|
||||
'''
|
||||
Make a very small database call
|
||||
'''
|
||||
load = _create_loader(opts, 'sdb', 'sdb')
|
||||
pack = {'name': '__sdb__',
|
||||
'value': functions}
|
||||
return LazyLoader(load,
|
||||
functions,
|
||||
pack,
|
||||
whitelist=whitelist,
|
||||
)
|
||||
|
||||
|
||||
def clouds(opts):
|
||||
'''
|
||||
Return the cloud functions
|
||||
|
@ -1152,7 +1152,7 @@ class AESFuncs(object):
|
||||
file_recv_max_size = 1024*1024 * self.opts.get('file_recv_max_size', 100)
|
||||
|
||||
if 'loc' in load and load['loc'] < 0:
|
||||
log.error("load['loc'] is < 0, this should not happen.")
|
||||
log.error('Should not happen: load[loc] < 0')
|
||||
return False
|
||||
|
||||
if len(load['data']) + load.get('loc', 0) > file_recv_max_size:
|
||||
|
238
salt/minion.py
238
salt/minion.py
@ -557,6 +557,7 @@ class Minion(MinionBase):
|
||||
This class instantiates a minion, runs connections for a minion,
|
||||
and loads all of the functions into the minion
|
||||
'''
|
||||
|
||||
def __init__(self, opts, timeout=60, safe=True):
|
||||
'''
|
||||
Pass in the options dict
|
||||
@ -575,79 +576,10 @@ class Minion(MinionBase):
|
||||
# module
|
||||
opts['grains'] = salt.loader.grains(opts)
|
||||
|
||||
# check if master_type was altered from its default
|
||||
if opts['master_type'] != 'str':
|
||||
# check for a valid keyword
|
||||
if opts['master_type'] == 'func':
|
||||
# split module and function and try loading the module
|
||||
mod, fun = opts['master'].split('.')
|
||||
try:
|
||||
master_mod = salt.loader.raw_mod(opts, mod, fun)
|
||||
if not master_mod:
|
||||
raise TypeError
|
||||
# we take whatever the module returns as master address
|
||||
opts['master'] = master_mod[mod + '.' + fun]()
|
||||
except TypeError:
|
||||
msg = ('Failed to evaluate master address from '
|
||||
'module \'{0}\''.format(opts['master']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
log.info('Evaluated master from module: {0}'.format(master_mod))
|
||||
|
||||
# if failover is set, master has to be of type list
|
||||
elif opts['master_type'] == 'failover':
|
||||
if type(opts['master']) is list:
|
||||
log.info('Got list of available master addresses:'
|
||||
' {0}'.format(opts['master']))
|
||||
else:
|
||||
msg = ('master_type set to \'failover\' but \'master\' '
|
||||
'is not of type list but of type '
|
||||
'{0}'.format(type(opts['master'])))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
else:
|
||||
msg = ('Invalid keyword \'{0}\' for variable '
|
||||
'\'master_type\''.format(opts['master_type']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
|
||||
# if we have a list of masters, loop through them and be
|
||||
# happy with the first one that allows us to connect
|
||||
if type(opts['master']) is list:
|
||||
conn = False
|
||||
# shuffle the masters and then loop through them
|
||||
local_masters = copy.copy(opts['master'])
|
||||
if opts['master_shuffle']:
|
||||
shuffle(local_masters)
|
||||
|
||||
for master in local_masters:
|
||||
opts['master'] = master
|
||||
opts.update(resolve_dns(opts))
|
||||
super(Minion, self).__init__(opts)
|
||||
try:
|
||||
if self.authenticate(timeout, safe) != 'full':
|
||||
conn = True
|
||||
break
|
||||
except SaltClientError:
|
||||
msg = ('Master {0} could not be reached, trying '
|
||||
'next master (if any)'.format(opts['master']))
|
||||
log.info(msg)
|
||||
continue
|
||||
|
||||
if not conn:
|
||||
msg = ('No master could be reached or all masters denied '
|
||||
'the minions connection attempt.')
|
||||
log.error(msg)
|
||||
|
||||
# single master sign in
|
||||
else:
|
||||
opts.update(resolve_dns(opts))
|
||||
super(Minion, self).__init__(opts)
|
||||
if self.authenticate(timeout, safe) == 'full':
|
||||
msg = ('master {0} rejected the minions connection because too '
|
||||
'many minions are already connected.'.format(opts['master']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
# evaluate the master to connect to and authenticate with it
|
||||
opts['master'] = self.eval_master(opts,
|
||||
timeout,
|
||||
safe)
|
||||
|
||||
self.opts['pillar'] = salt.pillar.get_pillar(
|
||||
opts,
|
||||
@ -684,7 +616,8 @@ class Minion(MinionBase):
|
||||
'function': 'status.master',
|
||||
'seconds': opts['master_alive_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2
|
||||
'maxrunning': 1,
|
||||
'args': [True]
|
||||
}
|
||||
})
|
||||
|
||||
@ -706,6 +639,121 @@ class Minion(MinionBase):
|
||||
log.debug('I am {0} and I am not supposed to start any proxies. '
|
||||
'(Likely not a problem)'.format(self.opts['id']))
|
||||
|
||||
# __init__() from MinionBase is called in Minion.eval_master()
|
||||
# pylint: disable=W0231
|
||||
|
||||
def eval_master(self,
|
||||
opts,
|
||||
timeout=60,
|
||||
safe=True,
|
||||
failed=False):
|
||||
'''
|
||||
Evaluates and returns the current master address. In standard mode, just calls
|
||||
authenticate() with the given master address.
|
||||
|
||||
With master_type=func evaluates the current master address from the given
|
||||
module and then calls authenticate().
|
||||
|
||||
With master_type=failover takes the list of masters and loops through them.
|
||||
The first one that allows the minion to connect is used to authenticate() and
|
||||
then returned. If this function is called outside the minions initialisation
|
||||
phase (for example from the minions main event-loop when a master connection
|
||||
loss was detected), 'failed' should be set to True. The current
|
||||
(possibly failed) master will then be removed from the list of masters.
|
||||
'''
|
||||
# check if master_type was altered from its default
|
||||
if opts['master_type'] != 'str':
|
||||
# check for a valid keyword
|
||||
if opts['master_type'] == 'func':
|
||||
# split module and function and try loading the module
|
||||
mod, fun = opts['master'].split('.')
|
||||
try:
|
||||
master_mod = salt.loader.raw_mod(opts, mod, fun)
|
||||
if not master_mod:
|
||||
raise TypeError
|
||||
# we take whatever the module returns as master address
|
||||
opts['master'] = master_mod[mod + '.' + fun]()
|
||||
except TypeError:
|
||||
msg = ('Failed to evaluate master address from '
|
||||
'module \'{0}\''.format(opts['master']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
log.info('Evaluated master from module: {0}'.format(master_mod))
|
||||
|
||||
# if failover is set, master has to be of type list
|
||||
elif opts['master_type'] == 'failover':
|
||||
if isinstance(opts['master'], list):
|
||||
log.info('Got list of available master addresses:'
|
||||
' {0}'.format(opts['master']))
|
||||
if opts['master_shuffle']:
|
||||
shuffle(opts['master'])
|
||||
|
||||
# if failed=True, the minion was previously connected
|
||||
# we're probably called from the minions main-event-loop
|
||||
# because a master connection loss was detected. remove
|
||||
# the possibly failed master from the list of masters.
|
||||
elif failed:
|
||||
log.info('Removing possibly failed master {0} from list of'
|
||||
' masters'.format(opts['master']))
|
||||
# create new list of master with the possibly failed one removed
|
||||
opts['master'] = [x for x in opts['master_list'] if opts['master'] != x]
|
||||
|
||||
else:
|
||||
msg = ('master_type set to \'failover\' but \'master\' '
|
||||
'is not of type list but of type '
|
||||
'{0}'.format(type(opts['master'])))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
else:
|
||||
msg = ('Invalid keyword \'{0}\' for variable '
|
||||
'\'master_type\''.format(opts['master_type']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
|
||||
# if we have a list of masters, loop through them and be
|
||||
# happy with the first one that allows us to connect
|
||||
if isinstance(opts['master'], list):
|
||||
conn = False
|
||||
# shuffle the masters and then loop through them
|
||||
local_masters = copy.copy(opts['master'])
|
||||
|
||||
for master in local_masters:
|
||||
opts['master'] = master
|
||||
opts.update(resolve_dns(opts))
|
||||
super(Minion, self).__init__(opts)
|
||||
|
||||
# make a backup of the master list for later use
|
||||
self.opts['master_list'] = local_masters
|
||||
|
||||
try:
|
||||
if self.authenticate(timeout, safe) != 'full':
|
||||
conn = True
|
||||
break
|
||||
except SaltClientError:
|
||||
msg = ('Master {0} could not be reached, trying '
|
||||
'next master (if any)'.format(opts['master']))
|
||||
log.info(msg)
|
||||
continue
|
||||
|
||||
if not conn:
|
||||
msg = ('No master could be reached or all masters denied '
|
||||
'the minions connection attempt.')
|
||||
log.error(msg)
|
||||
else:
|
||||
return opts['master']
|
||||
|
||||
# single master sign in
|
||||
else:
|
||||
opts.update(resolve_dns(opts))
|
||||
super(Minion, self).__init__(opts)
|
||||
if self.authenticate(timeout, safe) == 'full':
|
||||
msg = ('master {0} rejected the minions connection because too '
|
||||
'many minions are already connected.'.format(opts['master']))
|
||||
log.error(msg)
|
||||
sys.exit(1)
|
||||
else:
|
||||
return opts['master']
|
||||
|
||||
def _prep_mod_opts(self):
|
||||
'''
|
||||
Returns a copy of the opts with key bits stripped out
|
||||
@ -1476,6 +1524,7 @@ class Minion(MinionBase):
|
||||
|
||||
ping_interval = self.opts.get('ping_interval', 0) * 60
|
||||
ping_at = None
|
||||
self.connected = True
|
||||
while self._running is True:
|
||||
loop_interval = self.process_schedule(self, loop_interval)
|
||||
try:
|
||||
@ -1512,9 +1561,46 @@ class Minion(MinionBase):
|
||||
tag, data = salt.utils.event.MinionEvent.unpack(package)
|
||||
log.debug('Forwarding master event tag={tag}'.format(tag=data['tag']))
|
||||
self._fire_master(data['data'], data['tag'], data['events'], data['pretag'])
|
||||
elif package.startswith('__master_disconnect'):
|
||||
log.debug('handling master disconnect')
|
||||
elif package.startswith('__master_disconnected'):
|
||||
# handle this event only once. otherwise it will polute the log
|
||||
if self.connected:
|
||||
log.info('Connection to master {0} lost'.format(self.opts['master']))
|
||||
if self.opts['master_type'] == 'failover':
|
||||
log.info('Trying to tune in to next master from master-list')
|
||||
self.eval_master(opts=self.opts,
|
||||
failed=True)
|
||||
|
||||
# modify the __master_alive job to only fire,
|
||||
# once the connection was re-established
|
||||
schedule = {
|
||||
'function': 'status.master',
|
||||
'seconds': self.opts['master_alive_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2,
|
||||
'kwargs': {'connected': False}
|
||||
}
|
||||
self.schedule.modify_job(name='__master_alive',
|
||||
schedule=schedule)
|
||||
self.connected = False
|
||||
|
||||
elif package.startswith('__master_connected'):
|
||||
# handle this event only once. otherwise it will polute the log
|
||||
if not self.connected:
|
||||
log.info('Connection to master {0} re-established'.format(self.opts['master']))
|
||||
self.connected = True
|
||||
# modify the __master_alive job to only fire,
|
||||
# if the connection is lost again
|
||||
schedule = {
|
||||
'function': 'status.master',
|
||||
'seconds': self.opts['master_alive_interval'],
|
||||
'jid_include': True,
|
||||
'maxrunning': 2,
|
||||
'kwargs': {'connected': True}
|
||||
}
|
||||
|
||||
self.schedule.modify_job(name='__master_alive',
|
||||
schedule=schedule)
|
||||
self.connected = True
|
||||
self.epub_sock.send(package)
|
||||
except Exception:
|
||||
log.debug('Exception while handling events', exc_info=True)
|
||||
|
@ -1223,14 +1223,16 @@ def exec_code(lang, code, cwd=None):
|
||||
|
||||
def run_chroot(root, cmd):
|
||||
'''
|
||||
Chroot into a directory and run a cmd, this routines calls cmd.run_all
|
||||
wrapped in `chroot` with dev and proc mounted in the chroot
|
||||
.. versionadded:: Helium
|
||||
|
||||
This function runs :mod:`cmd.run_all <salt.modules.cmdmod.run_all>` wrapped
|
||||
within a chroot, with dev and proc mounted in the chroot
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' cmd.chroot_run /var/lib/lxc/container_name/rootfs 'sh /tmp/bootstrap.sh'
|
||||
salt '*' cmd.run_chroot /var/lib/lxc/container_name/rootfs 'sh /tmp/bootstrap.sh'
|
||||
'''
|
||||
__salt__['mount.mount'](
|
||||
os.path.join(root, 'dev'),
|
||||
|
@ -11,6 +11,7 @@ import os
|
||||
import salt.utils
|
||||
import salt._compat
|
||||
import salt.syspaths as syspaths
|
||||
import salt.utils.sdb as sdb
|
||||
|
||||
__proxyenabled__ = ['*']
|
||||
|
||||
@ -226,16 +227,20 @@ def get(key, default=''):
|
||||
'''
|
||||
ret = salt.utils.traverse_dict_and_list(__opts__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
return ret
|
||||
return sdb.sdb_get(ret, __opts__)
|
||||
|
||||
ret = salt.utils.traverse_dict_and_list(__grains__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
return ret
|
||||
return sdb.sdb_get(ret, __opts__)
|
||||
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__, key, '_|-')
|
||||
if ret != '_|-':
|
||||
return ret
|
||||
return sdb.sdb_get(ret, __opts__)
|
||||
|
||||
ret = salt.utils.traverse_dict_and_list(__pillar__.get('master', {}), key, '_|-')
|
||||
if ret != '_|-':
|
||||
return ret
|
||||
return sdb.sdb_get(ret, __opts__)
|
||||
|
||||
return default
|
||||
|
||||
|
||||
|
@ -117,6 +117,26 @@ _DEB_CONFIG_BRIDGEING_OPTS = [
|
||||
'pathcost', 'portprio', 'ports',
|
||||
'stp', 'waitport'
|
||||
]
|
||||
_DEB_CONFIG_PPPOE_OPTS = {
|
||||
'user': 'user',
|
||||
'password': 'password',
|
||||
'provider': 'provider',
|
||||
'pppoe_iface': 'pppoe_iface',
|
||||
'noipdefault': 'noipdefault',
|
||||
'usepeerdns': 'usepeerdns',
|
||||
'defaultroute': 'defaultroute',
|
||||
'holdoff': 'holdoff',
|
||||
'maxfail': 'maxfail',
|
||||
'hide-password': 'hide-password',
|
||||
'lcp-echo-interval': 'lcp-echo-interval',
|
||||
'lcp-echo-failure': 'lcp-echo-failure',
|
||||
'connect': 'connect',
|
||||
'noauth': 'noauth',
|
||||
'persist': 'persist',
|
||||
'mtu': 'mtu',
|
||||
'noaccomp': 'noaccomp',
|
||||
}
|
||||
|
||||
_DEB_ROUTES_FILE = '/etc/network/routes'
|
||||
_DEB_NETWORK_FILE = '/etc/network/interfaces'
|
||||
_DEB_NETWORK_DIR = '/etc/network/interfaces.d'
|
||||
@ -126,12 +146,13 @@ _DEB_NETWORK_CONF_FILES = '/etc/modprobe.d'
|
||||
_DEB_NETWORKING_FILE = '/etc/default/networking'
|
||||
_DEB_HOSTNAME_FILE = '/etc/hostname'
|
||||
_DEB_RESOLV_FILE = '/etc/resolv.conf'
|
||||
_DEB_PPP_DIR = '/etc/ppp/peers'
|
||||
|
||||
_CONFIG_TRUE = ['yes', 'on', 'true', '1', True]
|
||||
_CONFIG_FALSE = ['no', 'off', 'false', '0', False]
|
||||
_IFACE_TYPES = [
|
||||
'eth', 'bond', 'alias', 'clone',
|
||||
'ipsec', 'dialup', 'bridge', 'slave', 'vlan',
|
||||
'ipsec', 'dialup', 'bridge', 'slave', 'vlan', 'pppoe',
|
||||
]
|
||||
|
||||
|
||||
@ -339,6 +360,9 @@ def _parse_interfaces():
|
||||
if sline[0] == 'vlan-raw-device':
|
||||
adapters[iface_name]['data'][context]['vlan_raw_device'] = sline[1]
|
||||
|
||||
if sline[0] == 'provider':
|
||||
adapters[iface_name]['data'][context]['provider'] = sline[1]
|
||||
|
||||
if sline[0] in _REV_ETHTOOL_CONFIG_OPTS:
|
||||
ethtool_key = sline[0]
|
||||
if 'ethtool' not in adapters[iface_name]['data'][context]:
|
||||
@ -452,6 +476,38 @@ def _parse_ethtool_opts(opts, iface):
|
||||
return config
|
||||
|
||||
|
||||
def _parse_ethtool_pppoe_opts(opts, iface):
|
||||
'''
|
||||
Filters given options and outputs valid settings for ETHTOOLS_PPPOE_OPTS
|
||||
If an option has a value that is not expected, this
|
||||
function will log what the Interface, Setting and what it was
|
||||
expecting.
|
||||
'''
|
||||
config = {}
|
||||
|
||||
for opt in _DEB_CONFIG_PPPOE_OPTS:
|
||||
if opt in opts:
|
||||
config[opt] = opts[opt]
|
||||
|
||||
if 'provider' in opts:
|
||||
if opts['provider']:
|
||||
pass
|
||||
else:
|
||||
_raise_error_iface(iface, 'provider', _CONFIG_TRUE + _CONFIG_FALSE)
|
||||
|
||||
valid = _CONFIG_TRUE + _CONFIG_FALSE
|
||||
for option in ('noipdefault', 'usepeerdns', 'defaultroute', 'hide-password', 'noauth', 'persist', 'noaccomp'):
|
||||
if option in opts:
|
||||
if opts[option] in _CONFIG_TRUE:
|
||||
config.update({option: 'True'})
|
||||
elif opts[option] in _CONFIG_FALSE:
|
||||
config.update({option: 'False'})
|
||||
else:
|
||||
_raise_error_iface(iface, option, valid)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def _parse_settings_bond(opts, iface):
|
||||
'''
|
||||
Filters given options and outputs valid settings for requested
|
||||
@ -936,6 +992,12 @@ def _parse_settings_eth(opts, iface_type, enabled, iface):
|
||||
if iface_type == 'vlan':
|
||||
adapters[iface]['data']['inet']['vlan_raw_device'] = re.sub(r'\.\d*', '', iface)
|
||||
|
||||
if iface_type == 'pppoe':
|
||||
tmp_ethtool = _parse_ethtool_pppoe_opts(opts, iface)
|
||||
if tmp_ethtool:
|
||||
for item in tmp_ethtool:
|
||||
adapters[iface]['data']['inet'][_DEB_CONFIG_PPPOE_OPTS[item]] = tmp_ethtool[item]
|
||||
|
||||
if iface_type == 'bridge':
|
||||
bridgeing = _parse_bridge_opts(opts, iface)
|
||||
if bridgeing:
|
||||
@ -943,7 +1005,7 @@ def _parse_settings_eth(opts, iface_type, enabled, iface):
|
||||
adapters[iface]['data']['inet']['bridgeing_keys'] = sorted(bridgeing.keys())
|
||||
|
||||
if 'proto' in opts:
|
||||
valid = ['bootp', 'dhcp', 'none', 'static', 'manual', 'loopback']
|
||||
valid = ['bootp', 'dhcp', 'none', 'static', 'manual', 'loopback', 'ppp']
|
||||
if opts['proto'] in valid:
|
||||
# no 'none' proto for Debian, set to static
|
||||
if opts['proto'] == 'none':
|
||||
@ -1188,6 +1250,37 @@ def _write_file_ifaces(iface, data):
|
||||
return saved_ifcfg.split('\n')
|
||||
|
||||
|
||||
def _write_file_ppp_ifaces(iface, data):
|
||||
'''
|
||||
Writes a file to disk
|
||||
'''
|
||||
try:
|
||||
template = JINJA.get_template('debian_ppp_eth.jinja')
|
||||
except jinja2.exceptions.TemplateNotFound:
|
||||
log.error('Could not load template debian_ppp_eth.jinja')
|
||||
return ''
|
||||
|
||||
adapters = _parse_interfaces()
|
||||
adapters[iface] = data
|
||||
|
||||
ifcfg = ''
|
||||
tmp = template.render({'data': adapters[iface]})
|
||||
ifcfg = tmp + ifcfg
|
||||
|
||||
filename = _DEB_PPP_DIR + '/' + adapters[iface]['data']['inet']['provider']
|
||||
if not os.path.exists(os.path.dirname(filename)):
|
||||
msg = '{0} cannot be written.'
|
||||
msg = msg.format(os.path.dirname(filename))
|
||||
log.error(msg)
|
||||
raise AttributeError(msg)
|
||||
fout = salt.utils.fopen(filename, 'w')
|
||||
fout.write(ifcfg)
|
||||
fout.close()
|
||||
|
||||
# Return as a array so the difflib works
|
||||
return filename
|
||||
|
||||
|
||||
def build_bond(iface, **settings):
|
||||
'''
|
||||
Create a bond script in /etc/modprobe.d with the passed settings
|
||||
@ -1259,6 +1352,11 @@ def build_interface(iface, iface_type, enabled, **settings):
|
||||
if iface_type == 'vlan':
|
||||
settings['vlan'] = 'yes'
|
||||
|
||||
if iface_type == 'pppoe':
|
||||
settings['pppoe'] = 'yes'
|
||||
if not __salt__['pkg.version']("ppp"):
|
||||
inst = __salt__['pkg.install']("ppp")
|
||||
|
||||
if iface_type is 'bond':
|
||||
if 'slaves' not in settings:
|
||||
msg = 'slaves is a required setting for bond interfaces'
|
||||
@ -1272,7 +1370,7 @@ def build_interface(iface, iface_type, enabled, **settings):
|
||||
raise AttributeError(msg)
|
||||
__salt__['pkg.install']('bridge-utils')
|
||||
|
||||
if iface_type in ['eth', 'bond', 'bridge', 'slave', 'vlan']:
|
||||
if iface_type in ['eth', 'bond', 'bridge', 'slave', 'vlan', 'pppoe']:
|
||||
opts = _parse_settings_eth(settings, iface_type, enabled, iface)
|
||||
|
||||
if 'test' in settings and settings['test']:
|
||||
@ -1280,6 +1378,9 @@ def build_interface(iface, iface_type, enabled, **settings):
|
||||
|
||||
ifcfg = _write_file_ifaces(iface, opts[iface])
|
||||
|
||||
if iface_type == 'pppoe':
|
||||
_write_file_ppp_ifaces(iface, opts[iface])
|
||||
|
||||
# ensure lines in list end with newline, so difflib works
|
||||
return [item + '\n' for item in ifcfg]
|
||||
|
||||
|
@ -480,6 +480,7 @@ def check(table='filter', chain=None, rule=None, family='ipv4'):
|
||||
if not rule:
|
||||
return 'Error: Rule needs to be specified'
|
||||
|
||||
HAS_CHECK = False
|
||||
if '--check' in salt_cmd.run('iptables --help', output_loglevel='quiet'):
|
||||
HAS_CHECK = True
|
||||
|
||||
|
@ -107,6 +107,8 @@ def purge():
|
||||
schedule.update(__pillar__['schedule'])
|
||||
|
||||
for name in schedule.keys():
|
||||
if name == 'enabled':
|
||||
continue
|
||||
if name.startswith('__'):
|
||||
continue
|
||||
|
||||
|
@ -545,7 +545,7 @@ def version():
|
||||
return ret
|
||||
|
||||
|
||||
def master():
|
||||
def master(connected=True):
|
||||
'''
|
||||
.. versionadded:: Helium
|
||||
|
||||
@ -562,6 +562,11 @@ def master():
|
||||
port = int(__salt__['config.option']('publish_port'))
|
||||
ips = _remote_port_tcp(port)
|
||||
|
||||
if ip not in ips:
|
||||
event = salt.utils.event.get_event('minion', opts=__opts__, listen=False)
|
||||
event.fire_event({'master': ip}, '__master_disconnected')
|
||||
if connected:
|
||||
if ip not in ips:
|
||||
event = salt.utils.event.get_event('minion', opts=__opts__, listen=False)
|
||||
event.fire_event({'master': ip}, '__master_disconnected')
|
||||
else:
|
||||
if ip in ips:
|
||||
event = salt.utils.event.get_event('minion', opts=__opts__, listen=False)
|
||||
event.fire_event({'master': ip}, '__master_connected')
|
||||
|
@ -34,8 +34,9 @@ def echo(text):
|
||||
|
||||
def ping():
|
||||
'''
|
||||
Just used to make sure the minion is up and responding
|
||||
Return True
|
||||
Used to make sure the minion is up and responding. Not an ICMP ping.
|
||||
|
||||
Returns ``True``.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -178,8 +178,12 @@ class SREQ(object):
|
||||
delete socket if you have it
|
||||
'''
|
||||
if hasattr(self, '_socket'):
|
||||
if self._socket in self.poller:
|
||||
self.poller.unregister(self._socket)
|
||||
if isinstance(self.poller.sockets, dict):
|
||||
for socket in self.poller.sockets.keys():
|
||||
self.poller.unregister(socket)
|
||||
else:
|
||||
for socket in self.poller.sockets:
|
||||
self.poller.unregister(socket[0])
|
||||
del self._socket
|
||||
|
||||
def send(self, enc, load, tries=1, timeout=60):
|
||||
|
@ -11,7 +11,7 @@ configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
my_etd_config:
|
||||
my_etcd_config:
|
||||
etcd.host: 127.0.0.1
|
||||
etcd.port: 4001
|
||||
|
||||
|
136
salt/scripts.py
136
salt/scripts.py
@ -8,6 +8,8 @@ from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
|
||||
# Import salt libs
|
||||
import salt
|
||||
@ -21,6 +23,27 @@ except ImportError:
|
||||
HAS_SALTCLOUD = False
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _handle_interrupt(exc, original_exc, hardfail=False, trace=''):
|
||||
'''
|
||||
if hardfalling:
|
||||
If we got the original stacktrace, log it
|
||||
If all cases, raise the original exception
|
||||
but this is logically part the initial
|
||||
stack.
|
||||
else just let salt exit gracefully
|
||||
|
||||
'''
|
||||
if hardfail:
|
||||
if trace:
|
||||
log.error(trace)
|
||||
raise original_exc
|
||||
else:
|
||||
raise exc
|
||||
|
||||
|
||||
def salt_master():
|
||||
'''
|
||||
Start the salt-master.
|
||||
@ -65,11 +88,20 @@ def salt_key():
|
||||
'''
|
||||
Manage the authentication keys with salt-key.
|
||||
'''
|
||||
client = None
|
||||
try:
|
||||
saltkey = salt.cli.SaltKey()
|
||||
saltkey.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
client = salt.cli.SaltKey()
|
||||
client.run()
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_cp():
|
||||
@ -77,11 +109,20 @@ def salt_cp():
|
||||
Publish commands to the salt system from the command line on the
|
||||
master.
|
||||
'''
|
||||
client = None
|
||||
try:
|
||||
cp_ = salt.cli.SaltCP()
|
||||
cp_.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
client = salt.cli.SaltCP()
|
||||
client.run()
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_call():
|
||||
@ -91,11 +132,20 @@ def salt_call():
|
||||
'''
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.SaltCall()
|
||||
client.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_run():
|
||||
@ -104,11 +154,20 @@ def salt_run():
|
||||
'''
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.SaltRun()
|
||||
client.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_ssh():
|
||||
@ -117,13 +176,30 @@ def salt_ssh():
|
||||
'''
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.SaltSSH()
|
||||
client.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
except salt.exceptions.SaltClientError as err:
|
||||
raise SystemExit(err)
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit(err),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_cloud():
|
||||
@ -137,11 +213,20 @@ def salt_cloud():
|
||||
print('salt-cloud is not available in this system')
|
||||
sys.exit(os.EX_UNAVAILABLE)
|
||||
|
||||
client = None
|
||||
try:
|
||||
cloud = salt.cloud.cli.SaltCloud()
|
||||
cloud.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
client = salt.cloud.cli.SaltCloud()
|
||||
client.run()
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
||||
|
||||
def salt_main():
|
||||
@ -151,8 +236,17 @@ def salt_main():
|
||||
'''
|
||||
if '' in sys.path:
|
||||
sys.path.remove('')
|
||||
client = None
|
||||
try:
|
||||
client = salt.cli.SaltCMD()
|
||||
client.run()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit('\nExiting gracefully on Ctrl-c')
|
||||
except KeyboardInterrupt, err:
|
||||
trace = traceback.format_exc()
|
||||
try:
|
||||
hardcrash = client.options.hard_crash
|
||||
except (AttributeError, KeyError):
|
||||
hardcrash = False
|
||||
_handle_interrupt(
|
||||
SystemExit('\nExiting gracefully on Ctrl-c'),
|
||||
err,
|
||||
hardcrash, trace=trace)
|
||||
|
4
salt/sdb/__init__.py
Normal file
4
salt/sdb/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
SDB Module Directory
|
||||
'''
|
98
salt/sdb/keyring_db.py
Normal file
98
salt/sdb/keyring_db.py
Normal file
@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Keyring Database Module
|
||||
|
||||
:maintainer: SaltStack
|
||||
:maturity: New
|
||||
:depends: keyring
|
||||
:platform: all
|
||||
|
||||
This module allows access to the keyring package using an ``sdb://`` URI. This
|
||||
package is located at ``https://pypi.python.org/pypi/keyring``.
|
||||
|
||||
Care must be taken when using keyring. Not all keyend backends are supported on
|
||||
all operating systems. Also, many backends require an agent to be running in
|
||||
order to work. For instance, the "Secret Service" backend requires a compatible
|
||||
agent such as ``gnome-keyring-daemon`` or ``kwallet`` to be running. The
|
||||
keyczar backend does not seem to enjoy the benefits of an agent, and so using
|
||||
it will require either that the password is typed in manually (which is
|
||||
unreasonable for the salt-minion and salt-master daemons, especially in
|
||||
production) or an agent is written for it.
|
||||
|
||||
Like all sdb modules, the keyring module requires a configuration profile to
|
||||
be configured in either the minion or master configuration file. This profile
|
||||
requires very little. In the example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
mykeyring:
|
||||
- driver: keyring
|
||||
- service: system
|
||||
|
||||
The ``driver`` refers to the keyring module, ``service`` refers to the service
|
||||
that will be used inside of keyring (which may be likened unto a database
|
||||
table) and ``mykeyring`` refers to the name that will appear in the URI:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
password: sdb://mykeyring/mypassword
|
||||
|
||||
The underlying backend configuration must be configured via keyring itself. For
|
||||
examples and documentation, see keyring:
|
||||
|
||||
https://pypi.python.org/pypi/keyring
|
||||
|
||||
.. versionadded:: 2014.1.4 (Hydrogen)
|
||||
'''
|
||||
|
||||
# import python libs
|
||||
import logging
|
||||
|
||||
try:
|
||||
import keyring
|
||||
HAS_LIBS = True
|
||||
except ImportError:
|
||||
HAS_LIBS = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
__func_alias__ = {
|
||||
'set_': 'set'
|
||||
}
|
||||
|
||||
__virtualname__ = 'keyring'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load the module if keyring is installed
|
||||
'''
|
||||
if HAS_LIBS:
|
||||
return __virtualname__
|
||||
return False
|
||||
|
||||
|
||||
def set_(key, value, service=None, profile=None):
|
||||
'''
|
||||
Set a key/value pair in a keyring service
|
||||
'''
|
||||
service = _get_service(service, profile)
|
||||
keyring.set_password(service, key, value)
|
||||
|
||||
|
||||
def get(key, service=None, profile=None):
|
||||
'''
|
||||
Get a value from a keyring service
|
||||
'''
|
||||
service = _get_service(service, profile)
|
||||
return keyring.get_password(service, key)
|
||||
|
||||
|
||||
def _get_service(service, profile):
|
||||
'''
|
||||
Get a service name
|
||||
'''
|
||||
if isinstance(profile, dict) and 'service' in profile:
|
||||
return profile['service']
|
||||
|
||||
return service
|
@ -73,6 +73,13 @@ STATE_INTERNAL_KEYWORDS = frozenset([
|
||||
])
|
||||
|
||||
|
||||
def _odict_hashable(self):
|
||||
return id(self)
|
||||
|
||||
|
||||
OrderedDict.__hash__ = _odict_hashable
|
||||
|
||||
|
||||
def split_low_tag(tag):
|
||||
'''
|
||||
Take a low tag and split it back into the low dict that it came from
|
||||
@ -477,9 +484,14 @@ class Compiler(object):
|
||||
chunk.update(arg)
|
||||
if names:
|
||||
name_order = 1
|
||||
for low_name in names:
|
||||
for entry in names:
|
||||
live = copy.deepcopy(chunk)
|
||||
live['name'] = low_name
|
||||
if isinstance(entry, dict):
|
||||
low_name = entry.keys()[0]
|
||||
live['name'] = low_name
|
||||
live.update(entry[low_name][0])
|
||||
else:
|
||||
live['name'] = entry
|
||||
live['name_order'] = name_order
|
||||
name_order = name_order + 1
|
||||
for fun in funcs:
|
||||
@ -1059,9 +1071,14 @@ class State(object):
|
||||
chunk[key] = val
|
||||
if names:
|
||||
name_order = 1
|
||||
for low_name in names:
|
||||
for entry in names:
|
||||
live = copy.deepcopy(chunk)
|
||||
live['name'] = low_name
|
||||
if isinstance(entry, dict):
|
||||
low_name = entry.keys()[0]
|
||||
live['name'] = low_name
|
||||
live.update(entry[low_name][0])
|
||||
else:
|
||||
live['name'] = entry
|
||||
live['name_order'] = name_order
|
||||
name_order = name_order + 1
|
||||
for fun in funcs:
|
||||
|
@ -82,7 +82,6 @@ def managed(name, **kwargs):
|
||||
The name of the package repo, as it would be referred to when running
|
||||
the regular package manager commands.
|
||||
|
||||
|
||||
For yum-based systems, take note of the following configuration values:
|
||||
|
||||
humanname
|
||||
@ -148,8 +147,13 @@ def managed(name, **kwargs):
|
||||
- name: deb http://us.archive.ubuntu.com/ubuntu precise main
|
||||
|
||||
disabled
|
||||
On apt-based systems, disabled toggles whether or not the repo is
|
||||
used for resolving dependencies and/or installing packages
|
||||
Toggles whether or not the repo is used for resolving dependencies
|
||||
and/or installing packages.
|
||||
|
||||
enabled
|
||||
Enables the repository, even if the repository has been disabled, in
|
||||
order for the respective package requiring the repository can be found
|
||||
and installed.
|
||||
|
||||
comps
|
||||
On apt-based systems, comps dictate the types of packages to be
|
||||
|
@ -52,6 +52,9 @@ def __virtual__():
|
||||
|
||||
|
||||
def _enabled_used_error(ret):
|
||||
'''
|
||||
Warn of potential typo.
|
||||
'''
|
||||
ret['result'] = False
|
||||
ret['comment'] = (
|
||||
'Service {0} uses non-existent option "enabled". ' +
|
||||
@ -241,7 +244,9 @@ def _disable(name, started, result=True, **kwargs):
|
||||
|
||||
|
||||
def _available(name, ret):
|
||||
# Check if the service is available
|
||||
'''
|
||||
Check if the service is available
|
||||
'''
|
||||
avail = False
|
||||
if 'service.available' in __salt__:
|
||||
avail = __salt__['service.available'](name)
|
||||
@ -420,8 +425,7 @@ def mod_watch(name, sfun=None, sig=None, reload=False, full_restart=False):
|
||||
|
||||
sfun
|
||||
The original function which triggered the mod_watch call
|
||||
(`service.running`, for example). Currently not used, but must be
|
||||
supported for the future.
|
||||
(`service.running`, for example).
|
||||
|
||||
sig
|
||||
The string to search for when looking for the service process with ps
|
||||
@ -430,31 +434,44 @@ def mod_watch(name, sfun=None, sig=None, reload=False, full_restart=False):
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
action = ''
|
||||
|
||||
if __salt__['service.status'](name, sig):
|
||||
if 'service.reload' in __salt__ and reload:
|
||||
restart_func = __salt__['service.reload']
|
||||
action = 'reload'
|
||||
elif 'service.full_restart' in __salt__ and full_restart:
|
||||
restart_func = __salt__['service.full_restart']
|
||||
action = 'fully restart'
|
||||
if sfun == 'dead':
|
||||
verb = 'stop'
|
||||
past_participle = verb + 'ped'
|
||||
if __salt__['service.status'](name, sig):
|
||||
func = __salt__['service.stop']
|
||||
else:
|
||||
restart_func = __salt__['service.restart']
|
||||
action = 'restart'
|
||||
else:
|
||||
restart_func = __salt__['service.start']
|
||||
action = 'start'
|
||||
ret['result'] = True
|
||||
ret['comment'] = 'Service is already {0}'.format(past_participle)
|
||||
return ret
|
||||
elif sfun == 'running':
|
||||
if __salt__['service.status'](name, sig):
|
||||
if 'service.reload' in __salt__ and reload:
|
||||
func = __salt__['service.reload']
|
||||
verb = 'reload'
|
||||
past_participle = verb + 'ed'
|
||||
elif 'service.full_restart' in __salt__ and full_restart:
|
||||
func = __salt__['service.full_restart']
|
||||
verb = 'fully restart'
|
||||
past_participle = verb + 'ed'
|
||||
else:
|
||||
func = __salt__['service.restart']
|
||||
verb = 'restart'
|
||||
past_participle = verb + 'ed'
|
||||
else:
|
||||
func = __salt__['service.start']
|
||||
verb = 'start'
|
||||
past_participle = verb + 'ed'
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = 'Service is set to be {0}ed'.format(action)
|
||||
ret['comment'] = 'Service is set to be {0}'.format(past_participle)
|
||||
return ret
|
||||
|
||||
result = restart_func(name)
|
||||
result = func(name)
|
||||
|
||||
ret['changes'] = {name: result}
|
||||
ret['result'] = result
|
||||
ret['comment'] = 'Service {0}ed'.format(action) if result else \
|
||||
'Failed to {0} the service'.format(action)
|
||||
ret['comment'] = 'Service {0}'.format(past_participle) if result else \
|
||||
'Failed to {0} the service'.format(verb)
|
||||
return ret
|
||||
|
@ -27,8 +27,13 @@ def _check_error(result, success_message):
|
||||
ret = {}
|
||||
|
||||
if 'ERROR' in result:
|
||||
ret['comment'] = result
|
||||
ret['result'] = False
|
||||
if 'already running' in result:
|
||||
ret['comment'] = success_message
|
||||
elif 'not running' in result:
|
||||
ret['comment'] = success_message
|
||||
else:
|
||||
ret['comment'] = result
|
||||
ret['result'] = False
|
||||
else:
|
||||
ret['comment'] = success_message
|
||||
|
||||
|
@ -9,6 +9,7 @@ iface {{name}} {{interface.inet_type}} {{interface.proto}}
|
||||
{%endif%}{% if interface.gateway %} gateway {{interface.gateway}}
|
||||
{%endif%}{% if interface.addr %} hwaddress {{interface.addr}}
|
||||
{%endif%}{% if interface.vlan_raw_device %} vlan-raw-device {{interface.vlan_raw_device}}
|
||||
{%endif%}{% if interface.provider %} provider {{interface.provider}}
|
||||
{%endif%}{% if interface.mtu %} mtu {{interface.mtu}}
|
||||
{%endif%}{% if interface.dns %} dns-nameservers {%for item in interface.dns %}{{item}} {%endfor%}
|
||||
{%endif%}{% if interface.ethtool %}{%for item in interface.ethtool_keys %} {{item}} {{interface.ethtool[item]}}
|
||||
|
22
salt/templates/debian_ip/debian_ppp_eth.jinja
Normal file
22
salt/templates/debian_ip/debian_ppp_eth.jinja
Normal file
@ -0,0 +1,22 @@
|
||||
{%- set iface = data.data.inet -%}
|
||||
{% if iface['user'] %}user {{ iface['user']}}
|
||||
{% if iface['password']%}password {{ iface['password'] }} {% endif %}
|
||||
plugin rp-pppoe.so {{iface['pppoe_iface']|default('eth0')}}
|
||||
|
||||
{% if iface['noipdefault']|default(True) %}noipdefault{% endif %}
|
||||
{% if iface['usepeerdns']|default(True) %}usepeerdns {% endif %}
|
||||
{% if iface['defaultroute']|default(True) %}defaultroute{% endif %}
|
||||
|
||||
{% if iface['holdoff']|default('15') %}holdoff {{iface['holdoff']|default('15')}}{% endif %}
|
||||
{% if iface['maxfail']|default('0') %}maxfail {{iface['maxfail']|default('0')}}{% endif %}
|
||||
|
||||
{% if iface['hide-password']|default(True) %}hide-password{% endif %}
|
||||
{% if iface['lcp-echo-interval']|default('20') %}lcp-echo-interval {{ iface['lcp-echo-interval']|default('20')}} {% endif %}
|
||||
{% if iface['lcp-echo-failure']|default('3') %}lcp-echo-failure {{iface['lcp-echo-failure']|default('3')}} {% endif %}
|
||||
|
||||
{% if iface['noauth']|default(True) %}noauth{% endif %}
|
||||
{% if iface['persist']|default(True) %}persist{% endif %}
|
||||
{% if iface['mtu']|default('1492') %}mtu {{iface['mtu']|default('1492')}} {% endif %}
|
||||
{% if iface['noaccomp']|default(True) %}noaccomp{% endif %}
|
||||
{% if iface['default-asyncmap'] %}default-asyncmap{% endif %}
|
||||
{% endif %}
|
@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# {{route_type}}
|
||||
{% for route in routes %}{% if route.name %}# {{route.name}}
|
||||
{%endif%}route {{route_type}} -net {% if route.ipaddr %}{{route.ipaddr}}{%endif%} {% if route.netmask %}netmask {{route.netmask}}{%endif%} {% if route.gateway %}gateway {{route.gateway}}{%endif%}dev {{iface}}
|
||||
{%endif%}route {{route_type}} -net {% if route.ipaddr %}{{route.ipaddr}}{%endif%} {% if route.netmask %}netmask {{route.netmask}}{%endif%} {% if route.gateway %}gateway {{route.gateway}}{%endif%} dev {{iface}}
|
||||
{% endfor %}
|
||||
|
@ -62,12 +62,12 @@ class RAETChannel(Channel):
|
||||
'''
|
||||
yid = salt.utils.gen_jid()
|
||||
stackname = self.opts['id'] + yid
|
||||
dirpath = os.path.join(self.opts['cachedir'], stackname)
|
||||
dirpath = os.path.join(self.opts['cachedir'], 'raet')
|
||||
self.stack = LaneStack(
|
||||
name=stackname,
|
||||
lanename=self.opts['id'],
|
||||
yid=yid,
|
||||
dirpath=dirpath,
|
||||
basedirpath=dirpath,
|
||||
sockdirpath=self.opts['sock_dir'])
|
||||
self.stack.Pk = raeting.packKinds.pack
|
||||
self.router_yard = yarding.RemoteYard(
|
||||
@ -93,12 +93,19 @@ class RAETChannel(Channel):
|
||||
'''
|
||||
msg = {'route': self.route, 'load': load}
|
||||
self.stack.transmit(msg, self.stack.uids['yard0'])
|
||||
tried = 1
|
||||
start = time.time()
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
self.stack.serviceAll()
|
||||
if self.stack.rxMsgs:
|
||||
for msg in self.stack.rxMsgs:
|
||||
return msg.get('return', {})
|
||||
if time.time() - start > timeout:
|
||||
if tried >= tries:
|
||||
raise ValueError
|
||||
self.stack.transmit(msg, self.stack.uids['yard0'])
|
||||
tried += 1
|
||||
|
||||
|
||||
class ZeroMQChannel(Channel):
|
||||
|
@ -15,7 +15,7 @@ import subprocess
|
||||
import multiprocessing
|
||||
import logging
|
||||
import pipes
|
||||
import json
|
||||
import msgpack
|
||||
import traceback
|
||||
import copy
|
||||
import re
|
||||
@ -1869,10 +1869,10 @@ def request_minion_cachedir(
|
||||
'provider': provider,
|
||||
}
|
||||
|
||||
fname = '{0}.json'.format(minion_id)
|
||||
fname = '{0}.pp'.format(minion_id)
|
||||
path = os.path.join(base, 'requested', fname)
|
||||
with salt.utils.fopen(path, 'w') as fh_:
|
||||
json.dump(data, fh_)
|
||||
msgpack.dump(data, fh_)
|
||||
|
||||
|
||||
def change_minion_cachedir(
|
||||
@ -1900,16 +1900,16 @@ def change_minion_cachedir(
|
||||
if base is None:
|
||||
base = os.path.join(syspaths.CACHE_DIR, 'cloud')
|
||||
|
||||
fname = '{0}.json'.format(minion_id)
|
||||
fname = '{0}.pp'.format(minion_id)
|
||||
path = os.path.join(base, cachedir, fname)
|
||||
|
||||
with salt.utils.fopen(path, 'r') as fh_:
|
||||
cache_data = json.load(fh_)
|
||||
cache_data = msgpack.load(fh_)
|
||||
|
||||
cache_data.update(data)
|
||||
|
||||
with salt.utils.fopen(path, 'w') as fh_:
|
||||
json.dump(cache_data, fh_)
|
||||
msgpack.dump(cache_data, fh_)
|
||||
|
||||
|
||||
def activate_minion_cachedir(minion_id, base=None):
|
||||
@ -1921,7 +1921,7 @@ def activate_minion_cachedir(minion_id, base=None):
|
||||
if base is None:
|
||||
base = os.path.join(syspaths.CACHE_DIR, 'cloud')
|
||||
|
||||
fname = '{0}.json'.format(minion_id)
|
||||
fname = '{0}.pp'.format(minion_id)
|
||||
src = os.path.join(base, 'requested', fname)
|
||||
dst = os.path.join(base, 'active')
|
||||
shutil.move(src, dst)
|
||||
@ -1940,7 +1940,7 @@ def delete_minion_cachedir(minion_id, provider, opts, base=None):
|
||||
base = os.path.join(syspaths.CACHE_DIR, 'cloud')
|
||||
|
||||
driver = opts['providers'][provider].keys()[0]
|
||||
fname = '{0}.json'.format(minion_id)
|
||||
fname = '{0}.pp'.format(minion_id)
|
||||
for cachedir in ('requested', 'active'):
|
||||
path = os.path.join(base, cachedir, driver, provider, fname)
|
||||
log.debug('path: {0}'.format(path))
|
||||
@ -2079,9 +2079,9 @@ def cache_node_list(nodes, provider, opts):
|
||||
|
||||
for node in nodes:
|
||||
diff_node_cache(prov_dir, node, nodes[node], opts)
|
||||
path = os.path.join(prov_dir, '{0}.json'.format(node))
|
||||
path = os.path.join(prov_dir, '{0}.pp'.format(node))
|
||||
with salt.utils.fopen(path, 'w') as fh_:
|
||||
json.dump(nodes[node], fh_)
|
||||
msgpack.dump(nodes[node], fh_)
|
||||
|
||||
|
||||
def cache_node(node, provider, opts):
|
||||
@ -2101,9 +2101,9 @@ def cache_node(node, provider, opts):
|
||||
prov_dir = os.path.join(base, driver, provider)
|
||||
if not os.path.exists(prov_dir):
|
||||
os.makedirs(prov_dir)
|
||||
path = os.path.join(prov_dir, '{0}.json'.format(node['name']))
|
||||
path = os.path.join(prov_dir, '{0}.pp'.format(node['name']))
|
||||
with salt.utils.fopen(path, 'w') as fh_:
|
||||
json.dump(node, fh_)
|
||||
msgpack.dump(node, fh_)
|
||||
|
||||
|
||||
def missing_node_cache(prov_dir, node_list, provider, opts):
|
||||
@ -2122,7 +2122,7 @@ def missing_node_cache(prov_dir, node_list, provider, opts):
|
||||
'''
|
||||
cached_nodes = []
|
||||
for node in os.listdir(prov_dir):
|
||||
cached_nodes.append(node.replace('.json', ''))
|
||||
cached_nodes.append(node.replace('.pp', ''))
|
||||
|
||||
log.debug(sorted(cached_nodes))
|
||||
log.debug(sorted(node_list))
|
||||
@ -2157,7 +2157,7 @@ def diff_node_cache(prov_dir, node, new_data, opts):
|
||||
return
|
||||
|
||||
path = os.path.join(prov_dir, node)
|
||||
path = '{0}.json'.format(path)
|
||||
path = '{0}.pp'.format(path)
|
||||
|
||||
if not os.path.exists(path):
|
||||
event_data = _strip_cache_events(new_data, opts)
|
||||
@ -2173,7 +2173,7 @@ def diff_node_cache(prov_dir, node, new_data, opts):
|
||||
|
||||
with salt.utils.fopen(path, 'r') as fh_:
|
||||
try:
|
||||
cache_data = json.load(fh_)
|
||||
cache_data = msgpack.load(fh_)
|
||||
except ValueError as exc:
|
||||
log.warning('Cache for {0} was corrupt: Deleting'.format(node))
|
||||
cache_data = {}
|
||||
|
@ -376,6 +376,20 @@ class SaltfileMixIn(object):
|
||||
cli_config[option.dest])
|
||||
|
||||
|
||||
class HardCrashMixin(object):
|
||||
__metaclass__ = MixInMeta
|
||||
_mixin_prio_ = 40
|
||||
_config_filename_ = None
|
||||
|
||||
def _mixin_setup(self):
|
||||
hc = os.environ.get('SALT_HARD_CRASH', False)
|
||||
self.add_option(
|
||||
'--hard-crash', action='store_true', default=hc,
|
||||
help=('Raise any original exception rather than exiting gracefully'
|
||||
' Default: %default')
|
||||
)
|
||||
|
||||
|
||||
class ConfigDirMixIn(object):
|
||||
__metaclass__ = MixInMeta
|
||||
_mixin_prio_ = -10
|
||||
@ -1518,7 +1532,7 @@ class SyndicOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
TimeoutMixIn, ExtendedTargetOptionsMixIn,
|
||||
OutputOptionsMixIn, LogLevelMixIn):
|
||||
OutputOptionsMixIn, LogLevelMixIn, HardCrashMixin):
|
||||
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
@ -1724,7 +1738,8 @@ class SaltCMDOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
|
||||
class SaltCPOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
TimeoutMixIn, TargetOptionsMixIn, LogLevelMixIn):
|
||||
TimeoutMixIn, TargetOptionsMixIn, LogLevelMixIn,
|
||||
HardCrashMixin):
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
description = (
|
||||
@ -1766,7 +1781,8 @@ class SaltCPOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
|
||||
class SaltKeyOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
LogLevelMixIn, OutputOptionsMixIn, RunUserMixin):
|
||||
LogLevelMixIn, OutputOptionsMixIn, RunUserMixin,
|
||||
HardCrashMixin):
|
||||
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
@ -1979,7 +1995,7 @@ class SaltKeyOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
|
||||
class SaltCallOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
LogLevelMixIn, OutputOptionsMixIn):
|
||||
LogLevelMixIn, OutputOptionsMixIn, HardCrashMixin):
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
description = ('Salt call is used to execute module functions locally '
|
||||
@ -2110,7 +2126,7 @@ class SaltCallOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
|
||||
class SaltRunOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
TimeoutMixIn, LogLevelMixIn):
|
||||
TimeoutMixIn, LogLevelMixIn, HardCrashMixin):
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
default_timeout = 1
|
||||
@ -2172,7 +2188,7 @@ class SaltRunOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
|
||||
class SaltSSHOptionParser(OptionParser, ConfigDirMixIn, MergeConfigMixIn,
|
||||
LogLevelMixIn, TargetOptionsMixIn,
|
||||
OutputOptionsMixIn, SaltfileMixIn):
|
||||
OutputOptionsMixIn, SaltfileMixIn, HardCrashMixin):
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
usage = '%prog [options]'
|
||||
@ -2313,7 +2329,8 @@ class SaltCloudParser(OptionParser,
|
||||
CloudQueriesMixIn,
|
||||
ExecutionOptionsMixIn,
|
||||
CloudProvidersListsMixIn,
|
||||
CloudCredentialsMixIn):
|
||||
CloudCredentialsMixIn,
|
||||
HardCrashMixin):
|
||||
|
||||
__metaclass__ = OptionParserMeta
|
||||
|
||||
|
@ -319,6 +319,9 @@ class Schedule(object):
|
||||
Reload the schedule from saved schedule file.
|
||||
'''
|
||||
|
||||
# Remove all jobs from self.intervals
|
||||
self.intervals = {}
|
||||
|
||||
if 'schedule' in self.opts:
|
||||
self.opts['schedule'].update(schedule['schedule'])
|
||||
else:
|
||||
|
60
salt/utils/sdb.py
Normal file
60
salt/utils/sdb.py
Normal file
@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Basic functions for accessing the SDB interface
|
||||
'''
|
||||
import salt.loader
|
||||
from salt._compat import string_types
|
||||
|
||||
|
||||
def sdb_get(uri, opts):
|
||||
'''
|
||||
Get a value from a db, using a uri in the form of sdb://<profile>/<key>. If
|
||||
the uri provided does not start with sdb://, then it will be returned as-is.
|
||||
'''
|
||||
if not isinstance(uri, string_types):
|
||||
return uri
|
||||
|
||||
if not uri.startswith('sdb://'):
|
||||
return uri
|
||||
|
||||
comps = uri.replace('sdb://', '').split('/')
|
||||
|
||||
if len(comps) < 2:
|
||||
return uri
|
||||
|
||||
profile = opts.get(comps[0], {})
|
||||
if 'driver' not in profile:
|
||||
return uri
|
||||
|
||||
fun = '{0}.get'.format(profile['driver'])
|
||||
query = comps[1]
|
||||
|
||||
loaded_db = salt.loader.sdb(opts, fun)
|
||||
return loaded_db[fun](query, profile=profile)
|
||||
|
||||
|
||||
def sdb_set(uri, value, opts):
|
||||
'''
|
||||
Get a value from a db, using a uri in the form of sdb://<profile>/<key>. If
|
||||
the uri provided does not start with sdb://, then it will be returned as-is.
|
||||
'''
|
||||
if not isinstance(uri, string_types):
|
||||
return uri
|
||||
|
||||
if not uri.startswith('sdb://'):
|
||||
return False
|
||||
|
||||
comps = uri.replace('sdb://', '').split('/')
|
||||
|
||||
if len(comps) < 2:
|
||||
return False
|
||||
|
||||
profile = opts.get(comps[0], {})
|
||||
if 'driver' not in profile:
|
||||
return False
|
||||
|
||||
fun = '{0}.set'.format(profile['driver'])
|
||||
query = comps[1]
|
||||
|
||||
loaded_db = salt.loader.sdb(opts, fun)
|
||||
return loaded_db[fun](query, value, profile=profile)
|
286
setup.py
286
setup.py
@ -18,9 +18,11 @@ from datetime import datetime
|
||||
from distutils import log
|
||||
from distutils.cmd import Command
|
||||
from distutils.command.build import build
|
||||
from distutils.command.check import check
|
||||
from distutils.command.clean import clean
|
||||
from distutils.command.sdist import sdist
|
||||
from distutils.command.install_lib import install_lib
|
||||
from distutils.dist import Distribution as BaseDistribution
|
||||
# pylint: enable=E0611
|
||||
|
||||
try:
|
||||
@ -63,6 +65,7 @@ WITH_SETUPTOOLS = False
|
||||
if 'USE_SETUPTOOLS' in os.environ or 'setuptools' in sys.modules:
|
||||
try:
|
||||
from setuptools import setup
|
||||
from setuptools.dist import Distribution as BaseDistribution
|
||||
from setuptools.command.install import install
|
||||
from setuptools.command.sdist import sdist
|
||||
WITH_SETUPTOOLS = True
|
||||
@ -92,17 +95,11 @@ try:
|
||||
except ImportError:
|
||||
HAS_ESKY = False
|
||||
|
||||
SALT_VERSION = os.path.join(
|
||||
os.path.abspath(SETUP_DIRNAME), 'salt', 'version.py'
|
||||
)
|
||||
|
||||
SALT_REQS = os.path.join(
|
||||
os.path.abspath(SETUP_DIRNAME), 'requirements.txt'
|
||||
)
|
||||
|
||||
SALT_SYSPATHS = os.path.join(
|
||||
os.path.abspath(SETUP_DIRNAME), 'salt', 'syspaths.py'
|
||||
)
|
||||
SALT_VERSION = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', 'version.py')
|
||||
SALT_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), '_requirements.txt')
|
||||
SALT_ZEROMQ_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'zeromq-requirements.txt')
|
||||
SALT_RAET_REQS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'raet-requirements.txt')
|
||||
SALT_SYSPATHS = os.path.join(os.path.abspath(SETUP_DIRNAME), 'salt', 'syspaths.py')
|
||||
|
||||
# pylint: disable=W0122
|
||||
exec(compile(open(SALT_VERSION).read(), SALT_VERSION, 'exec'))
|
||||
@ -110,12 +107,24 @@ exec(compile(open(SALT_SYSPATHS).read(), SALT_SYSPATHS, 'exec'))
|
||||
# pylint: enable=W0122
|
||||
|
||||
|
||||
# ----- Helper Functions -------------------------------------------------------------------------------------------->
|
||||
def _parse_requirements_file(requirements_file):
|
||||
parsed_requirements = []
|
||||
with open(requirements_file) as rfh:
|
||||
for line in rfh.readlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith(('#', '-r')):
|
||||
continue
|
||||
if IS_WINDOWS_PLATFORM and 'libcloud' in line:
|
||||
continue
|
||||
parsed_requirements.append(line)
|
||||
return parsed_requirements
|
||||
# <---- Helper Functions ---------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# ----- Custom Distutils/Setuptools Commands ------------------------------------------------------------------------>
|
||||
class CloudSdist(sdist):
|
||||
user_options = sdist.user_options + [
|
||||
('skip-bootstrap-download', None,
|
||||
'[DEPRECATED] Skip downloading the bootstrap-salt.sh script. This '
|
||||
'can also be triggered by having `SKIP_BOOTSTRAP_DOWNLOAD=1` as an '
|
||||
'environment variable.'),
|
||||
('download-bootstrap-script', None,
|
||||
'Download the latest stable bootstrap-salt.sh script. This '
|
||||
'can also be triggered by having `DOWNLOAD_BOOTSTRAP_SCRIPT=1` as an '
|
||||
@ -123,21 +132,15 @@ class CloudSdist(sdist):
|
||||
|
||||
]
|
||||
boolean_options = sdist.boolean_options + [
|
||||
'skip-bootstrap-download',
|
||||
'download-bootstrap-script'
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
sdist.initialize_options(self)
|
||||
self.skip_bootstrap_download = True
|
||||
self.download_bootstrap_script = False
|
||||
|
||||
def finalize_options(self):
|
||||
sdist.finalize_options(self)
|
||||
if 'SKIP_BOOTSTRAP_DOWNLOAD' in os.environ:
|
||||
log('Please stop using \'SKIP_BOOTSTRAP_DOWNLOAD\' and use '
|
||||
'\'DOWNLOAD_BOOTSTRAP_SCRIPT\' instead')
|
||||
|
||||
if 'DOWNLOAD_BOOTSTRAP_SCRIPT' in os.environ:
|
||||
download_bootstrap_script = os.environ.get(
|
||||
'DOWNLOAD_BOOTSTRAP_SCRIPT', '0'
|
||||
@ -154,7 +157,6 @@ class CloudSdist(sdist):
|
||||
BOOTSTRAP_SCRIPT_DISTRIBUTED_VERSION
|
||||
)
|
||||
)
|
||||
req = urllib2.urlopen(url)
|
||||
deploy_path = os.path.join(
|
||||
SETUP_DIRNAME,
|
||||
'salt',
|
||||
@ -162,28 +164,45 @@ class CloudSdist(sdist):
|
||||
'deploy',
|
||||
'bootstrap-salt.sh'
|
||||
)
|
||||
if req.getcode() == 200:
|
||||
try:
|
||||
log.info(
|
||||
'Updating bootstrap-salt.sh.'
|
||||
'\n\tSource: {0}'
|
||||
'\n\tDestination: {1}'.format(
|
||||
url,
|
||||
deploy_path
|
||||
log.info(
|
||||
'Updating bootstrap-salt.sh.'
|
||||
'\n\tSource: {0}'
|
||||
'\n\tDestination: {1}'.format(
|
||||
url,
|
||||
deploy_path
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
import requests
|
||||
req = requests.get(url)
|
||||
if req.status_code == 200:
|
||||
script_contents = req.text.encode(req.encoding)
|
||||
else:
|
||||
log.error(
|
||||
'Failed to update the bootstrap-salt.sh script. HTTP '
|
||||
'Error code: {0}'.format(
|
||||
req.status_code
|
||||
)
|
||||
)
|
||||
with open(deploy_path, 'w') as fp_:
|
||||
fp_.write(req.read())
|
||||
except (OSError, IOError) as err:
|
||||
except ImportError:
|
||||
req = urllib2.urlopen(url)
|
||||
|
||||
if req.getcode() == 200:
|
||||
script_contents = req.read()
|
||||
else:
|
||||
log.error(
|
||||
'Failed to write the updated script: {0}'.format(err)
|
||||
'Failed to update the bootstrap-salt.sh script. HTTP '
|
||||
'Error code: {0}'.format(
|
||||
req.getcode()
|
||||
)
|
||||
)
|
||||
else:
|
||||
try:
|
||||
with open(deploy_path, 'w') as fp_:
|
||||
fp_.write(script_contents)
|
||||
except (OSError, IOError) as err:
|
||||
log.error(
|
||||
'Failed to update the bootstrap-salt.sh script. HTTP '
|
||||
'Error code: {0}'.format(
|
||||
req.getcode()
|
||||
)
|
||||
'Failed to write the updated script: {0}'.format(err)
|
||||
)
|
||||
|
||||
# Let's the rest of the build command
|
||||
@ -403,32 +422,122 @@ class InstallLib(install_lib):
|
||||
os.chmod(filename, 0755)
|
||||
|
||||
|
||||
class Check(check):
|
||||
'''
|
||||
Since check is always executed, or at least on most of the commands we use
|
||||
we simply override it to adapt the install_requires distribution parameter
|
||||
based on the chosen salt transport
|
||||
'''
|
||||
def run(self):
|
||||
if self.distribution.salt_transport == 'zeromq':
|
||||
self.distribution.install_requires.extend(_parse_requirements_file(SALT_ZEROMQ_REQS))
|
||||
elif self.distribution.salt_transport == 'raet':
|
||||
self.distribution.install_requires.extend(_parse_requirements_file(SALT_RAET_REQS))
|
||||
return check.run(self)
|
||||
# <---- Custom Distutils/Setuptools Commands -------------------------------------------------------------------------
|
||||
|
||||
|
||||
class SaltDistribution(BaseDistribution):
|
||||
|
||||
global_options = BaseDistribution.global_options + [
|
||||
('salt-transport=', None,
|
||||
'The transport to prepare salt for. Choices are \'zeromq\' '
|
||||
'and \'raet\'. Defaults to \'zeromq\''),
|
||||
]
|
||||
|
||||
def __init__(self, attrs=None):
|
||||
BaseDistribution.__init__(self, attrs=attrs)
|
||||
|
||||
# At this point options haven't been parsed yet. Provide defaults
|
||||
self.salt_transport = 'zeromq'
|
||||
|
||||
# This flag is required to tweak the salt paths at install time
|
||||
self.running_salt_install = False
|
||||
|
||||
self.cmdclass['check'] = Check
|
||||
self.cmdclass['test'] = TestCommand
|
||||
self.cmdclass['clean'] = Clean
|
||||
self.cmdclass['build'] = Build
|
||||
self.cmdclass['install'] = Install
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
self.cmdclass['sdist'] = CloudSdist
|
||||
self.cmdclass['install_lib'] = InstallLib
|
||||
|
||||
self.setup_requires = ['requests']
|
||||
self.install_requires = _parse_requirements_file(SALT_REQS)
|
||||
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
# self.packages.extend(['salt.cloud',
|
||||
# 'salt.cloud.clouds'])
|
||||
self.package_data['salt.cloud'] = ['deploy/*.sh']
|
||||
|
||||
self.data_files[0][1].extend([
|
||||
'doc/man/salt-master.1',
|
||||
'doc/man/salt-key.1',
|
||||
'doc/man/salt.1',
|
||||
'doc/man/salt-syndic.1',
|
||||
'doc/man/salt-run.1',
|
||||
'doc/man/salt-ssh.1',
|
||||
'doc/man/salt-cloud.1'
|
||||
])
|
||||
else:
|
||||
self.install_requires.append('WMI')
|
||||
|
||||
if WITH_SETUPTOOLS:
|
||||
self.entry_points = {
|
||||
'console_scripts': ['salt-call = salt.scripts:salt_call',
|
||||
'salt-cp = salt.scripts:salt_cp',
|
||||
'salt-minion = salt.scripts:salt_minion',
|
||||
]
|
||||
}
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
self.entry_points['console_scripts'].extend([
|
||||
'salt = salt.scripts:salt_main',
|
||||
'salt-cloud = salt.scripts:salt_cloud',
|
||||
'salt-key = salt.scripts:salt_key',
|
||||
'salt-master = salt.scripts:salt_master',
|
||||
'salt-run = salt.scripts:salt_run',
|
||||
'salt-ssh = salt.scripts:salt_ssh',
|
||||
'salt-syndic = salt.scripts:salt_syndic',
|
||||
])
|
||||
|
||||
# Required for running the tests suite
|
||||
self.dependency_links = [
|
||||
'https://github.com/saltstack/salt-testing/tarball/develop#egg=SaltTesting'
|
||||
]
|
||||
self.tests_require = ['SaltTesting']
|
||||
else:
|
||||
self.scripts = [
|
||||
'scripts/salt-call',
|
||||
'scripts/salt-cp',
|
||||
'scripts/salt-minion',
|
||||
'scripts/salt-unity',
|
||||
]
|
||||
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
self.scripts.extend([
|
||||
'scripts/salt',
|
||||
'scripts/salt-cloud',
|
||||
'scripts/salt-key',
|
||||
'scripts/salt-master',
|
||||
'scripts/salt-run',
|
||||
'scripts/salt-ssh',
|
||||
'scripts/salt-syndic',
|
||||
])
|
||||
|
||||
|
||||
NAME = 'salt'
|
||||
VER = __version__ # pylint: disable=E0602
|
||||
DESC = ('Portable, distributed, remote execution and '
|
||||
'configuration management system')
|
||||
DESC = 'Portable, distributed, remote execution and configuration management system'
|
||||
|
||||
REQUIREMENTS = []
|
||||
with open(SALT_REQS) as rfh:
|
||||
for line in rfh.readlines():
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
if IS_WINDOWS_PLATFORM and 'libcloud' in line:
|
||||
continue
|
||||
REQUIREMENTS.append(line.strip())
|
||||
|
||||
SETUP_KWARGS = {'name': NAME,
|
||||
SETUP_KWARGS = {'distclass': SaltDistribution,
|
||||
'name': NAME,
|
||||
'version': VER,
|
||||
'description': DESC,
|
||||
'author': 'Thomas S Hatch',
|
||||
'author_email': 'thatch45@gmail.com',
|
||||
'url': 'http://saltstack.org',
|
||||
'cmdclass': {
|
||||
'test': TestCommand,
|
||||
'clean': Clean,
|
||||
'build': Build,
|
||||
'install': Install
|
||||
},
|
||||
'license': 'Apache Software License, Version 2.0',
|
||||
'classifiers': ['Programming Language :: Python',
|
||||
'Programming Language :: Cython',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
@ -500,29 +609,11 @@ SETUP_KWARGS = {'name': NAME,
|
||||
['doc/man/salt.7',
|
||||
]),
|
||||
],
|
||||
# Required for esky builds
|
||||
'install_requires': REQUIREMENTS,
|
||||
# The dynamic module loading in salt.modules makes this
|
||||
# package zip unsafe. Required for esky builds
|
||||
'zip_safe': False
|
||||
}
|
||||
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
SETUP_KWARGS['cmdclass']['sdist'] = CloudSdist
|
||||
SETUP_KWARGS['cmdclass']['install_lib'] = InstallLib
|
||||
#SETUP_KWARGS['packages'].extend(['salt.cloud',
|
||||
# 'salt.cloud.clouds'])
|
||||
SETUP_KWARGS['package_data']['salt.cloud'] = ['deploy/*.sh']
|
||||
SETUP_KWARGS['data_files'][0][1].extend([
|
||||
'doc/man/salt-master.1',
|
||||
'doc/man/salt-key.1',
|
||||
'doc/man/salt.1',
|
||||
'doc/man/salt-syndic.1',
|
||||
'doc/man/salt-run.1',
|
||||
'doc/man/salt-ssh.1',
|
||||
'doc/man/salt-cloud.1'
|
||||
])
|
||||
|
||||
|
||||
# bbfreeze explicit includes
|
||||
# Sometimes the auto module traversal doesn't find everything, so we
|
||||
@ -575,7 +666,6 @@ if IS_WINDOWS_PLATFORM:
|
||||
'site',
|
||||
'psutil',
|
||||
])
|
||||
SETUP_KWARGS['install_requires'].append('WMI')
|
||||
elif sys.platform.startswith('linux'):
|
||||
FREEZER_INCLUDES.append('spwd')
|
||||
try:
|
||||
@ -590,10 +680,10 @@ elif sys.platform.startswith('sunos'):
|
||||
try:
|
||||
from bbfreeze.modulegraph.modulegraph import ModuleGraph
|
||||
mf = ModuleGraph(sys.path[:])
|
||||
for arg in glob.glob("salt/modules/*.py"):
|
||||
for arg in glob.glob('salt/modules/*.py'):
|
||||
mf.run_script(arg)
|
||||
for mod in mf.flatten():
|
||||
if type(mod).__name__ != "Script" and mod.filename:
|
||||
if type(mod).__name__ != 'Script' and mod.filename:
|
||||
FREEZER_INCLUDES.append(str(os.path.basename(mod.identifier)))
|
||||
except ImportError:
|
||||
pass
|
||||
@ -610,46 +700,6 @@ if HAS_ESKY:
|
||||
}
|
||||
SETUP_KWARGS['options'] = OPTIONS
|
||||
|
||||
if WITH_SETUPTOOLS:
|
||||
SETUP_KWARGS['entry_points'] = {
|
||||
'console_scripts': ['salt-call = salt.scripts:salt_call',
|
||||
'salt-cp = salt.scripts:salt_cp',
|
||||
'salt-minion = salt.scripts:salt_minion',
|
||||
]
|
||||
}
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
SETUP_KWARGS['entry_points']['console_scripts'].extend([
|
||||
'salt = salt.scripts:salt_main',
|
||||
'salt-cloud = salt.scripts:salt_cloud',
|
||||
'salt-key = salt.scripts:salt_key',
|
||||
'salt-master = salt.scripts:salt_master',
|
||||
'salt-run = salt.scripts:salt_run',
|
||||
'salt-ssh = salt.scripts:salt_ssh',
|
||||
'salt-syndic = salt.scripts:salt_syndic',
|
||||
])
|
||||
|
||||
# Required for running the tests suite
|
||||
SETUP_KWARGS['dependency_links'] = [
|
||||
'https://github.com/saltstack/salt-testing/tarball/develop#egg=SaltTesting'
|
||||
]
|
||||
SETUP_KWARGS['tests_require'] = ['SaltTesting']
|
||||
else:
|
||||
SETUP_KWARGS['scripts'] = ['scripts/salt-call',
|
||||
'scripts/salt-cp',
|
||||
'scripts/salt-minion',
|
||||
'scripts/salt-unity',
|
||||
]
|
||||
|
||||
if IS_WINDOWS_PLATFORM is False:
|
||||
SETUP_KWARGS['scripts'].extend([
|
||||
'scripts/salt',
|
||||
'scripts/salt-cloud',
|
||||
'scripts/salt-key',
|
||||
'scripts/salt-master',
|
||||
'scripts/salt-run',
|
||||
'scripts/salt-ssh',
|
||||
'scripts/salt-syndic',
|
||||
])
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup(**SETUP_KWARGS)
|
||||
|
@ -129,14 +129,14 @@ class GitFSTest(integration.ModuleCase):
|
||||
with patch.dict(gitfs.__opts__, {'cachedir': self.master_opts['cachedir'],
|
||||
'gitfs_remotes': ['file://' + self.tmp_repo_git],
|
||||
'sock_dir': self.master_opts['sock_dir'],
|
||||
'hash_type': 'blob_sha1'}):
|
||||
'hash_type': 'sha1'}):
|
||||
tmp_load = LOAD.copy()
|
||||
tmp_load['loc'] = 0
|
||||
tmp_load['path'] = 'testfile'
|
||||
fnd = {'rel': 'testfile',
|
||||
'path': 'testfile'}
|
||||
ret = gitfs.file_hash(tmp_load, fnd)
|
||||
self.assertDictEqual({'hash_type': 'blob_sha1', 'hsum': '0d234303e6451128d756c5c259175de37d767742'}, ret)
|
||||
self.assertDictEqual({'hash_type': 'sha1', 'hsum': '6b18d04b61238ba13b5e4626b13ac5fb7432b5e2'}, ret)
|
||||
|
||||
def test_serve_file(self):
|
||||
with patch.dict(gitfs.__opts__, {'cachedir': self.master_opts['cachedir'],
|
||||
|
1273
tests/jenkins-ng.py
Executable file
1273
tests/jenkins-ng.py
Executable file
File diff suppressed because it is too large
Load Diff
5
zeromq-requirements.txt
Normal file
5
zeromq-requirements.txt
Normal file
@ -0,0 +1,5 @@
|
||||
-r _requirements.txt
|
||||
|
||||
M2Crypto
|
||||
pycrypto
|
||||
pyzmq >= 2.2.0
|
Loading…
Reference in New Issue
Block a user