diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..9881f4bfa --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +branches: + only: + - master + + +before_install: + - sudo apt-get update -qq + - sudo apt-get install -y python-sqlalchemy python-mysqldb python-twisted-web python-ldap python-gobject xsltproc docbook-xsl + +install: sh -c ' cd core && sh autogen.sh && ./configure && make && sudo make install && cd ../pulse2 && sh autogen.sh && ./configure && make && sudo make install ' + +script: + - echo "DONE" + +notifications: + email: + recipients: + - nicolas.lecureuil@siveo.net + on_success: change + on_failure: always + irc: + channels: + - "irc01.siveo.net#main" + on_success: always #|never|change] # default: always + on_failure: always #|never|change] # default: always diff --git a/README.md b/README.md index 09ec05cb2..13af7819f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,22 @@ -## Mandriva Management Console ## +## Pulse - IT Infrastructure Management Software ## -This repository is the place where you will find **Mandriva Directory Server** and **Mandriva Pulse** projects. -Both share the same framework: **Mandriva Management Console**, this is why you have to install the core part first. + + Documentation Status + + + Compilation Status + + +This repository is the place where you will find **Directory Server** and **Pulse** projects. +Both share the same framework: **IT Infrastructure Management Software**, this is why you have to install the core part first. Read INSTALL files of each project for installation instructions. + +Documentation : http://pulse-automation-tools.readthedocs.org/ + +IRC Chat + +You can start a conversation with our comunity here. If you have any problem, or any question, do not hesitate! We are friendly. + +server : irc.freenode.net +channel : #pulse-fr, #pulse-en diff --git a/core/agent/init/mmc-agent.in b/core/agent/init/mmc-agent.in index 1316ef88c..cdd8d57db 100755 --- a/core/agent/init/mmc-agent.in +++ b/core/agent/init/mmc-agent.in @@ -31,7 +31,7 @@ # description: MMC agent # Variables -DESC="Mandriva Management Console : mmc-agent" +DESC="Management Console : mmc-agent" DAEMON="@sbindir@/mmc-agent" PIDFILE="@localstatedir@/run/mmc-agent.pid" diff --git a/core/agent/mmc/core/audit/writers.py b/core/agent/mmc/core/audit/writers.py index 1651446d8..052947587 100644 --- a/core/agent/mmc/core/audit/writers.py +++ b/core/agent/mmc/core/audit/writers.py @@ -23,6 +23,8 @@ """ Contains singleton classes that writes to the audit backend """ +# standard modules +import time import socket import sys @@ -360,6 +362,7 @@ def _initTablesmysqlV2(self): """ Init MySQL table for audit database version 2 """ + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") self.module_table = Table("module", self.metadata, Column("id", Integer, primary_key=True), Column("name", String(15), nullable=False), @@ -431,7 +434,7 @@ def _initTablesmysqlV2(self): self.record_table=Table("record", self.metadata, Column("id", Integer, primary_key=True), - Column("date", DateTime , default=func.now(), nullable=False), + Column("date", DateTime , default=nowsystem, nullable=False), Column("result", Boolean, nullable=False), Column("initiator_id", Integer, ForeignKey('initiator.id'), nullable=False), Column("source_id", Integer, ForeignKey('source.id'), nullable=False), @@ -446,6 +449,7 @@ def _initTablespostgresV2(self): FIXME: to check PostgreSQL db tables for audit database version 2 """ + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") self.module_table = Table("module", self.metadata, Column("id", Integer, primary_key=True), Column("name", String(15), nullable=False) @@ -507,7 +511,7 @@ def _initTablespostgresV2(self): self.record_table=Table("record", self.metadata, Column("id", Integer, primary_key=True), - Column("date", DateTime, default=func.now(), nullable=False), + Column("date", DateTime, default=nowsystem, nullable=False), Column("result", Boolean, nullable=False), Column("initiator_id", Integer, ForeignKey('initiator.id'), nullable=False), Column("source_id", Integer, ForeignKey('source.id')), diff --git a/core/agent/mmc/database/database_helper.py b/core/agent/mmc/database/database_helper.py index 325beddfd..84a23b74d 100644 --- a/core/agent/mmc/database/database_helper.py +++ b/core/agent/mmc/database/database_helper.py @@ -33,7 +33,10 @@ from sqlalchemy import func from sqlalchemy.orm import sessionmaker, Query from sqlalchemy.exc import NoSuchTableError -from sqlalchemy.orm.util import _entity_descriptor +try: + from sqlalchemy.orm.util import _entity_descriptor +except ImportError: + from sqlalchemy.orm.base import _entity_descriptor Session = sessionmaker() logger = logging.getLogger() diff --git a/core/agent/mmc/database/sqlalchemy_tests.py b/core/agent/mmc/database/sqlalchemy_tests.py index 961725089..1f1ef834c 100644 --- a/core/agent/mmc/database/sqlalchemy_tests.py +++ b/core/agent/mmc/database/sqlalchemy_tests.py @@ -20,15 +20,16 @@ # along with Pulse 2; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. - +from distutils.version import StrictVersion from sqlalchemy import __version__ MIN_VERSION = '0.6.3' # Debian Squeeze version -MAX_VERSION = '0.7.9' # Debian Jessie version +MAX_VERSION = '0.9.8' # Debian Jessie version CUR_VERSION = __version__ def checkSqlalchemy(): - if MIN_VERSION <= CUR_VERSION <= MAX_VERSION: + #if MIN_VERSION <= CUR_VERSION <= MAX_VERSION: + if StrictVersion(MIN_VERSION) <= StrictVersion(CUR_VERSION) <= StrictVersion(MAX_VERSION) : return True else: return False diff --git a/core/agent/mmc/plugins/base/__init__.py b/core/agent/mmc/plugins/base/__init__.py index ad9b1b674..21023b6e9 100644 --- a/core/agent/mmc/plugins/base/__init__.py +++ b/core/agent/mmc/plugins/base/__init__.py @@ -2376,7 +2376,7 @@ def getRestrictedComputersListLen(self, ctx, filt): """ return len(self.getComputersList(filt)) - def getRestrictedComputersList(self, ctx, min, max, filt, advanced): + def getRestrictedComputersList(self, ctx, min, max, filt, advanced, justid): """ we can't do that directly in ldap, so we do it in python, just to return less xml... """ @@ -2563,9 +2563,9 @@ def getRestrictedComputersListLen(self, filt = None): ctx = self.currentContext return xmlrpcCleanup(ComputerManager().getRestrictedComputersListLen(ctx, filt)) - def getRestrictedComputersList(self, min = 0, max = -1, filt = None, advanced = True): + def getRestrictedComputersList(self, min = 0, max = -1, filt = None, advanced = True, justid=False): ctx = self.currentContext - return xmlrpcCleanup(ComputerManager().getRestrictedComputersList(ctx, min, max, filt, advanced)) + return xmlrpcCleanup(ComputerManager().getRestrictedComputersList(ctx, min, max, filt, advanced, justid)) def getComputerCount(self, filt = {}): ctx = self.currentContext diff --git a/core/agent/mmc/plugins/base/externalldap.py b/core/agent/mmc/plugins/base/externalldap.py index 3bde013a7..c77c9bcb1 100644 --- a/core/agent/mmc/plugins/base/externalldap.py +++ b/core/agent/mmc/plugins/base/externalldap.py @@ -169,13 +169,18 @@ def readConf(self): if option.startswith(PROFILEACL): self.profilesAcl[option.replace(PROFILEACL, "").lower()] = self.get(self.section, option) + PROFILEENTITY = 'profile_entity_' + for option in self.options(self.section): + if option.startswith(PROFILEENTITY): + self.profilesEntity[option.replace(PROFILEENTITY, '').lower()] = self.get(self.section, option) + def setDefault(self): ProvisionerConfig.setDefault(self) self.profileAttr = None self.profilesAcl = {} self.profileGroupMapping = False self.profileGroupPrefix = "" - + self.profilesEntity = {} class ExternalLdapProvisioner(ProvisionerI): """ @@ -206,6 +211,58 @@ def doProvisioning(self, authtoken): self.logger.info("No profile information for user %s in attribute %s" % (uid, self.config.profileAttr)) profile = "" profile = profile.strip() + + try: + entities = self.config.profilesEntity[profile].split() + self.logger.info("*******ENTITE '%s' " % (entities)) + except KeyError: + if self.config.profilesEntity.has_key("default"): + entities = self.config.profilesEntity["default"].split() + self.logger.info("Set the default profile to user.") + profile = 'default' + else: + self.logger.info("No entity defined in configuration file for profile '%s'" % profile) + self.logger.info("Setting user's entity to empty") + entities = [] + if profile and entities: + tmp = [] + for entity in entities: + if entity.startswith('%') and entity.endswith('%'): + attr = entity.strip('%') + if attr in userentry: + tmp.extend(userentry[attr]) + else: + self.logger.info("The user '%s' doesn't have an attribute '%s'" % (uid, attr)) + + elif entity.startswith('plugin:'): + plugin = entity.replace('plugin:', '') + searchpath = os.path.join(os.path.dirname(__file__), 'provisioning_plugins') + try: + f, p, d = imp.find_module(plugin, [searchpath]) + mod = imp.load_module(plugin, f, p, d) + klass = mod.PluginEntities + found = klass().get(authtoken) + if found: + self.logger.info("Plugin '%s' found these entities: %s" % (plugin, found)) + else: + self.logger.info("Plugin '%s' found no matching entity" % plugin) + tmp.extend(found) + except ImportError: + self.logger.error("The plugin '%s' can't be imported" % plugin) + except Exception, e: + self.logger.error("Error while using the plugin '%s'" % plugin) + self.logger.exception(e) + + + + else: + tmp.append(entity) + entities = tmp[:] + self.logger.info("****Setting user '%s' entities corresponding to user profile '%s': %s" % (uid, profile, str(entities))) + from pulse2.database.inventory import Inventory + Inventory().setUserEntities(uid, entities) + + try: acls = self.config.profilesAcl[profile] except KeyError: diff --git a/core/web/forgotpassword.php b/core/web/forgotpassword.php index ae4a549b5..51298302a 100644 --- a/core/web/forgotpassword.php +++ b/core/web/forgotpassword.php @@ -28,10 +28,10 @@ ?> - + - Mandriva Linux / Mandriva Management Console / Reset Password + Siveo Pulse diff --git a/core/web/graph/bootstrap-alerts.css b/core/web/graph/bootstrap-alerts.css index cbd2503db..8df38c47b 100644 --- a/core/web/graph/bootstrap-alerts.css +++ b/core/web/graph/bootstrap-alerts.css @@ -9,14 +9,13 @@ */ .alert { padding: 8px 35px 8px 14px; - margin-bottom: 10px; - margin-top: 10px; + margin:10px 0px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; color: #c09853; font-size: 12px; } @@ -36,10 +35,12 @@ } .alert-danger, .alert-error { - background-color: #f2dede; + /*background-color: #f2dede;*/ + background-color: #f9efef; border-color: #eed3d7; color: #b94a48; } + .alert-info { background-color: #d9edf7; border-color: #bce8f1; diff --git a/core/web/graph/bootstrap-buttons.css b/core/web/graph/bootstrap-buttons.css index ba308e63e..48043b8e5 100644 --- a/core/web/graph/bootstrap-buttons.css +++ b/core/web/graph/bootstrap-buttons.css @@ -13,7 +13,7 @@ /* IE7 inline-block hack */ *zoom: 1; - padding: 4px 12px; + padding: 4px 10px; margin-bottom: 0; font-size: 11px; line-height: 20px; @@ -22,31 +22,30 @@ vertical-align: middle; cursor: pointer; color: #333333; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + /*text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);*/ background-color: #f5f5f5; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + /*background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);*/ background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #292f36; + /*border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*/ *background-color: #e6e6e6; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - border: 1px solid #bbbbbb; + border: 1px solid #292f36; *border: 0; - border-bottom-color: #a2a2a2; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - *margin-left: .3em; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + /**margin-left: .3em; -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); - box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*/ text-decoration: none; } .btn:hover, .btnPrimary:hover, .btnSecondary:hover, .btnDisabled:hover, @@ -69,6 +68,7 @@ color: #333333; text-decoration: none; background-color: #e6e6e6; + border: 1px solid #8FA0B1; *background-color: #d9d9d9; /* Buttons in IE7 don't get borders, so darken on hover */ @@ -116,11 +116,15 @@ margin-top: 2px; } .btn-small { - padding: 2px 10px; - font-size: 9px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + padding: 3px 10px; + font-size: 11px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + min-width: 150px; + max-width: 150px; + margin-top: 3px; + margin-bottom: 3px; } .btn-small [class^="icon-"], .btn-small [class*=" icon-"] { @@ -157,8 +161,9 @@ input[type="button"].btn-block { } .btn-primary, .btnPrimary { color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #006dcc; + background-color: #292F36; + border-radius: 4px; + /*text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-image: -moz-linear-gradient(top, #466EBE, #324C96); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#466EBE), to(#324C96)); background-image: -webkit-linear-gradient(top, #466EBE, #324C96); @@ -178,9 +183,9 @@ input[type="button"].btn-block { .btn-primary.active, .btnPrimary.active, .btn-primary.disabled, .btnPrimary.disabled, .btn-primary[disabled], .btnPrimary[disabled] { - color: #ffffff; - background-color: #324C96; - *background-color: #003bb3; + color: #333; + background-color: #E6E6E6; + /**background-color: #003bb3;*/ } .btn-primary:active, .btnPrimary:active, .btn-primary.active, .btnPrimary.active { @@ -282,14 +287,14 @@ input[type="button"].btn-block { .btn-info { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #49afcd; - background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-color: #8fa0b1; + /*background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);*/ border-color: #2f96b4 #2f96b4 #1f6377; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); *background-color: #2f96b4; @@ -303,8 +308,9 @@ input[type="button"].btn-block { .btn-info.disabled, .btn-info[disabled] { color: #ffffff; - background-color: #2f96b4; + background-color: #292F36;/*#2f96b4*/ *background-color: #2a85a0; + border-radius: 2px; } .btn-info:active, .btn-info.active { diff --git a/core/web/graph/bootstrap-forms.css b/core/web/graph/bootstrap-forms.css index 9dcd63d7a..307f4cc29 100644 --- a/core/web/graph/bootstrap-forms.css +++ b/core/web/graph/bootstrap-forms.css @@ -55,14 +55,28 @@ legend small { color: #999999; } label, -input, button, select, textarea { - font-size: 11px; + font-size: 12px; font-weight: normal; - /*line-height: 20px;*/ } + +input { + font-size: 12px; + font-weight: normal; + border: 1px solid #2295D2; + color: #2295D2; + border-radius: 3px; + padding: 5px; + vertical-align: middle; +} + +input:hover{ + color: white; + background-color: #2295D2; +} + label { display: block; margin-bottom: 5px; @@ -85,13 +99,13 @@ input[type="tel"], input[type="color"], .uneditable-input { display: inline-block; - padding: 4px 6px; + padding: 7px 6px; font-size: 11px; /*line-height: 20px;*/ color: #555555; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; vertical-align: middle; } input[type="text"], @@ -111,7 +125,8 @@ input[type="color"], textarea, select, .uneditable-input { - width: auto; + width: 206px; + height: auto; } textarea { height: auto; @@ -141,6 +156,9 @@ input[type="color"], -moz-transition: border linear .2s, box-shadow linear .2s; -o-transition: border linear .2s, box-shadow linear .2s; transition: border linear .2s, box-shadow linear .2s; + margin-right: 10px; + /*margin-left: -8px;*/ + padding-left: 8px; } textarea:focus, input[type="text"]:focus, @@ -158,18 +176,21 @@ input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, .uneditable-input:focus { - border-color: rgba(82, 168, 236, 0.8); + /*border-color: rgba(82, 168, 236, 0.8);*/ + border-color: #2295d2; outline: 0; outline: thin dotted \9; /* IE6-9 */ - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(50,76,150,.6); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(50,76,150,.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(50,76,150,.6); +/*-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(50,76,150,.6);*/ + + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0), 0 0 0px rgb(253, 213, 0); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0), 0 0 0px rgb(253, 213, 0); + box-shadow: inset 0 1px 1px rgba(0,0,0,0), 0 0 0px rgb(253, 213, 0); } input[type="radio"], input[type="checkbox"] { - margin: 4px 0 0; + margin: 5px 5px 0; *margin-top: 0; /* IE7 */ @@ -196,9 +217,11 @@ input[type="file"] { line-height: 30px; } select { - min-width: 100px; + min-width: 220px; + height: 30px; border: 1px solid #cccccc; background-color: #ffffff; + margin-right: 20px; } select[multiple], select[size] { @@ -344,7 +367,7 @@ input.span4, textarea.span4, .uneditable-input.span4 { width: 286px; } input.span3, textarea.span3, .uneditable-input.span3 { - width: auto; + width: 206px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 126px; @@ -851,3 +874,5 @@ legend + .control-group { .form-horizontal .form-actions { padding-left: 180px; } + +.launchActionImg{top:2px;} diff --git a/core/web/graph/croix.gif b/core/web/graph/croix.gif index 9baabe601..7f4ae5c1c 100644 Binary files a/core/web/graph/croix.gif and b/core/web/graph/croix.gif differ diff --git a/core/web/graph/footer.inc.php b/core/web/graph/footer.inc.php index de4b84a63..f9b210ff7 100644 --- a/core/web/graph/footer.inc.php +++ b/core/web/graph/footer.inc.php @@ -28,7 +28,8 @@ diff --git a/core/web/graph/global.css b/core/web/graph/global.css index f7e09e181..d353f5e25 100644 --- a/core/web/graph/global.css +++ b/core/web/graph/global.css @@ -20,41 +20,57 @@ */ * { - font-family: Verdana, Lucida, Geneva, Helvetica, Arial, sans-serif; - font-size: 11px; + font-family: Arial, Verdana, Lucida, Geneva, Helvetica, sans-serif; + font-size: 12px; } body { color: #333; padding: 0; margin: 0; - background: url("../img/common/background.gif") #999; + background-color: #fff; + overflow-x: hidden; + outline: 0; } .error { color : #A40000; } .form-error { border-color: #D44848 !important; } -a { color: #2A557E;} -a:visited { color: #2A557E; } +a { color: #8fa0b1;text-decoration: none; + /*opacity: 0.9; + transition: opacity .25s ease-in-out; + -moz-transition: opacity .25s ease-in-out; + -webkit-transition: opacity .25s ease-in-out;*/} + +a:visited { color: #8fa0b1; } a:visited.error { color: #A40000; } -a:hover { color: #000; } + +a:hover { color: #000;/*opacity: 1;*/} a.btn { color: #333; } a.btn-primary, a.btn-info, a.btn-danger { color: white; } -a.link { color: #2A557E; border-bottom: 1px dotted #777; text-decoration: none; } -a.link:hover { color: #000; border-bottom: 1px dotted #777; background: #ddd; } +a.link { color: #2A557E; /*border-bottom: 1px dotted #777;*/ text-decoration: none;} +a.link:hover { color: #000; /*border-bottom: 1px dotted #777; background: #ddd;*/ } img { border: none; } p { - padding: 0 0 10px 0; margin: 0; } +/*ADD*/ +.path { + background-color: white; + padding: 10px 0 10px 30px; + +} +/*ADD*/ + + #wrapper { position: relative; width: 100%; @@ -74,21 +90,20 @@ p { /* ---------------------------------------- */ #header { - background-color: #EE4510; - padding: 0 17px 7px 17px; - border-top: solid 1px #000; - border-bottom: solid 1px #000; - background-image: url("../img/common/bg_header.gif"); - background-repeat: repeat-x; - height: 17px; + background-color: #292f36; + border-bottom: 1px solid #d4d4d4; + border-top: 1px solid #21262b; + padding: 0 0px 0px 0px; + height: auto; } #header p { - font-size: 10px; + font-size: 12px; padding: 5px 0 0 0; margin: 0; position: absolute; - color: #f8f8f8; + color: green; + background-color:red; } #header p a { @@ -103,6 +118,10 @@ p { float: right; overflow: hidden; position: relative; + font-size: 12px; + color: #292F36; + margin-top: 6px; + /*background-color: #d4d4d4;*/ } #header #menuTopRight ul { @@ -123,41 +142,49 @@ p { #header #menuTopRight ul li a { width: 50px; - font-size: 10px; - color: #FFF; + font-size: 11px; + color: #6f6f6f; padding: 5px 0 0 18px; margin: 0 0 0 0; text-decoration: none; display: block; } + + /* Commented Backslash Hack hides rule from IE5-Mac \*/ #header #menuTopRight ul li { float: left; } #header #menuTopRight ul li a { width: auto; } /* End IE5-Mac hack */ -#header #menuTopRight ul li a:hover { color: #000000; } +#header #menuTopRight ul li a:hover { color: #fff; } #header #menuTopRight ul li#expertmode a { padding-right: 15px; + border-right: 1px solid #ccc; + height: 15px; + padding: 5px 20px; } #header #menuTopRight ul li#username { width: auto; + height: 70px; padding: 5px 0px 0px 9px; /*background: url("../img/common/icn_user.gif") no-repeat 0 4px transparent;*/ - font-size: 10px; + font-size: 12px; color : #FFF; } -#header #menuTopRight ul li#expertmode a:hover { background-position: 0 4px; } +#header #menuTopRight ul li#expertmode a:hover { background-position: 0 4px; color: #2295D2} #header #menuTopRight ul li#disconnect a { - background: url("../img/common/icn_disconnect.gif") no-repeat 0 -15px transparent; - padding-right: 15px; + background: url("../img/common/icn_disconnect.gif") no-repeat 0 -11px transparent; + padding-right: 33px; + margin-left: 20px; + } -#header #menuTopRight ul li#disconnect a:hover { background-position: 0 4px; } +#header #menuTopRight ul li#disconnect a:hover { background-position: 0 8px; color: #2295D2;} #header #menuTopRight ul li#help a { background: url("../img/common/icn_help.gif") no-repeat 0 -15px transparent;} @@ -168,19 +195,18 @@ p { /* ---------------------------------------- */ #navbar { - padding: 0px 17px 0px 17px; - height: 69px; - background-color: #f6f6f6; + padding: 0px 0px 0px 0px; + /*height: 69px;*/ + background-color: none; overflow: hidden; position: relative; - -webkit-box-shadow: 0 0 4px rgba(0,0,0,0.3); - box-shadow: 0 0 4px rgba(0,0,0,0.3); - border-bottom: 1px solid #aaa; + width: auto; + height: auto; } #navbar #logo { - float: right; - margin-top: 14px; + float: left; + padding: 15px 15px 15px 30px; } #navbar ul { @@ -192,22 +218,21 @@ p { } #navbar ul li { - width: 85px; - display: block; + width: 70px; + display: inline-block; float: left; text-align: center; - padding: 0; - margin: 0; + margin: 0 5px 0 5px; + border-left: 1px solid #21262b; } #navbar ul li a { - padding: 50px 3px 7px 3px; - margin: 0; + padding: 40px 5px 15px 5px; text-decoration: none; display: block; text-align: center; - font-size: 10px; - color: #333; + font-size: 11px; + color: #81919e; line-height: 16px; /* default icon */ position: relative; @@ -215,10 +240,48 @@ p { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + background-color: #1b1e21; } #navbar ul li a:hover {color: #999;} + +/*Media Queries*/ +/*@media only screen and (max-width:800px) { + +#navbar ul { + border: 0; + margin: 0; + padding: 0; + list-style-type: none; + text-align: center; +} + +#navbar ul li { + width: 70px; + display: block; + float: left; + text-align: center; + margin: 0 0px 0 0px; + border-left: 1px solid #21262b; +} + +#navbar ul li a { + padding: 40px 0px 15px 0px; + text-decoration: none; + display: block; + text-align: center; + font-size: 11px; + color: #81919e; + line-height: 16px; + position: relative; + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + background-color: red;} +}*/ + /* ---------------------------------------- */ /* 2a. Configuration */ /* ---------------------------------------- */ @@ -228,10 +291,12 @@ p { /* ---------------------------------------- */ #sidebar { - float: left; - width: 200px; - margin-left: -227px; + left: 0; min-height: 300px; + padding: 0; + position: absolute; + width: 200px; + border-top: 1px solid #ccc; } * html #sidebar { /* lte IE6 */ @@ -245,19 +310,25 @@ p { } #sidebar ul li { - margin: 0; - padding: 0; + /*clear: both; + float: left; + line-height: 41px;*/ + margin: 0px; + padding: 0px; + width: 200px; + + } #sidebar ul li a { - word-wrap: break-word; - font-size: 10px; text-decoration: none; - padding: 12px 8px 12px 61px; - margin: 0; background-repeat: no-repeat; - background-position: 25px 0%; - color: #666; + background-color:#f5f6f7; + color: #8fa0b1; + padding: 12px 8px 12px 60px; + background-position: 20px 0; + border-bottom: 1px solid #ccc; + border-right: 1px solid #ccc; display: block; } @@ -318,45 +389,59 @@ p { /* ---------------------------------------- */ #content { - background: white; + background: #f7f7f7; + padding: 0px 30px 100px 30px ; + border-top: 1px solid #d4d4d4; } #section { - padding: 25px; + padding: 0px 0 0 0px; min-height: 350px; /* IE6 fake min-height */ height: auto !important; - height: 350px; + /*height: 350px;*/ + /*margin-left: 200px;*/ + padding-top: 10px; } #section h1, h2, h3, h4, h5, h6 { color: #666; font-weight: normal; - padding: 0 0 10px 0; + padding: 0 0 0px 0; margin: 0; + /*background-color: #e1e1e1;*/ } -#section h2 { font-size: 17px; } +#section h2 { font-size: 17px; + font-size: 17px; + color: black; +} #section h3 { font-size: 14px; } #section form h3 { font-size: 14px; } #section form h4 { font-size: 13px; } p.listInfos { - font-size: 9px; color: #999; - padding: 0; - margin: 0; + font-size: 9px; height: 22px; line-height: 22px; - margin-top: 7px; + margin: 0px 0 5px 0; + padding: 0; + /*padding: 90px 0 0 15px; + margin: -15px 15px 0 15px; + line-height: 22px;*/ + + } ul.navList { - float: right; - padding: 0; + padding: 0px 28px 0 0; + position: absolute; margin: 0; - height: 22px; - line-height: 22px; + + right: 0; + /*height: 22px; + line-height: 22px;*/ } ul.navList li { @@ -415,6 +500,8 @@ ul.action { padding: 0px; margin: 0px; float: right; + clear: both; + line-height: 41px; } ul.action li { @@ -422,6 +509,7 @@ ul.action li { color: #999; display: inline; list-style-type: none; + margin-left: 10px; } span.pagination { @@ -649,38 +737,35 @@ li.wait a { color: #FFF; } +.user_container { + padding-top: 40px; +} + +#container .action{ + line-height: 18px; +} + #section table { - width: 99%; + width: 100%; } #section table.listinfos { border: 1px solid #CCCCCC; border-top: 0px; - margin-bottom: 0.5em; - margin-top: 0.5em; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - -o-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - filter:progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa, Direction=NaN, Strength=2); + margin:15px 30px 15px 0px; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; } #section table.listinfos tbody tr { - background: white; + background: #f3f3f3; } #section table.listinfos tbody tr.alternate { - background-color: #f6f6f6; + background-color: #fff; } -#section table.listinfos tbody tr.disabledRow { - background-color: #FCC1C1; -} - - #section table.membersTpl { width: auto; @@ -695,11 +780,12 @@ li.wait a { * html #section table {float: left; margin: 0 0 10px 0;} /* End IE5-Mac hack */ -td { - padding: 6px; +td, th { + padding: 10px 25px 10px 10px; border-color: #CCCCCC; border-width: 1px 0 0 0; border-style: solid; + vertical-align: center; } td.printerName, @@ -793,7 +879,7 @@ td.shareName { td.shareAction { text-align: right; } td.groupName { - padding: 0 0 0 34px; + padding: 0 0 0 43px; background-image: url("../img/groups/icn_groupsList.gif"); background-position: 9px 6px; } @@ -802,24 +888,54 @@ td.groupAction { text-align: right; } td.userName { padding: 0 0 0 34px; - background-image: url("../modules/base/graph/users/img/icn_usersList.gif"); + background-image: url("../img/users/icn_usersList.gif"); background-position: 13px 6px; } td.userNameDisabled { padding: 0 0 0 34px; - background-image: url("../modules/base/graph/users/img/icn_usersList.gif"); + background-image: url("../img/users/icn_usersList.gif"); background-position: 13px 6px; } td.userAction { text-align: right; } +td.laptopName { + padding: 0 0 0 37px; + background-image: url("../img/machines/icn_laptopsList.gif"); + background-position: 7px center; + /*background-position: 7px 7px;*/ +} + td.machineName { padding: 0 0 0 37px; background-image: url("../img/machines/icn_machinesList.gif"); - background-position: 7px 7px; + background-position: 7px center; + /*background-position: 7px 7px;*/ +} + +td.phoneName { + padding: 0 0 0 37px; + background-image: url("../img/machines/icn_phonesList.gif"); + background-position: 7px center; + /*background-position: 7px 7px;*/ } +td.smartPhoneName { + padding: 0 0 0 37px; + background-image: url("../img/machines/icn_smartPhonesList.gif"); + background-position: 7px center; + /*background-position: 7px 7px;*/ +} + +td.tabletName { + padding: 0 0 0 37px; + background-image: url("../img/machines/icn_tabletsList.gif"); + background-position: 7px center; + /*background-position: 7px 7px;*/ +} + + td.machinePull { padding: 0 0 0 37px; background-image: url("../img/machines/icn_machinePull.gif"); @@ -833,21 +949,24 @@ td.machineAction { text-align: right; } /* ---------------------------------------- */ #footer { - height: 12px; - color: #555; - font-size: 9px; - background: #f6f6f6; - border-top: 1px solid #ddd; - box-shadow: 0 2px 2px rgba(0,0,0,0.1); - border-bottom: 1px solid #aaa; - padding-left: 5px; + color: #8FA0B1; + font-size: 11px; + background: #fff; + border-top: 3px solid #B3BECA; + padding: 5px 0 10px 30px; + height: 20px; + margin: 0px 0 0px 0; + position: fixed; + bottom: 0px; + z-index: 1000; + width: 100% } #footer a { - font-size: 9px; + font-size: 11px; text-decoration: none; font-weight: bold; - color: #555; + color: #8FA0B1; } /* ---------------------------------------- */ @@ -855,38 +974,60 @@ td.machineAction { text-align: right; } /* ---------------------------------------- */ form { - padding: 0; + padding: 0px 0 0px 0; margin: 0; } .searchfield { - margin-top: 0px; - margin-bottom: 0px; - margin-left:0px; + /**/margin:0px 0px 0 0px; clear: right; - padding: 4px 2px 2px; + /*padding: 4px 2px 2px;*/ padding-top: 0px !ie; color: #666; + cursor:pointer; + top: 0px; } +select#location.searchfieldreal.noborder { + margin-right: 0px; +} +input#param.searchfieldreal { +} .searchbox { - border: 1px solid #BBB; - padding-left: 2px; - padding-right: 2px; - padding-top: 2px; - padding-bottom: 2px; - background-color: #EEE; + /*background-color: #eee;*/ -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - -o-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.1); - filter:progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa, Direction=NaN, Strength=2); + position: relative; + top: 0px; + right: 0px; + padding: 10px 10px 10px 10px; + margin-bottom: 30px + /*height: 36px;*/ + +} + +#searchBest{ + background: url('search.gif') #FFF no-repeat; + padding-left: 55px; + border-radius: 6px; + background-position: left center; + margin-right: 0; + border: 1px solid #ccc; + height:30px; + min-width: 230px; } +#searchBest input, #searchBest select{border:0; max-height:28px} + + + +.searchbox input { + /*margin-right: 0px !important;*/ +} + + .ajaxfilterlog { margin-bottom: 10px; } @@ -911,9 +1052,10 @@ form { .loader { float: right; - position : relative; - top : 7px; - left: 4px + /*left: -7px;*/ + position: relative; + top: 17px; + margin-right: 9px; } .items { @@ -923,29 +1065,35 @@ form { } #Location { - padding: 0px; - padding-top: 5px; - padding-bottom: 5px; + margin: 10px 60px 15px 0; + float: left; } #Location #searchSpan { - padding: 0px; - padding-top: 5px; - padding-bottom: 5px; + /*padding: 0px; + padding-top: 0px; + padding-bottom: 0px;*/ /* IE Hack */ !padding: 0px; + /*float: left;*/ } #Location .searchfieldreal { clear: none; - padding: 0px; + /*padding: 0px;*/ } +img.searchfield { + top: 5px; + left: -22px; + display: float; + margin-right: -36px; +} #Location img { - vertical-align: top; - padding-top: 2px; - padding-left: 2px; + vertical-align: middle; + padding-top: 0px; + padding-left: 0px; } #FormLocation { @@ -990,11 +1138,12 @@ div.autocomplete ul li { } .listinfos thead { - background-color: #eee; + background-color: #e6e6e6; } .listinfos thead td { - border-width: 1px 0px 1px 0px; + /*border-width: 1px 1px 0px 0px;*/ + font-weight: bold; } form.inplaceeditor-form input[type="text"] { @@ -1003,11 +1152,18 @@ form.inplaceeditor-form input[type="text"] { } .popup { - position: absolute; - background: #fff; - border: 1px solid #999; + + left: 1512px; + top: 50px; + width: 200px; + background:#fff; + background: none repeat scroll 0 0 #fff; + border: 1px solid #bababa; + border-radius: 4px; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.3); margin: 5px; - padding: 5px; + padding: 10px; + position: fixed; z-index: 999; -webkit-border-radius: 4px; -moz-border-radius: 4px; @@ -1018,7 +1174,6 @@ form.inplaceeditor-form input[type="text"] { box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.3); filter:progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa, Direction=NaN, Strength=2); } - .overlay { height:100%; width:100%; @@ -1099,10 +1254,10 @@ a.tooltip:hover img{ .formblock { padding: 1em; - margin: 1em; - -webkit-border-radius: 9px; - -moz-border-radius: 9px; - border-radius: 9px; + margin: 1em 0em; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; } /* Tab selector */ @@ -1111,7 +1266,7 @@ a.tooltip:hover img{ background-color: #EEE ; border: 1px solid #A0A0A0; font-size: 10px; - margin: .66em 0 20px; + margin: 2em 0 20px; padding: .2em 0; } @@ -1176,29 +1331,36 @@ ul.roACL { .column { width: 230px; float: left; - padding-bottom: 100px; + padding: 20px 0 100px 0; + /*margin: 0px 0 0 0;*/ } .portlet { background-color: #fafafa; - padding: 5px; - margin: 0 1em 1em 0; - -webkit-border-radius: 4px; + padding:0px; + margin: 20px 20px 10px 10px; + min-width: 220px; + border: 1px solid #ddd; + /* -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - border: 1px solid #ddd; + -webkit-box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.05); -moz-box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.05); -o-box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.05); box-shadow: 0px 0px 2px 0px rgba(0,0,0,0.05); - filter:progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa, Direction=NaN, Strength=2); + filter:progid:DXImageTransform.Microsoft.Shadow(color=#aaaaaa, Direction=NaN, Strength=2);*/ } .portlet-header { - font-size:14px; - color: #666; - padding: 0 0 10px; + font-size: 13px; + font-weight:bold; + color: #333; + padding: 10px; + margin: auto; cursor:move; + background-color: #E6E6E6; + border-bottom: 1px solid #dadada; } .portlet-header .ui-icon { @@ -1206,9 +1368,11 @@ ul.roACL { } .portlet-content { - padding: 0.4em; + padding: 10px; + /*background-color: red;*/ } + .ui-sortable-placeholder { border: 1px dotted #324C96; visibility: visible !important; @@ -1221,11 +1385,11 @@ ul.roACL { .subpanel, .submod { background-color: #f1f1f1; - padding: 5px; - margin-bottom: 10px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; + padding: 10px; + margin: 10px 0px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; } .subpanel ul, .submod ul { diff --git a/core/web/graph/header.inc.php b/core/web/graph/header.inc.php index fe9e56cc2..99df3bfd0 100644 --- a/core/web/graph/header.inc.php +++ b/core/web/graph/header.inc.php @@ -22,7 +22,7 @@ */ $root = $conf["global"]["root"]; ?> - + Mandriva Management Console @@ -113,13 +113,14 @@ function selectAll(formId) { // Popup under mouseevent function _defaultPlacement(evt) { - var left = Math.max(0, evt.clientX - jQuery('#popup').outerWidth() + jQuery(window).scrollLeft()); - var top = Math.max(0, evt.clientY + jQuery(window).scrollTop()); + var window_width = jQuery(window).width(); + var window_height = jQuery(window).height(); + var top = (window_height/ 2) - (jQuery('#popup').height() / 2) + jQuery(window).scrollTop(); + var left = (window_width/ 2) - (jQuery('#popup').width() / 2) + jQuery(window).scrollLeft(); jQuery('#popup').css({'left': left + "px", 'top': top + "px"}); } function _centerPlacement(evt) { - jQuery('#popup').css({ 'width': '50%', 'left': '25%', @@ -206,7 +207,7 @@ function displayConfirmationPopup(message, url_yes, url_no, klass) { jQuery('#popup').css({ 'width': '50%', 'left': '25%', - 'top': '15%' + 'top': '25%' }); jQuery('#overlay').fadeIn().click(closePopup); @@ -239,7 +240,7 @@ function nl2br(str, is_xhtml) { jQuery('#popup').css({ 'width': '50%', 'left': '25%', - 'top': '15%' + 'top': '25%' }); jQuery('#overlay').fadeIn().click(closePopup); diff --git a/core/web/graph/login/index.css b/core/web/graph/login/index.css index 862ca1d77..2e630929a 100644 --- a/core/web/graph/login/index.css +++ b/core/web/graph/login/index.css @@ -44,12 +44,12 @@ Notes: @import '../bootstrap-alerts.css'; * { - font-family: Verdana, Lucida, Geneva, Helvetica, Arial, sans-serif; - font-size: 11px; + font-family: Arial, Verdana, Lucida, Geneva, Helvetica, Arial, sans-serif; + font-size: 12px; } body { - background: url(../../img/common/background.gif) top left #C0C0C0; + background-color: #f5f6f7; } #loginBox { @@ -64,18 +64,20 @@ body { #interface { background: white; - margin: 0 5px; - box-shadow: 0 0 5px; + margin: auto; + border:1px solid #ccc; + border-radius: 2px; + max-width: 260px; } #content { text-align: left; - min-height: 248px; - background: url(../../img/login/bg_mandriva_large.gif) no-repeat top left transparent; + min-height: 200px; + /*background: url(../../img/login/bg_mandriva_large.gif) no-repeat top left transparent;*/ } #login { - padding: 50px 10px 10px 250px; + padding: 20px; } #login img { @@ -87,24 +89,28 @@ body { /* ---------------------------------------- */ #header { - text-align: left; - background-color: #326495; - background: url(../../img/login/bg_header.gif) repeat-x top left #C0C0C0; -} + + /*background-color: #326495; + background: url(../../img/login/bg_header.gif) repeat-x top left #C0C0C0;*/ + height: 42px; + width: 161px; + margin: auto auto 20px; + position: relative; + } #headerLeft { - background: url(../../img/login/corner_header_left.gif) no-repeat top left transparent; + /*background: url(../../img/login/corner_header_left.gif) no-repeat top left transparent;*/ } #headerRight { height: 26px; - background: url(../../img/login/corner_header_right.gif) no-repeat top right transparent; + /*background: url(../../img/login/corner_header_right.gif) no-repeat top right transparent;*/ } #header p { font-size: 10px; color: #A3BBD1; - padding: 7px 0 0 13px; + /*padding: 7px 0 0 13px;*/ } #header p a {color: #E7ECF2;} @@ -114,7 +120,7 @@ body { #header p.lock { margin: 0 5px 0 0; height: 26px; - background: url(../../img/login/icn_lock.gif) no-repeat top right transparent; + /*background: url(../../img/login/icn_lock.gif) no-repeat top right transparent;*/ color: #FFF; font-weight: bold; } @@ -125,17 +131,17 @@ body { #footer { height: 9px; - background: url(../../img/login/bg_footer.gif) repeat-x transparent; + /*background: url(../../img/login/bg_footer.gif) repeat-x transparent;*/ } #footerLeft { height: 9px; - background: url(../../img/login/corner_footer_left.gif) no-repeat top left transparent; + /*background: url(../../img/login/corner_footer_left.gif) no-repeat top left transparent;*/ } #footerRight { height: 9px; - background: url(../../img/login/corner_footer_right.gif) no-repeat top right transparent; + /*background: url(../../img/login/corner_footer_right.gif) no-repeat top right transparent;*/ } /* ---------------------------------------- */ @@ -144,8 +150,8 @@ body { #alert { position: relative; - left: 22px; - top: 22px; + left: 14px; + top: 0px; width: 170px; float: left; color: #666; @@ -212,10 +218,11 @@ body { input[type=text], input[type=password], select { - width: 100px; + width: 200px; } select { - padding: 2px 4px; + padding: 6px 2px; + width: 215px; } .form-inline .control-group { @@ -223,9 +230,14 @@ select { } .form-inline .control-label { - width: 90px; - float: left; - text-align: right; + /*width: 90px;*/ margin-right: 5px; margin-top: 5px; + font-weight: bold; + font-size: 13px; + color: #666; } + +/*ADD*/ + +.controls{margin: auto;} diff --git a/core/web/graph/mandriva-logo.png b/core/web/graph/mandriva-logo.png new file mode 100644 index 000000000..2a6251851 Binary files /dev/null and b/core/web/graph/mandriva-logo.png differ diff --git a/core/web/graph/navbar.inc.php b/core/web/graph/navbar.inc.php index 6ac698a13..fccbbc378 100644 --- a/core/web/graph/navbar.inc.php +++ b/core/web/graph/navbar.inc.php @@ -31,6 +31,39 @@ + + + + +

_modules[$_GET['module']]; $submod = $mod->_submod[$_GET['submod']]; -list($m, $s, $a) = split('/',$submod->_defaultpage,3); +list($m, $s, $a) = preg_split('@/@',$submod->_defaultpage,3); print '' . $submod->getDescription() . ''; $action = $submod->_pages[$_GET["action"]]; if (is_object($action)) { @@ -72,24 +116,10 @@ } ?>

- + - diff --git a/core/web/modules/base/views/index.tpl.php b/core/web/modules/base/views/index.tpl.php index 128883fb4..1672e0ced 100644 --- a/core/web/modules/base/views/index.tpl.php +++ b/core/web/modules/base/views/index.tpl.php @@ -29,7 +29,7 @@
loader
-" /> +" /> -" /> +" /> @@ -224,9 +224,9 @@ function _getShareValue() { function _shareNameAndPathCheckings($name, $path) { if ($name and !(preg_match("/^[a-zA-Z][a-zA-Z0-9.]*$/", $name))) - new NotifyWidgetFailure(_T("Invalid share name")); + new NotifyWidgetFailure(_T("Invalid share name", "samba4")); else if (!isAuthorizedSharePath($path)) - new NotifyWidgetFailure(_T("The share path is not authorized by configuration")); + new NotifyWidgetFailure(_T("The share path is not authorized by configuration", "samba4")); else return True; diff --git a/mds/web/modules/samba4/shares/index.php b/mds/web/modules/samba4/shares/index.php index 4910b3301..96e5416fa 100644 --- a/mds/web/modules/samba4/shares/index.php +++ b/mds/web/modules/samba4/shares/index.php @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ $shareDescription = ""; } else { $sharesEnabled[] = "disabledRow"; - $shareDescription = "(" . _T("Disabled") . ") "; + $shareDescription = "(" . _T("Hidden", "samba4") . ") "; } $shareDescription = isset($share[$shareComponent["description"]]) ? @@ -81,27 +81,27 @@ $share[$shareComponent["guest_access"]] : ""; if (isset($protectedShares) and !in_array($share[$shareComponent["name"]], $protectedShares)) { - $editActions[] = new ActionItem(_T("Edit"),"edit","edit","share"); - $delActions[] = new ActionPopupItem(_T("Delete"),"delete","delete","share"); + $editActions[] = new ActionItem(_T("Edit", "samba4"),"edit","edit","share"); + $delActions[] = new ActionPopupItem(_T("Delete", "samba4"),"delete","delete","share"); } else { $editActions[] = new EmptyActionItem(); $delActions[] = new EmptyActionItem(); } } -$page = new PageGenerator(_T("Current list of shares")); +$page = new PageGenerator(_T("Current list of shares", "samba4")); $page->setSideMenu($sidemenu); $page->display(); -$list = new ListInfos($sharesName, _T("Share")); +$list = new ListInfos($sharesName, _T("Share", "samba4")); $list->setCssClass("shareName"); $list->setCssClasses($sharesEnabled); -$list->addExtraInfo($sharesPath, _T("Path")); -$list->addExtraInfo($sharesDescription, _T("Description")); +$list->addExtraInfo($sharesPath, _T("Path", "samba4")); +$list->addExtraInfo($sharesDescription, _T("Description", "samba4")); $list->addActionItemArray($editActions); $list->addActionItemArray($delActions); -$list->addActionItem(new ActionPopupItem(_T("Archive"),"backup","backup","share")); +$list->addActionItem(new ActionPopupItem(_T("Archive", "samba4"),"backup","backup","share")); $list->disableFirstColumnActionLink(); $list->display(); diff --git a/mds/web/modules/samba4/views/groups.tpl.php b/mds/web/modules/samba4/views/groups.tpl.php index 4e4856032..55a78e38b 100644 --- a/mds/web/modules/samba4/views/groups.tpl.php +++ b/mds/web/modules/samba4/views/groups.tpl.php @@ -5,7 +5,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ function auto() { } else { - window.alert(""); + window.alert(""); } } @@ -115,7 +115,7 @@ function auto() { this.select.options[i].selected = true; } } - + autoObj = new auto(); --> @@ -126,7 +126,7 @@ function auto() { - +
diff --git a/mds/web/modules/samba4/views/users.tpl.php b/mds/web/modules/samba4/views/users.tpl.php index 16f31dc9d..bed8a5008 100644 --- a/mds/web/modules/samba4/views/users.tpl.php +++ b/mds/web/modules/samba4/views/users.tpl.php @@ -5,7 +5,7 @@ * * $Id: groups.tpl.php 1220 2008-03-03 15:15:58Z cedric $ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ function auto() { } else { - window.alert(""); + window.alert(""); } } @@ -115,7 +115,7 @@ function auto() { this.select.options[i].selected = true; } } - + autoObj = new auto(); --> @@ -126,7 +126,7 @@ function auto() { - +
diff --git a/mds/web/modules/shorewall/Makefile.am b/mds/web/modules/shorewall/Makefile.am index 8f6e954c2..95d8f8efe 100644 --- a/mds/web/modules/shorewall/Makefile.am +++ b/mds/web/modules/shorewall/Makefile.am @@ -34,9 +34,10 @@ datafiles = \ shorewall/delete_internal_external_rule.php \ shorewall/external_internal.php \ shorewall/ajax_external_internal.php \ + shorewall/delete_external_internal_rule.php \ shorewall/internal_internal.php \ shorewall/ajax_internal_internal.php \ - shorewall/delete_external_internal_rule.php \ + shorewall/delete_internal_internal_rule.php \ shorewall/rules.php \ shorewall/ajax_rules.php \ shorewall/delete_rule.php \ diff --git a/mds/web/modules/shorewall/graph/actions/icn_ext_int.gif b/mds/web/modules/shorewall/graph/actions/icn_ext_int.gif new file mode 100644 index 000000000..971672be8 Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_ext_int.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_ext_int_active.gif b/mds/web/modules/shorewall/graph/actions/icn_ext_int_active.gif new file mode 100644 index 000000000..17c0f3c4d Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_ext_int_active.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_ext_server.gif b/mds/web/modules/shorewall/graph/actions/icn_ext_server.gif new file mode 100644 index 000000000..9e71a52df Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_ext_server.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_ext_server_active.gif b/mds/web/modules/shorewall/graph/actions/icn_ext_server_active.gif new file mode 100644 index 000000000..1b05c178a Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_ext_server_active.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_ext.gif b/mds/web/modules/shorewall/graph/actions/icn_int_ext.gif new file mode 100644 index 000000000..7d62cfaa8 Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_ext.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_ext_active.gif b/mds/web/modules/shorewall/graph/actions/icn_int_ext_active.gif new file mode 100644 index 000000000..31d8bcd4a Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_ext_active.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_int.gif b/mds/web/modules/shorewall/graph/actions/icn_int_int.gif new file mode 100644 index 000000000..59ff3c1f8 Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_int.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_int_active.gif b/mds/web/modules/shorewall/graph/actions/icn_int_int_active.gif new file mode 100644 index 000000000..1403ded40 Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_int_active.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_server.gif b/mds/web/modules/shorewall/graph/actions/icn_int_server.gif new file mode 100644 index 000000000..dba330119 Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_server.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_int_server_active.gif b/mds/web/modules/shorewall/graph/actions/icn_int_server_active.gif new file mode 100644 index 000000000..4861e8a3c Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_int_server_active.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_nat.gif b/mds/web/modules/shorewall/graph/actions/icn_nat.gif new file mode 100644 index 000000000..d2a22d20c Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_nat.gif differ diff --git a/mds/web/modules/shorewall/graph/actions/icn_nat_active.gif b/mds/web/modules/shorewall/graph/actions/icn_nat_active.gif new file mode 100644 index 000000000..bbd845b3c Binary files /dev/null and b/mds/web/modules/shorewall/graph/actions/icn_nat_active.gif differ diff --git a/mds/web/modules/shorewall/graph/navbar/shorewall.png b/mds/web/modules/shorewall/graph/navbar/shorewall.png index 5a1facab0..a4f1e3fc9 100644 Binary files a/mds/web/modules/shorewall/graph/navbar/shorewall.png and b/mds/web/modules/shorewall/graph/navbar/shorewall.png differ diff --git a/mds/web/modules/shorewall/graph/navbar/shorewall_hl.png b/mds/web/modules/shorewall/graph/navbar/shorewall_hl.png index 6f38e2480..067b651d2 100644 Binary files a/mds/web/modules/shorewall/graph/navbar/shorewall_hl.png and b/mds/web/modules/shorewall/graph/navbar/shorewall_hl.png differ diff --git a/mds/web/modules/shorewall/graph/navbar/shorewall_select.png b/mds/web/modules/shorewall/graph/navbar/shorewall_select.png index 7342f8fbb..df517b0b4 100644 Binary files a/mds/web/modules/shorewall/graph/navbar/shorewall_select.png and b/mds/web/modules/shorewall/graph/navbar/shorewall_select.png differ diff --git a/mds/web/modules/shorewall/includes/errorHandling.php b/mds/web/modules/shorewall/includes/errorHandling.php index 6fe546872..5f499e6ac 100644 --- a/mds/web/modules/shorewall/includes/errorHandling.php +++ b/mds/web/modules/shorewall/includes/errorHandling.php @@ -2,7 +2,7 @@ /** * (c) 2014 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,4 +39,32 @@ $errItem->setTraceBackDisplay(False); $errObj->add($errItem); +$errItem = new ErrorHandlingItem(": Invalid IP"); +$errItem->setMsg(_T("Invalid IP", "shorewall")); +$errItem->setAdvice(_T("The IP address is not correct.", "shorewall")); +$errItem->setLevel(1); +$errItem->setTraceBackDisplay(False); +$errObj->add($errItem); + +$errItem = new ErrorHandlingItem(": Invalid IP range"); +$errItem->setMsg(_T("Invalid IP range", "shorewall")); +$errItem->setAdvice(_T("The IP range is not correct.", "shorewall")); +$errItem->setLevel(1); +$errItem->setTraceBackDisplay(False); +$errObj->add($errItem); + +$errItem = new ErrorHandlingItem(": Invalid network"); +$errItem->setMsg(_T("Invalid network", "shorewall")); +$errItem->setAdvice(_T("The network is not correct.", "shorewall")); +$errItem->setLevel(1); +$errItem->setTraceBackDisplay(False); +$errObj->add($errItem); + +$errItem = new ErrorHandlingItem(": Invalid network masq"); +$errItem->setMsg(_T("Invalid network masq", "shorewall")); +$errItem->setAdvice(_T("The network masq is not correct.", "shorewall")); +$errItem->setLevel(1); +$errItem->setTraceBackDisplay(False); +$errObj->add($errItem); + ?> diff --git a/mds/web/modules/shorewall/includes/functions.inc.php b/mds/web/modules/shorewall/includes/functions.inc.php index de50aaeb1..1ea0c6808 100644 --- a/mds/web/modules/shorewall/includes/functions.inc.php +++ b/mds/web/modules/shorewall/includes/functions.inc.php @@ -3,7 +3,7 @@ /** * (c) 2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/includes/shorewall-xmlrpc.inc.php b/mds/web/modules/shorewall/includes/shorewall-xmlrpc.inc.php index ee0ccb414..cbb54fe15 100644 --- a/mds/web/modules/shorewall/includes/shorewall-xmlrpc.inc.php +++ b/mds/web/modules/shorewall/includes/shorewall-xmlrpc.inc.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/infoPackage.inc.php b/mds/web/modules/shorewall/infoPackage.inc.php index 0e56ef7e4..b3190c7df 100644 --- a/mds/web/modules/shorewall/infoPackage.inc.php +++ b/mds/web/modules/shorewall/infoPackage.inc.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ $wan_zones = getShorewallZones($zones_types['external']); $mod = new Module("shorewall"); -$mod->setVersion("2.5.89"); +$mod->setVersion("2.5.95"); $mod->setRevision(''); $mod->setDescription(_T("Firewall management", "shorewall")); $mod->setAPIVersion("0:0:0"); diff --git a/mds/web/modules/shorewall/locale/fr_FR/LC_MESSAGES/shorewall.po b/mds/web/modules/shorewall/locale/fr_FR/LC_MESSAGES/shorewall.po index acae2369c..31f574d99 100644 --- a/mds/web/modules/shorewall/locale/fr_FR/LC_MESSAGES/shorewall.po +++ b/mds/web/modules/shorewall/locale/fr_FR/LC_MESSAGES/shorewall.po @@ -8,20 +8,21 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" -"Language-Team: French (France) (http://transifex.mandriva.com/projects/p/mds/" -"team/fr_FR/)\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-12-23 10:17+0200\n" +"Last-Translator: Jean-Philippe \n" +"Language-Team: French " +"\n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 2.1-dev\n" -#: modules/shorewall/shorewall/dnat_rules.php:124 #: modules/shorewall/shorewall/rules.php:133 #: modules/shorewall/shorewall/rules.php:167 +#: modules/shorewall/shorewall/dnat_rules.php:124 msgid "Accept" msgstr "Accepter" @@ -34,9 +35,9 @@ msgstr "Ajouter une règle NAT" msgid "Add port forwarding rule" msgstr "Ajouter une règle de transfert de ports" -#: modules/shorewall/shorewall/dnat_rules.php:245 #: modules/shorewall/shorewall/rules.php:160 #: modules/shorewall/shorewall/rules.php:240 +#: modules/shorewall/shorewall/dnat_rules.php:245 msgid "Add rule" msgstr "Ajouter une règle" @@ -48,7 +49,7 @@ msgstr "Tous" msgid "Allow connection from IP(s) address(es) (separate IPs with ',')." msgstr "" "Autoriser la connexion depuis les adresses IP (séparer les adresses IPs avec " -"',')" +"',')." #: modules/shorewall/shorewall/delete_dnat_rule.php:42 #: modules/shorewall/shorewall/delete_masquerade_rule.php:40 @@ -60,8 +61,8 @@ msgstr "Annuler" msgid "Custom..." msgstr "Personnaliser..." -#: modules/shorewall/shorewall/ajax_rules.php:43 #: modules/shorewall/shorewall/rules.php:170 +#: modules/shorewall/shorewall/ajax_rules.php:43 msgid "Decision" msgstr "Décision" @@ -75,8 +76,8 @@ msgstr "Supprimer" msgid "Delete NAT rule" msgstr "Supprimer la règle de NAT" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:28 #: modules/shorewall/shorewall/ajax_rules.php:28 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:28 msgid "Delete rule" msgstr "Supprimer la règle" @@ -86,10 +87,10 @@ msgstr "Supprimer la règle" msgid "Delete this rule ?" msgstr "Supprimer cette règle ?" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:48 -#: modules/shorewall/shorewall/ajax_rules.php:50 #: modules/shorewall/shorewall/rules.php:204 #: modules/shorewall/shorewall/rules.php:207 +#: modules/shorewall/shorewall/ajax_rules.php:50 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:48 msgid "Destination" msgstr "Destination" @@ -106,9 +107,9 @@ msgstr "Port(s) de destination" msgid "Destination zone" msgstr "Zone de destination" -#: modules/shorewall/shorewall/dnat_rules.php:124 #: modules/shorewall/shorewall/rules.php:133 #: modules/shorewall/shorewall/rules.php:167 +#: modules/shorewall/shorewall/dnat_rules.php:124 msgid "Drop" msgstr "Refuser" @@ -130,25 +131,25 @@ msgstr "Externe → Serveur" msgid "External network (Internet)" msgstr "Réseau externe (Internet)" -#: modules/shorewall/shorewall/dnat_rules.php:95 #: modules/shorewall/shorewall/rules.php:104 +#: modules/shorewall/shorewall/dnat_rules.php:95 msgid "Failed to add the rule." msgstr "Erreur lors de l'ajout de la règle." -#: modules/shorewall/shorewall/dnat_rules.php:44 #: modules/shorewall/shorewall/rules.php:43 +#: modules/shorewall/shorewall/dnat_rules.php:44 msgid "Failed to change the policy." msgstr "Erreur lors du changement de la politique." #: modules/shorewall/infoPackage.inc.php:39 +#: modules/shorewall/shorewall/masquerade.php:44 +#: modules/shorewall/shorewall/rules.php:40 +#: modules/shorewall/shorewall/rules.php:99 #: modules/shorewall/shorewall/delete_dnat_rule.php:29 #: modules/shorewall/shorewall/delete_masquerade_rule.php:28 -#: modules/shorewall/shorewall/delete_rule.php:29 #: modules/shorewall/shorewall/dnat_rules.php:39 #: modules/shorewall/shorewall/dnat_rules.php:90 -#: modules/shorewall/shorewall/masquerade.php:44 -#: modules/shorewall/shorewall/rules.php:40 -#: modules/shorewall/shorewall/rules.php:99 +#: modules/shorewall/shorewall/delete_rule.php:29 msgid "Firewall" msgstr "Firewall" @@ -158,11 +159,11 @@ msgstr "Gestion du firewall" #: modules/shorewall/shorewall/dnat_rules.php:240 msgid "" -"If not specified, destination port(s) will be the same as the incoming port" -"(s)" +"If not specified, destination port(s) will be the same as the incoming " +"port(s)" msgstr "" "Si non spécifié, les ports de destination seront les même que les ports " -"source." +"source" #: modules/shorewall/includes/functions.inc.php:25 msgid "Internal" @@ -176,7 +177,7 @@ msgstr "Interne → Externe" #: modules/shorewall/infoPackage.inc.php:99 #: modules/shorewall/shorewall/localSidebar.php:45 msgid "Internal → Internal" -msgstr "" +msgstr "Interne → Interne" #: modules/shorewall/infoPackage.inc.php:45 #: modules/shorewall/shorewall/localSidebar.php:32 @@ -189,11 +190,11 @@ msgstr "Réseau interne" #: modules/shorewall/includes/errorHandling.php:29 msgid "Invalid port number" -msgstr "" +msgstr "Numéro de port invalide" #: modules/shorewall/includes/errorHandling.php:36 msgid "Invalid port range" -msgstr "" +msgstr "Plage de port invalide" #: modules/shorewall/infoPackage.inc.php:112 #: modules/shorewall/shorewall/localSidebar.php:54 @@ -212,13 +213,13 @@ msgstr "Règle de NAT" msgid "NAT rule added." msgstr "Règle NAT ajoutée." -#: modules/shorewall/shorewall/dnat_rules.php:111 #: modules/shorewall/shorewall/rules.php:120 +#: modules/shorewall/shorewall/dnat_rules.php:111 msgid "Policy" msgstr "Politique" -#: modules/shorewall/shorewall/dnat_rules.php:38 #: modules/shorewall/shorewall/rules.php:39 +#: modules/shorewall/shorewall/dnat_rules.php:38 msgid "Policy changed." msgstr "Politique modifiée." @@ -228,12 +229,12 @@ msgstr "Règles de transfert de ports" #: modules/shorewall/includes/errorHandling.php:30 msgid "Port should be between 0 and 65535." -msgstr "" +msgstr "Le port doit être entre 0 et 65535." -#: modules/shorewall/shorewall/ajax_dnat_rules.php:46 +#: modules/shorewall/shorewall/rules.php:233 #: modules/shorewall/shorewall/ajax_rules.php:52 #: modules/shorewall/shorewall/dnat_rules.php:178 -#: modules/shorewall/shorewall/rules.php:233 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:46 msgid "Port(s)" msgstr "Ports(s)" @@ -242,16 +243,18 @@ msgid "" "Ports should be between 0 and 65535 and the left side port must be lower " "that the right side port." msgstr "" +"Les ports doivent être compris entre 0 et 65535 et le port de gauche doit " +"être plus petit que le port de droite." -#: modules/shorewall/shorewall/ajax_dnat_rules.php:45 +#: modules/shorewall/shorewall/rules.php:231 #: modules/shorewall/shorewall/ajax_rules.php:51 #: modules/shorewall/shorewall/dnat_rules.php:176 -#: modules/shorewall/shorewall/rules.php:231 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:45 msgid "Protocol" msgstr "Protocole" -#: modules/shorewall/shorewall/dnat_rules.php:60 #: modules/shorewall/shorewall/rules.php:57 +#: modules/shorewall/shorewall/dnat_rules.php:60 msgid "Protocol and port must be specified." msgstr "Le protocole et le port doit être spécifié." @@ -260,14 +263,14 @@ msgid "Provide internet access to internal network(s)." msgstr "Permet à vos réseaux internes d'accéder à Internet." #: modules/shorewall/infoPackage.inc.php:125 -#: modules/shorewall/shorewall/dnat_rules.php:251 #: modules/shorewall/shorewall/masquerade.php:94 #: modules/shorewall/shorewall/rules.php:246 +#: modules/shorewall/shorewall/dnat_rules.php:251 msgid "Restart service" msgstr "Redémarrer le service" -#: modules/shorewall/shorewall/dnat_rules.php:89 #: modules/shorewall/shorewall/rules.php:98 +#: modules/shorewall/shorewall/dnat_rules.php:89 msgid "Rule added." msgstr "Règle ajoutée." @@ -275,8 +278,8 @@ msgstr "Règle ajoutée." msgid "Rules" msgstr "Règles" -#: modules/shorewall/shorewall/dnat_rules.php:132 #: modules/shorewall/shorewall/rules.php:141 +#: modules/shorewall/shorewall/dnat_rules.php:132 msgid "Save" msgstr "Sauvegarder" @@ -284,22 +287,22 @@ msgstr "Sauvegarder" msgid "Server" msgstr "Serveur" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:42 +#: modules/shorewall/shorewall/rules.php:219 #: modules/shorewall/shorewall/ajax_rules.php:46 #: modules/shorewall/shorewall/dnat_rules.php:164 -#: modules/shorewall/shorewall/rules.php:219 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:42 msgid "Service" msgstr "Service" -#: modules/shorewall/shorewall/dnat_rules.php:100 #: modules/shorewall/shorewall/rules.php:109 +#: modules/shorewall/shorewall/dnat_rules.php:100 msgid "Service must be specified." msgstr "Le service doit être spécifié." -#: modules/shorewall/shorewall/ajax_dnat_rules.php:47 -#: modules/shorewall/shorewall/ajax_rules.php:48 #: modules/shorewall/shorewall/rules.php:184 #: modules/shorewall/shorewall/rules.php:187 +#: modules/shorewall/shorewall/ajax_rules.php:48 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:47 msgid "Source" msgstr "Source" @@ -318,8 +321,8 @@ msgid "" msgstr "" "L'adresse IP de l'ordinateur dans le réseau interne qui recevra la requête." -#: modules/shorewall/shorewall/dnat_rules.php:115 #: modules/shorewall/shorewall/rules.php:124 +#: modules/shorewall/shorewall/dnat_rules.php:115 msgid "The policy applies if no rule match the request." msgstr "La politique s'applique si aucune règle ne s'applique." @@ -331,18 +334,18 @@ msgstr "La règle à été supprimée." #: modules/shorewall/includes/errorHandling.php:23 msgid "The rule is invalid" -msgstr "" +msgstr "La règle est invalide" #: modules/shorewall/shorewall/restart_service.php:26 msgid "The service has been asked to restart." -msgstr "Il a été demandé au service de redémarrer." +msgstr "Une demande de redémarrage a été envoyée au service." #: modules/shorewall/includes/functions.inc.php:32 msgid "Unknow" msgstr "Inconnu" -#: modules/shorewall/shorewall/dnat_rules.php:179 #: modules/shorewall/shorewall/rules.php:234 +#: modules/shorewall/shorewall/dnat_rules.php:179 msgid "" "You can specify multiple ports using ',' as separator (eg: 22,34,56). Port " "ranges can be defined with ':' (eg: 3400:3500 - from port 3400 to port 3500)." diff --git a/mds/web/modules/shorewall/locale/pt_BR/LC_MESSAGES/shorewall.po b/mds/web/modules/shorewall/locale/pt_BR/LC_MESSAGES/shorewall.po index c2a0bc73a..d769f0600 100644 --- a/mds/web/modules/shorewall/locale/pt_BR/LC_MESSAGES/shorewall.po +++ b/mds/web/modules/shorewall/locale/pt_BR/LC_MESSAGES/shorewall.po @@ -9,20 +9,21 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" -"Language-Team: Portuguese (Brazilian) (http://transifex.mandriva.com/" -"projects/p/mds/team/pt_BR/)\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-12-10 21:46+0200\n" +"Last-Translator: Andre \n" +"Language-Team: Portuguese (Brazil) " +"\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.1-dev\n" -#: modules/shorewall/shorewall/dnat_rules.php:124 #: modules/shorewall/shorewall/rules.php:133 #: modules/shorewall/shorewall/rules.php:167 +#: modules/shorewall/shorewall/dnat_rules.php:124 msgid "Accept" msgstr "Aceitar" @@ -35,9 +36,9 @@ msgstr "Adicionar regra de NAT" msgid "Add port forwarding rule" msgstr "Adiciona regra de redirecionamento de porta" -#: modules/shorewall/shorewall/dnat_rules.php:245 #: modules/shorewall/shorewall/rules.php:160 #: modules/shorewall/shorewall/rules.php:240 +#: modules/shorewall/shorewall/dnat_rules.php:245 msgid "Add rule" msgstr "Adicionar regra" @@ -47,20 +48,20 @@ msgstr "Todos" #: modules/shorewall/shorewall/dnat_rules.php:209 msgid "Allow connection from IP(s) address(es) (separate IPs with ',')." -msgstr "Permite conexões dos endereço(s) IP(s) (separados com ','). " +msgstr "Permite conexões dos endereço(s) IP(s) (IPs separados com ',')." #: modules/shorewall/shorewall/delete_dnat_rule.php:42 #: modules/shorewall/shorewall/delete_masquerade_rule.php:40 #: modules/shorewall/shorewall/delete_rule.php:42 msgid "Cancel" -msgstr "Cancela" +msgstr "Cancelar" #: modules/shorewall/shorewall/dnat_rules.php:158 msgid "Custom..." msgstr "Personalizar..." -#: modules/shorewall/shorewall/ajax_rules.php:43 #: modules/shorewall/shorewall/rules.php:170 +#: modules/shorewall/shorewall/ajax_rules.php:43 msgid "Decision" msgstr "Decisão" @@ -74,8 +75,8 @@ msgstr "Remover" msgid "Delete NAT rule" msgstr "Remover regra de NAT" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:28 #: modules/shorewall/shorewall/ajax_rules.php:28 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:28 msgid "Delete rule" msgstr "Remover regra" @@ -85,10 +86,10 @@ msgstr "Remover regra" msgid "Delete this rule ?" msgstr "Remover esta regra?" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:48 -#: modules/shorewall/shorewall/ajax_rules.php:50 #: modules/shorewall/shorewall/rules.php:204 #: modules/shorewall/shorewall/rules.php:207 +#: modules/shorewall/shorewall/ajax_rules.php:50 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:48 msgid "Destination" msgstr "Destino" @@ -105,9 +106,9 @@ msgstr "Porta(s) de destino" msgid "Destination zone" msgstr "Zona de destino" -#: modules/shorewall/shorewall/dnat_rules.php:124 #: modules/shorewall/shorewall/rules.php:133 #: modules/shorewall/shorewall/rules.php:167 +#: modules/shorewall/shorewall/dnat_rules.php:124 msgid "Drop" msgstr "Negar" @@ -129,25 +130,25 @@ msgstr "Externo → Servidor" msgid "External network (Internet)" msgstr "Rede externa (Internet)" -#: modules/shorewall/shorewall/dnat_rules.php:95 #: modules/shorewall/shorewall/rules.php:104 +#: modules/shorewall/shorewall/dnat_rules.php:95 msgid "Failed to add the rule." msgstr "Falhou ao adicionar a regra." -#: modules/shorewall/shorewall/dnat_rules.php:44 #: modules/shorewall/shorewall/rules.php:43 +#: modules/shorewall/shorewall/dnat_rules.php:44 msgid "Failed to change the policy." msgstr "Falhou ao aplicar a política." #: modules/shorewall/infoPackage.inc.php:39 +#: modules/shorewall/shorewall/masquerade.php:44 +#: modules/shorewall/shorewall/rules.php:40 +#: modules/shorewall/shorewall/rules.php:99 #: modules/shorewall/shorewall/delete_dnat_rule.php:29 #: modules/shorewall/shorewall/delete_masquerade_rule.php:28 -#: modules/shorewall/shorewall/delete_rule.php:29 #: modules/shorewall/shorewall/dnat_rules.php:39 #: modules/shorewall/shorewall/dnat_rules.php:90 -#: modules/shorewall/shorewall/masquerade.php:44 -#: modules/shorewall/shorewall/rules.php:40 -#: modules/shorewall/shorewall/rules.php:99 +#: modules/shorewall/shorewall/delete_rule.php:29 msgid "Firewall" msgstr "Firewall" @@ -157,8 +158,8 @@ msgstr "Gerenciamento do Firewall" #: modules/shorewall/shorewall/dnat_rules.php:240 msgid "" -"If not specified, destination port(s) will be the same as the incoming port" -"(s)" +"If not specified, destination port(s) will be the same as the incoming " +"port(s)" msgstr "" "Se não especificado, as porta(s) de destino serão as mesmas porta(s) da " "entrada" @@ -174,8 +175,9 @@ msgstr "Interno → Exrterno" #: modules/shorewall/infoPackage.inc.php:99 #: modules/shorewall/shorewall/localSidebar.php:45 +#, fuzzy msgid "Internal → Internal" -msgstr "" +msgstr "Externo → Interno" #: modules/shorewall/infoPackage.inc.php:45 #: modules/shorewall/shorewall/localSidebar.php:32 @@ -211,13 +213,13 @@ msgstr "Regra de NAT" msgid "NAT rule added." msgstr "Regra de NAT adicionada." -#: modules/shorewall/shorewall/dnat_rules.php:111 #: modules/shorewall/shorewall/rules.php:120 +#: modules/shorewall/shorewall/dnat_rules.php:111 msgid "Policy" msgstr "Política" -#: modules/shorewall/shorewall/dnat_rules.php:38 #: modules/shorewall/shorewall/rules.php:39 +#: modules/shorewall/shorewall/dnat_rules.php:38 msgid "Policy changed." msgstr "Política alterada." @@ -229,10 +231,10 @@ msgstr "Regras de direcionamento de porta" msgid "Port should be between 0 and 65535." msgstr "" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:46 +#: modules/shorewall/shorewall/rules.php:233 #: modules/shorewall/shorewall/ajax_rules.php:52 #: modules/shorewall/shorewall/dnat_rules.php:178 -#: modules/shorewall/shorewall/rules.php:233 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:46 msgid "Port(s)" msgstr "Porta(s)" @@ -242,40 +244,40 @@ msgid "" "that the right side port." msgstr "" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:45 +#: modules/shorewall/shorewall/rules.php:231 #: modules/shorewall/shorewall/ajax_rules.php:51 #: modules/shorewall/shorewall/dnat_rules.php:176 -#: modules/shorewall/shorewall/rules.php:231 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:45 msgid "Protocol" msgstr "Protocolo" -#: modules/shorewall/shorewall/dnat_rules.php:60 #: modules/shorewall/shorewall/rules.php:57 +#: modules/shorewall/shorewall/dnat_rules.php:60 msgid "Protocol and port must be specified." msgstr "O protocolo e a porta precisam ser especificados." #: modules/shorewall/shorewall/masquerade.php:34 msgid "Provide internet access to internal network(s)." -msgstr "Provê acesso da Internet pra a rede(s) interna" +msgstr "Provê acesso da Internet pra a rede(s) interna(s)." #: modules/shorewall/infoPackage.inc.php:125 -#: modules/shorewall/shorewall/dnat_rules.php:251 #: modules/shorewall/shorewall/masquerade.php:94 #: modules/shorewall/shorewall/rules.php:246 +#: modules/shorewall/shorewall/dnat_rules.php:251 msgid "Restart service" msgstr "Reiniciar o serviço" -#: modules/shorewall/shorewall/dnat_rules.php:89 #: modules/shorewall/shorewall/rules.php:98 +#: modules/shorewall/shorewall/dnat_rules.php:89 msgid "Rule added." -msgstr "Regra adicionada" +msgstr "Regra adicionada." #: modules/shorewall/shorewall/rules.php:151 msgid "Rules" msgstr "Regras" -#: modules/shorewall/shorewall/dnat_rules.php:132 #: modules/shorewall/shorewall/rules.php:141 +#: modules/shorewall/shorewall/dnat_rules.php:132 msgid "Save" msgstr "Salvar" @@ -283,22 +285,22 @@ msgstr "Salvar" msgid "Server" msgstr "Servidor" -#: modules/shorewall/shorewall/ajax_dnat_rules.php:42 +#: modules/shorewall/shorewall/rules.php:219 #: modules/shorewall/shorewall/ajax_rules.php:46 #: modules/shorewall/shorewall/dnat_rules.php:164 -#: modules/shorewall/shorewall/rules.php:219 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:42 msgid "Service" msgstr "Serviço" -#: modules/shorewall/shorewall/dnat_rules.php:100 #: modules/shorewall/shorewall/rules.php:109 +#: modules/shorewall/shorewall/dnat_rules.php:100 msgid "Service must be specified." msgstr "O serviço precisa ser especificado." -#: modules/shorewall/shorewall/ajax_dnat_rules.php:47 -#: modules/shorewall/shorewall/ajax_rules.php:48 #: modules/shorewall/shorewall/rules.php:184 #: modules/shorewall/shorewall/rules.php:187 +#: modules/shorewall/shorewall/ajax_rules.php:48 +#: modules/shorewall/shorewall/ajax_dnat_rules.php:47 msgid "Source" msgstr "Origem" @@ -316,8 +318,8 @@ msgid "" "The computer IP in the internal network where the request will be transfered." msgstr "IP do computador da rede interna onde a requisisão será transferida." -#: modules/shorewall/shorewall/dnat_rules.php:115 #: modules/shorewall/shorewall/rules.php:124 +#: modules/shorewall/shorewall/dnat_rules.php:115 msgid "The policy applies if no rule match the request." msgstr "A política se aplica se nenhuma regra corresponder ao pedido." @@ -328,19 +330,20 @@ msgid "The rule has been deleted." msgstr "A regra ja foi removida." #: modules/shorewall/includes/errorHandling.php:23 +#, fuzzy msgid "The rule is invalid" -msgstr "" +msgstr "A regra ja foi removida." #: modules/shorewall/shorewall/restart_service.php:26 msgid "The service has been asked to restart." -msgstr "O serviço foi solicitado a reiniciar." +msgstr "O serviço solicitou reiniciar." #: modules/shorewall/includes/functions.inc.php:32 msgid "Unknow" msgstr "Desconhecido" -#: modules/shorewall/shorewall/dnat_rules.php:179 #: modules/shorewall/shorewall/rules.php:234 +#: modules/shorewall/shorewall/dnat_rules.php:179 msgid "" "You can specify multiple ports using ',' as separator (eg: 22,34,56). Port " "ranges can be defined with ':' (eg: 3400:3500 - from port 3400 to port 3500)." diff --git a/mds/web/modules/shorewall/shorewall/ajax_dnat_rules.php b/mds/web/modules/shorewall/shorewall/ajax_dnat_rules.php index 6d5bf1e3c..b42f840e6 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_dnat_rules.php +++ b/mds/web/modules/shorewall/shorewall/ajax_dnat_rules.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_external_fw.php b/mds/web/modules/shorewall/shorewall/ajax_external_fw.php index e0cdb50ae..388c80695 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_external_fw.php +++ b/mds/web/modules/shorewall/shorewall/ajax_external_fw.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_external_internal.php b/mds/web/modules/shorewall/shorewall/ajax_external_internal.php index 5ce555738..03e58adcb 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_external_internal.php +++ b/mds/web/modules/shorewall/shorewall/ajax_external_internal.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_internal_external.php b/mds/web/modules/shorewall/shorewall/ajax_internal_external.php index 208f53430..10294043f 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_internal_external.php +++ b/mds/web/modules/shorewall/shorewall/ajax_internal_external.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_internal_fw.php b/mds/web/modules/shorewall/shorewall/ajax_internal_fw.php index 0518369ac..0e97e2911 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_internal_fw.php +++ b/mds/web/modules/shorewall/shorewall/ajax_internal_fw.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_internal_internal.php b/mds/web/modules/shorewall/shorewall/ajax_internal_internal.php index 39f21f556..90a8940bf 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_internal_internal.php +++ b/mds/web/modules/shorewall/shorewall/ajax_internal_internal.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_masquerade.php b/mds/web/modules/shorewall/shorewall/ajax_masquerade.php index c69546701..8202d16e9 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_masquerade.php +++ b/mds/web/modules/shorewall/shorewall/ajax_masquerade.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/ajax_rules.php b/mds/web/modules/shorewall/shorewall/ajax_rules.php index 22e3084bc..917b22a3c 100644 --- a/mds/web/modules/shorewall/shorewall/ajax_rules.php +++ b/mds/web/modules/shorewall/shorewall/ajax_rules.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_dnat_rule.php b/mds/web/modules/shorewall/shorewall/delete_dnat_rule.php index ec5579d06..a4aa6819f 100644 --- a/mds/web/modules/shorewall/shorewall/delete_dnat_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_dnat_rule.php @@ -2,7 +2,7 @@ /** * (c) 2012 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_external_fw_rule.php b/mds/web/modules/shorewall/shorewall/delete_external_fw_rule.php index 12a648ef3..8765423e1 100644 --- a/mds/web/modules/shorewall/shorewall/delete_external_fw_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_external_fw_rule.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_external_internal_rule.php b/mds/web/modules/shorewall/shorewall/delete_external_internal_rule.php index a0a47ecc9..001d737b1 100644 --- a/mds/web/modules/shorewall/shorewall/delete_external_internal_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_external_internal_rule.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_internal_external_rule.php b/mds/web/modules/shorewall/shorewall/delete_internal_external_rule.php index 068f4ca6b..8dbe20fe0 100644 --- a/mds/web/modules/shorewall/shorewall/delete_internal_external_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_internal_external_rule.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_internal_fw_rule.php b/mds/web/modules/shorewall/shorewall/delete_internal_fw_rule.php index 9d8b9889c..2526d34a4 100644 --- a/mds/web/modules/shorewall/shorewall/delete_internal_fw_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_internal_fw_rule.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_internal_internal_rule.php b/mds/web/modules/shorewall/shorewall/delete_internal_internal_rule.php index c69d858a7..7b7fa2f29 100644 --- a/mds/web/modules/shorewall/shorewall/delete_internal_internal_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_internal_internal_rule.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_masquerade_rule.php b/mds/web/modules/shorewall/shorewall/delete_masquerade_rule.php index ba120c6f2..3c8cba0fb 100644 --- a/mds/web/modules/shorewall/shorewall/delete_masquerade_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_masquerade_rule.php @@ -2,7 +2,7 @@ /** * (c) 2012 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/delete_rule.php b/mds/web/modules/shorewall/shorewall/delete_rule.php index ec5579d06..a4aa6819f 100644 --- a/mds/web/modules/shorewall/shorewall/delete_rule.php +++ b/mds/web/modules/shorewall/shorewall/delete_rule.php @@ -2,7 +2,7 @@ /** * (c) 2012 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/dnat_rules.php b/mds/web/modules/shorewall/shorewall/dnat_rules.php index 5ea6a0aae..c391929d8 100644 --- a/mds/web/modules/shorewall/shorewall/dnat_rules.php +++ b/mds/web/modules/shorewall/shorewall/dnat_rules.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/external_fw.php b/mds/web/modules/shorewall/shorewall/external_fw.php index 69eacdda1..f82b9c916 100644 --- a/mds/web/modules/shorewall/shorewall/external_fw.php +++ b/mds/web/modules/shorewall/shorewall/external_fw.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/external_internal.php b/mds/web/modules/shorewall/shorewall/external_internal.php index 884c97475..8f9adec5b 100644 --- a/mds/web/modules/shorewall/shorewall/external_internal.php +++ b/mds/web/modules/shorewall/shorewall/external_internal.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/internal_external.php b/mds/web/modules/shorewall/shorewall/internal_external.php index 4985f4ca5..9777c0c0f 100644 --- a/mds/web/modules/shorewall/shorewall/internal_external.php +++ b/mds/web/modules/shorewall/shorewall/internal_external.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/internal_fw.php b/mds/web/modules/shorewall/shorewall/internal_fw.php index 9a9f3b299..a9e50fdf6 100644 --- a/mds/web/modules/shorewall/shorewall/internal_fw.php +++ b/mds/web/modules/shorewall/shorewall/internal_fw.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/internal_internal.php b/mds/web/modules/shorewall/shorewall/internal_internal.php index c20549d44..96ee9a964 100644 --- a/mds/web/modules/shorewall/shorewall/internal_internal.php +++ b/mds/web/modules/shorewall/shorewall/internal_internal.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/localSidebar.php b/mds/web/modules/shorewall/shorewall/localSidebar.php index 7018c4e3d..a997a5f8a 100644 --- a/mds/web/modules/shorewall/shorewall/localSidebar.php +++ b/mds/web/modules/shorewall/shorewall/localSidebar.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ $sidemenu = new SideMenu(); $sidemenu->setClass("shorewall"); -$sidemenu->setBackgroundImage("img/users/icn_users_large.gif"); +$sidemenu->setBackgroundImage("modules/base/graph/users/img/icn_users_large.gif"); $zones_types = getZonesTypes(); $lan_zones = getShorewallZones($zones_types['internal']); diff --git a/mds/web/modules/shorewall/shorewall/masquerade.php b/mds/web/modules/shorewall/shorewall/masquerade.php index 97f7e5b10..1a9c43291 100644 --- a/mds/web/modules/shorewall/shorewall/masquerade.php +++ b/mds/web/modules/shorewall/shorewall/masquerade.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/restart_service.php b/mds/web/modules/shorewall/shorewall/restart_service.php index 94c89707d..cc6f233fa 100644 --- a/mds/web/modules/shorewall/shorewall/restart_service.php +++ b/mds/web/modules/shorewall/shorewall/restart_service.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/shorewall/shorewall/rules.php b/mds/web/modules/shorewall/shorewall/rules.php index 8cb7df6ca..bd3faedb6 100644 --- a/mds/web/modules/shorewall/shorewall/rules.php +++ b/mds/web/modules/shorewall/shorewall/rules.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2012 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,6 @@ global $errorStatus; // Handle form return - if (isset($_POST['bpolicy'])) { foreach(getPolicies() as $policy) { if (isset($_POST[$policy[0] . "_" . $policy[1] . "_policy"])) { @@ -48,69 +47,77 @@ } } -if (isset($_POST['brule'])) { - if (isset($_POST['service'])) { - $service = $_POST['service']; - if ($service) { - if ($service == "custom") { - if (!$_POST['proto'] || !$_POST['port']) { - new NotifyWidgetFailure(_T("Protocol and port must be specified.")); - redirectTo(urlStrRedirect("shorewall/shorewall/" . $page)); - } - else { - $action = $_POST['decision']; - $proto = $_POST['proto']; - $port = $_POST['port']; - } +if (fromPOST('brule')) { + if (fromPOST('service')) { + $service = fromPOST('service'); + if ($service == "custom") { + if (! fromPOST('proto') || ! fromPOST('port')) { + new NotifyWidgetFailure(_T("Protocol and port must be specified.")); + redirectTo(urlStrRedirect("shorewall/shorewall/" . $page)); } else { - $action = $service . "/" . $_POST['decision']; - $proto = ""; - $port = ""; + $action = fromPOST('decision'); + $proto = fromPOST('proto'); + $port = fromPOST('port'); } + } + else { + $action = $service . "/" . fromPOST('decision'); + $proto = ""; + $port = ""; + } - # Source - $sources = array(); - if ($_POST['source'] == "all") { - foreach(getShorewallZones($src) as $zone) - $sources[] = $zone; - } - else - $sources[] = $_POST['source']; - - # Destination - $destinations = array(); - if ($_POST['destination'] == "all") { - foreach(getShorewallZones($dst) as $zone) - $destinations[] = $zone; - } - else - $destinations[] = $_POST['destination']; + # Source + $sources = array(); + if (fromPOST('source') == "all") { + foreach(getShorewallZones($src) as $zone) + $sources[] = $zone; + } + else + $sources[] = fromPOST('source'); - # Add rules - foreach($sources as $src) { - foreach($destinations as $dst) { - addRule($action, $src, $dst, $proto, $port); - } - } + if (fromPOST('source_ip')) { + foreach($sources as $k => $v) + $sources[$k] = $v . ":" . fromPOST('source_ip'); + } - if (!isXMLRPCError()) { - $n = new NotifyWidgetSuccess(_T("Rule added.")); - handleServicesModule($n, array("shorewall" => _T("Firewall"))); - redirectTo(urlStrRedirect("shorewall/shorewall/" . $page)); - } - else { - $errorStatus = false; - new NotifyWidgetFailure(_T("Failed to add the rule.")); + # Destination + $destinations = array(); + if (fromPOST('destination') == "all") { + foreach(getShorewallZones($dst) as $zone) + $destinations[] = $zone; + } + else + $destinations[] = fromPOST('destination'); + + if ($_POST['destination_ip']) { + foreach($destinations as $k => $v) + $destinations[$k] = $v . ":" . fromPOST('destination_ip'); + } + + # Add rules + foreach($sources as $final_src) { + foreach($destinations as $final_dst) { + addRule($action, $final_src, $final_dst, $proto, $port); } } + + if (!isXMLRPCError()) { + $n = new NotifyWidgetSuccess(_T("Rule added.")); + handleServicesModule($n, array("shorewall" => _T("Firewall"))); + redirectTo(urlStrRedirect("shorewall/shorewall/" . $page)); + } + else { + $errorStatus = false; + new NotifyWidgetFailure(_T("Failed to add the rule.")); + } } else { new NotifyWidgetFailure(_T("Service must be specified.")); } } -if (isset($_POST['brestart'])) { +if (fromPOST('brestart')) { redirectTo(urlStrRedirect("shorewall/shorewall/restart_service", array("page" => $page))); } @@ -166,8 +173,11 @@ $decisionTpl = new SelectItem("decision"); $decisionTpl->setElements(array(_T("Accept"), _T("Drop"))); $decisionTpl->setElementsVal(array("ACCEPT", "DROP")); +$decisionTpl->setSelected(fromPOST("decisionTpl")); -$f->add(new TrFormElement(_T("Decision"), $decisionTpl)); +$f->add( + new TrFormElement(_T("Decision"), $decisionTpl) +); $src_zones = getZonesInterfaces($src); if (count($src_zones) > 1) { @@ -180,15 +190,25 @@ $sourcesTpl = new SelectItem("source"); $sourcesTpl->setElements($sources); $sourcesTpl->setElementsVal($sourcesVals); - - $f->add(new TrFormElement(_T("Source"), $sourcesTpl)); + $sourcesTpl->setSelected(fromPOST("source")); + $f->add( + new TrFormElement(_T("Source zone"), $sourcesTpl) + ); } else { - $tr = new TrFormElement(_T("Source"), new HiddenTpl("source")); + $tr = new TrFormElement(_T("Source zone"), new HiddenTpl("source")); $tr->setStyle("display: none"); $f->add($tr, array("value" => "all")); } +if ($src != array("fw")) { + $f->add( + new TrFormElement(_T("Limit source IP(s)"), new InputTpl("source_ip"), + array("tooltip" => "Specify source IP(s), IP range(s), network for this rule separated by commas. (eg: 192.168.2.2,192.0.2.11-192.0.2.17)")), + array("value" => fromPOST('source_ip')) + ); +} + $dst_zones = getZonesInterfaces($dst); if (count($dst_zones) > 1) { $destinations = array("All"); @@ -200,15 +220,24 @@ $destinationsTpl = new SelectItem("destination"); $destinationsTpl->setElements($destinations); $destinationsTpl->setElementsVal($destinationsVals); + $destinationsTpl->setSelected(fromPOST("destination")); - $f->add(new TrFormElement(_T("Destination"), $destinationsTpl)); + $f->add( + new TrFormElement(_T("Destination zone"), $destinationsTpl) + ); } else { - $tr = new TrFormElement(_T("Destination"), new HiddenTpl("destination")); + $tr = new TrFormElement(_T("Destination zone"), new HiddenTpl("destination")); $tr->setStyle("display: none"); $f->add($tr, array("value" => "all")); } +if ($dst != array("fw")) { + $tr = new TrFormElement(_T("Limit destination IP(s)"), new InputTpl("destination_ip"), + array("tooltip" => "Specify destination IP(s), IP range(s), network for this rule separated by commas. (eg: 155.186.235.0/24,155.186.233.23)")); + $f->add($tr, array("value" => fromPOST("destination_ip"))); +} + $macros = getServices(); $services = array("", "Custom rule...") + $macros; $servicesVals = array("", "custom") + $macros; @@ -216,7 +245,10 @@ $serviceTpl->setElements($services); $serviceTpl->setElementsVal($servicesVals); -$f->add(new TrFormElement(_T("Service"), $serviceTpl)); +$f->add( + new TrFormElement(_T("Service"), $serviceTpl), + array("value" => fromPOST('service')) +); $f->pop(); $customDiv = new Div(array("id" => "custom")); @@ -228,11 +260,14 @@ $protoTpl->setElements(array("", "TCP", "UDP")); $protoTpl->setElementsVal(array("", "tcp", "udp")); -$f->add(new TrFormElement(_T("Protocol"), $protoTpl)); $f->add( - new TrFormElement(_T("Port(s)"), new InputTpl("port", "/^([0-9:,]{1,4}|[1-5][0-9:,]{4}|6[0-4][0-9:,]{3}|65[0-4][0-9:,]{2}|655[0-2][0-9:,]|6553[0-5:,])+$/"), - array("tooltip" => _T("You can specify multiple ports using ',' as separator (eg: 22,34,56). Port ranges can be defined with ':' (eg: 3400:3500 - from port 3400 to port 3500)."))), - array("value" => "") + new TrFormElement(_T("Protocol"), $protoTpl), + array("value" => fromPOST('proto')) +); +$f->add( + new TrFormElement(_T("Port(s)"), new InputTpl("port", "/^([0-9:,]{1,4}|[1-5][0-9:,]{4}|6[0-4][0-9:,]{3}|65[0-4][0-9:,]{2}|655[0-2][0-9:,]|6553[0-5:,])+$/"), + array("tooltip" => _T("You can specify multiple ports using ',' as separator (eg: 22,34,56). Port ranges can be defined with ':' (eg: 3400:3500 - from port 3400 to port 3500)."))), + array("value" => fromPOST('ports')) ); $f->pop(); diff --git a/mds/web/modules/squid/graph/actions/icn_blacklist.gif b/mds/web/modules/squid/graph/actions/icn_blacklist.gif new file mode 100644 index 000000000..6f80aa160 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_blacklist.gif differ diff --git a/mds/web/modules/squid/graph/actions/icn_blacklist_active.gif b/mds/web/modules/squid/graph/actions/icn_blacklist_active.gif new file mode 100644 index 000000000..b4631baa3 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_blacklist_active.gif differ diff --git a/mds/web/modules/squid/graph/actions/icn_blacklist_extend.gif b/mds/web/modules/squid/graph/actions/icn_blacklist_extend.gif new file mode 100644 index 000000000..d221058bc Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_blacklist_extend.gif differ diff --git a/mds/web/modules/squid/graph/actions/icn_blacklist_extend_active.gif b/mds/web/modules/squid/graph/actions/icn_blacklist_extend_active.gif new file mode 100644 index 000000000..3894b3eff Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_blacklist_extend_active.gif differ diff --git a/mds/web/modules/squid/graph/actions/icn_interval.png b/mds/web/modules/squid/graph/actions/icn_interval.png new file mode 100644 index 000000000..6b1385c74 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_interval.png differ diff --git a/mds/web/modules/squid/graph/actions/icn_interval_active.png b/mds/web/modules/squid/graph/actions/icn_interval_active.png new file mode 100644 index 000000000..81cfe97e4 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_interval_active.png differ diff --git a/mds/web/modules/squid/graph/actions/icn_ip_autorised.png b/mds/web/modules/squid/graph/actions/icn_ip_autorised.png new file mode 100644 index 000000000..fdaf41c73 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_ip_autorised.png differ diff --git a/mds/web/modules/squid/graph/actions/icn_ip_autorised_active.png b/mds/web/modules/squid/graph/actions/icn_ip_autorised_active.png new file mode 100644 index 000000000..a9f20c56d Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_ip_autorised_active.png differ diff --git a/mds/web/modules/squid/graph/actions/icn_whitelist.gif b/mds/web/modules/squid/graph/actions/icn_whitelist.gif new file mode 100644 index 000000000..4128eb3b7 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_whitelist.gif differ diff --git a/mds/web/modules/squid/graph/actions/icn_whitelist_active.gif b/mds/web/modules/squid/graph/actions/icn_whitelist_active.gif new file mode 100644 index 000000000..53e9c1785 Binary files /dev/null and b/mds/web/modules/squid/graph/actions/icn_whitelist_active.gif differ diff --git a/mds/web/modules/squid/graph/internet/add.css b/mds/web/modules/squid/graph/internet/add.css index 2dec99ae1..7b60cae65 100644 --- a/mds/web/modules/squid/graph/internet/add.css +++ b/mds/web/modules/squid/graph/internet/add.css @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/graph/internet/index.css b/mds/web/modules/squid/graph/internet/index.css index cb9245696..1469154b3 100644 --- a/mds/web/modules/squid/graph/internet/index.css +++ b/mds/web/modules/squid/graph/internet/index.css @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/includes/delete.php b/mds/web/modules/squid/includes/delete.php index 723f47b73..34ff2d776 100644 --- a/mds/web/modules/squid/includes/delete.php +++ b/mds/web/modules/squid/includes/delete.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/includes/manager.php b/mds/web/modules/squid/includes/manager.php index 172983a76..cd3f61150 100644 --- a/mds/web/modules/squid/includes/manager.php +++ b/mds/web/modules/squid/includes/manager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/includes/restart.php b/mds/web/modules/squid/includes/restart.php index 866d7b45a..d1be90b9a 100644 --- a/mds/web/modules/squid/includes/restart.php +++ b/mds/web/modules/squid/includes/restart.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/includes/squid-xmlrpc.inc.php b/mds/web/modules/squid/includes/squid-xmlrpc.inc.php index d2539a914..02ee7cbe6 100644 --- a/mds/web/modules/squid/includes/squid-xmlrpc.inc.php +++ b/mds/web/modules/squid/includes/squid-xmlrpc.inc.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/includes/squid.inc.php b/mds/web/modules/squid/includes/squid.inc.php index daaae2941..90c4b6fff 100644 --- a/mds/web/modules/squid/includes/squid.inc.php +++ b/mds/web/modules/squid/includes/squid.inc.php @@ -5,7 +5,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/infoPackage.inc.php b/mds/web/modules/squid/infoPackage.inc.php index d0c9b8c48..950183673 100644 --- a/mds/web/modules/squid/infoPackage.inc.php +++ b/mds/web/modules/squid/infoPackage.inc.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ */ $mod = new Module("squid"); -$mod->setVersion("2.5.89"); +$mod->setVersion("2.5.95"); $mod->setRevision(''); $mod->setDescription(_T("Web Proxy Content filter"),"squid"); $mod->setAPIVersion('1:1:0'); diff --git a/mds/web/modules/squid/internet/blackmanager.php b/mds/web/modules/squid/internet/blackmanager.php index 2cb934202..4b45fd21a 100644 --- a/mds/web/modules/squid/internet/blackmanager.php +++ b/mds/web/modules/squid/internet/blackmanager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/deleteb.php b/mds/web/modules/squid/internet/deleteb.php index 589e814de..47d2ff90c 100644 --- a/mds/web/modules/squid/internet/deleteb.php +++ b/mds/web/modules/squid/internet/deleteb.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/deletem.php b/mds/web/modules/squid/internet/deletem.php index bdca8286e..13d7d7254 100644 --- a/mds/web/modules/squid/internet/deletem.php +++ b/mds/web/modules/squid/internet/deletem.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/deletet.php b/mds/web/modules/squid/internet/deletet.php index dba52ccc8..149e10eda 100644 --- a/mds/web/modules/squid/internet/deletet.php +++ b/mds/web/modules/squid/internet/deletet.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/deletew.php b/mds/web/modules/squid/internet/deletew.php index e0d135a2a..435845329 100644 --- a/mds/web/modules/squid/internet/deletew.php +++ b/mds/web/modules/squid/internet/deletew.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/deletex.php b/mds/web/modules/squid/internet/deletex.php index b32f29b3f..3cf2c51e9 100644 --- a/mds/web/modules/squid/internet/deletex.php +++ b/mds/web/modules/squid/internet/deletex.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/extmanager.php b/mds/web/modules/squid/internet/extmanager.php index 9722ec58a..34a637340 100644 --- a/mds/web/modules/squid/internet/extmanager.php +++ b/mds/web/modules/squid/internet/extmanager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/localSidebar.php b/mds/web/modules/squid/internet/localSidebar.php index 514bf8935..710384c87 100644 --- a/mds/web/modules/squid/internet/localSidebar.php +++ b/mds/web/modules/squid/internet/localSidebar.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/machmanager.php b/mds/web/modules/squid/internet/machmanager.php index bb1acb327..faf3d2356 100644 --- a/mds/web/modules/squid/internet/machmanager.php +++ b/mds/web/modules/squid/internet/machmanager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/timemanager.php b/mds/web/modules/squid/internet/timemanager.php index 2ddd47fc1..b69f45f4a 100644 --- a/mds/web/modules/squid/internet/timemanager.php +++ b/mds/web/modules/squid/internet/timemanager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/internet/whitemanager.php b/mds/web/modules/squid/internet/whitemanager.php index 7bfb625a7..22d2763df 100644 --- a/mds/web/modules/squid/internet/whitemanager.php +++ b/mds/web/modules/squid/internet/whitemanager.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2008 Mandriva, http://www.mandriva.com/ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/localCss.php b/mds/web/modules/squid/localCss.php index f2c21923f..06f223fe3 100644 --- a/mds/web/modules/squid/localCss.php +++ b/mds/web/modules/squid/localCss.php @@ -5,7 +5,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/squid/locale/fr_FR/LC_MESSAGES/squid.po b/mds/web/modules/squid/locale/fr_FR/LC_MESSAGES/squid.po index 428f7c0bd..1c3c11db4 100644 --- a/mds/web/modules/squid/locale/fr_FR/LC_MESSAGES/squid.po +++ b/mds/web/modules/squid/locale/fr_FR/LC_MESSAGES/squid.po @@ -8,16 +8,17 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-12-22 01:00+0100\n" -"PO-Revision-Date: 2013-03-11 14:51+0000\n" -"Last-Translator: Jean-Philippe Braun \n" -"Language-Team: French (France) (http://transifex.mandriva.com/projects/p/mds/" -"team/fr_FR/)\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2015-01-29 15:17+0200\n" +"Last-Translator: Jean-Philippe \n" +"Language-Team: French " +"\n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 2.1-dev\n" #: modules/squid/includes/manager.php:91 msgid "Add" @@ -90,7 +91,7 @@ msgstr "Annuler" msgid "Default Position" msgstr "Position par défaut" -#: modules/squid/includes/delete.php:41 modules/squid/includes/manager.php:72 +#: modules/squid/includes/manager.php:72 modules/squid/includes/delete.php:41 msgid "Delete" msgstr "Supprimer" @@ -144,7 +145,6 @@ msgstr "Cacher les chemins" #: modules/squid/internet/accesslog.php:95 #: modules/squid/internet/accesslog/index.php:95 -#, fuzzy msgid "Hide different sub domains" msgstr "Cacher différents sous-domaines" @@ -162,8 +162,8 @@ msgid "IP address" msgstr "Adresse IP" #: modules/squid/infoPackage.inc.php:47 -#: modules/squid/internet/localSidebar.php:29 #: modules/squid/internet/machmanager.php:32 +#: modules/squid/internet/localSidebar.php:29 msgid "IP whitelist" msgstr "IPs autorisées" @@ -234,7 +234,7 @@ msgstr "" "Accès non filtré à Internet pendant l'intervalle de temps. Prévaut sur les " "listes noires. (ex: 08:00-14:00)" -#: modules/squid/includes/delete.php:30 modules/squid/includes/manager.php:43 +#: modules/squid/includes/manager.php:43 modules/squid/includes/delete.php:30 #: modules/squid/infoPackage.inc.php:30 msgid "Proxy" msgstr "Proxy" @@ -275,8 +275,8 @@ msgid "Time range is not valid." msgstr "L'intervalle n'est pas valide." #: modules/squid/infoPackage.inc.php:41 -#: modules/squid/internet/localSidebar.php:28 #: modules/squid/internet/timemanager.php:32 +#: modules/squid/internet/localSidebar.php:28 msgid "Time range whitelist" msgstr "Intervalles autorisés" diff --git a/mds/web/modules/squid/locale/pt_BR/LC_MESSAGES/squid.po b/mds/web/modules/squid/locale/pt_BR/LC_MESSAGES/squid.po index 4918fea12..59a729ea8 100644 --- a/mds/web/modules/squid/locale/pt_BR/LC_MESSAGES/squid.po +++ b/mds/web/modules/squid/locale/pt_BR/LC_MESSAGES/squid.po @@ -8,11 +8,11 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-26 01:00+0100\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2014-12-10 21:43+0200\n" "Last-Translator: Andre \n" -"Language-Team: Portuguese (Brazil) \n" +"Language-Team: Portuguese (Brazil) " +"\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -91,7 +91,7 @@ msgstr "Cancelar" msgid "Default Position" msgstr "Posição inicial" -#: modules/squid/includes/delete.php:41 modules/squid/includes/manager.php:72 +#: modules/squid/includes/manager.php:72 modules/squid/includes/delete.php:41 msgid "Delete" msgstr "Remover" @@ -161,8 +161,8 @@ msgid "IP address" msgstr "Endereço IP" #: modules/squid/infoPackage.inc.php:47 -#: modules/squid/internet/localSidebar.php:29 #: modules/squid/internet/machmanager.php:32 +#: modules/squid/internet/localSidebar.php:29 msgid "IP whitelist" msgstr "IP Lista Branca" @@ -234,7 +234,7 @@ msgstr "" "listas negras. O intervalo de tempo deve ser no formato de 24 horas. (Por " "exemplo: 08:00-18:00)" -#: modules/squid/includes/delete.php:30 modules/squid/includes/manager.php:43 +#: modules/squid/includes/manager.php:43 modules/squid/includes/delete.php:30 #: modules/squid/infoPackage.inc.php:30 msgid "Proxy" msgstr "Proxy" @@ -275,8 +275,8 @@ msgid "Time range is not valid." msgstr "Intervalo de tempo não é válido." #: modules/squid/infoPackage.inc.php:41 -#: modules/squid/internet/localSidebar.php:28 #: modules/squid/internet/timemanager.php:32 +#: modules/squid/internet/localSidebar.php:28 msgid "Time range whitelist" msgstr "Intervalo de tempo" diff --git a/mds/web/modules/sshlpk/Makefile.am b/mds/web/modules/sshlpk/Makefile.am index 71af8f175..747e1e7d3 100644 --- a/mds/web/modules/sshlpk/Makefile.am +++ b/mds/web/modules/sshlpk/Makefile.am @@ -2,7 +2,7 @@ # # $Id$ # -# This file is part of Mandriva Management Console (MMC). +# This file is part of Management Console. # # MMC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,7 +24,8 @@ datafiles = \ infoPackage.inc.php \ includes/sshlpk-xmlrpc.php \ includes/publicFunc.php \ - includes/auditCodes.php + includes/auditCodes.php \ + keys/edit.php langs = nb_NO es_ES ru_RU pt_BR da_DK de_DE pl_PL fr_FR diff --git a/mds/web/modules/sshlpk/includes/publicFunc.php b/mds/web/modules/sshlpk/includes/publicFunc.php index 7b7b0a256..ab624c801 100644 --- a/mds/web/modules/sshlpk/includes/publicFunc.php +++ b/mds/web/modules/sshlpk/includes/publicFunc.php @@ -6,7 +6,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/sshlpk/includes/sshlpk-xmlrpc.php b/mds/web/modules/sshlpk/includes/sshlpk-xmlrpc.php index e4c54e3ed..d9cdc9e0c 100644 --- a/mds/web/modules/sshlpk/includes/sshlpk-xmlrpc.php +++ b/mds/web/modules/sshlpk/includes/sshlpk-xmlrpc.php @@ -6,7 +6,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/sshlpk/infoPackage.inc.php b/mds/web/modules/sshlpk/infoPackage.inc.php index 67efa4498..e48ca2863 100644 --- a/mds/web/modules/sshlpk/infoPackage.inc.php +++ b/mds/web/modules/sshlpk/infoPackage.inc.php @@ -4,7 +4,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2014 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ $MMCApp =& MMCApp::getInstance(); $mod = new Module("sshlpk"); -$mod->setVersion("2.5.89"); +$mod->setVersion("2.5.95"); $mod->setRevision('$Rev$'); $mod->setDescription(_T("LDAP Public SSH key management","sshlpk")); $mod->setAPIVersion("0:0:0"); diff --git a/mds/web/modules/sshlpk/keys/edit.php b/mds/web/modules/sshlpk/keys/edit.php index b14ff254f..399a8fe4e 100644 --- a/mds/web/modules/sshlpk/keys/edit.php +++ b/mds/web/modules/sshlpk/keys/edit.php @@ -3,7 +3,7 @@ * (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com * (c) 2007-2014 Mandriva, http://www.mandriva.com * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/sshlpk/locale/da_DK/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/da_DK/LC_MESSAGES/sshlpk.po index 13e818171..237d106b3 100644 --- a/mds/web/modules/sshlpk/locale/da_DK/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/da_DK/LC_MESSAGES/sshlpk.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: da_DK\n" diff --git a/mds/web/modules/sshlpk/locale/de_DE/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/de_DE/LC_MESSAGES/sshlpk.po index 6b7169ad5..d4787044b 100644 --- a/mds/web/modules/sshlpk/locale/de_DE/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/de_DE/LC_MESSAGES/sshlpk.po @@ -8,24 +8,25 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" -"Language-Team: German (Germany) (http://transifex.mandriva.com/projects/p/" -"mds/team/de_DE/)\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2015-03-02 17:36+0200\n" +"Last-Translator: Maik \n" +"Language-Team: German " +"\n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 2.1-dev\n" #: modules/sshlpk/infoPackage.inc.php:40 msgid "Change SSH keys" -msgstr "" +msgstr "SSH-Schlüssel ändern" #: modules/sshlpk/keys/edit.php:48 msgid "Change your SSH keys" -msgstr "" +msgstr "SSH-Schlüssel modifizieren" #: modules/sshlpk/includes/publicFunc.php:51 modules/sshlpk/keys/edit.php:58 msgid "Enable SSH keys management" @@ -37,7 +38,7 @@ msgstr "LDAP SSH Public Key-Management" #: modules/sshlpk/infoPackage.inc.php:35 msgid "Manage SSH keys" -msgstr "" +msgstr "Verwaltung der SSH-Schlüssel" #: modules/sshlpk/includes/publicFunc.php:73 modules/sshlpk/keys/edit.php:73 msgid "Public SSH Key" diff --git a/mds/web/modules/sshlpk/locale/es_ES/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/es_ES/LC_MESSAGES/sshlpk.po index f999390a4..e91736d6e 100644 --- a/mds/web/modules/sshlpk/locale/es_ES/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/es_ES/LC_MESSAGES/sshlpk.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2011-08-24 16:11+0000\n" +"Last-Translator: Jean-Philippe Braun \n" "Language-Team: Spanish (Spain) (http://transifex.mandriva.com/projects/p/mds/" "team/es_ES/)\n" "Language: es_ES\n" @@ -20,12 +20,14 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: modules/sshlpk/infoPackage.inc.php:40 +#, fuzzy msgid "Change SSH keys" -msgstr "" +msgstr "Gestionar claves SSH" #: modules/sshlpk/keys/edit.php:48 +#, fuzzy msgid "Change your SSH keys" -msgstr "" +msgstr "Gestionar claves SSH" #: modules/sshlpk/includes/publicFunc.php:51 modules/sshlpk/keys/edit.php:58 msgid "Enable SSH keys management" @@ -36,8 +38,9 @@ msgid "LDAP Public SSH key management" msgstr "Gestión LDAP de claves públicas SSH " #: modules/sshlpk/infoPackage.inc.php:35 +#, fuzzy msgid "Manage SSH keys" -msgstr "" +msgstr "Gestionar claves SSH" #: modules/sshlpk/includes/publicFunc.php:73 modules/sshlpk/keys/edit.php:73 msgid "Public SSH Key" diff --git a/mds/web/modules/sshlpk/locale/fr_FR/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/fr_FR/LC_MESSAGES/sshlpk.po index 03e55e7a6..4ff1e43a1 100644 --- a/mds/web/modules/sshlpk/locale/fr_FR/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/fr_FR/LC_MESSAGES/sshlpk.po @@ -8,24 +8,25 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" -"Language-Team: French (France) (http://transifex.mandriva.com/projects/p/mds/" -"team/fr_FR/)\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-12-23 10:14+0200\n" +"Last-Translator: Jean-Philippe \n" +"Language-Team: French " +"\n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 2.1-dev\n" #: modules/sshlpk/infoPackage.inc.php:40 msgid "Change SSH keys" -msgstr "" +msgstr "Modifier les clés SSH" #: modules/sshlpk/keys/edit.php:48 msgid "Change your SSH keys" -msgstr "" +msgstr "Modifier vos clés SSH" #: modules/sshlpk/includes/publicFunc.php:51 modules/sshlpk/keys/edit.php:58 msgid "Enable SSH keys management" @@ -37,7 +38,7 @@ msgstr "Gestion des clés publiques SSH par LDAP" #: modules/sshlpk/infoPackage.inc.php:35 msgid "Manage SSH keys" -msgstr "" +msgstr "Gestion des clés SSH" #: modules/sshlpk/includes/publicFunc.php:73 modules/sshlpk/keys/edit.php:73 msgid "Public SSH Key" diff --git a/mds/web/modules/sshlpk/locale/nb_NO/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/nb_NO/LC_MESSAGES/sshlpk.po index 31af7200f..17ac7d506 100644 --- a/mds/web/modules/sshlpk/locale/nb_NO/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/nb_NO/LC_MESSAGES/sshlpk.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: nb_NO\n" diff --git a/mds/web/modules/sshlpk/locale/pl_PL/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/pl_PL/LC_MESSAGES/sshlpk.po index 9f75104a4..9c0f9eac6 100644 --- a/mds/web/modules/sshlpk/locale/pl_PL/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/pl_PL/LC_MESSAGES/sshlpk.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: pl_PL\n" diff --git a/mds/web/modules/sshlpk/locale/pt_BR/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/pt_BR/LC_MESSAGES/sshlpk.po index 5edd2b69f..013de9d77 100644 --- a/mds/web/modules/sshlpk/locale/pt_BR/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/pt_BR/LC_MESSAGES/sshlpk.po @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2012-12-13 17:44+0000\n" +"Last-Translator: Alexandre Proença \n" "Language-Team: Portuguese (Brazilian) (http://transifex.mandriva.com/" "projects/p/mds/team/pt_BR/)\n" "Language: pt_BR\n" @@ -21,12 +21,14 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1)\n" #: modules/sshlpk/infoPackage.inc.php:40 +#, fuzzy msgid "Change SSH keys" -msgstr "" +msgstr "Gerenciar chave SSH" #: modules/sshlpk/keys/edit.php:48 +#, fuzzy msgid "Change your SSH keys" -msgstr "" +msgstr "Gerenciar chave SSH" #: modules/sshlpk/includes/publicFunc.php:51 modules/sshlpk/keys/edit.php:58 msgid "Enable SSH keys management" @@ -37,8 +39,9 @@ msgid "LDAP Public SSH key management" msgstr "Gerenciamento LDAP público de chaves SSH" #: modules/sshlpk/infoPackage.inc.php:35 +#, fuzzy msgid "Manage SSH keys" -msgstr "" +msgstr "Gerenciar chave SSH" #: modules/sshlpk/includes/publicFunc.php:73 modules/sshlpk/keys/edit.php:73 msgid "Public SSH Key" diff --git a/mds/web/modules/sshlpk/locale/ru_RU/LC_MESSAGES/sshlpk.po b/mds/web/modules/sshlpk/locale/ru_RU/LC_MESSAGES/sshlpk.po index 2f00b74ce..63006a053 100644 --- a/mds/web/modules/sshlpk/locale/ru_RU/LC_MESSAGES/sshlpk.po +++ b/mds/web/modules/sshlpk/locale/ru_RU/LC_MESSAGES/sshlpk.po @@ -8,9 +8,9 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2014-12-15 15:09+0000\n" -"Last-Translator: Buildbot Mandriva \n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2011-08-24 16:11+0000\n" +"Last-Translator: Jean-Philippe Braun \n" "Language-Team: Russian (Russia) (http://transifex.mandriva.com/projects/p/" "mds/team/ru_RU/)\n" "Language: ru_RU\n" @@ -21,12 +21,14 @@ msgstr "" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" #: modules/sshlpk/infoPackage.inc.php:40 +#, fuzzy msgid "Change SSH keys" -msgstr "" +msgstr "Управлять ключем SSH" #: modules/sshlpk/keys/edit.php:48 +#, fuzzy msgid "Change your SSH keys" -msgstr "" +msgstr "Управлять ключем SSH" #: modules/sshlpk/includes/publicFunc.php:51 modules/sshlpk/keys/edit.php:58 msgid "Enable SSH keys management" @@ -37,8 +39,9 @@ msgid "LDAP Public SSH key management" msgstr "Управление публичными ключами SSH для LDAP" #: modules/sshlpk/infoPackage.inc.php:35 +#, fuzzy msgid "Manage SSH keys" -msgstr "" +msgstr "Управлять ключем SSH" #: modules/sshlpk/includes/publicFunc.php:73 modules/sshlpk/keys/edit.php:73 msgid "Public SSH Key" diff --git a/mds/web/modules/userquota/Makefile.am b/mds/web/modules/userquota/Makefile.am index f1ae3c573..b7d47e5e7 100644 --- a/mds/web/modules/userquota/Makefile.am +++ b/mds/web/modules/userquota/Makefile.am @@ -2,7 +2,7 @@ # # $Id$ # -# This file is part of Mandriva Management Console (MMC). +# This file is part of Management Console. # # MMC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/userquota/includes/publicFunc.php b/mds/web/modules/userquota/includes/publicFunc.php index 818c2341a..8c54efa50 100644 --- a/mds/web/modules/userquota/includes/publicFunc.php +++ b/mds/web/modules/userquota/includes/publicFunc.php @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/userquota/includes/userquota-xmlrpc.php b/mds/web/modules/userquota/includes/userquota-xmlrpc.php index 280f5bfb1..a35725251 100644 --- a/mds/web/modules/userquota/includes/userquota-xmlrpc.php +++ b/mds/web/modules/userquota/includes/userquota-xmlrpc.php @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/userquota/includes/userquota.php b/mds/web/modules/userquota/includes/userquota.php index ca94fb541..984e23c00 100644 --- a/mds/web/modules/userquota/includes/userquota.php +++ b/mds/web/modules/userquota/includes/userquota.php @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/mds/web/modules/userquota/infoPackage.inc.php b/mds/web/modules/userquota/infoPackage.inc.php index fed97461c..f9013ff09 100644 --- a/mds/web/modules/userquota/infoPackage.inc.php +++ b/mds/web/modules/userquota/infoPackage.inc.php @@ -4,7 +4,7 @@ * * $Id$ * - * This file is part of Mandriva Management Console (MMC). + * This file is part of Management Console. * * MMC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ * module declaration */ $mod = new Module("userquota"); -$mod->setVersion("2.5.89"); +$mod->setVersion("2.5.95"); $mod->setRevision('$Rev$'); $mod->setDescription(_T("Manage user quotas for filesystems and networks", "userquota")); $mod->setAPIVersion('0:0:0'); diff --git a/mds/web/modules/userquota/locale/da_DK/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/da_DK/LC_MESSAGES/userquota.po index 71998678c..d528a0e1d 100644 --- a/mds/web/modules/userquota/locale/da_DK/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/da_DK/LC_MESSAGES/userquota.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: da_DK\n" diff --git a/mds/web/modules/userquota/locale/de_DE/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/de_DE/LC_MESSAGES/userquota.po index 4b246ae2c..fa9e7352e 100644 --- a/mds/web/modules/userquota/locale/de_DE/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/de_DE/LC_MESSAGES/userquota.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2013-08-18 11:31+0000\n" "Last-Translator: Maik Wagner \n" "Language-Team: German (Germany) (http://transifex.mandriva.com/projects/p/" diff --git a/mds/web/modules/userquota/locale/es_ES/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/es_ES/LC_MESSAGES/userquota.po index 7a5237d37..4329afe12 100644 --- a/mds/web/modules/userquota/locale/es_ES/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/es_ES/LC_MESSAGES/userquota.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2013-08-16 13:13+0000\n" "Last-Translator: Buildbot Mandriva \n" "Language-Team: Spanish (Spain) (http://transifex.mandriva.com/projects/p/mds/" diff --git a/mds/web/modules/userquota/locale/fr_FR/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/fr_FR/LC_MESSAGES/userquota.po index d0af2fceb..7087f8a1d 100644 --- a/mds/web/modules/userquota/locale/fr_FR/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/fr_FR/LC_MESSAGES/userquota.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2014-01-23 14:41+0000\n" "Last-Translator: Jean-Philippe Braun \n" "Language-Team: French (France) (http://transifex.mandriva.com/projects/p/mds/" diff --git a/mds/web/modules/userquota/locale/nb_NO/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/nb_NO/LC_MESSAGES/userquota.po index 446330884..ab3e9dfd9 100644 --- a/mds/web/modules/userquota/locale/nb_NO/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/nb_NO/LC_MESSAGES/userquota.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: nb_NO\n" diff --git a/mds/web/modules/userquota/locale/pl_PL/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/pl_PL/LC_MESSAGES/userquota.po index 5239d9830..37902af80 100644 --- a/mds/web/modules/userquota/locale/pl_PL/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/pl_PL/LC_MESSAGES/userquota.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" -"PO-Revision-Date: 2015-05-24 23:01+0000\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" +"PO-Revision-Date: 2014-11-03 00:01+0000\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: pl_PL\n" diff --git a/mds/web/modules/userquota/locale/pt_BR/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/pt_BR/LC_MESSAGES/userquota.po index 8bad9d381..77a0bb0b4 100644 --- a/mds/web/modules/userquota/locale/pt_BR/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/pt_BR/LC_MESSAGES/userquota.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2014-09-10 20:22+0000\n" "Last-Translator: Andre Machado \n" "Language-Team: Portuguese (Brazilian) (http://transifex.mandriva.com/" diff --git a/mds/web/modules/userquota/locale/ru_RU/LC_MESSAGES/userquota.po b/mds/web/modules/userquota/locale/ru_RU/LC_MESSAGES/userquota.po index 9d9b61d27..9389b769f 100644 --- a/mds/web/modules/userquota/locale/ru_RU/LC_MESSAGES/userquota.po +++ b/mds/web/modules/userquota/locale/ru_RU/LC_MESSAGES/userquota.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Mandriva Directory Server\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-05-25 01:02+0200\n" +"POT-Creation-Date: 2014-12-10 17:18+0100\n" "PO-Revision-Date: 2013-08-16 13:12+0000\n" "Last-Translator: Buildbot Mandriva \n" "Language-Team: Russian (Russia) (http://transifex.mandriva.com/projects/p/" diff --git a/mds/web/scripts/build_pot.sh b/mds/web/scripts/build_pot.sh index 054d2b075..222dcfdc8 100755 --- a/mds/web/scripts/build_pot.sh +++ b/mds/web/scripts/build_pot.sh @@ -5,7 +5,7 @@ # # $Id: build_pot.sh 6329 2010-03-30 07:51:21Z cdelfosse $ # -# This file is part of Mandriva Management Console (MMC). +# This file is part of Management Console. # # MMC is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/packaging/debian/pulse2/debian/changelog b/packaging/debian/pulse2/debian/changelog index 3f101ec36..727e04e16 100644 --- a/packaging/debian/pulse2/debian/changelog +++ b/packaging/debian/pulse2/debian/changelog @@ -1,3 +1,61 @@ +pulse2 (3.0.2-9) unstable; urgency=low + * Bugfixes ( multicast, menus, ... ) ( 8d8908e1f4555d751b15db1f561e620514f11b3d ) + + -- Nicolas Lécureuil Wed, 9 Feb 2016 17:00:11 +0100 + +pulse2 (3.0.2-8) unstable; urgency=low + * Bugfixes ( multicast, menus, ... ) + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-7) unstable; urgency=low + * Fix several menu bugs + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-6) unstable; urgency=low + * Fix sysinit choice. + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-5) unstable; urgency=low + * Fix postinst scripts + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-4) unstable; urgency=low + * Fix pulse2-cm initscript + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-3) unstable; urgency=low + * Fix support with newer sqlalchemy + * Fix support with newer python-twisted + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-2) unstable; urgency=low + * Multicast fixes + + -- Nicolas Lécureuil Wed, 13 Jan 2016 17:00:11 +0100 + +pulse2 (3.0.2-1) unstable; urgency=low + * Add Support for multicast + + -- root Mon, 02 Mar 2015 17:00:11 +0100 + +pulse2 (3.0-6) unstable; urgency=low + * Fix support URL + + -- root Mon, 02 Mar 2015 17:00:11 +0100 + +pulse2 (3.0-5) unstable; urgency=low + * New Snaphot + * Fix URL + * Fix icons + * Fix logo + + -- root Mon, 02 Mar 2015 17:00:11 +0100 + pulse2 (3.0-1) unstable; urgency=low * New upstream release diff --git a/packaging/debian/pulse2/debian/control b/packaging/debian/pulse2/debian/control index c56e8ebb4..c417a5477 100644 --- a/packaging/debian/pulse2/debian/control +++ b/packaging/debian/pulse2/debian/control @@ -24,7 +24,6 @@ Depends: ${misc:Depends}, pulse2-launchers, pulse2-package-server, pulse2-scheduler, - pulse2-cm, pulse2-homepage Description: Pulse 2 metapackage This empty package depends on all Pulse2/MMC required packages. diff --git a/packaging/debian/pulse2/debian/mmc-web-monitoring.install b/packaging/debian/pulse2/debian/mmc-web-monitoring.install deleted file mode 100644 index b908d284f..000000000 --- a/packaging/debian/pulse2/debian/mmc-web-monitoring.install +++ /dev/null @@ -1 +0,0 @@ -usr/share/mmc/modules/monitoring diff --git a/packaging/debian/pulse2/debian/pulse2-cm.init b/packaging/debian/pulse2/debian/pulse2-cm.init index 806972a95..a54d46601 100644 --- a/packaging/debian/pulse2/debian/pulse2-cm.init +++ b/packaging/debian/pulse2/debian/pulse2-cm.init @@ -1,3 +1,4 @@ +#!/bin/sh # Pulse 2 is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or diff --git a/packaging/debian/pulse2/debian/python-mmc-monitoring.install b/packaging/debian/pulse2/debian/python-mmc-monitoring.install deleted file mode 100644 index 38ffd928d..000000000 --- a/packaging/debian/pulse2/debian/python-mmc-monitoring.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/lib/python2.?/*-packages/mmc/plugins/monitoring -etc/mmc/plugins/monitoring.ini diff --git a/packaging/debian/pulse2/debian/python-pulse2-common-database-monitoring.install b/packaging/debian/pulse2/debian/python-pulse2-common-database-monitoring.install deleted file mode 100644 index bc76fcdc7..000000000 --- a/packaging/debian/pulse2/debian/python-pulse2-common-database-monitoring.install +++ /dev/null @@ -1 +0,0 @@ -/usr/lib/python2.?/*-packages/pulse2/database/monitoring diff --git a/pulse2/ChangeLog b/pulse2/ChangeLog index f9770f473..10a60ae48 100644 --- a/pulse2/ChangeLog +++ b/pulse2/ChangeLog @@ -1,9 +1,8 @@ -Pulse 2 1.3.0 +Pulse 2 3.3.0 ============= - - * The new imaging module allows bare-metal backup and recovery under - Windows or GNU/Linux - * Profile system for computers - * New features in the MMC web interface for our native inventory backend - * Support for GLPI backend version 0.72.x and latest 0.78 version - * More details at http://pulse2.mandriva.org/milestone/1.3.0 + * [BUGFIX] Allow to disable backuppc + * [BUGFIX] Enhance systemd support in pulse2-setup + * [FEATURE] Add Multicast support + * [BUGFIX] Fix support for new sqlalchemy + * [BUGFIX] Fix support for new python-twisted + * [BUGFIX] Fix pulse2-cm initscipt for debian diff --git a/pulse2/bump.sh b/pulse2/bump.sh index 90b38dde1..ee2757920 100755 --- a/pulse2/bump.sh +++ b/pulse2/bump.sh @@ -4,7 +4,7 @@ version=$1 if [ ! -z $1 ]; then - sed -i "s/^AC_INIT.*$/AC_INIT\(project, [$1], [http:\/\/www.mandriva.com]\)/" configure.ac + sed -i "s/^AC_INIT.*$/AC_INIT\(project, [$1], [http:\/\/www.siveo.org]\)/" configure.ac git diff git commit -a -m "pulse: bump version to $1" diff --git a/pulse2/configure.ac b/pulse2/configure.ac index 1cb49df24..f0a0197bd 100644 --- a/pulse2/configure.ac +++ b/pulse2/configure.ac @@ -22,7 +22,7 @@ AC_PREREQ(2.59) dnl autoconf initialization define([project], [pulse2]) -AC_INIT(project, [3.0], [http://www.mandriva.com]) +AC_INIT(project, [3.0.2], [http://www.siveo.net]) AC_CANONICAL_BUILD AC_CANONICAL_HOST diff --git a/pulse2/services/bin/pulse2-setup b/pulse2/services/bin/pulse2-setup index 6e124361e..32fe9670d 100755 --- a/pulse2/services/bin/pulse2-setup +++ b/pulse2/services/bin/pulse2-setup @@ -258,35 +258,43 @@ class SystemctlHandler(object): apache_dir = None def enable_srv(self, name): - ret = call("/bin/systemctl enable %(name)s.service" % {'name': name}, shell=True) + default_config = os.path.join(sysconfdir, 'default', name) + if os.path.exists(default_config): + ret = call("sed -i 's/ENABLE=no/ENABLE=yes/' %s" % default_config, shell=True) + else: + ret = call("/bin/systemctl enable %(name)s.service" % {'name': name}, shell=True) if ret != 0: return False return ret==0 def disable_srv(self, name): - ret = call("/bin/systemctl disable %(name)s.service" % {'name': name}, shell=True) + default_config = os.path.join(sysconfdir, 'default', name) + if os.path.exists(default_config): + ret = call("sed -i 's/ENABLE=yes/ENABLE=no/' %s" % default_config, shell=True) + else: + ret = call("/bin/systemctl disable %(name)s.service" % {'name': name}, shell=True) if ret != 0: return False return ret==0 def start_srv(self, name): - ret = call("/sbin/service %(name)s start" % {'name': name}, shell=True) + ret = call("/bin/systemctl start %(name)s.service" % {'name': name}, shell=True) return ret==0 def stop_srv(self, name): - ret = call("/sbin/service %(name)s stop" % {'name': name}, shell=True) + ret = call("/bin/systemctl stop %(name)s.service" % {'name': name}, shell=True) return ret==0 def reload_srv(self, name): - ret = call("/sbin/service %(name)s reload" % {'name': name}, shell=True) + ret = call("/bin/systemctl reload %(name)s.service" % {'name': name}, shell=True) return ret==0 def get_distro_handler(): - if os.path.exists('/usr/sbin/update-rc.d'): - return DebianHandler() - elif os.path.exists('/bin/systemctl'): + if os.path.exists('/bin/systemctl') and os.path.realpath('/sbin/init') == "/lib/systemd/systemd": return SystemctlHandler() + elif os.path.exists('/usr/sbin/update-rc.d'): + return DebianHandler() else: return DistroHandler() @@ -792,6 +800,7 @@ class SetupApp(object): self.defaults['inventory.service.enable'] = self.options["server_inventory"] self.defaults['package.service.enable'] = self.options["server_package"] self.defaults['glpi.plugin.enable'] = self.options["glpi_enable"] + self.defaults['backup.service.enable'] = self.options["server_backup"] self.defaults['ldapurl'] = self.options['ldapurl'] or self.confs['plugins/base.ini'].get('ldap', 'ldapurl') self.defaults['ldapbasedn'] = self.options['ldapbasedn'] or self.confs['plugins/base.ini'].get('ldap', 'baseDN') @@ -834,6 +843,8 @@ class SetupApp(object): self.defaults['glpi.plugin.enable']) self.config['package.service.enable'] = self.read_bool('Enable package server (proxy)', self.defaults['package.service.enable']) + self.config['backup.service.enable'] = self.read_bool('Enable backup server (backuppc)', + self.defaults['backup.service.enable']) self.config['server.ip.external'] = self.read_ip('Server external IP address', self.defaults['ipexternal']) self.config['backuppc_ip'] = self.read_opt('BackupPC IP', self.defaults['backuppc_ip']) @@ -860,14 +871,17 @@ class SetupApp(object): invalids += ['ldapbasedn', 'ldapadmindn', 'ldappasswd'] log.error("Invalid credentials, check base DN, admin DN and password.") log.debug(str(e)) + sys.exit() except ldap.SERVER_DOWN, e: invalids += ['ldapurl'] log.error("Incorrect server") log.debug(str(e)) + sys.exit() except ldap.UNWILLING_TO_PERFORM, e: invalids += ['ldappasswd'] log.error("Empty password not supported") log.debug(str(e)) + sys.exit() log.info("Connection to LDAP succesfull.") # Check mmc schema is installed @@ -1181,7 +1195,7 @@ class SetupApp(object): self.confs['plugins/msc.ini'].get('msc', 'download_directory_path'), self.confs['pulse2/package-server/package-server.ini'].get('main', 'tmp_input_dir'), LoggingConfig.log_dir]: - if not os.path.isdir(path): + if path and not os.path.isdir(path): log.info("Creating directory: %s" % path) os.makedirs(path) @@ -1255,7 +1269,7 @@ class SetupApp(object): # Associate local BackupPC server to first entity (UUID1) binpath = path_lookup('pulse2-backup-servers') - if binpath is not None: + if binpath is not None and self.config['backup.service.enable']: cmd = binpath + ' -a -e ' + self.config['backuppc_entity'] + ' -p http://' + self.config['backuppc_ip'] + '/backuppc/index.cgi' log.debug('Call: %s' % cmd) if call(cmd, shell=True) != 0: @@ -1350,6 +1364,9 @@ if __name__ == '__main__': parser.add_option("--disable-package", dest="disable_package", default=False, action="store_true", help="Disable package server") + parser.add_option("--disable-backup", dest="disable_backup", + default=False, action="store_true", + help="Disable backup server") parser.add_option("--glpi-enable", dest="enable_glpi", default=False, action="store_true", help="Enable GLPI plugin") @@ -1405,6 +1422,7 @@ if __name__ == '__main__': 'ldappasswd': options.ldappasswd, 'server_inventory': not options.disable_inventory, 'server_package': not options.disable_package, + 'server_backup': not options.disable_backup, 'glpi_enable': options.enable_glpi, 'glpi_purge_machines': options.glpi_purge_machines, 'glpi_webservices_user': options.glpi_webservices_user, diff --git a/pulse2/services/clients/agent/win32/artwork/header.bmp b/pulse2/services/clients/agent/win32/artwork/header.bmp index 134a3a061..dbdcbbf8e 100644 Binary files a/pulse2/services/clients/agent/win32/artwork/header.bmp and b/pulse2/services/clients/agent/win32/artwork/header.bmp differ diff --git a/pulse2/services/clients/agent/win32/artwork/wizard.bmp b/pulse2/services/clients/agent/win32/artwork/wizard.bmp index 7d838e7d8..07590ade4 100644 Binary files a/pulse2/services/clients/agent/win32/artwork/wizard.bmp and b/pulse2/services/clients/agent/win32/artwork/wizard.bmp differ diff --git a/pulse2/services/clients/create-repos.sh b/pulse2/services/clients/create-repos.sh index 909262e52..8165a30b6 100755 --- a/pulse2/services/clients/create-repos.sh +++ b/pulse2/services/clients/create-repos.sh @@ -25,8 +25,8 @@ # ---------------------- GPG KEY GENERATE ---------------------------- BASE_DIR=$(dirname $0) -NAME="Mandriva Support" -EMAIL="sales@mandriva.com" +NAME="Siveo Support" +EMAIL="support@siveo.net" HOME="/root" GPG_KEY_CONF=$HOME/gpg-key-conf GPG_KEY_FILE="pulse2-agents.gpg.key" diff --git a/pulse2/services/clients/win32/artwork/header.bmp b/pulse2/services/clients/win32/artwork/header.bmp index 134a3a061..dbdcbbf8e 100644 Binary files a/pulse2/services/clients/win32/artwork/header.bmp and b/pulse2/services/clients/win32/artwork/header.bmp differ diff --git a/pulse2/services/clients/win32/artwork/wizard.bmp b/pulse2/services/clients/win32/artwork/wizard.bmp index 7d838e7d8..07590ade4 100644 Binary files a/pulse2/services/clients/win32/artwork/wizard.bmp and b/pulse2/services/clients/win32/artwork/wizard.bmp differ diff --git a/pulse2/services/clients/win32/generate-agent-pack.sh.in b/pulse2/services/clients/win32/generate-agent-pack.sh.in index f405050cc..92c67ccfd 100755 --- a/pulse2/services/clients/win32/generate-agent-pack.sh.in +++ b/pulse2/services/clients/win32/generate-agent-pack.sh.in @@ -50,10 +50,11 @@ sfx_file=7zsd.sfx # https://www.dropbox.com/sh/qdrpsttj8tqsn2q/AAC4AN0h_TKtfkRocQawQQMHa # Compute downloads url -ssh_url=http://repo.pulse2.fr/pub/pulse2/client/windows/win32/pulse2-secure-agent/${ssh_file} -vnc_url=http://repo.pulse2.fr/pub/pulse2/client/windows/win32/pulse2-rda-agent/${vnc_file} -inv_url=http://repo.pulse2.fr/pub/pulse2/client/windows/win32/inventory-agent/${inv_file} -sfx_url=http://repo.pulse2.fr/pub/pulse2/client/windows/win32/${sfx_file} +ssh_url=http://pulse_agents.siveo.net/${ssh_file} +vnc_url=http://pulse_agents.siveo.net/${vnc_file} +inv_url=http://pulse_agents.siveo.net/${inv_file} +sfx_url=http://pulse_agents.siveo.net/${sfx_file} + # Unfortunately, MSI agent service is no more alive :-( # the idea was to provide a service to generate MSI version of Pulse's agents diff --git a/pulse2/services/conf/pulse2/package-server/package-server.ini b/pulse2/services/conf/pulse2/package-server/package-server.ini index 4fc1262aa..2e9ae76bb 100644 --- a/pulse2/services/conf/pulse2/package-server/package-server.ini +++ b/pulse2/services/conf/pulse2/package-server/package-server.ini @@ -112,9 +112,9 @@ password = s3cr3t # bootmenus_folder = bootmenus ### Diskless # Where kernel, initrd and other official diskless tools are stored, relative to "base_folder" -# diskless_folder = diskless # Where kernel, initrd and other official diskless tools are stored, relative to "base_folder" -# diskless_kernel = kernel # Name of the diskless kernel to run -# diskless_initrd = initrd # Name of the diskless initrd to boot (core) +# diskless_folder = davos # Where kernel, initrd and other official diskless tools are stored, relative to "base_folder" +# diskless_kernel = vmlinuz # Name of the diskless kernel to run +# diskless_initrd = initrd.img # Name of the diskless initrd to boot (core) # diskless_initrdcd = initrdcd # Name of the diskless initrd to boot (addon to boot on CD) # diskless_memtest = memtest # diskless memtest tool # diskless_dban = dban # diskless dban tool diff --git a/pulse2/services/contrib/Makefile.am b/pulse2/services/contrib/Makefile.am index 412ea2639..4d0ef4c2e 100644 --- a/pulse2/services/contrib/Makefile.am +++ b/pulse2/services/contrib/Makefile.am @@ -166,6 +166,7 @@ nobase_dist_contrib_DATA = dyngroup/sql/clean-db.sql \ update/sql/schema-005.sql \ update/sql/schema-006.sql \ monit/pulse2 \ + samba/smb.conf \ test-xmlrpc.php \ test-xmlrpc.examples \ test-xmlrpc.py diff --git a/pulse2/services/contrib/imaging-server/dhcpd.conf b/pulse2/services/contrib/imaging-server/dhcpd.conf index e23e23d6a..6a5a85feb 100644 --- a/pulse2/services/contrib/imaging-server/dhcpd.conf +++ b/pulse2/services/contrib/imaging-server/dhcpd.conf @@ -2,8 +2,6 @@ # This is a dhcpd sample file for Pulse 2 # ########################################### -ddns-update-style ad-hoc; # mandatory since 3.0b2pl11 - # When using a NAS, uses DHCP option 177 option pulse2-nfs code 177 = text; diff --git a/pulse2/services/contrib/samba/smb.conf b/pulse2/services/contrib/samba/smb.conf new file mode 100644 index 000000000..55832e5f5 --- /dev/null +++ b/pulse2/services/contrib/samba/smb.conf @@ -0,0 +1,44 @@ +[global] + workgroup = WORKGROUP + server string = Pulse2 Server + netbios name = Pulse2 + dns proxy = no + log file = /var/log/samba/log.%m + max log size = 1000 + syslog = 0 + panic action = /usr/share/samba/panic-action %d + encrypt passwords = true + passdb backend = tdbsam + obey pam restrictions = yes + unix password sync = yes + passwd program = /usr/bin/passwd %u + passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . + pam password change = yes + +[iso] + comment = Pulse2 ISO images + path = /var/lib/pulse2/imaging/isos + browseable = yes + writable = yes + valid users = root + +[postinst] + comment = Pulse2 Postinstallation files + path = /var/lib/pulse2/imaging/postinst + browseable = yes + writable = yes + valid users = root + +[packages] + comment = Pulse2 Package + path = /var/lib/pulse2/package-server-tmpdir + browseable = yes + writable = yes + valid users = root + +[drivers] + comment = Pulse2 Drivers folder for Sysprep + path = /var/lib/pulse2/imaging/postinst/sysprep/drivers + browseable = yes + writable = yes + valid users = drivers diff --git a/pulse2/services/mmc/plugins/glpi/__init__.py b/pulse2/services/mmc/plugins/glpi/__init__.py index b398b440b..018cc20bd 100644 --- a/pulse2/services/mmc/plugins/glpi/__init__.py +++ b/pulse2/services/mmc/plugins/glpi/__init__.py @@ -201,19 +201,15 @@ def setGlpiEditableValue(uuid, name, value): def getInventoryEM(part): return [] - def getGlpiMachineUri(): return Glpi().config.glpi_computer_uri - def getMachineUUIDByMacAddress(mac): return xmlrpcCleanup(Glpi().getMachineUUIDByMacAddress(mac)) - def getMachinesLocations(uuids): return xmlrpcCleanup(Glpi().getMachinesLocations(uuids)) - def hasKnownOS(uuid): return xmlrpcCleanup(Glpi().hasKnownOS(uuid)) diff --git a/pulse2/services/mmc/plugins/glpi/auth.py b/pulse2/services/mmc/plugins/glpi/auth.py index 79c4e51cc..da9511ed0 100644 --- a/pulse2/services/mmc/plugins/glpi/auth.py +++ b/pulse2/services/mmc/plugins/glpi/auth.py @@ -26,7 +26,12 @@ import re from twisted.internet import reactor, defer -from twisted.web.client import HTTPClientFactory, _parse, getPage +try: + from twisted.web.client import HTTPClientFactory, _parse, getPage + parseAvailable = True +except ImportError: + from twisted.web.client import HTTPClientFactory, _URI, getPage + parseAvailable = False from mmc.plugins.base.auth import AuthenticatorConfig, AuthenticatorI from mmc.support.mmctools import getConfigFile @@ -117,9 +122,17 @@ def getPageWithHeader(url, contextFactory=None, *args, **kwargs): Same as twisted.web.client.getPage, but we keep the HTTP header in the result thanks to the HTTPClientFactoryWithHeader class """ - scheme, host, port, path = _parse(url) + if parseAvailable: + scheme, host, port, path = _parse(url) + else: + uri = _URI.fromBytes(url) + scheme = uri.scheme + host = uri.host + port = uri.port + factory = HTTPClientFactoryWithHeader(url, *args, **kwargs) d = factory.deferred + if scheme == 'https': from twisted.internet import ssl if contextFactory is None: diff --git a/pulse2/services/mmc/plugins/glpi/config.py b/pulse2/services/mmc/plugins/glpi/config.py index 338d44c82..8a03c823d 100644 --- a/pulse2/services/mmc/plugins/glpi/config.py +++ b/pulse2/services/mmc/plugins/glpi/config.py @@ -41,7 +41,8 @@ class GlpiConfig(PluginConfig): # computer_list section # complete list: ['cn', 'description', 'os', 'type', 'user', 'inventorynumber', 'state', 'entity', 'location', 'model', 'manufacturer'] - summary = ['cn', 'description', 'os', 'type', 'user', 'owner', 'owner_firstname', 'owner_realname', 'entity', 'location'] + #summary = ['cn', 'description', 'os', 'type', 'user', 'owner', 'owner_firstname', 'owner_realname', 'entity', 'location'] + summary = ['cn', 'description', 'os', 'type', 'user', 'entity'] ordered = False # antivirus section diff --git a/pulse2/services/mmc/plugins/glpi/database.py b/pulse2/services/mmc/plugins/glpi/database.py index 0fab2c92f..537a686a4 100644 --- a/pulse2/services/mmc/plugins/glpi/database.py +++ b/pulse2/services/mmc/plugins/glpi/database.py @@ -29,7 +29,10 @@ from mmc.plugins.glpi.config import GlpiConfig from mmc.plugins.glpi.database_07 import Glpi07 from mmc.plugins.glpi.database_08 import Glpi08 -from mmc.plugins.glpi.database_084 import Glpi084 +from mmc.plugins.glpi.database_084 import Glpi084 +from mmc.plugins.glpi.database_0855 import Glpi0855 + + from pulse2.database.dyngroup.dyngroup_database_helper import DyngroupDatabaseHelper import logging @@ -60,6 +63,8 @@ def activate(self, conffile = None): self.database = Glpi08() elif Glpi084().try_activation(self.config): self.database = Glpi084() + elif Glpi0855().try_activation(self.config): + self.database = Glpi0855() else: self.logger.warn("Can't load the right database backend for your version of GLPI") return False diff --git a/pulse2/services/mmc/plugins/glpi/database_07.py b/pulse2/services/mmc/plugins/glpi/database_07.py index 336b72f96..47478940b 100644 --- a/pulse2/services/mmc/plugins/glpi/database_07.py +++ b/pulse2/services/mmc/plugins/glpi/database_07.py @@ -46,7 +46,11 @@ Date, Integer, ForeignKey, asc, or_, not_, desc, func, distinct from sqlalchemy.orm import create_session, mapper from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound -from sqlalchemy.sql.expression import ColumnOperators + +try: + from sqlalchemy.sql.expression import ColumnOperators +except ImportError: + from sqlalchemy.sql.operators import ColumnOperators import logging import re diff --git a/pulse2/services/mmc/plugins/glpi/database_08.py b/pulse2/services/mmc/plugins/glpi/database_08.py index e24c8efd2..b6e9510c5 100644 --- a/pulse2/services/mmc/plugins/glpi/database_08.py +++ b/pulse2/services/mmc/plugins/glpi/database_08.py @@ -36,7 +36,10 @@ from sqlalchemy import and_, create_engine, MetaData, Table, Column, String, \ Integer, Date, ForeignKey, asc, or_, not_, desc, func, distinct from sqlalchemy.orm import create_session, mapper -from sqlalchemy.sql.expression import ColumnOperators +try: + from sqlalchemy.sql.expression import ColumnOperators +except ImportError: + from sqlalchemy.sql.operators import ColumnOperators from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound from sqlalchemy.exc import OperationalError diff --git a/pulse2/services/mmc/plugins/glpi/database_084.py b/pulse2/services/mmc/plugins/glpi/database_084.py index 3013582c0..c6712833b 100644 --- a/pulse2/services/mmc/plugins/glpi/database_084.py +++ b/pulse2/services/mmc/plugins/glpi/database_084.py @@ -35,7 +35,12 @@ from sqlalchemy import and_, create_engine, MetaData, Table, Column, String, \ Integer, Date, ForeignKey, asc, or_, not_, desc, func, distinct from sqlalchemy.orm import create_session, mapper, relationship -from sqlalchemy.sql.expression import ColumnOperators + +try: + from sqlalchemy.sql.expression import ColumnOperators +except ImportError: + from sqlalchemy.sql.operators import ColumnOperators + from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound from sqlalchemy.exc import OperationalError @@ -51,6 +56,8 @@ from mmc.plugins.glpi.database_utils import decode_latin1, encode_latin1, decode_utf8, encode_utf8, fromUUID, toUUID, setUUID from mmc.plugins.glpi.database_utils import DbTOA # pyflakes.ignore from mmc.plugins.dyngroup.config import DGConfig +from distutils.version import LooseVersion, StrictVersion + class Glpi084(DyngroupDatabaseHelper): @@ -77,7 +84,8 @@ def try_activation(self, config): self._glpi_version = self.db.execute('SELECT version FROM glpi_configs').fetchone().values()[0].replace(' ', '') except OperationalError: self._glpi_version = self.db.execute('SELECT value FROM glpi_configs WHERE name = "version"').fetchone().values()[0].replace(' ', '') - if self._glpi_version >= '0.84': + if LooseVersion(self._glpi_version) >= LooseVersion('0.84') and LooseVersion(self._glpi_version) < LooseVersion("0.85"): +# if self._glpi_version >= '0.84': logging.getLogger().debug('GLPI version %s found !' % self._glpi_version) return True else: @@ -3441,7 +3449,7 @@ def getMachineMac(self, uuid): Get a machine mac addresses """ return self.getMachinesMac(uuid)[uuid] - + def orderIpAdresses(self, uuid, hostname, netiface, empty_macs=False): ret_ifmac = [] ret_ifaddr = [] diff --git a/pulse2/services/mmc/plugins/glpi/database_0855.py b/pulse2/services/mmc/plugins/glpi/database_0855.py new file mode 100644 index 000000000..0f50d6839 --- /dev/null +++ b/pulse2/services/mmc/plugins/glpi/database_0855.py @@ -0,0 +1,4383 @@ +# -*- coding: utf-8; -*- +# +# (c) 2004-2007 Linbox / Free&ALter Soft, http://linbox.com +# (c) 2007-2010 Mandriva, http://www.mandriva.com +# +# $Id$ +# +# This file is part of Mandriva Management Console (MMC). +# +# MMC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# MMC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MMC. If not, see . + +""" +This module declare all the necessary stuff to connect to a glpi database in it's +version 0.8x +""" +import os +import logging +import re +from sets import Set +import datetime +import calendar, hashlib +import time +from configobj import ConfigObj +from xmlrpclib import ProtocolError + +from sqlalchemy import and_, create_engine, MetaData, Table, Column, String, \ + Integer, Date, ForeignKey, asc, or_, not_, desc, func, distinct +from sqlalchemy.orm import create_session, mapper, relationship +try: + from sqlalchemy.sql.expression import ColumnOperators +except ImportError: + from sqlalchemy.sql.operators import ColumnOperators +from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound +from sqlalchemy.exc import OperationalError + +from mmc.site import mmcconfdir +from mmc.database.database_helper import DatabaseHelper +# TODO rename location into entity (and locations in location) +from pulse2.utils import same_network, unique, noNone +from pulse2.database.dyngroup.dyngroup_database_helper import DyngroupDatabaseHelper +from pulse2.managers.group import ComputerGroupManager +from mmc.plugins.glpi.config import GlpiConfig +from mmc.plugins.glpi.GLPIClient import XMLRPCClient +from mmc.plugins.glpi.utilities import complete_ctx +from mmc.plugins.glpi.database_utils import decode_latin1, encode_latin1, decode_utf8, encode_utf8, fromUUID, toUUID, setUUID +from mmc.plugins.glpi.database_utils import DbTOA # pyflakes.ignore +from mmc.plugins.dyngroup.config import DGConfig +from distutils.version import LooseVersion, StrictVersion + +class Glpi0855(DyngroupDatabaseHelper): + """ + Singleton Class to query the glpi database in version > 0.80. + + """ + is_activated = False + + def db_check(self): + self.my_name = "Glpi" + self.configfile = "glpi.ini" + return DyngroupDatabaseHelper.db_check(self) + + def try_activation(self, config): + """ + function to see if that glpi database backend is the one we need to use + """ + self.config = config + dburi = self.makeConnectionPath() + self.db = create_engine(dburi, pool_recycle = self.config.dbpoolrecycle, pool_size = self.config.dbpoolsize) + logging.getLogger().debug('Trying to detect if GLPI version is higher than 0.85') + try: + self._glpi_version = self.db.execute('SELECT version FROM glpi_configs').fetchone().values()[0].replace(' ', '') + except OperationalError: + self._glpi_version = self.db.execute('SELECT value FROM glpi_configs WHERE name = "version"').fetchone().values()[0].replace(' ', '') + + if LooseVersion(self._glpi_version) >= LooseVersion("0.85") and LooseVersion(self._glpi_version) < LooseVersion("0.86"): + logging.getLogger().debug('GLPI version %s found !' % self._glpi_version) + return True + else: + logging.getLogger().debug('GLPI higher than version 0.85 was not detected') + return False + + @property + def glpi_version(self): + return self._glpi_version + + def glpi_version_new(self): + return False + + def activate(self, config = None): + self.logger = logging.getLogger() + DyngroupDatabaseHelper.init(self) + if self.is_activated: + self.logger.info("Glpi don't need activation") + return None + self.logger.info("Glpi is activating") + if config != None: + self.config = config + else: + self.config = GlpiConfig("glpi") + dburi = self.makeConnectionPath() + self.db = create_engine(dburi, pool_recycle = self.config.dbpoolrecycle, pool_size = self.config.dbpoolsize) + try: + self.db.execute(u'SELECT "\xe9"') + setattr(Glpi0855, "decode", decode_utf8) + setattr(Glpi0855, "encode", encode_utf8) + except: + self.logger.warn("Your database is not in utf8, will fallback in latin1") + setattr(Glpi0855, "decode", decode_latin1) + setattr(Glpi0855, "encode", encode_latin1) + try: + self._glpi_version = self.db.execute('SELECT version FROM glpi_configs').fetchone().values()[0].replace(' ', '') + except OperationalError: + self._glpi_version = self.db.execute('SELECT value FROM glpi_configs WHERE name = "version"').fetchone().values()[0].replace(' ', '') + self.metadata = MetaData(self.db) + self.initMappers() + self.logger.info("Glpi is in version %s" % (self.glpi_version)) + self.metadata.create_all() + self.is_activated = True + self.logger.debug("Glpi finish activation") + + searchOptionConfFile = os.path.join(mmcconfdir, "plugins", "glpi_search_options.ini") + self.searchOptions = ConfigObj(searchOptionConfFile) + + return True + + def getTableName(self, name): + return ''.join(map(lambda x:x.capitalize(), name.split('_'))) + + def initMappers(self): + """ + Initialize all SQLalchemy mappers needed for the inventory database + """ + + self.klass = {} + + # simply declare some tables (that dont need and FK relations, or anything special to declare) + for i in ('glpi_operatingsystemversions', 'glpi_computertypes', 'glpi_operatingsystems', 'glpi_operatingsystemservicepacks', 'glpi_domains', \ + 'glpi_computermodels', 'glpi_networks'): + setattr(self, i, Table(i, self.metadata, autoload = True)) + j = self.getTableName(i) + exec "class %s(DbTOA): pass" % j + mapper(eval(j), getattr(self, i)) + self.klass[i] = eval(j) + + # declare all the glpi_device* and glpi_computer_device* + # two of these tables have a nomenclature one (devicecasetypes and devicememorytypes) but we dont need it for the moment. + # + # List of devices: + # cases, controls, drives, graphiccards, harddrives, motherboards, networkcards, + # pcis, powersupplies, soundcards + + self.devices = ('devicecases', 'devicecontrols', 'devicedrives', 'devicegraphiccards', 'deviceharddrives', \ + 'devicemotherboards', 'devicenetworkcards', 'devicepcis', 'devicepowersupplies', 'devicesoundcards') + for i in self.devices: + setattr(self, i, Table("glpi_%s"%i, self.metadata, autoload = True)) + j = self.getTableName(i) + exec "class %s(DbTOA): pass" % j + mapper(eval(j), getattr(self, i)) + self.klass[i] = eval(j) + + setattr(self, "computers_%s"%i, Table("glpi_items_%s"%i, self.metadata, + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + Column('%s_id'%i, Integer, ForeignKey('glpi_%s.id'%i)), + autoload = True)) + j = self.getTableName("computers_%s"%i) + exec "class %s(DbTOA): pass" % j + mapper(eval(j), getattr(self, "computers_%s"%i)) + self.klass["computers_%s"%i] = eval(j) + + # entity + self.entities = Table("glpi_entities", self.metadata, autoload = True) + mapper(Entities, self.entities) + + # rules + self.rules = Table("glpi_rules", self.metadata, autoload = True) + mapper(Rule, self.rules) + + self.rule_criterias = Table("glpi_rulecriterias", self.metadata, autoload = True) + mapper(RuleCriterion, self.rule_criterias) + + self.rule_actions = Table("glpi_ruleactions", self.metadata, autoload = True) + mapper(RuleAction, self.rule_actions) + + # location + self.locations = Table("glpi_locations", self.metadata, autoload = True) + mapper(Locations, self.locations) + + # logs + self.logs = Table("glpi_logs", self.metadata, + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + autoload = True) + mapper(Logs, self.logs) + + # processor + self.processor = Table("glpi_deviceprocessors", self.metadata, autoload = True) + mapper(Processor, self.processor) + + self.computerProcessor = Table("glpi_items_deviceprocessors", self.metadata, + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + Column('deviceprocessors_id', Integer, ForeignKey('glpi_deviceprocessors.id')), + autoload = True) + mapper(ComputerProcessor, self.computerProcessor) + + # memory + self.memory = Table("glpi_devicememories", self.metadata, + Column('devicememorytypes_id', Integer, ForeignKey('glpi_devicememorytypes.id')), + autoload = True) + mapper(Memory, self.memory) + + self.memoryType = Table("glpi_devicememorytypes", self.metadata, autoload = True) + mapper(MemoryType, self.memoryType) + + self.computerMemory = Table("glpi_items_devicememories", self.metadata, + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + Column('devicememories_id', Integer, ForeignKey('glpi_devicememories.id')), + autoload = True) + mapper(ComputerMemory, self.computerMemory) + + # interfaces types + self.interfaceType = Table("glpi_interfacetypes", self.metadata, autoload = True) + + # os + self.os = Table("glpi_operatingsystems", self.metadata, autoload = True) + mapper(OS, self.os) + + self.os_sp = Table("glpi_operatingsystemservicepacks", self.metadata, autoload = True) + mapper(OsSp, self.os_sp) + + # domain + self.domain = Table('glpi_domains', self.metadata, autoload = True) + mapper(Domain, self.domain) + + # glpi_infocoms + self.infocoms = Table('glpi_infocoms', self.metadata, + Column('suppliers_id', Integer, ForeignKey('glpi_suppliers.id')), + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + autoload = True) + mapper(Infocoms, self.infocoms) + + # glpi_suppliers + self.suppliers = Table('glpi_suppliers', self.metadata, autoload = True) + mapper(Suppliers, self.suppliers) + + # glpi_filesystems + self.diskfs = Table('glpi_filesystems', self.metadata, autoload = True) + mapper(DiskFs, self.diskfs) + + ## Fusion Inventory tables + + # glpi_plugin_fusinvinventory_antivirus + # this table comes with Fusioninventory plugin and could not exists + # if you don't use this plugin, so use try / except + self.fusionantivirus = None + try: + self.logger.debug('Try to load fusion antivirus table...') + self.fusionantivirus = Table('glpi_plugin_fusioninventory_inventorycomputerantiviruses', self.metadata, + Column('computers_id', Integer, ForeignKey('glpi_computers.id')), + Column('manufacturers_id', Integer, ForeignKey('glpi_manufacturers.id')), + autoload = True) + mapper(FusionAntivirus, self.fusionantivirus) + self.logger.debug('... Success !!') + except: + self.logger.warn('Load of fusion antivirus table failed') + self.logger.warn('This means you can not know antivirus statuses of your machines.') + self.logger.warn('This feature comes with Fusioninventory GLPI plugin') + + # glpi_plugin_fusioninventory_locks + self.fusionlocks = None + # glpi_plugin_fusioninventory_agents + self.fusionagents = None + + if self.fusionantivirus is not None: # Fusion is not installed + self.logger.debug('Load glpi_plugin_fusioninventory_locks') + self.fusionlocks = Table('glpi_plugin_fusioninventory_locks', self.metadata, + Column('items_id', Integer, ForeignKey('glpi_computers.id')), + autoload = True) + mapper(FusionLocks, self.fusionlocks) + self.logger.debug('Load glpi_plugin_fusioninventory_agents') + self.fusionagents = Table('glpi_plugin_fusioninventory_agents', self.metadata, + Column('computers_id', Integer, ForeignKey('glpi_computers.id')), + autoload = True) + mapper(FusionAgents, self.fusionagents) + + # glpi_computerdisks + self.disk = Table('glpi_computerdisks', self.metadata, + Column('computers_id', Integer, ForeignKey('glpi_computers.id')), + Column('filesystems_id', Integer, ForeignKey('glpi_filesystems.id')), + autoload = True) + mapper(Disk, self.disk) + + ##################################### + # GLPI 0.855 Network tables + # TODO take care with the itemtype should we always set it to Computer => Yes + ##################################### + + # TODO Are these table needed (inherit of previous glpi database*py files) ? + self.networkinterfaces = Table("glpi_networkinterfaces", self.metadata, autoload = True) + mapper(NetworkInterfaces, self.networkinterfaces) + + self.net = Table("glpi_networks", self.metadata, autoload = True) + mapper(Net, self.net) + + # New network tables + self.ipnetworks = Table("glpi_ipnetworks", self.metadata, autoload = True) + mapper(IPNetworks, self.ipnetworks) + + self.ipaddresses_ipnetworks = Table("glpi_ipaddresses_ipnetworks", self.metadata, + Column('ipaddresses_id', Integer, ForeignKey('glpi_ipaddresses.id')), + Column('ipnetworks_id', Integer, ForeignKey('glpi_networks.id')), + autoload = True) + mapper(IPAddresses_IPNetworks, self.ipaddresses_ipnetworks) + + self.ipaddresses = Table("glpi_ipaddresses", self.metadata, autoload = True) + mapper(IPAddresses, self.ipaddresses, properties = { + 'ipnetworks': relationship(IPNetworks, secondary = self.ipaddresses_ipnetworks, + primaryjoin = self.ipaddresses.c.id == self.ipaddresses_ipnetworks.c.ipaddresses_id, + secondaryjoin = self.ipnetworks.c.id == self.ipaddresses_ipnetworks.c.ipnetworks_id, + foreign_keys = [ + self.ipaddresses_ipnetworks.c.ipaddresses_id, + self.ipaddresses_ipnetworks.c.ipnetworks_id, + ]) + }) + + self.networknames = Table("glpi_networknames", self.metadata, autoload = True) + mapper(NetworkNames, self.networknames, properties = { + # ipaddresses is a one2many relation from NetworkNames to IPAddresses + # so uselist must be set to True + 'ipaddresses': relationship(IPAddresses, primaryjoin=and_( + IPAddresses.items_id == self.networknames.c.id, + IPAddresses.itemtype == 'NetworkName' + ), uselist = True, foreign_keys = [self.networknames.c.id]), + }) + + self.networkports = Table("glpi_networkports", self.metadata, autoload = True) + mapper(NetworkPorts, self.networkports, properties = { + 'networknames': relationship(NetworkNames, primaryjoin=and_( + NetworkNames.items_id == self.networkports.c.id, + NetworkNames.itemtype == 'NetworkPort' + ), foreign_keys = [self.networkports.c.id]), + }) + + # machine (we need the foreign key, so we need to declare the table by hand ... + # as we don't need all columns, we don't declare them all) + self.machine = Table("glpi_computers", self.metadata, + Column('id', Integer, primary_key=True), + Column('entities_id', Integer, ForeignKey('glpi_entities.id')), + Column('operatingsystems_id', Integer, ForeignKey('glpi_operatingsystems.id')), + Column('operatingsystemversions_id', Integer, ForeignKey('glpi_operatingsystemversions.id')), + Column('operatingsystemservicepacks_id', Integer, ForeignKey('glpi_operatingsystemservicepacks.id')), + Column('locations_id', Integer, ForeignKey('glpi_locations.id')), + Column('domains_id', Integer, ForeignKey('glpi_domains.id')), + Column('networks_id', Integer, ForeignKey('glpi_networks.id')), + Column('computermodels_id', Integer, ForeignKey('glpi_computermodels.id')), + Column('computertypes_id', Integer, ForeignKey('glpi_computertypes.id')), + Column('groups_id', Integer, ForeignKey('glpi_groups.id')), + Column('users_id', Integer, ForeignKey('glpi_users.id')), + Column('manufacturers_id', Integer, ForeignKey('glpi_manufacturers.id')), + Column('name', String(255), nullable=False), + Column('serial', String(255), nullable=False), + Column('os_license_number', String(255), nullable=True), + Column('os_licenseid', String(255), nullable=True), + Column('is_deleted', Integer, nullable=False), + Column('is_template', Integer, nullable=False), + Column('states_id', Integer, ForeignKey('glpi_states.id'), nullable=False), + Column('comment', String(255), nullable=False), + Column('date_mod', Date, nullable=False), + autoload = True) + mapper(Machine, self.machine, properties = { + # networkports is a one2many relation from Machine to NetworkPorts + # so uselist must be set to True + 'networkports': relationship(NetworkPorts, primaryjoin=and_( + NetworkPorts.items_id == self.machine.c.id, + NetworkPorts.itemtype == 'Computer' + ), uselist = True, foreign_keys = [self.machine.c.id]), + 'domains': relationship(Domain), + }) + + + # states + self.state = Table("glpi_states", self.metadata, autoload = True) + mapper(State, self.state) + # profile + self.profile = Table("glpi_profiles", self.metadata, + Column('id', Integer, primary_key=True), + Column('name', String(255), nullable=False)) + mapper(Profile, self.profile) + + # user + self.user = Table("glpi_users", self.metadata, + Column('id', Integer, primary_key=True), + Column('name', String(255), nullable=False), + Column('password', String(40), nullable=False), + Column('firstname', String(255), nullable=False), + Column('realname', String(255), nullable=False), + Column('auths_id', Integer, nullable=False), + Column('is_deleted', Integer, nullable=False), + Column('is_active', Integer, nullable=False)) + mapper(User, self.user) + + # userprofile + self.userprofile = Table("glpi_profiles_users", self.metadata, + Column('id', Integer, primary_key=True), + Column('users_id', Integer, ForeignKey('glpi_users.id')), + Column('profiles_id', Integer, ForeignKey('glpi_profiles.id')), + Column('entities_id', Integer, ForeignKey('glpi_entities.id')), + Column('is_dynamic', Integer), + Column('is_recursive', Integer)) + mapper(UserProfile, self.userprofile) + + # glpi_manufacturers + self.manufacturers = Table("glpi_manufacturers", self.metadata, autoload = True) + mapper(Manufacturers, self.manufacturers) + + # software + self.software = Table("glpi_softwares", self.metadata, + Column('manufacturers_id', Integer, ForeignKey('glpi_manufacturers.id')), + autoload = True) + mapper(Software, self.software) + + # glpi_inst_software + self.inst_software = Table("glpi_computers_softwareversions", self.metadata, + Column('computers_id', Integer, ForeignKey('glpi_computers.id')), + Column('softwareversions_id', Integer, ForeignKey('glpi_softwareversions.id')), + autoload = True) + mapper(InstSoftware, self.inst_software) + + # glpi_licenses + self.licenses = Table("glpi_softwarelicenses", self.metadata, + Column('softwares_id', Integer, ForeignKey('glpi_softwares.id')), + autoload = True) + mapper(Licenses, self.licenses) + + # glpi_softwareversions + self.softwareversions = Table("glpi_softwareversions", self.metadata, + Column('softwares_id', Integer, ForeignKey('glpi_softwares.id')), + autoload = True) + mapper(SoftwareVersion, self.softwareversions) + + # model + self.model = Table("glpi_computermodels", self.metadata, autoload = True) + mapper(Model, self.model) + + # group + self.group = Table("glpi_groups", self.metadata, autoload = True) + mapper(Group, self.group) + + ##################### internal query generators + def __filter_on(self, query): + """ + Use the glpi.ini conf parameter filter_on to filter machines on some parameters + The request is in OR not in AND, so be carefull with what you want + """ + ret = self.__filter_on_filter(query) + if type(ret) == type(None): + return query + else: + return query.filter(ret) + + def __filter_on_filter(self, query): + if self.config.filter_on != None: + a_filter_on = [] + for filter_key, filter_values in self.config.filter_on.items(): + if filter_key == 'state': + self.logger.debug('will filter %s in (%s)' % (filter_key, str(filter_values))) + a_filter_on.append(self.machine.c.states_id.in_(filter_values)) + if filter_key == 'type': + self.logger.debug('will filter %s in (%s)' % (filter_key, str(filter_values))) + a_filter_on.append(self.machine.c.computertypes_id.in_(filter_values)) + if filter_key == 'entity': + self.logger.debug('will filter %s in (%s)' % (filter_key, str(filter_values))) + a_filter_on.append(self.machine.c.entities_id.in_(filter_values)) + if filter_key == 'autoupdatesystems_id': + self.logger.debug('will filter %s in (%s)' % (filter_key, str(filter_values))) + a_filter_on.append(self.machine.c.autoupdatesystems_id.in_(filter_values)) + if not filter_key in ('state','type','entity','autoupdatesystems_id') : + self.logger.warn('dont know how to filter on %s' % (filter_key)) + if len(a_filter_on) == 0: + return None + elif len(a_filter_on) == 1: + return a_filter_on[0] + else: + return and_(*a_filter_on) + return None + + def __filter_on_entity(self, query, ctx, other_locids = []): + ret = self.__filter_on_entity_filter(query, ctx, other_locids) + return query.filter(ret) + + def __filter_on_entity_filter(self, query, ctx, other_locids = []): + # FIXME: I put the locationsid in the security context to optimize the + # number of requests. locationsid is set by + # glpi.utilities.complete_ctx, but when querying via the dyngroup + # plugin it is not called. + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + return self.machine.c.entities_id.in_(ctx.locationsid + other_locids) + + def __getRestrictedComputersListQuery(self, ctx, filt = None, session = create_session(), displayList = False, count = False): + """ + Get the sqlalchemy query to get a list of computers with some filters + If displayList is True, we are displaying computers list + """ + if session == None: + session = create_session() + query = count and session.query(func.count(Machine.id)) or session.query(Machine) + if filt: + # filtering on query + join_query = self.machine + + if displayList and not count: + if 'os' in self.config.summary: + query = query.add_column(self.os.c.name) + if 'type' in self.config.summary: + query = query.add_column(self.glpi_computertypes.c.name) + if 'inventorynumber' in self.config.summary: + query = query.add_column(self.machine.c.otherserial) + if 'state' in self.config.summary: + query = query.add_column(self.state.c.name) + if 'entity' in self.config.summary: + query = query.add_column(self.entities.c.name) # entities + if 'location' in self.config.summary: + query = query.add_column(self.locations.c.name) # locations + if 'model' in self.config.summary: + query = query.add_column(self.glpi_computermodels.c.name) + if 'manufacturer' in self.config.summary: + query = query.add_column(self.manufacturers.c.name) + if 'owner_firstname' in self.config.summary: + query = query.add_column(self.user.c.firstname) + if 'owner_realname' in self.config.summary: + query = query.add_column(self.user.c.realname) + if 'owner' in self.config.summary: + query = query.add_column(self.user.c.name) + + query_filter = None + + filters = [self.machine.c.is_deleted == 0, self.machine.c.is_template == 0, self.__filter_on_filter(query), self.__filter_on_entity_filter(query, ctx)] + + join_query, query_filter = self.filter(ctx, self.machine, filt, session.query(Machine), self.machine.c.id, filters) + + # filtering on locations + if 'location' in filt: + location = filt['location'] + if location == '' or location == u'' or not self.displayLocalisationBar: + location = None + else: + location = None + + # Imaging group + if 'imaging_entities' in filt: + location = filt['imaging_entities'] + + if 'ctxlocation' in filt: + ctxlocation = filt['ctxlocation'] + if not self.displayLocalisationBar: + ctxlocation = None + else: + ctxlocation = None + + if ctxlocation != None: + locsid = [] + if isinstance(ctxlocation, list): + for loc in ctxlocation: + locsid.append(self.__getId(loc)) + join_query = join_query.join(self.entities) + + if location is not None: + # Imaging group case + if isinstance(location, list): + locationids = [int(x.replace('UUID', '')) for x in location] + for locationid in locationids: + if not locationid in locsid: + self.logger.warn("User '%s' is trying to get the content of an unauthorized entity : '%s'" % (ctx.userid, 'UUID' + location)) + session.close() + return None + query_filter = self.__addQueryFilter(query_filter, (self.machine.c.entities_id.in_(locationids))) + else: + locationid = int(location.replace('UUID', '')) + if locationid in locsid: + query_filter = self.__addQueryFilter(query_filter, (self.machine.c.entities_id == locationid)) + else: + self.logger.warn("User '%s' is trying to get the content of an unauthorized entity : '%s'" % (ctx.userid, location)) + session.close() + return None + + if displayList: + if 'os' in self.config.summary: + join_query = join_query.outerjoin(self.os) + if 'type' in self.config.summary: + join_query = join_query.outerjoin(self.glpi_computertypes) + if 'state' in self.config.summary: + join_query = join_query.outerjoin(self.state) + if 'location' in self.config.summary: + join_query = join_query.outerjoin(self.locations) + if 'model' in self.config.summary: + join_query = join_query.outerjoin(self.glpi_computermodels) + if 'manufacturer' in self.config.summary: + join_query = join_query.outerjoin(self.manufacturers) + if 'owner' in self.config.summary or \ + 'owner_firstname' in self.config.summary or \ + 'owner_realname' in self.config.summary: + join_query = join_query.outerjoin(self.user) + + + if self.fusionagents is not None: + join_query = join_query.outerjoin(self.fusionagents) + if 'antivirus' in filt: # Used for Antivirus dashboard + join_query = join_query.outerjoin(self.fusionantivirus) + join_query = join_query.outerjoin(self.os) + + query = query.select_from(join_query).filter(query_filter) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + + if filt.get('hostname'): + if displayList: + clauses = [] + # UUID filtering + if filt['hostname'].lower().startswith('uuid') and len(filt['hostname'])>3: + try: + clauses.append(self.machine.c.id==fromUUID(filt['hostname'])) + except: + pass + if 'cn' in self.config.summary: + clauses.append(self.machine.c.name.like('%'+filt['hostname']+'%')) + if 'os' in self.config.summary: + clauses.append(self.os.c.name.like('%'+filt['hostname']+'%')) + if 'description' in self.config.summary: + clauses.append(self.machine.c.comment.like('%'+filt['hostname']+'%')) + if 'type' in self.config.summary: + clauses.append(self.glpi_computertypes.c.name.like('%'+filt['hostname']+'%')) + if 'owner' in self.config.summary: + clauses.append(self.user.c.name.like('%'+filt['hostname']+'%')) + if 'owner_firstname' in self.config.summary: + clauses.append(self.user.c.firstname.like('%'+filt['hostname']+'%')) + if 'owner_realname' in self.config.summary: + clauses.append(self.user.c.realname.like('%'+filt['hostname']+'%')) + if 'user' in self.config.summary: + clauses.append(self.machine.c.contact.like('%'+filt['hostname']+'%')) + if 'state' in self.config.summary: + clauses.append(self.state.c.name.like('%'+filt['hostname']+'%')) + if 'inventorynumber' in self.config.summary: + clauses.append(self.machine.c.otherserial.like('%'+filt['hostname']+'%')) + if 'entity' in self.config.summary: + clauses.append(self.entities.c.name.like('%'+filt['hostname']+'%')) + if 'location' in self.config.summary: + clauses.append(self.locations.c.name.like('%'+filt['hostname']+'%')) + if 'model' in self.config.summary: + clauses.append(self.glpi_computermodels.c.name.like('%'+filt['hostname']+'%')) + if 'manufacturer' in self.config.summary: + clauses.append(self.manufacturers.c.name.like('%'+filt['hostname']+'%')) + # Filtering on computer list page + if clauses: + query = query.filter(or_(*clauses)) + else: + # filtering on machines (name or uuid) + query = query.filter(self.machine.c.name.like('%'+filt['hostname']+'%')) + if 'name' in filt: + query = query.filter(self.machine.c.name.like('%'+filt['name']+'%')) + + if 'filter' in filt: # Used with search field of static group creation + query = query.filter(self.machine.c.name.like('%'+filt['filter']+'%')) + + if 'uuid' in filt: + query = self.filterOnUUID(query, filt['uuid']) + + if 'uuids' in filt and type(filt['uuids']) == list and len(filt['uuids']) > 0: + query = self.filterOnUUID(query, filt['uuids']) + + if 'gid' in filt: + gid = filt['gid'] + machines = [] + if ComputerGroupManager().isrequest_group(ctx, gid): + machines = map(lambda m: fromUUID(m), ComputerGroupManager().requestresult_group(ctx, gid, 0, -1, '')) + else: + machines = map(lambda m: fromUUID(m), ComputerGroupManager().result_group(ctx, gid, 0, -1, '')) + query = query.filter(self.machine.c.id.in_(machines)) + + if 'request' in filt: + request = filt['request'] + if request != 'EMPTY': + bool = None + if 'equ_bool' in filt: + bool = filt['equ_bool'] + machines = map(lambda m: fromUUID(m), ComputerGroupManager().request(ctx, request, bool, 0, -1, '')) + query = query.filter(self.machine.c.id.in_(machines)) + + if 'date' in filt: + state = filt['date']['states'] + date_mod = filt['date']['date_mod'] + value = filt['date']['value'] + + if 'green' in value: + query = query.filter(date_mod > state['orange']) + if 'orange' in value: + query = query.filter(and_(date_mod < state['orange'], date_mod > state['red'])) + if 'red' in value: + query = query.filter(date_mod < state['red']) + + if 'antivirus' in filt: + if filt['antivirus'] == 'green': + query = query.filter( + and_( + FusionAntivirus.is_active == 1, + FusionAntivirus.uptodate == 1, + OS.name.ilike('%windows%'), + not_(FusionAntivirus.name.in_(self.config.av_false_positive)), + ) + ) + elif filt['antivirus'] == 'orange': + query = query.filter( + and_( + OS.name.ilike('%windows%'), + not_( + and_( + FusionAntivirus.is_active == 1, + FusionAntivirus.uptodate == 1, + ), + ), + not_(FusionAntivirus.name.in_(self.config.av_false_positive)), + ) + ) + elif filt['antivirus'] == 'red': + query = query.filter( + and_( + OS.name.ilike('%windows%'), + or_( + FusionAntivirus.is_active == None, + FusionAntivirus.uptodate == None, + and_( + FusionAntivirus.name.in_(self.config.av_false_positive), + not_(FusionAntivirus.computers_id.in_( + self.getMachineIdsNotInAntivirusRed(ctx), + )), + ), + ), + ) + ) + + if count: query = query.scalar() + return query + + def __getId(self, obj): + if type(obj) == dict: + return obj['uuid'] + if type(obj) != str and type(obj) != unicode: + return obj.id + return obj + + def __getName(self, obj): + if type(obj) == dict: + return obj['name'] + if type(obj) != str and type(obj) != unicode: + return obj.name + if type(obj) == str and re.match('UUID', obj): + l = self.getLocation(obj) + if l: return l.name + return obj + + def __addQueryFilter(self, query_filter, eq): + if str(query_filter) == str(None): # don't remove the str, sqlalchemy.sql._BinaryExpression == None return True! + query_filter = eq + else: + query_filter = and_(query_filter, eq) + return query_filter + + def computersTable(self): + return [self.machine] + + def computersMapping(self, computers, invert = False): + if not invert: + return Machine.id.in_(map(lambda x:fromUUID(x), computers)) + else: + return Machine.id.not_(ColumnOperators.in_(map(lambda x:fromUUID(x), computers))) + + def mappingTable(self, ctx, query): + """ + Map a table name on a table mapping + """ + base = [] + base.append(self.entities) + if query[2] == 'OS': + return base + [self.os] + elif query[2] == 'Entity': + return base + elif query[2] == 'SOFTWARE': + return base + [self.inst_software, self.licenses, self.software] + elif query[2] == 'Computer name': + return base + elif query[2] == 'Contact': + return base + elif query[2] == 'Contact number': + return base + elif query[2] == 'Description': + return base + elif query[2] == 'System model': + return base + [self.model] + elif query[2] == 'System manufacturer': + return base + [self.manufacturers] + elif query[2] == 'State': + return base + [self.state] + elif query[2] == 'System type': + return base + [self.glpi_computertypes] + elif query[2] == 'Inventory number': + return base + elif query[2] == 'Location': + return base + [self.locations] + elif query[2] == 'Operating system': + return base + [self.os] + elif query[2] == 'Service Pack': + return base + [self.os_sp] + elif query[2] == 'Group': + return base + [self.group] + elif query[2] == 'Network': + return base + [self.net] + elif query[2] == 'Installed software': + return base + [self.inst_software, self.softwareversions, self.software] + elif query[2] == 'Installed software (specific version)': + return base + [self.inst_software, self.softwareversions, self.software] + elif query[2] == 'Installed software (specific vendor and version)': # hidden internal dyngroup + return base + [self.inst_software, self.softwareversions, self.software, self.manufacturers] + return [] + + def mapping(self, ctx, query, invert = False): + """ + Map a name and request parameters on a sqlalchemy request + """ + if len(query) == 4: + # in case the glpi database is in latin1, don't forget dyngroup is in utf8 + # => need to convert what comes from the dyngroup database + query[3] = self.encode(query[3]) + r1 = re.compile('\*') + like = False + if type(query[3]) == list: + q3 = [] + for q in query[3]: + if r1.search(q): + like = True + q = r1.sub('%', q) + q3.append(q) + query[3] = q3 + else: + if r1.search(query[3]): + like = True + query[3] = r1.sub('%', query[3]) + + parts = self.__getPartsFromQuery(ctx, query) + ret = [] + + for part in parts: + partA, partB = part + partBcanBeNone = partB == '%' + if invert: + if like: + if partBcanBeNone: + ret.append(not_( + or_( + partA.like(self.encode(partB)), + partA == None, + ) + )) + else: + ret.append(not_(partA.like(self.encode(partB)))) + else: + ret.append(not_(partA.like(self.encode(partB)))) + else: + if like: + if partBcanBeNone: + ret.append( + or_( + partA.like(self.encode(partB)), + partA == None, + ) + ) + else: + ret.append(partA.like(self.encode(partB))) + else: + ret.append(partA.like(self.encode(partB))) + if ctx.userid != 'root': + ret.append(self.__filter_on_entity_filter(None, ctx)) + return and_(*ret) + else: + return self.__treatQueryLevel(query) + + def __getPartsFromQuery(self, ctx, query): + if query[2] in ['OS','Operating system']: + return [[self.os.c.name, query[3]]] + elif query[2] == 'Entity': + locid = None + for loc in ctx.locations: + if self.__getName(loc) == query[3]: + locid = self.__getId(loc) + if locid is not None: + return [[self.machine.c.entities_id, locid]] + else: + return [[self.entities.c.name, query[3]]] + elif query[2] == 'SOFTWARE': + return [[self.software.c.name, query[3]]] + elif query[2] == 'Computer name': + return [[self.machine.c.name, query[3]]] + elif query[2] == 'Contact': + return [[self.machine.c.contact, query[3]]] + elif query[2] == 'Contact number': + return [[self.machine.c.contact_num, query[3]]] + elif query[2] == 'Description': + return [[self.machine.c.comment, query[3]]] + elif query[2] == 'System model': + return [[self.model.c.name, query[3]]] + elif query[2] == 'System manufacturer': + return [[self.manufacturers.c.name, query[3]]] + elif query[2] == 'State': + return [[self.state.c.name, query[3]]] + elif query[2] == 'System type': + return [[self.glpi_computertypes.c.name, query[3]]] + elif query[2] == 'Inventory number': + return [[self.machine.c.otherserial, query[3]]] + elif query[2] == 'Location': + return [[self.locations.c.completename, query[3]]] + elif query[2] == 'Service Pack': + return [[self.os_sp.c.name, query[3]]] + elif query[2] == 'Group': # TODO double join on Entity + return [[self.group.c.name, query[3]]] + elif query[2] == 'Network': + return [[self.net.c.name, query[3]]] + elif query[2] == 'Installed software': # TODO double join on Entity + return [[self.software.c.name, query[3]]] + elif query[2] == 'Installed software (specific version)': # TODO double join on Entity + return [[self.software.c.name, query[3][0]], [self.softwareversions.c.name, query[3][1]]] + elif query[2] == 'Installed software (specific vendor and version)': # hidden internal dyngroup + return [[self.manufacturers.c.name, query[3][0]], [self.software.c.name, query[3][1]], [self.softwareversions.c.name, query[3][2]]] + return [] + + + def __getTable(self, table): + if table == 'OS': + return self.os.c.name + elif table == 'Entity': + return self.entities.c.name + elif table == 'SOFTWARE': + return self.software.c.name + raise Exception("dont know table for %s"%(table)) + + ##################### machine list management + def getComputer(self, ctx, filt, empty_macs=False): + """ + Get the first computers that match filters parameters + """ + ret = self.getRestrictedComputersList(ctx, + 0, + 10, + filt, + displayList=False, + empty_macs=empty_macs) + if len(ret) != 1: + for i in ['location', 'ctxlocation']: + try: + filt.pop(i) + except: + pass + ret = self.getRestrictedComputersList(ctx, + 0, + 10, + filt, + displayList=False, + empty_macs=empty_macs) + if len(ret) > 0: + raise Exception("NOPERM##%s" % (ret[0][1]['fullname'])) + return False + return ret.values()[0] + + def getRestrictedComputersListStatesLen(self, ctx, filt, orange, red): + """ + Return number of computers by state + """ + session = create_session() + now = datetime.datetime.now() + states = { + 'orange': now - datetime.timedelta(orange), + 'red': now - datetime.timedelta(red), + } + + date_mod = self.machine.c.date_mod + if self.fusionagents is not None: + date_mod = FusionAgents.last_contact + + for value in ['green', 'orange', 'red']: + # This loop instanciate self.filt_green, + # self.filt_orange and self.filt_red + setattr(self, 'filt_%s' % value, filt.copy()) + + newFilter = getattr(self, 'filt_%s' % value) + values = { + 'states': states, + 'date_mod': date_mod, + 'value': value, + } + newFilter['date'] = values + + ret = { + "green": int(self.__getRestrictedComputersListQuery(ctx, self.filt_green, session, count=True)), + "orange": int(self.__getRestrictedComputersListQuery(ctx, self.filt_orange, session, count=True)), + "red": int(self.__getRestrictedComputersListQuery(ctx, self.filt_red, session, count=True)), + } + session.close() + return ret + + def getRestrictedComputersListLen(self, ctx, filt = None): + """ + Get the size of the computer list that match filters parameters + """ + session = create_session() + + displayList = None + + # When search field is used on main computer's list page, + # Pagination PHP Widget must know total machine result + # So, set displayList to True to count on glpi_computers + # and all needed joined tables + if 'hostname' in filt: + if len(filt['hostname']) > 0: + displayList = True + + ret = self.__getRestrictedComputersListQuery(ctx, filt, session, displayList, count=True) + if ret == None: + return 0 + session.close() + return ret + + def getRestrictedComputersList(self, + ctx, + min = 0, + max = -1, + filt = None, + advanced = True, + justId = False, + toH = False, + displayList = None, + empty_macs=False): + """ + Get the computer list that match filters parameters between min and max + + FIXME: may return a list or a dict according to the parameters + + @param displayList: if True, we are displaying Computers list main page + @type displayList: None or bool + """ + session = create_session() + ret = {} + + # If we are displaying Computers list main page, set displayList to True + if displayList is None: + if justId or toH or 'uuid' in filt: # if 'uuid' in filt: used where adding a command to a group + displayList = False + else: + displayList = True + + query = self.__getRestrictedComputersListQuery(ctx, filt, session, displayList) + if query == None: + return {} + + if self.config.ordered: + query = query.order_by(asc(self.machine.c.name)) + + if min != 0: + query = query.offset(min) + if max != -1: + max = int(max) - int(min) + query = query.limit(max) + + if justId: + ret = map(lambda m: self.getMachineUUID(m), query.all()) + elif toH: + ret = map(lambda m: m.toH(), query.all()) + else: + if filt is not None and filt.has_key('get'): + ret = self.__formatMachines(query.all(), + advanced, + filt['get'], + empty_macs=empty_macs) + else: + ret = self.__formatMachines(query.all(), + advanced, + None, + empty_macs=empty_macs) + session.close() + return ret + + def getTotalComputerCount(self): + session = create_session() + query = session.query(Machine) + query = self.__filter_on(query) + c = query.count() + session.close() + return c + + def getComputerCount(self, ctx, filt = None): + """ + Same as getRestrictedComputersListLen + TODO : remove this one + """ + return self.getRestrictedComputersListLen(ctx, filt) + + def getComputersList(self, ctx, filt = None): + """ + Same as getRestrictedComputersList without limits + """ + return self.getRestrictedComputersList(ctx, 0, -1, filt) + + ##################### UUID policies + def getMachineUUID(self, machine): + """ + Get this machine UUID + """ + return toUUID(str(machine.id)) + + def getMachineByUUID(self, uuid): + """ + Get the machine that as this UUID + """ + session = create_session() + ret = session.query(Machine).filter(self.machine.c.id == int(str(uuid).replace("UUID", ""))) + ret = ret.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + ret = self.__filter_on(ret).first() + session.close() + return ret + + def filterOnUUID(self, query, uuid): + """ + Modify the given query to filter on the machine UUID + """ + if type(uuid) == list: + return query.filter(self.machine.c.id.in_([int(str(a).replace("UUID", "")) for a in uuid])) + else: + return query.filter(self.machine.c.id == int(str(uuid).replace("UUID", ""))) + + ##################### Machine output format (for ldap compatibility) + def __getAttr(self, machine, get): + ma = {} + for field in get: + if hasattr(machine, field): + ma[field] = getattr(machine, field) + if field == 'uuid' or field == 'objectUUID': + ma[field] = toUUID(str(machine.id)) + if field == 'cn': + ma[field] = machine.name + return ma + + def __formatMachines(self, machines, advanced, get=None, empty_macs=False): + """ + Give an LDAP like version of machines + """ + ret = {} + if get != None: + for m in machines: + if isinstance(m, tuple): + m = m[0] + ret[m.getUUID()] = self.__getAttr(m, get) + return ret + + names = {} + for m in machines: + displayList = False + if isinstance(m, tuple): + displayList = True + # List of fields defined around line 439 + # m, os, type, inventorynumber, state, entity, location, model, manufacturer, owner = m + l = list(m) + if 'owner' in self.config.summary: + owner_login = l.pop() + if 'owner_firstname' in self.config.summary: + owner_firstname = l.pop() + if 'owner_realname' in self.config.summary: + owner_realname = l.pop() + if 'manufacturer' in self.config.summary: + manufacturer = l.pop() + if 'model' in self.config.summary: + model = l.pop() + if 'location' in self.config.summary: + location = l.pop() + if 'entity' in self.config.summary: + entity = l.pop() + if 'state' in self.config.summary: + state = l.pop() + if 'inventorynumber' in self.config.summary: + inventorynumber = l.pop() + if 'type' in self.config.summary: + type = l.pop() + if 'os' in self.config.summary: + os = l.pop() + + m = l.pop() + owner_login, owner_firstname, owner_realname = self.getMachineOwner(m) + datas = { + 'cn': m.name not in ['', None] and [m.name] or ['(%s)' % m.id], + 'displayName': [m.comment], + 'objectUUID': [m.getUUID()], + 'user': [m.contact], + 'owner': [owner_login], + 'owner_realname': [owner_realname], + 'owner_firstname': [owner_firstname], + } + + if displayList: + if 'manufacturer' in self.config.summary: + datas['manufacturer'] = manufacturer + if 'model' in self.config.summary: + datas['model'] = model + if 'location' in self.config.summary: + datas['location'] = location + if 'entity' in self.config.summary: + datas['entity'] = entity + if 'state' in self.config.summary: + datas['state'] = state + if 'inventorynumber' in self.config.summary: + datas['inventorynumber'] = inventorynumber + if 'type' in self.config.summary: + datas['type'] = type + if 'os' in self.config.summary: + datas['os'] = os + if 'owner' in self.config.summary: + datas['owner'] = owner_login + if 'owner_firstname' in self.config.summary: + datas['owner_firstname'] = owner_firstname + if 'owner_realname' in self.config.summary: + datas['owner_realname'] = owner_realname + + + + + ret[m.getUUID()] = [None, datas] + + if advanced: + names[m.getUUID()] = m.name + if advanced: + uuids = [] + for m in machines: + if isinstance(m, tuple): + m = m[0] + uuids.append(m.getUUID()) + + nets = self.getMachinesNetwork(uuids) + for uuid in ret: + try: + (ret[uuid][1]['macAddress'], + ret[uuid][1]['ipHostNumber'], + ret[uuid][1]['subnetMask'], + ret[uuid][1]['domain'], + ret[uuid][1]['networkUuids']) = self.orderIpAdresses(uuid, + names[uuid], + nets[uuid], + empty_macs=empty_macs) + if ret[uuid][1]['domain'] != '' and len(ret[uuid][1]['domain']) > 0 : + ret[uuid][1]['fullname'] = ret[uuid][1]['cn'][0]+'.'+ret[uuid][1]['domain'][0] + else: + ret[uuid][1]['fullname'] = ret[uuid][1]['cn'][0] + except KeyError: + ret[uuid][1]['macAddress'] = [] + ret[uuid][1]['ipHostNumber'] = [] + ret[uuid][1]['subnetMask'] = [] + ret[uuid][1]['domain'] = '' + ret[uuid][1]['fullname'] = ret[uuid][1]['cn'][0] + return ret + + def __formatMachine(self, machine, advanced, get = None): + """ + Give an LDAP like version of the machine + """ + + uuid = self.getMachineUUID(machine) + + if get != None: + return self.__getAttr(machine, get) + + ret = { + 'cn': [machine.name], + 'displayName': [machine.comment], + 'objectUUID': [uuid] + } + if advanced: + (ret['macAddress'], ret['ipHostNumber'], ret['subnetMask'], domain, ret['networkUuids']) = self.orderIpAdresses(uuid, machine.name, self.getMachineNetwork(uuid)) + if domain == None: + domain = '' + elif domain != '': + domain = '.'+domain + ret['fullname'] = machine.name + domain + return [None, ret] + + ##################### entities, profiles and user rigths management + def displayLocalisationBar(self): + """ + This module know how to give data to localisation bar + """ + return True + + def getMachineOwner(self, machine): + """ + Returns the owner of computer. + + @param machine: computer's instance + @type machine: Machine + + @return: owner (glpi_computers.user_id -> name) + @rtype: str + """ + + ret = None, None, None + session = create_session() + query = session.query(User).select_from(self.user.join(self.machine)) + query = query.filter(self.machine.c.id==machine.id).first() + if query is not None: + ret = query.name, query.firstname, query.realname + + session.close() + return ret + + + + def getUserProfile(self, user): + """ + @return: Return the first user GLPI profile as a string, or None + """ + session = create_session() + qprofile = session.query(Profile).select_from(self.profile.join(self.userprofile).join(self.user)).filter(self.user.c.name == user).first() + if qprofile == None: + ret = None + else: + ret= qprofile.name + session.close() + return ret + + def getUserProfiles(self, user): + """ + @return: Return all user GLPI profiles as a list of string, or None + """ + session = create_session() + profiles = session.query(Profile).select_from(self.profile.join(self.userprofile).join(self.user)).filter(self.user.c.name == user) + if profiles: + ret = [] + for profile in profiles: + ret.append(profile.name) + else: + ret = None + session.close() + return ret + + @DatabaseHelper._session + def getAllUserProfiles(self, session): + """ + @return: Return all GLPI profiles as a dict + """ + result = {} + for profile in session.query(Profile): + result[profile.id] = profile.name + return result + + def getUserParentLocations(self, user): + """ + get + return: the list of user locations'parents + """ + pass + + def getUserLocation(self, user): + """ + @return: Return one user GLPI entities as a list of string, or None + TODO : check it is still used! + """ + session = create_session() + qentities = session.query(Entities).select_from(self.entities.join(self.userprofile).join(self.user)).filter(self.user.c.name == user).first() + if qentities == None: + ret = None + else: + ret = qentities.name + return ret + + def getUserLocations(self, user): + """ + Get the GPLI user locations. + + @return: the list of user locations + @rtype: list + """ + ret = [] + if user == 'root': + ret = self.__get_all_locations() + else: + # check if user is linked to the root entity + # (which is not declared explicitly in glpi... + # we have to emulate it...) + session = create_session() + entids = session.query(UserProfile).select_from(self.userprofile.join(self.user).join(self.profile)).filter(self.user.c.name == user).filter(self.profile.c.name.in_(self.config.activeProfiles)).all() + for entid in entids: + if entid.entities_id == 0 and entid.is_recursive == 1: + session.close() + return self.__get_all_locations() + + # the normal case... + plocs = session.query(Entities).add_column(self.userprofile.c.is_recursive).select_from(self.entities.join(self.userprofile).join(self.user).join(self.profile)).filter(self.user.c.name == user).filter(self.profile.c.name.in_(self.config.activeProfiles)).all() + for ploc in plocs: + if ploc[1]: + # The user profile link to the entities is recursive, and so + # the children locations should be added too + for l in self.__add_children(ploc[0]): + ret.append(l) + else: + ret.append(ploc[0]) + if len(ret) == 0: + ret = [] + session.close() + + ret = map(lambda l: setUUID(l), ret) + return ret + + def __get_all_locations(self): + ret = [] + session = create_session() + q = session.query(Entities).group_by(self.entities.c.name).order_by(asc(self.entities.c.completename)).all() + session.close() + for entities in q: + ret.append(entities) + return ret + + def __add_children(self, child): + """ + Recursive function used by getUserLocations to get entities tree if needed + """ + session = create_session() + children = session.query(Entities).filter(self.entities.c.entities_id == child.id).all() + ret = [child] + for c in children: + for res in self.__add_children(c): + ret.append(res) + session.close() + return ret + + def getLocation(self, uuid): + """ + Get a Location by it's uuid + """ + session = create_session() + ret = session.query(Entities).filter(self.entities.c.id == uuid.replace('UUID', '')).first() + session.close() + return ret + + def getLocationName(self, uuid): + if isinstance(uuid, list): + uuid = uuid[0] + + return self.getLocation(uuid).name + + def getLocationsList(self, ctx, filt = None): + """ + Get the list of all entities that user can access + """ + ret = [] + complete_ctx(ctx) + filtr = re.compile(filt) + for loc in ctx.locations: + if filt: + if filtr.search(loc.name): + ret.append(loc.name) + else: + ret.append(loc.name) + + return ret + + def getLocationsCount(self): + """ + Returns the total count of entities + """ + session = create_session() + ret = session.query(Entities).count() + session.close() + return ret + + def getMachinesLocations(self, machine_uuids): + session = create_session() + q = session.query(Entities.id, Entities.name, Entities.completename, Entities.comment, Entities.level).add_column(self.machine.c.id).select_from(self.entities.join(self.machine)).filter(self.machine.c.id.in_(map(fromUUID, machine_uuids))).all() + ret = {} + for idp, namep,namepc,commentp,levelp,machineid in q: + val={} + val['uuid']=toUUID(idp) + val['name']=namep + val['completename']=namepc + val['comments']=commentp + val['level']=levelp + ret[toUUID(machineid)] = val + session.close() + return ret + + #def getMachinesLocations(self, machine_uuids): + #self.logger.info("***********getMachinesLocations"); + #session = create_session() + #q = session.query(Entities).add_column(self.machine.c.id).select_from(self.entities.join(self.machine)).filter(self.machine.c.id.in_(map(fromUUID, machine_uuids))).all() + #session.close() + #ret = {} + #for loc, mid in q: + #ret[toUUID(mid)] = loc.toH() + #return ret + + def getUsersInSameLocations(self, userid, locations = None): + """ + Returns all users name that share the same locations with the given + user + """ + if locations == None: + locations = self.getUserLocations(userid) + ret = [] + if locations: + inloc = [] + for location in locations: + inloc.append(location.name) + session = create_session() + q = session.query(User).select_from(self.user.join(self.userprofile).join(self.entities)).filter(self.entities.c.name.in_(inloc)).filter(self.user.c.name != userid).distinct().all() + session.close() + # Only returns the user names + ret = map(lambda u: u.name, q) + # Always append the given userid + ret.append(userid) + return ret + + def getComputerInLocation(self, location = None): + """ + Get all computers in that location + """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.entities)).filter(self.entities.c.name == location) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + ret = [] + for machine in query.group_by(self.machine.c.name).order_by(asc(self.machine.c.name)): + ret[machine.name] = self.__formatMachine(machine) + session.close() + return ret + + def getLocationsFromPathString(self, location_path): + """ + """ + session = create_session() + ens = [] + for loc_path in location_path: + loc_path = " > ".join(loc_path) + q = session.query(Entities).filter(self.entities.c.completename == loc_path).all() + if len(q) != 1: + ens.append(False) + else: + ens.append(toUUID(str(q[0].id))) + session.close() + return ens + + def getLocationParentPath(self, loc_uuid): + session = create_session() + path = [] + en_id = fromUUID(loc_uuid) + en = session.query(Entities).filter(self.entities.c.id == en_id).first() + parent_id = en.entities_id + if parent_id == -1: # parent_id is -1 for root entity + parent_id = 0 + + while parent_id != 0: + en_id = parent_id + en = session.query(Entities).filter(self.entities.c.id == parent_id).first() + path.append(toUUID(en.id)) + parent_id = en.entities_id + path.append('UUID0') + return path + + def doesUserHaveAccessToMachines(self, ctx, a_machine_uuid, all = True): + """ + Check if the user has correct permissions to access more than one or to all machines + + Return always true for the root user. + + @rtype: bool + """ + if not self.displayLocalisationBar: + return True + + session = create_session() + # get the number of computers the user have access to + query = session.query(Machine) + if ctx.userid == "root": + query = self.filterOnUUID(query, a_machine_uuid) + else: + a_locations = map(lambda loc:loc.name, ctx.locations) + query = query.select_from(self.machine.join(self.entities)) + query = query.filter(self.entities.c.name.in_(a_locations)) + query = self.filterOnUUID(query, a_machine_uuid) + ret = query.group_by(self.machine.c.id).all() + # get the number of computers that had not been deleted + machines_uuid_size = len(a_machine_uuid) + all_computers = session.query(Machine) + all_computers = self.filterOnUUID(all_computers, a_machine_uuid).all() + all_computers = Set(map(lambda m:toUUID(str(m.id)), all_computers)) + if len(all_computers) != machines_uuid_size: + self.logger.info("some machines have been deleted since that list was generated (%s)"%(str(Set(a_machine_uuid) - all_computers))) + machines_uuid_size = len(all_computers) + size = 1 + if type(ret) == list: + size = len(ret) + if all and size == machines_uuid_size: + return True + elif (not all) and machines_uuid_size == 0: + return True + elif (not all) and len(ret) > 0: + return True + ret = Set(map(lambda m:toUUID(str(m.id)), ret)) + self.logger.info("dont have permissions on %s"%(str(Set(a_machine_uuid) - ret))) + return False + + def doesUserHaveAccessToMachine(self, ctx, machine_uuid): + """ + Check if the user has correct permissions to access this machine + + @rtype: bool + """ + return self.doesUserHaveAccessToMachines(ctx, [machine_uuid]) + + ##################### for inventory purpose (use the same API than OCSinventory to keep the same GUI) + def getLastMachineInventoryFull(self, uuid): + session = create_session() + # there is glpi_entreprise missing + query = self.filterOnUUID(session.query(Machine) \ + .add_column(self.glpi_operatingsystems.c.name) \ + .add_column(self.glpi_operatingsystemservicepacks.c.name) \ + .add_column(self.glpi_operatingsystemversions.c.name) \ + .add_column(self.glpi_domains.c.name) \ + .add_column(self.locations.c.name) \ + .add_column(self.glpi_computermodels.c.name) \ + .add_column(self.glpi_computertypes.c.name) \ + .add_column(self.glpi_networks.c.name) \ + .add_column(self.entities.c.completename) \ + .select_from( \ + self.machine.outerjoin(self.glpi_operatingsystems).outerjoin(self.glpi_operatingsystemservicepacks).outerjoin(self.glpi_operatingsystemversions).outerjoin(self.glpi_computertypes) \ + .outerjoin(self.glpi_domains).outerjoin(self.locations).outerjoin(self.glpi_computermodels).outerjoin(self.glpi_networks) \ + .join(self.entities) + ), uuid).all() + ret = [] + ind = {'os':1, 'os_sp':2, 'os_version':3, 'type':7, 'domain':4, 'location':5, 'model':6, 'network':8, 'entity':9} # 'entreprise':9 + for m in query: + ma1 = m[0].to_a() + ma2 = [] + for x,y in ma1: + if x in ind.keys(): + ma2.append([x,m[ind[x]]]) + else: + ma2.append([x,y]) + ret.append(ma2) + if type(uuid) == list: + return ret + return ret[0] + + def inventoryExists(self, uuid): + machine = self.getMachineByUUID(uuid) + if machine: + return True + else: + return False + + def getWarrantyEndDate(self, infocoms): + """ + Get a computer's warranty end date + @param infocoms: Content of glpi_infocoms SQL table + @type infocoms: self.infocoms sqlalchemy object + + @return: computer's warranty end date if exists, else None + @rtype: string or None + """ + + def add_months(sourcedate, months): + """ + Add x months to a datetime object + thanks to http://stackoverflow.com/questions/4130922/how-to-increment-datetime-month-in-python + """ + month = sourcedate.month - 1 + months + year = sourcedate.year + month / 12 + month = month % 12 + 1 + day = min(sourcedate.day, calendar.monthrange(year, month)[1]) + return datetime.date(year,month,day) + + if infocoms is not None and infocoms.warranty_date is not None: + endDate = add_months(infocoms.warranty_date, infocoms.warranty_duration) + if datetime.datetime.now().date() > endDate: + return '%s' % endDate.strftime('%Y-%m-%d') + else: + return endDate.strftime('%Y-%m-%d') + + return '' + + def getManufacturerWarranty(self, manufacturer, serial): + for manufacturer_key, manufacturer_infos in self.config.manufacturerWarranty.items(): + if manufacturer in manufacturer_infos['names']: + manufacturer_info = manufacturer_infos.copy() + manufacturer_info['url'] = manufacturer_info['url'].replace('@@SERIAL@@', serial) + manufacturer_info['params'] = manufacturer_info['params'].replace('@@SERIAL@@', serial) + return manufacturer_info + return False + + def getSearchOptionId(self, filter, lang = 'en_US'): + """ + return a list of ids corresponding to filter + @param filter: a value to search + @type filter: string + """ + + ids = [] + dict = self.searchOptions[lang] + for key, value in dict.iteritems(): + if filter.lower() in value.lower(): + ids.append(key) + + return ids + + def getLinkedActionKey(self, filter, lang = 'en_US'): + """ + return a list of ids corresponding to filter + """ + ids = [] + dict = self.getLinkedActions() + for key, value in dict.iteritems(): + if filter.lower() in value.lower(): + ids.append(key) + + return ids + + def countLastMachineInventoryPart(self, uuid, part, filt = None, options = {}): + return self.getLastMachineInventoryPart(uuid, part, filt = filt, options = options, count = True) + + @property + def _network_types(self): + """ + Dict with GLPI available Network types + """ + return { + 'NetworkPortLocal': 'Local', + 'NetworkPortEthernet': 'Ethernet', + 'NetworkPortWifi': 'Wifi', + 'NetworkPortDialup': 'Dialup', + 'NetworkPortAggregate': 'Aggregate', + 'NetworkPortAlias': 'Alias', + } + + def _get_network_type(self, instantiation_type): + """ + Return human readable glpi network type for given instantiation_type + If not found, return instantiation_type + """ + if instantiation_type in self._network_types: + return self._network_types[instantiation_type] + return instantiation_type + + def getLastMachineNetworkPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID(session.query(Machine), uuid) + + ret = [] + for machine in query: + if count: + ret = len(machine.networkports) + else: + for networkport in machine.networkports: + # Get IP, one networkport can have multiple IPs + ipaddresses = [] + gateways = [] + netmasks = [] + if networkport.networknames is not None: + ipaddresses = list(set([ip.name for ip in networkport.networknames.ipaddresses if ip.name != ''])) + gateways = [] + netmasks = [] + for ip in networkport.networknames.ipaddresses: + gateways += [ipnetwork.gateway for ipnetwork in ip.ipnetworks if ipnetwork.gateway not in ['', '0.0.0.0']] + netmasks += [ipnetwork.netmask for ipnetwork in ip.ipnetworks if ipnetwork.netmask not in ['', '0.0.0.0']] + gateways = list(set(gateways)) + netmasks = list(set(netmasks)) + l = [ + ['Name', networkport.name], + ['Network Type', self._get_network_type(networkport.instantiation_type)], + ['MAC Address', networkport.mac], + ['IP', ' / '.join(ipaddresses)], + ['Netmask', ' / '.join(netmasks)], + ['Gateway', ' / '.join(gateways)], + ] + ret.append(l) + return ret + + def getLastMachineStoragePart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(Disk).add_column(self.diskfs.c.name).select_from( + self.machine.outerjoin(self.disk).outerjoin(self.diskfs) + ), uuid) + if count: + ret = query.count() + else: + ret = [] + for disk, diskfs in query: + if diskfs not in ['rootfs', 'tmpfs', 'devtmpfs']: + if disk is not None: + l = [ + ['Name', disk.name], + ['Device', disk.device], + ['Mount Point', disk.mountpoint], + ['Filesystem', diskfs], + ['Size', disk.totalsize and str(disk.totalsize) + ' MB' or ''], + ['Free Size', disk.freesize and str(disk.freesize) + ' MB' or ''], + ] + ret.append(l) + return ret + + def getLastMachineAdministrativePart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(Infocoms).add_column(self.suppliers.c.name).select_from( + self.machine.outerjoin(self.infocoms).outerjoin(self.suppliers) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for infocoms, supplierName in query: + if infocoms is not None: + endDate = self.getWarrantyEndDate(infocoms) + dateOfPurchase = '' + if infocoms.buy_date is not None: + dateOfPurchase = infocoms.buy_date.strftime('%Y-%m-%d') + + l = [ + ['Supplier', supplierName], + ['Invoice Number', infocoms.bill], + ['Date Of Purchase', dateOfPurchase], + ['Warranty End Date', endDate], + ] + ret.append(l) + return ret + + def getLastMachineAntivirusPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + if self.fusionantivirus is None: # glpi_plugin_fusinvinventory_antivirus doesn't exists + return [] + + query = self.filterOnUUID( + session.query(FusionAntivirus).add_column(self.manufacturers.c.name).select_from( + self.machine.outerjoin(self.fusionantivirus).outerjoin(self.manufacturers) + ), uuid) + + def __getAntivirusName(manufacturerName, antivirusName): + """ + Return complete antivirus name (manufacturer + antivirus name) + if antivirus name is a false positive, display it in bracket + """ + if antivirusName in self.config.av_false_positive: + antivirusName += '@@FALSE_POSITIVE@@' + + return manufacturerName and ' '.join([manufacturerName, antivirusName]) or antivirusName + + if count: + ret = query.count() + else: + ret = [] + for antivirus, manufacturerName in query: + if antivirus: + l = [ + ['Name', __getAntivirusName(manufacturerName, antivirus.name)], + ['Enabled', antivirus.is_active == 1 and 'Yes' or 'No'], + ['Up-to-date', antivirus.uptodate == 1 and 'Yes' or 'No'], + ] + if antivirus.version: + l.insert(1, ['Version', antivirus.version]) + ret.append(l) + return ret + + def getLastMachineSoftwaresPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + hide_win_updates = False + if 'hide_win_updates' in options: + hide_win_updates = options['hide_win_updates'] + + query = self.filterOnUUID( + session.query(Software).add_column(self.manufacturers.c.name) \ + .add_column(self.softwareversions.c.name).select_from( + self.machine.outerjoin(self.inst_software) \ + .outerjoin(self.softwareversions) \ + .outerjoin(self.software) \ + .outerjoin(self.manufacturers) + ), uuid) + query = query.order_by(self.software.c.name) + + if filt: + clauses = [] + clauses.append(self.manufacturers.c.name.like('%'+filt+'%')) + clauses.append(self.softwareversions.c.name.like('%'+filt+'%')) + clauses.append(self.software.c.name.like('%'+filt+'%')) + query = query.filter(or_(*clauses)) + + if hide_win_updates: + query = query.filter( + not_( + and_( + self.manufacturers.c.name.contains('microsoft'), + self.software.c.name.op('regexp')('KB[0-9]+(-v[0-9]+)?(v[0-9]+)?') + ) + ) + ) + + if min != 0: + query = query.offset(min) + if max != -1: + max = int(max) - int(min) + query = query.limit(max) + + if count: + ret = query.count() + else: + ret = [] + for software, manufacturer, version in query: + if software is not None: + l = [ + ['Vendor', manufacturer], + ['Name', software.name], + ['Version', version], + ] + ret.append(l) + return ret + + def __getTableAndFieldFromName(self, name): + """ + return table class and field name for a given name + used for editable fields + + @param name: a given name + @type name: string + + @return: table class and field name + @rtype: tuple + """ + + # Reminder: + # If you add some other classes, check + # if __tablename__ exists for these classes + + values = { + 'computer_name': (Machine, 'name'), + 'description': (Machine, 'comment'), + 'inventory_number': (Machine, 'otherserial'), + } + + return values[name] + + def setGlpiEditableValue(self, uuid, name, value): + """ + Set a new value for a Glpi field + + @param uuid: machine uuid + @type uuid: string + + @param name: Glpi field who will be updated + @param name: string + + @param value: The new value + @param value: string + """ + + self.logger.debug("Update an editable field") + self.logger.debug("%s: Set %s as new value for %s" % (uuid, value, name)) + try: + session = create_session() + + # Get SQL field who will be updated + table, field = self.__getTableAndFieldFromName(name) + session.query(table).filter_by(id=fromUUID(uuid)).update({field: value}) + + # Set updated field as a locked field so it won't be updated + # at next inventory + query = session.query(FusionLocks).filter(self.fusionlocks.c.items_id == fromUUID(uuid)) + flocks = query.first() + if flocks is not None: + # Update glpi_plugin_fusioninventory_locks tablefields table + flocksFields = eval(flocks.tablefields) + if field not in flocksFields: + flocksFields.append(field) + query.update({'tablefields': str(flocksFields).replace("'", '"')}) + else: + # Create new glpi_plugin_fusioninventory_locks entry + session.execute( + self.fusionlocks.insert().values({ + 'tablename': table.__tablename__, + 'items_id': fromUUID(uuid), + 'tablefields': str([field]).replace("'", '"'), + }) + ) + + session.close() + return True + except Exception, e: + self.logger.error(e) + return False + + def getLastMachineSummaryPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(Machine).add_entity(Infocoms) \ + .add_column(self.entities.c.name) \ + .add_column(self.locations.c.name) \ + .add_column(self.os.c.name) \ + .add_column(self.manufacturers.c.name) \ + .add_column(self.glpi_computertypes.c.name) \ + .add_column(self.glpi_computermodels.c.name) \ + .add_column(self.glpi_operatingsystemservicepacks.c.name) \ + .add_column(self.glpi_domains.c.name) \ + .add_column(self.state.c.name) \ + .add_column(self.fusionagents.c.last_contact) \ + .select_from( + self.machine.outerjoin(self.entities) \ + .outerjoin(self.locations) \ + .outerjoin(self.os) \ + .outerjoin(self.manufacturers) \ + .outerjoin(self.infocoms) \ + .outerjoin(self.glpi_computertypes) \ + .outerjoin(self.glpi_computermodels) \ + .outerjoin(self.glpi_operatingsystemservicepacks) \ + .outerjoin(self.state) \ + .outerjoin(self.fusionagents) \ + .outerjoin(self.glpi_domains) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for machine, infocoms, entity, location, os, manufacturer, type, model, servicepack, domain, state, last_contact in query: + endDate = '' + if infocoms is not None: + endDate = self.getWarrantyEndDate(infocoms) + + modelType = [] + if model is not None: + modelType.append(model) + if type is not None: + modelType.append(type) + + if len(modelType) == 0: + modelType = '' + elif len(modelType) == 1: + modelType = modelType[0] + elif len(modelType) == 2: + modelType = " / ".join(modelType) + + manufacturerWarranty = False + if machine.serial is not None and len(machine.serial) > 0: + manufacturerWarranty = self.getManufacturerWarranty(manufacturer, machine.serial) + + if manufacturerWarranty: + if manufacturerWarranty['type'] == 'get': + url = manufacturerWarranty['url'] + '?' + manufacturerWarranty['params'] + serialNumber = '%s / @@WARRANTY_LINK_TEXT@@' % (machine.serial, url) + else: + url = manufacturerWarranty['url'] + serialNumber = '%s /
' % (machine.serial, url) + for param in manufacturerWarranty['params'].split('&'): + name, value = param.split('=') + serialNumber += '' % (name, value) + serialNumber += '@@WARRANTY_LINK_TEXT@@
' + else: + serialNumber = machine.serial + + entityValue = '' + if entity: + entityValue += entity + if location: + entityValue += ' (%s)' % location + + owner_login, owner_firstname, owner_realname = self.getMachineOwner(machine) + + # Last inventory date + date_mod = machine.date_mod + if self.fusionagents is not None and last_contact is not None: + date_mod = last_contact + + l = [ + ['Computer Name', ['computer_name', 'text', machine.name]], + ['Description', ['description', 'text', machine.comment]], + ['Entity (Location)', '%s' % entityValue], + ['Domain', domain], + ['Last Logged User', machine.contact], + ['Owner', owner_login], + ['Owner Firstname', owner_firstname], + ['Owner Realname', owner_realname], + ['OS', os], + ['Service Pack', servicepack], + ['Windows Key', machine.os_license_number], + ['Model / Type', modelType], + ['Manufacturer', manufacturer], + ['Serial Number', serialNumber], + ['Inventory Number', ['inventory_number', 'text', machine.otherserial]], + ['State', state], + ['Warranty End Date', endDate], + ['Last Inventory Date', date_mod.strftime("%Y-%m-%d %H:%M:%S")], + ] + ret.append(l) + return ret + + def getLastMachineProcessorsPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(ComputerProcessor).add_column(self.processor.c.designation) \ + .select_from( + self.machine.outerjoin(self.computerProcessor) \ + .outerjoin(self.processor) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for processor, designation in query: + if processor is not None: + l = [ + ['Name', designation], + ['Frequency', processor.frequency and str(processor.frequency) + ' MHz' or ''], + ] + ret.append(l) + return ret + + def getLastMachineMemoryPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(ComputerMemory) \ + .add_column(self.memoryType.c.name) \ + .add_column(self.memory.c.frequence) \ + .add_column(self.memory.c.designation).select_from( + self.machine.outerjoin(self.computerMemory) \ + .outerjoin(self.memory) \ + .outerjoin(self.memoryType) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for memory, type, frequence, designation in query: + if memory is not None: + l = [ + ['Name', designation], + ['Type', type], + ['Frequency', frequence], + ['Size', memory.size and str(memory.size) + ' MB' or ''], + ] + ret.append(l) + return ret + + def getLastMachineHarddrivesPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['computers_deviceharddrives']) \ + .add_column(self.deviceharddrives.c.designation) \ + .select_from( + self.machine.outerjoin(self.computers_deviceharddrives) \ + .outerjoin(self.deviceharddrives) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for hd, designation in query: + if hd is not None: + l = [ + ['Name', designation], + ['Size', hd.capacity and str(hd.capacity) + ' MB' or ''], + ] + ret.append(l) + return ret + + def getLastMachineNetworkCardsPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['computers_devicenetworkcards']) \ + .add_entity(self.klass['devicenetworkcards']) \ + .select_from( + self.machine.outerjoin(self.computers_devicenetworkcards) \ + .outerjoin(self.devicenetworkcards) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for mac, network in query: + if network is not None: + l = [ + ['Name', network.designation], + ['Bandwidth', network.bandwidth], + ['MAC Address', mac.mac], + ] + ret.append(l) + return ret + + def getLastMachineDrivesPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['devicedrives']).select_from( + self.machine.outerjoin(self.computers_devicedrives) \ + .outerjoin(self.devicedrives) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for drive in query: + if drive is not None: + l = [ + ['Name', drive.designation], + ['Writer', drive.is_writer and 'Yes' or 'No'], + ] + ret.append(l) + return ret + + def getLastMachineGraphicCardsPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['devicegraphiccards']).add_column(self.interfaceType.c.name) \ + .select_from( + self.machine.outerjoin(self.computers_devicegraphiccards) \ + .outerjoin(self.devicegraphiccards) \ + .outerjoin(self.interfaceType, self.interfaceType.c.id == self.devicegraphiccards.c.interfacetypes_id) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for card, interfaceType in query: + if card is not None: + l = [ + ['Name', card.designation], + ['Memory', card.memory_default and str(card.memory_default) + ' MB' or ''], + ['Type', interfaceType], + ] + ret.append(l) + return ret + + def getLastMachineSoundCardsPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['devicesoundcards']).select_from( + self.machine.outerjoin(self.computers_devicesoundcards) \ + .outerjoin(self.devicesoundcards) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for sound in query: + if sound is not None: + l = [ + ['Name', sound.designation], + ] + ret.append(l) + return ret + + def getLastMachineControllersPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['computers_devicecontrols']) \ + .add_entity(self.klass['devicecontrols']).select_from( + self.machine.outerjoin(self.computers_devicecontrols) \ + .outerjoin(self.devicecontrols) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for computerControls, deviceControls in query: + if computerControls is not None: + l = [ + ['Name', deviceControls.designation], + ] + ret.append(l) + return ret + + def getLastMachineOthersPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + query = self.filterOnUUID( + session.query(self.klass['devicepcis']).select_from( + self.machine.outerjoin(self.computers_devicepcis) \ + .outerjoin(self.devicepcis) + ), uuid) + + if count: + ret = query.count() + else: + ret = [] + for pci in query: + if pci is not None: + l = [ + ['Name', pci.designation], + ['Comment', pci.comment], + ] + ret.append(l) + return ret + + def getLastMachineHistoryPart(self, session, uuid, part, min = 0, max = -1, filt = None, options = {}, count = False): + # Set options + history_delta = 'All' + if 'history_delta' in options: + history_delta = options['history_delta'] + + query = session.query(Logs) + query = query.filter(and_( + self.logs.c.items_id == int(uuid.replace('UUID', '')), + self.logs.c.itemtype == "Computer" + )) + + now = datetime.datetime.now() + if history_delta == 'today': + query = query.filter(self.logs.c.date_mod > now - datetime.timedelta(1)) + elif history_delta == 'week': + query = query.filter(self.logs.c.date_mod > now - datetime.timedelta(7)) + if history_delta == 'month': + query = query.filter(self.logs.c.date_mod > now - datetime.timedelta(30)) + + if filt: + clauses = [] + clauses.append(self.logs.c.date_mod.like('%'+filt+'%')) + clauses.append(self.logs.c.user_name.like('%'+filt+'%')) + clauses.append(self.logs.c.old_value.like('%'+filt+'%')) + clauses.append(self.logs.c.new_value.like('%'+filt+'%')) + clauses.append(self.logs.c.id_search_option.in_(self.getSearchOptionId(filt))) + clauses.append(self.logs.c.itemtype_link.in_(self.getLinkedActionKey(filt))) + # Treat Software case + if filt.lower() in 'software': + clauses.append(self.logs.c.linked_action.in_([4, 5])) + query = query.filter(or_(*clauses)) + + if count: + ret = query.count() + else: + query = query.order_by(desc(self.logs.c.date_mod)) + + if min != 0: + query = query.offset(min) + if max != -1: + max = int(max) - int(min) + query = query.limit(max) + + ret = [] + for log in query: + if log is not None: + update = '' + if log.old_value == '' and log.new_value != '': + update = '%s' % log.new_value + elif log.old_value != '' and log.new_value == '': + update = '%s' % log.old_value + else: + update = '%s --> %s' % (log.old_value, log.new_value) + + update = '%s%s' % (self.getLinkedActionValues(log)['update'], update) + + l = [ + ['Date', log.date_mod.strftime('%Y-%m-%d %H:%m')], + ['User', log.user_name], + ['Category', self.getLinkedActionValues(log)['field']], + ['Action', update], + ] + ret.append(l) + return ret + + def getLastMachineInventoryPart(self, uuid, part, minbound = 0, maxbound = -1, filt = None, options = {}, count = False): + session = create_session() + + ret = None + if hasattr(self, 'getLastMachine%sPart' % part): + ret = getattr(self, 'getLastMachine%sPart' % part)(session, uuid, part, minbound, maxbound, filt, options, count) + + session.close() + return ret + + def getSearchOptionValue(self, log): + try: + return self.searchOptions['en_US'][str(log.id_search_option)] + except: + if log.id_search_option != 0: + logging.getLogger().warn('I can\'t get a search option for id %s' % log.id_search_option) + return '' + + def getLinkedActionValues(self, log): + d = { + 0: { + 'update': '', + 'field': self.getSearchOptionValue(log), + }, + 1: { + 'update': 'Add a component: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + 2: { + 'update': 'Update a component: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + 3: { + 'update': 'Deletion of a component: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + 4: { + 'update': 'Install software: ', + 'field': 'Software', + }, + 5: { + 'update': 'Uninstall software: ', + 'field': 'Software', + }, + 6: { + 'update': 'Disconnect device: ', + 'field': log.itemtype_link, + }, + 7: { + 'update': 'Connect device: ', + 'field': log.itemtype_link, + }, + 8: { + 'update': 'OCS Import: ', + 'field': '', + }, + 9: { + 'update': 'OCS Delete: ', + 'field': '', + }, + 10: { + 'update': 'OCS ID Changed: ', + 'field': '', + }, + 11: { + 'update': 'OCS Link: ', + 'field': '', + }, + 12: { + 'update': 'Other (often from plugin): ', + 'field': '', + }, + 13: { + 'update': 'Delete item (put in trash): ', + 'field': '', + }, + 14: { + 'update': 'Restore item from trash: ', + 'field': '', + }, + 15: { + 'update': 'Add relation: ', + 'field': log.itemtype_link, + }, + 16: { + 'update': 'Delete relation: ', + 'field': log.itemtype_link, + }, + 17: { + 'update': 'Add an item: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + 18: { + 'update': 'Update an item: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + 19: { + 'update': 'Deletion of an item: ', + 'field': self.getLinkedActionField(log.itemtype_link), + }, + } + + if log.linked_action in d: + return d[log.linked_action] + else: + return { + 'update': '', + 'field': '', + } + + def getLinkedActions(self): + return { + 'DeviceDrive': 'Drive', + 'DeviceGraphicCard': 'Graphic Card', + 'DeviceHardDrive': 'Hard Drive', + 'DeviceMemory': 'Memory', + 'DeviceNetworkCard': 'Network Card', + 'DevicePci': 'Other Component', + 'DeviceProcessor': 'Processor', + 'DeviceSoundCard': 'Sound Card', + 'ComputerDisk': 'Volume', + 'NetworkPort': 'Network Port', + } + + def getLinkedActionField(self, itemtype): + """ + return Field content + """ + field = self.getLinkedActions() + try: + return field[itemtype] + except: + return itemtype + + def getUnknownPXEOSId(self, unknownOsString): + """ + Return id of Unknown OS depending given string + + @param unknownOsString: unknown OS string + @type: str + + @return: id of Unknown OS string + @rtype: int + """ + ret = None + session = create_session() + query = session.query(OS).filter(self.os.c.name == unknownOsString) + result = query.first() + if result is not None: + ret = result.id + session.close() + return ret + + def hasKnownOS(self, uuid): + """ + Return True if machine has a known Operating System + Used to know if a PXE inventory will be sent or not + * If no known OS: send inventory + * if known OS: don't send inventory + + @param uuid: UUID of machine + @type uuid: str + + @return: True or False if machine has a known OS + @rtype: boolean + """ + session = create_session() + # In GLPI, unknown OS id is 0 + # PXE Inventory create a new one with name: "Unknown operating system (PXE network boot inventory)" + unknown_os_ids = [0] + unknown_os_pxe_id = self.getUnknownPXEOSId("Unknown operating system (PXE network boot inventory)") + if unknown_os_pxe_id: + unknown_os_ids.append(unknown_os_pxe_id) + + query = self.filterOnUUID(session.query(Machine).filter(not_(self.machine.c.operatingsystems_id.in_(unknown_os_ids))), uuid) + session.close() + + return query.first() and True or False + + ##################### functions used by querymanager + def getAllOs(self, ctx, filt = ''): + """ + @return: all os defined in the GLPI database + """ + session = create_session() + query = session.query(OS).select_from(self.os.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.os.c.name.like('%'+filt+'%')) + ret = query.all() + session.close() + return ret + def getMachineByOs(self, ctx, osname): + """ + @return: all machines that have this os + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.os)).filter(self.os.c.name == osname) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + ret = query.all() + session.close() + return ret + + @DatabaseHelper._session + def getMachineByOsLike(self, session, ctx, osnames, count = 0): + """ + @return: all machines that have this os using LIKE + """ + if isinstance(osnames, basestring): + osnames = [osnames] + + if int(count) == 1: + query = session.query(func.count(Machine.id)).select_from(self.machine.outerjoin(self.os)) + else: + query = session.query(Machine).select_from(self.machine.outerjoin(self.os)) + + query = query.filter(Machine.is_deleted == 0).filter(Machine.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + + if osnames == ["other"]: + query = query.filter( + or_( + not_(OS.name.like('%Microsoft%Windows%')), + Machine.operatingsystems_id == 0, + ) + ) + elif osnames == ["otherw"]: + query = query.filter(and_(not_(OS.name.like('%Microsoft%Windows%7%')),\ + not_(OS.name.like('%Microsoft%Windows%XP%')), OS.name.like('%Microsoft%Windows%'))) + # if osnames == ['%'], we want all machines, including machines without OS (used for reporting, per example...) + elif osnames != ['%']: + os_filter = [OS.name.like('%' + osname + '%') for osname in osnames] + query = query.filter(or_(*os_filter)) + + if int(count) == 1: + return int(query.scalar()) + else: + return [[q.id, q.name] for q in query] + + def getAllEntities(self, ctx, filt = ''): + """ + @return: all entities defined in the GLPI database + """ + session = create_session() + query = session.query(Entities) + if filter != '': + query = query.filter(self.entities.c.name.like('%'+filt+'%')) + + # Request only entites current user can access + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + query = query.filter(self.entities.c.id.in_(ctx.locationsid)) + + query = query.order_by(self.entities.c.name) + ret = query.all() + session.close() + return ret + + def getMachineByEntity(self, ctx, enname): + """ + @return: all machines that are in this entity + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.entities)).filter(self.entities.c.name == enname) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + ret = query.all() + session.close() + return ret + + def getEntitiesParentsAsList(self, lids): + my_parents_ids = [] + my_parents = self.getEntitiesParentsAsDict(lids) + for p in my_parents: + for i in my_parents[p]: + if not my_parents_ids.__contains__(i): + my_parents_ids.append(i) + return my_parents_ids + + def getEntitiesParentsAsDict(self, lids): + session = create_session() + if type(lids) != list and type(lids) != tuple: + lids = (lids) + query = session.query(Entities).all() + locs = {} + for l in query: + locs[l.id] = l.entities_id + + def __getParent(i): + if locs.has_key(i): + return locs[i] + else: + return None + ret = {} + for i in lids: + t = [] + p = __getParent(i) + while p != None: + t.append(p) + p = __getParent(p) + ret[i] = t + return ret + + @DatabaseHelper._session + def getAllVersion4Software(self, session, ctx, softname, version = ''): + """ + @return: all softwares defined in the GLPI database + """ + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + query = session.query(distinct(SoftwareVersion.name)) \ + .select_from(self.softwareversions.join(self.software)) + + my_parents_ids = self.getEntitiesParentsAsList(ctx.locationsid) + query = query.filter( + or_( + Software.entities_id.in_(ctx.locationsid), + and_( + Software.is_recursive == 1, + Software.entities_id.in_(my_parents_ids) + ) + ) + ) + + query = query.filter(Software.name.like('%' + softname + '%')) + + if version: + query = query.filter(SoftwareVersion.name.like('%' + version + '%')) + + # Last softwareversion entries first + query = query.order_by(desc(SoftwareVersion.id)) + + ret = query.all() + return ret + + @DatabaseHelper._session + def getAllSoftwares(self, session, ctx, softname='', vendor=None, limit=None): + """ + @return: all softwares defined in the GLPI database + """ + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + + query = session.query(distinct(Software.name)) + query = query.select_from( + self.software \ + .join(self.softwareversions) \ + .join(self.inst_software) \ + .join(self.manufacturers, isouter=True) + ) + my_parents_ids = self.getEntitiesParentsAsList(ctx.locationsid) + query = query.filter( + or_( + Software.entities_id.in_(ctx.locationsid), + and_( + Software.is_recursive == 1, + Software.entities_id.in_(my_parents_ids) + ) + ) + ) + if vendor is not None: + query = query.filter(Manufacturers.name.like(vendor)) + + if softname != '': + query = query.filter(Software.name.like('%' + softname + '%')) + + # Last software entries first + query = query.order_by(desc(Software.id)) + + if limit is None: + ret = query.all() + else: + ret = query.limit(limit).all() + return ret + + @DatabaseHelper._session + def getAllSoftwaresByManufacturer(self, session, ctx, vendor): + """ + Return all softwares of a vendor + """ + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + query = session.query(Software) + query = query.join(Manufacturers) + query = query.filter(Manufacturers.name.like(vendor)) + ret = query.group_by(Software.name).order_by(Software.name).all() + return ret + + @DatabaseHelper._session + def getMachineBySoftware(self, + session, + ctx, + name, + vendor=None, + version=None, + count=0): + """ + @return: all machines that have this software + """ + def all_elem_are_none(params): + for param in params: + if param is not None: + return False + return True + def check_list(param): + if not isinstance(param, list): + return [param] + elif all_elem_are_none(param): + return None + elif not param: + return None + else: + return param + + name = check_list(name) + if vendor is not None: vendor = check_list(vendor) + if version is not None: version = check_list(version) + + if int(count) == 1: + query = session.query(func.count(distinct(self.machine.c.id))) + else: + query = session.query(distinct(self.machine.c.id)) + + query = query.select_from(self.machine + .join(self.inst_software) + .join(self.softwareversions) + .join(self.software) + .outerjoin(self.manufacturers)) + query = query.filter(Machine.is_deleted == 0) + query = query.filter(Machine.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + + name_filter = [Software.name.like(n) for n in name] + query = query.filter(or_(*name_filter)) + + if version is not None: + version_filter = [SoftwareVersion.name.like(v) for v in version] + query = query.filter(or_(*version_filter)) + + if vendor is not None: + vendor_filter = [Manufacturers.name.like(v) for v in vendor] + query = query.filter(or_(*vendor_filter)) + + if int(count) == 1: + ret = int(query.scalar()) + else: + ret = query.all() + return ret + + @DatabaseHelper._session + def getAllSoftwaresImproved(self, + session, + ctx, + name, + vendor=None, + version=None, + count=0): + """ + This method is used for reporting and license count + it's inspired from getMachineBySoftware method, but instead of count + number of machines who have this soft, this method count number of + softwares + + Example: 5 firefox with different version on a single machine: + getMachineBySoftware: return 1 + this method: return 5 + + I should use getAllSoftwares method, but deadline is yesterday.... + """ + def all_elem_are_none(params): + for param in params: + if param is not None: + return False + return True + def check_list(param): + if not isinstance(param, list): + return [param] + elif all_elem_are_none(param): + return None + elif not param: + return None + else: + return param + + name = check_list(name) + if vendor is not None: vendor = check_list(vendor) + if version is not None: version = check_list(version) + + if int(count) == 1: + query = session.query(func.count(self.software.c.name)) + else: + query = session.query(self.software.c.name) + + query = query.select_from(self.software + .join(self.softwareversions) + .join(self.inst_software) + .outerjoin(self.manufacturers)) + + name_filter = [Software.name.like(n) for n in name] + query = query.filter(or_(*name_filter)) + + if version is not None: + version_filter = [SoftwareVersion.name.like(v) for v in version] + query = query.filter(or_(*version_filter)) + + if vendor is not None: + vendor_filter = [Manufacturers.name.like(v) for v in vendor] + query = query.filter(or_(*vendor_filter)) + + if hasattr(ctx, 'locationsid'): + query = query.filter(Software.entities_id.in_(ctx.locationsid)) + + if int(count) == 1: + ret = int(query.scalar()) + else: + ret = query.all() + return ret + + def getMachineBySoftwareAndVersion(self, ctx, swname, count=0): + # FIXME: the way the web interface process dynamic group sub-query + # is wrong, so for the moment we need this loop: + version = None + if type(swname) == list: + while type(swname[0]) == list: + swname = swname[0] + name = swname[0] + version = swname[1] + return self.getMachineBySoftware(ctx, name, version, count=count) + + def getAllHostnames(self, ctx, filt = ''): + """ + @return: all hostnames defined in the GLPI database + """ + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.machine.c.name.like('%'+filt+'%')) + ret = query.all() + session.close() + return ret + def getMachineByHostname(self, ctx, hostname): + """ + @return: all machines that have this hostname + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.machine.c.name == hostname) + ret = query.all() + session.close() + return ret + + def getAllContacts(self, ctx, filt = ''): + """ + @return: all hostnames defined in the GLPI database + """ + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.machine.c.contact.like('%'+filt+'%')) + ret = query.group_by(self.machine.c.contact).all() + session.close() + return ret + def getMachineByContact(self, ctx, contact): + """ + @return: all machines that have this contact + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.machine.c.contact == contact) + ret = query.all() + session.close() + return ret + + def getAllContactNums(self, ctx, filt = ''): + """ + @return: all hostnames defined in the GLPI database + """ + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.machine.c.contact_num.like('%'+filt+'%')) + ret = query.group_by(self.machine.c.contact_num).all() + session.close() + return ret + def getMachineByContactNum(self, ctx, contact_num): + """ + @return: all machines that have this contact number + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.machine.c.contact_num == contact_num) + ret = query.all() + session.close() + return ret + + def getAllComments(self, ctx, filt = ''): + """ + @return: all hostnames defined in the GLPI database + """ + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.machine.c.comment.like('%'+filt+'%')) + ret = query.group_by(self.machine.c.comment).all() + session.close() + return ret + def getMachineByComment(self, ctx, comment): + """ + @return: all machines that have this contact number + """ + # TODO use the ctx... + session = create_session() + query = session.query(Machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.machine.c.comment == comment) + ret = query.all() + session.close() + return ret + + def getAllModels(self, ctx, filt = ''): + """ @return: all machine models defined in the GLPI database """ + session = create_session() + query = session.query(Model).select_from(self.model.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.model.c.name.like('%'+filt+'%')) + ret = query.group_by(self.model.c.name).all() + session.close() + return ret + + def getAllManufacturers(self, ctx, filt = ''): + """ @return: all machine manufacturers defined in the GLPI database """ + session = create_session() + query = session.query(Manufacturers).select_from(self.manufacturers.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.manufacturers.c.name.like('%'+filt+'%')) + ret = query.group_by(self.manufacturers.c.name).all() + session.close() + return ret + + @DatabaseHelper._session + def getAllSoftwareVendors(self, session, ctx, filt='', limit=20): + """ @return: all software vendors defined in the GPLI database""" + query = session.query(Manufacturers).select_from(self.manufacturers + .join(self.software)) + query = query.filter(Software.is_deleted == 0) + query = query.filter(Software.is_template == 0) + if filt != '': + query = query.filter(Manufacturers.name.like('%' + filt + '%')) + query = query.group_by(Manufacturers.name) + ret = query.order_by(asc(Manufacturers.name)).limit(limit) + return ret + + @DatabaseHelper._session + def getAllSoftwareVersions(self, session, ctx, software=None, filt=''): + """ @return: all software versions defined in the GPLI database""" + query = session.query(SoftwareVersion) + query = query.select_from(self.softwareversions + .join(self.software)) + if software is not None: + query = query.filter(Software.name.like(software)) + if filt != '': + query = query.filter(SoftwareVersion.name.like('%' + filt + '%')) + ret = query.group_by(SoftwareVersion.name).all() + return ret + + def getAllStates(self, ctx, filt = ''): + """ @return: all machine models defined in the GLPI database """ + session = create_session() + query = session.query(State).select_from(self.state.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.state.c.name.like('%'+filt+'%')) + ret = query.group_by(self.state.c.name).all() + session.close() + return ret + + def getAllTypes(self, ctx, filt = ''): + """ @return: all machine types defined in the GLPI database """ + session = create_session() + query = session.query(self.klass['glpi_computertypes']).select_from(self.glpi_computertypes.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.glpi_computertypes.c.name.like('%'+filt+'%')) + ret = query.group_by(self.glpi_computertypes.c.name).all() + session.close() + return ret + + def getAllInventoryNumbers(self, ctx, filt = ''): + """ @return: all machine inventory numbers defined in the GLPI database """ + ret = [] + return ret + + def getMachineByModel(self, ctx, filt): + """ @return: all machines that have this model """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.model)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.model.c.name == filt) + ret = query.all() + session.close() + return ret + + @DatabaseHelper._session + def getMachineByType(self, session, ctx, types, count=0): + """ @return: all machines that have this type """ + if isinstance(types, basestring): + types = [types] + + if int(count) == 1: + query = session.query(func.count(Machine.id)).select_from(self.machine.join(self.glpi_computertypes)) + else: + query = session.query(Machine).select_from(self.machine.join(self.glpi_computertypes)) + query = query.filter(Machine.is_deleted == 0).filter(Machine.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + + type_filter = [self.klass['glpi_computertypes'].name.like(type) for type in types] + query = query.filter(or_(*type_filter)) + + if int(count) == 1: + ret = int(query.scalar()) + else: + ret = query.all() + return ret + + def getMachineByInventoryNumber(self, ctx, filt): + """ @return: all machines that have this type """ + session = create_session() + query = session.query(Machine).select_from(self.machine) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.machine.c.otherserial == filt) + ret = query.all() + session.close() + return ret + + def getMachineByManufacturer(self, ctx, filt): + """ @return: all machines that have this manufacturer """ + session = create_session() + query = session.query(Manufacturers).select_from(self.machine.join(self.manufacturers)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.manufacturers.c.name == filt) + ret = query.all() + session.close() + return ret + + def getMachineByState(self, ctx, filt, count=0): + """ @return: all machines that have this state """ + session = create_session() + if int(count) == 1: + query = session.query(func.count(Machine)).select_from(self.machine.join(self.state)) + else: + query = session.query(Machine).select_from(self.machine.join(self.state)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + if '%' in filt: + query = query.filter(self.state.c.name.like(filt)) + else: + query = query.filter(self.state.c.name == filt) + if int(count) == 1: + ret = int(query.scalar()) + else: + ret = query.all() + session.close() + return ret + + def getAllLocations(self, ctx, filt = ''): + """ @return: all hostnames defined in the GLPI database """ + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + session = create_session() + query = session.query(Locations).select_from(self.locations.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + my_parents_ids = self.getEntitiesParentsAsList(ctx.locationsid) + query = self.__filter_on_entity(query, ctx, my_parents_ids) + query = query.filter(or_(self.locations.c.entities_id.in_(ctx.locationsid), and_(self.locations.c.is_recursive == 1, self.locations.c.entities_id.in_(my_parents_ids)))) + if filter != '': + query = query.filter(self.locations.c.completename.like('%'+filt+'%')) + ret = query.group_by(self.locations.c.completename).all() + session.close() + return ret + def getMachineByLocation(self, ctx, filt): + """ @return: all machines that have this contact number """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.locations)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.locations.c.completename == filt) + ret = query.all() + session.close() + return ret + + def getAllOsSps(self, ctx, filt = ''): + """ @return: all hostnames defined in the GLPI database """ + session = create_session() + query = session.query(OsSp).select_from(self.os_sp.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.os_sp.c.name.like('%'+filt+'%')) + ret = query.group_by(self.os_sp.c.name).all() + session.close() + return ret + def getMachineByOsSp(self, ctx, filt): + """ @return: all machines that have this contact number """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.os_sp)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.os_sp.c.name == filt) + ret = query.all() + session.close() + return ret + + def getAllGroups(self, ctx, filt = ''): + """ @return: all hostnames defined in the GLPI database """ + if not hasattr(ctx, 'locationsid'): + complete_ctx(ctx) + session = create_session() + query = session.query(Group).select_from(self.group.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + my_parents_ids = self.getEntitiesParentsAsList(ctx.locationsid) + query = self.__filter_on_entity(query, ctx, my_parents_ids) + query = query.filter(or_(self.group.c.entities_id.in_(ctx.locationsid), and_(self.group.c.is_recursive == 1, self.group.c.entities_id.in_(my_parents_ids)))) + if filter != '': + query = query.filter(self.group.c.name.like('%'+filt+'%')) + ret = query.group_by(self.group.c.name).all() + session.close() + return ret + def getMachineByGroup(self, ctx, filt):# Entity! + """ @return: all machines that have this contact number """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.group)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.group.c.entities_id.in_(ctx.locationsid)) + query = query.filter(self.group.c.name == filt) + ret = query.all() + session.close() + return ret + + def getAllNetworks(self, ctx, filt = ''): + """ @return: all hostnames defined in the GLPI database """ + session = create_session() + query = session.query(Net).select_from(self.net.join(self.machine)) + query = self.__filter_on(query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0)) + query = self.__filter_on_entity(query, ctx) + if filter != '': + query = query.filter(self.net.c.name.like('%'+filt+'%')) + ret = query.group_by(self.net.c.name).all() + session.close() + return ret + def getMachineByNetwork(self, ctx, filt): + """ @return: all machines that have this contact number """ + session = create_session() + query = session.query(Machine).select_from(self.machine.join(self.net)) + query = query.filter(self.machine.c.is_deleted == 0).filter(self.machine.c.is_template == 0) + query = self.__filter_on(query) + query = self.__filter_on_entity(query, ctx) + query = query.filter(self.net.c.name == filt) + ret = query.all() + session.close() + return ret + + def getMachineByMacAddress(self, ctx, filt): + """ @return: all computers that have this mac address """ + session = create_session() + query = session.query(Machine).join(NetworkPorts, and_(Machine.id == NetworkPorts.items_id, NetworkPorts.itemtype == 'Computer')) + query = query.filter(Machine.is_deleted == 0).filter(Machine.is_template == 0) + query = query.filter(NetworkPorts.mac == filt) + query = self.__filter_on(query) + if ctx != 'imaging_module': + query = self.__filter_on_entity(query, ctx) + ret = query.all() + session.close() + return ret + + @DatabaseHelper._session + def getMachineByHostnameAndMacs(self, session, ctx, hostname, macs): + """ + Get machine who match given hostname and at least one of macs + + @param ctx: context + @type ctx: dict + + @param hostname: hostname of wanted machine + @type hostname: str + + @param macs: list of macs + @type macs: list + + @return: UUID of wanted machine or False + @rtype: str or None + """ + query = session.query(Machine).join(NetworkPorts, and_(Machine.id == NetworkPorts.items_id, NetworkPorts.itemtype == 'Computer')) + query = query.filter(Machine.is_deleted == 0).filter(Machine.is_template == 0) + query = query.filter(NetworkPorts.mac.in_(macs)) + query = query.filter(self.machine.c.name == hostname) + query = self.__filter_on(query) + if ctx != 'imaging_module': + query = self.__filter_on_entity(query, ctx) + try: + ret = query.one() + except (MultipleResultsFound, NoResultFound) as e: + self.logger.warn('I can\'t get any UUID for machine %s and macs %s: %s' % (hostname, macs, e)) + return None + return toUUID(ret.id) + + def getComputersOS(self, uuids): + if isinstance(uuids, str): + uuids = [uuids] + session = create_session() + query = session.query(Machine) \ + .add_column(self.os.c.name) \ + .select_from(self.machine.join(self.os)) + query = query.filter(self.machine.c.id.in_([fromUUID(uuid) for uuid in uuids])) + session.close() + res = [] + for machine, OSName in query: + res.append({ + 'uuid': toUUID(machine.id), + 'OSName': OSName, + }) + return res + + def getComputersCountByOS(self, osname): + session = create_session() + query = session.query(func.count(Machine.id)) \ + .select_from(self.machine.join(self.os)) + query = query.filter(self.os.c.name.like('%'+osname+'%')) + count = query.scalar() + session.close() + return count + + def getMachineUUIDByMacAddress(self, mac): + """ + Return a machine's UUID by MAC address. + @param mac: MAC address of machine + @type mac: str + + @return: machine UUID + @rtype: str + """ + ret = self.getMachineByMacAddress('imaging_module', mac) + if type(ret) == list: + if len(ret) != 0: + return str(toUUID(ret[0].id)) + return None + + + ##################### for msc + def getMachinesNetwork(self, uuids): + """ + Get for each machine a list of its networkports + + return { + computer_uuid1: { + 'domain': 'xxx', + 'gateway': 'xxx', + 'ifaddr': 'xxx', + 'ifmac': 'xxx', + 'name': 'xxx', + 'netmask': 'xxx', + 'subnet': 'xxx', + 'uuid': 'xxx', <= UUID of networkport + }, + computer_uuid2: {}, + etc., + } + """ + def getComputerNetwork(machine, domain): + result = [] + for networkport in machine.networkports: + if networkport.networknames is not None: + if networkport.networknames.ipaddresses: + # If there is multiple adresses per interface, we + # create the same number of interfaces + for ipaddress in networkport.networknames.ipaddresses: + d = { + 'uuid': toUUID(networkport.id), + 'domain': domain, + 'ifmac': networkport.mac, + 'name': networkport.name, + 'netmask': '', + 'subnet': '', + 'gateway': '', + 'ifaddr': '', + } + + # IP Address + d['ifaddr'] = ipaddress.name + + # Init old iface dict + z = {} + + for ipnetwork in ipaddress.ipnetworks: + oz = z + + z = d.copy() + z['netmask'] = ipnetwork.netmask + z['gateway'] = ipnetwork.gateway + z['subnet'] = ipnetwork.address + + # Add this (network/ip/interface) to result + # and if its not duplicated + if z != oz: + result.append(z) + if not ipaddress.ipnetworks: + result.append(d) + return result + + session = create_session() + query = self.filterOnUUID(session.query(Machine), uuids) + ret = {} + for machine in query: + uuid = toUUID(machine.id) + domain = '' + if machine.domains is not None: + domain = machine.domains.name + ret[uuid] = getComputerNetwork(machine, domain) + session.close() + return ret + + def getMachineNetwork(self, uuid): + """ + Get a machine network + @see getMachinesNetwork() + """ + return self.getMachinesNetwork(uuid)[uuid] + + def getMachinesMac(self, uuids): + """ + Get several machines mac addresses + """ + session = create_session() + query = self.filterOnUUID(session.query(Machine), uuids) + ret = {} + for machine in query: + cuuid = toUUID(machine.id) + ret[cuuid] = [networkport.mac for networkport in machine.networkports] + return ret + + + def getMachineMac(self, uuid): + """ + Get a machine mac addresses + """ + return self.getMachinesMac(uuid)[uuid] + + def orderIpAdresses(self, uuid, hostname, netiface, empty_macs=False): + ret_ifmac = [] + ret_ifaddr = [] + ret_netmask = [] + ret_domain = [] + ret_networkUuids = [] + idx_good = 0 + failure = [True, True] + for iface in netiface: + if not empty_macs : + if not ('ifmac' in iface or iface['ifmac']): + continue + if 'ifaddr' in iface and iface['ifaddr']: + if iface['gateway'] == None: + ret_ifmac.append(iface['ifmac']) + ret_ifaddr.append(iface['ifaddr']) + ret_netmask.append(iface['netmask']) + ret_networkUuids.append(iface['uuid']) + if 'domain' in iface: + ret_domain.append(iface['domain']) + else: + ret_domain.append('') + else: + if same_network(iface['ifaddr'], iface['gateway'], iface['netmask']): + idx_good += 1 + ret_ifmac.insert(0, iface['ifmac']) + ret_ifaddr.insert(0, iface['ifaddr']) + ret_netmask.insert(0, iface['netmask']) + ret_networkUuids.insert(0, iface['uuid']) + if 'domain' in iface: + ret_domain.insert(0, iface['domain']) + else: + ret_domain.insert(0, '') + failure[0] = False + else: + ret_ifmac.insert(idx_good, iface['ifmac']) + ret_ifaddr.insert(idx_good, iface['ifaddr']) + ret_netmask.insert(idx_good, iface['netmask']) + ret_networkUuids.insert(idx_good, iface['uuid']) + if 'domain' in iface: + ret_domain.insert(idx_good, iface['domain']) + else: + ret_domain.insert(idx_good, '') + failure[1] = False + + return (ret_ifmac, ret_ifaddr, ret_netmask, ret_domain, ret_networkUuids) + + def dict2obj(d): + """ + Get a dictionnary and return an object + """ + from collections import namedtuple + o = namedtuple('dict2obj', ' '.join(d.keys())) + return o(**d) + + def getMachineIp(self, uuid): + """ + Get a machine ip addresses + """ + machine_network = self.getMachineNetwork(uuid) + ret_gw = [] + ret_nogw = [] + for m in machine_network: + m = self.dict2obj(m) + if same_network(m.ifaddr, m.gateway, m.netmask): + ret_gw.append(m.ifaddr) + else: + ret_nogw.append(m.ifaddr) + ret_gw = unique(ret_gw) + ret_gw.extend(unique(ret_nogw)) + + return ret_gw + + def getMachineListByState(self, ctx, groupName): + """ + """ + + # Read config from ini file + orange = self.config.orange + red = self.config.red + + complete_ctx(ctx) + filt = {'ctxlocation': ctx.locations} + + session = create_session() + now = datetime.datetime.now() + orange = now - datetime.timedelta(orange) + red = now - datetime.timedelta(red) + + date_mod = self.machine.c.date_mod + if self.fusionagents is not None: + date_mod = FusionAgents.last_contact + + query = self.__getRestrictedComputersListQuery(ctx, filt, session) + + # Limit list according to max_elements_for_static_list param in dyngroup.ini + limit = DGConfig().maxElementsForStaticList + + if groupName == "green": + result = query.filter(date_mod > orange).limit(limit) + elif groupName == "orange": + result = query.filter(and_(date_mod < orange, date_mod > red)).limit(limit) + elif groupName == "red": + result = query.filter(date_mod < red).limit(limit) + + ret = {} + for machine in result.all(): + if machine.name is not None: + ret[toUUID(machine.id) + '##' + machine.name] = {"hostname": machine.name, "uuid": toUUID(machine.id)} + + session.close() + return ret + + def getMachineNumberByState(self, ctx): + """ + return number of machines sorted by state + default states are: + * green: less than 10 days + * orange: more than 10 days and less than 35 days + * red: more than 35 days + + @return: dictionnary with state as key, number as value + @rtype: dict + """ + + # Read config from ini file + orange = self.config.orange + red = self.config.red + + complete_ctx(ctx) + filt = {'ctxlocation': ctx.locations} + + ret = { + "days": { + "orange": orange, + "red": red, + }, + "count": self.getRestrictedComputersListStatesLen(ctx, filt, orange, red), + } + + return ret + + def getAntivirusStatus(self, ctx): + """ + Return number of machine by antivirus status: + * green: Antivirus OK + * orange: Antivirus not running or not up-to-date + * red: No antivirus or unknown status + """ + session = create_session() + + __computersListQ = self.__getRestrictedComputersListQuery + + complete_ctx(ctx) + filt = { + 'ctxlocation': ctx.locations + } + + ret = { + 'green': int(__computersListQ(ctx, dict(filt, **{'antivirus': 'green'}), session, count=True)), + 'orange': int(__computersListQ(ctx, dict(filt, **{'antivirus': 'orange'}), session, count=True)), + 'red': int(__computersListQ(ctx, dict(filt, **{'antivirus': 'red'}), session, count=True)), + } + + session.close() + + return ret + + def getMachineIdsNotInAntivirusRed(self, ctx): + """ + return ids list of machines who are not in antivirus red status + """ + session = create_session() + __computersListQ = self.__getRestrictedComputersListQuery + + complete_ctx(ctx) + + filt = { + 'ctxlocation': ctx.locations + } + + query1 = __computersListQ(ctx, dict(filt, **{'antivirus': 'green'}), session) + query2 = __computersListQ(ctx, dict(filt, **{'antivirus': 'orange'}), session) + + session.close() + + return [machine.id for machine in query1.all()] + [machine.id for machine in query2.all()] + + def getMachineListByAntivirusState(self, ctx, groupName): + session = create_session() + + __computersListQ = self.__getRestrictedComputersListQuery + + complete_ctx(ctx) + filt = { + 'ctxlocation': ctx.locations + } + query = __computersListQ(ctx, dict(filt, **{'antivirus': groupName}), session) + + # Limit list according to max_elements_for_static_list param in dyngroup.ini + limit = DGConfig().maxElementsForStaticList + + query = query.limit(limit) + + ret = {} + for machine in query.all(): + if machine.name is not None: + ret[toUUID(machine.id) + '##' + machine.name] = {"hostname": machine.name, "uuid": toUUID(machine.id)} + + session.close() + return ret + + def getIpFromMac(self, mac): + """ + Get an ip address when a mac address is given + """ + session = create_session() + query = session.query(NetworkPorts).filter(NetworkPorts.mac == mac) + # Get first IP address found + ret = query.first().networknames.ipaddresses[0] + session.close() + return ret + + def getIpFromMachine(self, uuid): + """ + Same as getMachineIp + TODO: check where it is used + """ + return self.getMachineIp(uuid) + + def getMachineDomain(self, uuid): + """ + Get a machine domain name + """ + session = create_session() + machine = self.filterOnUUID(session.query(Machine), uuid).first() + domain = '' + if machine.domains is not None: + domain = machine.domains.name + return domain + + def isComputerNameAvailable(self, ctx, locationUUID, name): + raise Exception("need to be implemented when we would be able to add computers") + + def _get_webservices_client(self): + client = XMLRPCClient(baseurl=self.config.webservices['glpi_base_url']) + client.connect( + self.config.webservices['glpi_username'], + self.config.webservices['glpi_password'] + ) + + return client + + def purgeMachine(self, id): + to_delete = { + 'Computer': { + 'id': {'id': str(id)} + } + } + + self.logger.debug('machine ID %s will be purged from GLPI' % (id)) + webservices_client = self._get_webservices_client() + result = webservices_client.deleteObjects(fields=to_delete) + if isinstance(result, dict): + delete_result = False + try: + delete_result = result['Computer'][0] + except KeyError, e: + self.logger.error('Failed to delete machine ID %s: %s' % (id, e)) + return delete_result + + if isinstance(result, list) and not result[0]: + self.logger.error('Failed to delete machine ID %s: %s' % (id, result[1])) + + return False + + def delMachine(self, uuid): + """ + Deleting a machine in GLPI (only the flag 'is_deleted' updated) + + @param uuid: UUID of machine + @type uuid: str + + @return: True if the machine successfully deleted + @rtype: bool + """ + session = create_session() + id = fromUUID(uuid) + + machine = session.query(Machine).filter(self.machine.c.id == id).first() + + if machine: + webservice_ok = True + try: + self._get_webservices_client() + except ProtocolError, e: + webservice_ok = False + except Exception, e: + webservice_ok = False + + if self.config.webservices['purge_machine']: + if webservice_ok: + return self.purgeMachine(machine.id) + else: + self.logger.warn("Unable to purge machine (uuid=%s) because GLPI webservice is disabled" % uuid) + + connection = self.getDbConnection() + trans = connection.begin() + try: + machine.is_deleted = True + except Exception, e : + self.logger.warn("Unable to delete machine (uuid=%s): %s" % (uuid, str(e))) + session.flush() + session.close() + trans.rollback() + + return False + + session.flush() + session.close() + trans.commit() + self.logger.debug("Machine (uuid=%s) successfully deleted" % uuid) + + return True + + else: + return False + + @DatabaseHelper._session + def addUser(self, session, username, password, entity_rights=None): + # User settings + user = User() + user.name = username + user.password = hashlib.sha1(password).hexdigest() + user.firstname = '' + user.realname = '' + user.auths_id = 0 + user.is_deleted = 0 + user.is_active = 1 + session.add(user) + session.commit() + session.flush() + + # Setting entity rights + if entity_rights is not None: + self.setLocationsForUser(username, entity_rights) + return True + + @DatabaseHelper._session + def setUserPassword(self, session, username, password): + try: + user = session.query(User).filter_by(name=username).one() + except NoResultFound: + self.addUser(username, password) + return + user.password = hashlib.sha1(password).hexdigest() + session.commit() + session.flush() + + def removeUser(self, session, username): + # Too complicated, affects many tables + return True + + @DatabaseHelper._session + def addEntity(self, session, entity_name, parent_id, comment): + entity = Entities() + entity.id = session.query(func.max(Entities.id)).scalar() + 1 + entity.entities_id = parent_id #parent + entity.name = entity_name + entity.comment = comment + entity.level = parent_id + # Get parent entity object + parent_entity = session.query(Entities).filter_by(id=parent_id,).one() + completename = parent_entity.completename + ' > ' + entity_name + entity.completename = completename + + session.add(entity) + session.commit() + session.flush() + return True + + @DatabaseHelper._session + def editEntity(self, session, id, entity_name, parent_id, comment): + entity = session.query(Entities).filter_by(id=id).one() + entity.entities_id = parent_id #parent + entity.name = entity_name + entity.comment = comment + entity.level = parent_id + + entity = self.updateEntityCompleteName(entity) + + session.commit() + session.flush() + return True + + @DatabaseHelper._session + def updateEntityCompleteName(self, session, entity): + # Get parent entity object + parent_entity = session.query(Entities).filter_by(id=entity.entities_id).one() + completename = parent_entity.completename + ' > ' + entity.name + entity.completename = completename + + # Update all children complete names + children = session.query(Entities).filter_by(entities_id=entity.id).all() + + for item in children: + self.updateEntityCompleteName(item) + + return entity + + def removeEntity(self, entity_id): + # Too complicated, affects many tables + pass + + @DatabaseHelper._listinfo + @DatabaseHelper._session + def getAllEntitiesPowered(self, session, params): + return session.query(Entities).order_by(Entities.completename) + + @DatabaseHelper._session + def addLocation(self, session, name, parent_id, comment): + location = Locations() + location.entities_id = 0 #entity is root + location.name = name + location.locations_id = parent_id + + location.comment = comment + location.level = parent_id + location.building = '' + location.room = '' + + # Get parent location object + parent_location = session.query(Locations).filter_by(id=parent_id,).one() + completename = parent_location.completename + ' > ' + name + location.completename = completename + + session.add(location) + session.commit() + session.flush() + return True + + @DatabaseHelper._session + def editLocation(self, session, id, name, parent_id, comment): + location = session.query(Locations).filter_by(id=id).one() + location.locations_id = parent_id #parent + location.name = name + location.comment = comment + location.level = parent_id + + location = self.updateLocationCompleteName(location) + + session.commit() + session.flush() + return True + + @DatabaseHelper._session + def updateLocationCompleteName(self, session, location): + # Get parent location object + parent_location = session.query(Locations).filter_by(id=location.locations_id).one() + completename = parent_location.completename + ' > ' + location.name + location.completename = completename + + # Update all children complete names + children = session.query(Locations).filter_by(locations_id=location.id).all() + + for item in children: + self.updateLocationCompleteName(item) + + return location + + @DatabaseHelper._listinfo + @DatabaseHelper._session + def getAllLocationsPowered(self, session, params): + return session.query(Locations).order_by(Locations.completename) + + @DatabaseHelper._listinfo + @DatabaseHelper._session + def getAllEntityRules(self, session, params): + # TODO: Filter this by user context entities + return session.query(self.rules).filter_by(sub_type='PluginFusioninventoryInventoryRuleEntity')\ + .filter(self.rules.c.name != 'Root')\ + .order_by(self.rules.c.ranking) + + @DatabaseHelper._session + def addEntityRule(self, session, rule_data): + rule = Rule() + # root entity (this means that rule is appliable on root entity and all subentities) + rule.entities_id = 0 + rule.sub_type = 'PluginFusioninventoryInventoryRuleEntity' + # Get the last ranking for this class +1 + rank = session.query(func.max(self.rules.c.ranking))\ + .filter(self.rules.c.sub_type=='PluginFusioninventoryInventoryRuleEntity')\ + .filter(self.rules.c.name != 'Root')\ + .scalar() + if rank is None: + rank = 0 + rule.ranking = rank + 1 + rule.name = rule_data['name'] + rule.description = rule_data['description'] + rule.match = rule_data['aggregator'] + if rule_data['active'] == 'on': + rule.is_active = 1 + else: + rule.is_active = 0 + + session.add(rule) + session.commit() + session.flush() + + # Make sure "Root" entity rule ranking is very high + session.query(Rule).filter_by(sub_type='PluginFusioninventoryInventoryRuleEntity',\ + name='Root').update({'ranking': rule.ranking+1}, synchronize_session=False) + + # Adding rule criteria + + for i in xrange(len(rule_data['criteria'])): + + cr = RuleCriterion() + cr.rules_id = rule.id + cr.criteria = rule_data['criteria'][i] + cr.condition = rule_data['operators'][i] + cr.pattern = rule_data['patterns'][i] + session.add(cr) + session.commit() + + # Adding rule actions + + # If a target entity is specified, add it + if rule_data['target_entity'] != '-1': + action = RuleAction() + action.rules_id = rule.id + action.action_type = 'assign' + action.field = 'entities_id' + action.value = rule_data['target_entity'] + session.add(action) + + # If a target location is specified, add it + if rule_data['target_location'] != '-1': + action = RuleAction() + action.rules_id = rule.id + action.action_type = 'assign' + action.field = 'locations_id' + action.value = rule_data['target_location'] + session.add(action) + + session.commit() + return True + + + # it s shit do it from dict directly + #{'ranking' : 2, 'sub_type': 'PluginFusioninventoryInventoryRuleEntity', + # date_mod: NOW(), + + # criteria + # {'criteria': 'ip', // 'name' => hostanme, 'domain', 'serial', 'subnet', 'tag', + #'condition': 0=is, 1=is_not, 2=contains, 3=doesnt contain, 4=start with, 5= finishes by + # 6=regex_check, 7=not_regex, 8=exists, 9=doesnt eixts + # 'pattern' : 192.168.44., + # 'rules_id' : rule_id + + # rule actions + # { 'rules_id', rid + # action_type = assign, + # field = entities_id + # value = ENTITY_ID + # + #action_type=regex_result,field=_affect_entity_by_tag, value=? + #action_type=assign, field=locations_id, value=id + + @DatabaseHelper._session + def moveEntityRuleUp(self, session, id): + + rule = session.query(Rule).filter_by(id=id).one() + # get previous rule + previous = session.query(Rule).filter(Rule.rankingrule.ranking)\ + .filter(Rule.name != 'Root')\ + .filter(Rule.sub_type=='PluginFusioninventoryInventoryRuleEntity')\ + .order_by(Rule.ranking.asc()).first() + if next_: + next_ranking = next_.ranking + rule_ranking = rule.ranking + next_.ranking = rule_ranking + session.commit() + rule.ranking = next_ranking + session.commit() + + return True + + + @DatabaseHelper._session + def editEntityRule(self, session, id, rule_data): + + rule = session.query(Rule).filter_by(id=id).one() + # Delete associated criteria and actions + session.query(RuleCriterion).filter_by(rules_id=id).delete() + session.query(RuleAction).filter_by(rules_id=id).delete() + + rule.name = rule_data['name'] + rule.description = rule_data['description'] + rule.match = rule_data['aggregator'] + if rule_data['active'] == 'on': + rule.is_active = 1 + else: + rule.is_active = 0 + + session.commit() + session.flush() + + # Adding rule criteria + + for i in xrange(len(rule_data['criteria'])): + + cr = RuleCriterion() + cr.rules_id = rule.id + cr.criteria = rule_data['criteria'][i] + cr.condition = rule_data['operators'][i] + cr.pattern = rule_data['patterns'][i] + session.add(cr) + session.commit() + + # Adding rule actions + + # If a target entity is specified, add it + if rule_data['target_entity'] != '-1': + action = RuleAction() + action.rules_id = rule.id + action.action_type = 'assign' + action.field = 'entities_id' + action.value = rule_data['target_entity'] + session.add(action) + + # If a target location is specified, add it + if rule_data['target_location'] != '-1': + action = RuleAction() + action.rules_id = rule.id + action.action_type = 'assign' + action.field = 'locations_id' + action.value = rule_data['target_location'] + session.add(action) + + session.commit() + return True + + @DatabaseHelper._session + def getEntityRule(self, session, id): + + + rule = session.query(Rule).filter_by(id=id).one() + criteria = session.query(RuleCriterion).filter_by(rules_id=id).all() + actions = session.query(RuleAction).filter_by(rules_id=id).all() + + result = {} + result['active'] = rule.is_active + result['name'] = rule.name + result['description'] = rule.description + result['aggregator'] = rule.match + + result['criteria'] = [] + result['operators'] = [] + result['patterns'] = [] + + for cr in criteria: + result['criteria'].append(cr.criteria) + result['operators'].append(cr.condition) + result['patterns'].append(cr.pattern) + + # By default, don't assign entity nor location + result['target_entity'] = -1 + result['target_location'] = -1 + + for action in actions: + if action.field == 'entities_id' and action.action_type == 'assign': + result['target_entity'] = action.value + if action.field == 'locations_id' and action.action_type == 'assign': + result['target_entity'] = action.value + + return result + + @DatabaseHelper._session + def deleteEntityRule(self, session, id): + + # Delete rule + session.query(Rule).filter_by(id=id).delete() + # Delete associated criteria and actions + session.query(RuleCriterion).filter_by(rules_id=id).delete() + session.query(RuleAction).filter_by(rules_id=id).delete() + return True + + def moveComputerToEntity(self, uuid, entity_id): + pass + #UPDATE `glpi_computers` + #SET `entities_id` = '5' WHERE `id` ='3' + + @DatabaseHelper._session + def getLocationsForUser(self, session, username): + try: + user_id = session.query(User).filter_by(name=username).one().id + except NoResultFound: + return [] + entities = [] + for profile in session.query(UserProfile).filter_by(users_id = user_id): + entities += [{ + 'entity_id' : profile.entities_id, + 'profile': profile.profiles_id, + 'is_recursive' : profile.is_recursive, + 'is_dynamic' : profile.is_dynamic + }] + return entities + + @DatabaseHelper._session + def setLocationsForUser(self, session, username, profiles): + + user_id = session.query(User).filter_by(name=username).one().id + # Delete all user entity profiles + session.query(UserProfile).filter_by(users_id = user_id).delete() + + for attr in profiles: + p = UserProfile() + p.users_id = user_id + p.profiles_id = attr['profile'] + p.entities_id = attr['entity_id'] + p.is_recursive = attr['is_recursive'] + p.is_dynamic = attr['is_dynamic'] + session.add(p) + session.commit() + + session.flush() + return True + +# Class for SQLalchemy mapping +class Machine(object): + __tablename__ = 'glpi_computers' + + def getUUID(self): + return toUUID(self.id) + def toH(self): + return { 'hostname':self.name, 'uuid':toUUID(self.id) } + def to_a(self): + owner_login, owner_firstname, owner_realname = Glpi0855().getMachineOwner(self) + return [ + ['name',self.name], + ['comments',self.comment], + ['serial',self.serial], + ['otherserial',self.otherserial], + ['contact',self.contact], + ['contact_num',self.contact_num], + ['owner', owner_login], + ['owner_firstname', owner_firstname], + ['owner_realname', owner_realname], + # ['tech_num',self.tech_num], + ['os',self.operatingsystems_id], + ['os_version',self.operatingsystemversions_id], + ['os_sp',self.operatingsystemservicepacks_id], + ['os_license_number',self.os_license_number], + ['os_license_id',self.os_licenseid], + ['location',self.locations_id], + ['domain',self.domains_id], + ['network',self.networks_id], + ['model',self.computermodels_id], + ['type',self.computertypes_id], + ['entity',self.entities_id], + ['uuid',Glpi0855().getMachineUUID(self)] + ] + +class Entities(object): + def toH(self): + return { + 'uuid':toUUID(self.id), + 'name':self.name, + 'completename':self.completename, + 'comments':self.comment, + 'level':self.level + } + +class State(object): + pass + +class DiskFs(object): + pass + +class FusionAntivirus(object): + pass + +class FusionLocks(object): + pass + +class FusionAgents(object): + to_be_exported = ['last_contact'] + +class Disk(object): + pass + +class Suppliers(object): + pass + +class Infocoms(object): + pass + +class Processor(object): + pass + +class ComputerProcessor(object): + pass + +class Memory(object): + pass + +class MemoryType(object): + pass + +class ComputerMemory(object): + pass + +class Logs(object): + pass + +class User(object): + pass + +class Profile(object): + pass + +class UserProfile(object): + pass + +class NetworkPorts(object): + def toH(self): + return { + 'uuid':toUUID(self.id), + 'name': self.name, + 'ifaddr': self.ip, + 'ifmac': self.mac, + 'netmask': noNone(self.netmask), + 'gateway': self.gateway, + 'subnet': self.subnet + } + +class OS(object): + pass + +class ComputerDevice(object): + pass + +class Domain(object): + pass + +class Manufacturers(object): + pass + +class Software(object): + pass + +class InstSoftware(object): + pass + +class Licenses(object): + pass + +class SoftwareVersion(object): + pass + +class Group(object): + pass + +class OsSp(object): + pass + +class Model(object): + pass + +class Locations(object): + pass + +class Net(object): + pass + +class NetworkInterfaces(object): + pass + +class IPAddresses(object): + pass + +class IPNetworks(object): + pass + +class NetworkNames(object): + pass + +class IPAddresses_IPNetworks(object): + pass + +class Rule(DbTOA): + pass + +class RuleCriterion(DbTOA): + pass + +class RuleAction(DbTOA): + pass diff --git a/pulse2/services/mmc/plugins/imaging/functions.py b/pulse2/services/mmc/plugins/imaging/functions.py index 80a6f7366..54c47393c 100644 --- a/pulse2/services/mmc/plugins/imaging/functions.py +++ b/pulse2/services/mmc/plugins/imaging/functions.py @@ -25,7 +25,7 @@ Class to manage imaging mmc-agent api imaging plugin """ - +import time import logging from twisted.internet import defer from sets import Set as set @@ -43,11 +43,12 @@ from pulse2.database.imaging.types import P2IT, P2ISS, P2IM, P2ERR from pulse2.apis.clients.imaging import ImagingApi import pulse2.utils - +import threading from os import path, makedirs class ImagingRpcProxy(RpcProxyI): - + checkThread = {} + checkThreadData={} def getGeneratedMenu(self, mac): # uuid logger = logging.getLogger() @@ -55,7 +56,9 @@ def getGeneratedMenu(self, mac): uuid = 'UUID' + str(db_computer.id) menu = generateMenus(logger, ImagingDatabase(), [uuid], unique=True) return xmlrpcCleanup(menu) - + + def check_process(self, process): + return xmlrpcCleanup(pulse2.utils.check_process(process)) """ XML/RPC Bindings """ ################################################### web def @@ -409,6 +412,180 @@ def moveItemDownInMenu4Location(self, loc_id, mi_uuid): db.setLocationSynchroState(loc_id, P2ISS.TODO) return db.moveItemDownInMenu4Location(loc_id, mi_uuid) + def imagingServermenuMulticast(self, objmenu): + try: + if ImagingRpcProxy.checkThread[objmenu['location']]==False: + ImagingRpcProxy.checkThread[objmenu['location']] = True + except KeyError: + ImagingRpcProxy.checkThread[objmenu['location']] = True + finally: + a = threading.Thread(None, self.monitorsUDPSender, None, (objmenu,)) + a.start() + location=objmenu['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.imagingServermenuMulticast(objmenu) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + ## Imaging server configuration + def check_process_multicast(self, process): + # controle execution process multicast + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.check_process_multicast(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + def check_process_multicast_finish(self, process): + # controle execution process multicast finish + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.check_process_multicast_finish(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + def muticast_script_exist(self,process): + # controle existance multicast script + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.muticast_script_exist(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + def clear_script_multicast(self, process): + #check if the script is installed multicast.sh + try: + if ImagingRpcProxy.checkThread[process['location']]==True: + ImagingRpcProxy.checkThread[process['location']] = False + except KeyError: + ImagingRpcProxy.checkThread[process['location']] = False + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.clear_script_multicast(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + def start_process_multicast(self,process): + # Multicast start + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.start_process_multicast(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + + def monitorsUDPSender(self,objmenu): + temp=10; + while(ImagingRpcProxy.checkThread[objmenu['location']] == True): + time.sleep(temp) + logging.getLogger().debug("monitorsUDPSender") + result=self.checkDeploymentUDPSender(objmenu) + try: + logging.getLogger().debug("[checkThreadData] %s"%ImagingRpcProxy.checkThreadData) + logging.getLogger().debug("[tranfert] %s"%ImagingRpcProxy.checkThreadData[objmenu['location']]['tranfert']) + if ImagingRpcProxy.checkThreadData[objmenu['location']]['tranfert'] == True: + logging.getLogger().debug("[tranfert] %s"%ImagingRpcProxy.checkThreadData[objmenu['location']]['tranfert']) + ImagingRpcProxy.checkThreadData[objmenu['location']]['tranfert'] = False + ImagingRpcProxy.checkThread[objmenu['location']] = False + logging.getLogger().debug("REGENERATE menu group %s [%s]"%(objmenu['description'],objmenu['group'])) + self.synchroProfile(objmenu['group']) + return + except KeyError: + logging.getLogger().debug("[initialisation checkThreadData]") + ImagingRpcProxy.checkThreadData[objmenu['location']]={} + ImagingRpcProxy.checkThreadData[objmenu['location']]['tranfert'] = False + else: + logging.getLogger().debug("REGENERATE menu group %s [%s]"%(objmenu['description'],objmenu['group'])) + self.synchroProfile(objmenu['group']) + + def checkDeploymentUDPSender(self,process): + """ + check whether multicast transfer is in progress + """ + resultat = False + logger = logging.getLogger() + logging.getLogger().debug("checkDeploymentUDPSender %s"%process) + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + i = ImagingApi(imaging_server.encode('utf8')) + if i == None: + logger.error("couldn't initialize the ImagingApi to %s"%( my_is.url)) + return [False, "couldn't initialize the ImagingApi to %s"%( my_is.url)] + + def treatResult(results): + if results: + ImagingRpcProxy.checkThreadData[process['location']]=results + resultat=results + return [resultat] + else: + ImagingRpcProxy.checkThreadData={} + return [] + + d = i.checkDeploymentUDPSender(process) + d.addCallback(treatResult) + return d + + def stop_process_multicast(self,process): + # Multicast stop + try: + if ImagingRpcProxy.checkThread[process['location']]==True: + ImagingRpcProxy.checkThread[process['location']] = False + except KeyError: + ImagingRpcProxy.checkThread[process['location']] = False + location=process['location'] + db = ImagingDatabase() + my_is = db.getImagingServerByUUID(location) + imaging_server = my_is.url + i = ImagingApi(imaging_server.encode('utf8')) + if i != None: + deferred = i.stop_process_multicast(process) + deferred.addCallback(lambda x: x) + else: + deferred = [] + return deferred + ###### IMAGES def imagingServerISOCreate(self, image_uuid, size, title): """ @@ -2200,9 +2377,39 @@ def sendResult(results, pid = pid, db = db): defer_list = defer.DeferredList(defer_list) defer_list.addCallback(sendResult) return defer_list - return [True] + def Windows_Answer_list_File(self,start=0,end=-1): + """ + returns a list of names (with extension, without full path) of all files + """ + filexml="/var/lib/pulse2/imaging/postinst/sysprep/" + if not path.exists(filexml): + makedirs(filexml, 0722) + files = [] + osfile = [] + for name in listdir(filexml): + absolufile = path.join(filexml, name) + if name.endswith('.xml') and path.isfile(absolufile): + files.append(name) + fichier = open(absolufile,"r") + for ligne in fichier: + if ligne.startswith("OS"): + print ligne + osfile.append(ligne) + break; + else: + osfile.append("os missing") + fichier.close() + # create object reponse + result = {} + result['count'] = len(files) + if end == -1: + end = result['count'] + result['file'] = files[start:end] + result['os'] = osfile[start:end] + return result + def Windows_Answer_File_Generator(self, xmlWAFG, title): filexml="/var/lib/pulse2/imaging/postinst/sysprep/" if not path.exists(filexml): @@ -3092,11 +3299,14 @@ def synchroTargets(ctx, uuids, target_type, macs = {}, wol = False): # initialize stuff logger = logging.getLogger() + ListImagingServerAssociated=[] db = ImagingDatabase() # store the fact that we are attempting a sync db.changeTargetsSynchroState(uuids, target_type, P2ISS.RUNNING) - + dfdf = db.getListImagingServerAssociated() + for t in dfdf: + ListImagingServerAssociated.append(t.url) # Load up l_uuids with the required info (computer within profile OR given computers) if target_type == P2IT.PROFILE: pid = uuids[0] @@ -3204,12 +3414,24 @@ def treatRegister(results, uuids = to_register.keys(), logger = logger, url = ur distinct_loc = xmlrpcCleanup(distinct_loc) if len(defer_list) == 0: - return synchroTargetsSecondPart(ctx, distinct_loc, target_type, pid, macs = macs) + distinct_locs = distinct_loc + keyvaleur = distinct_loc.keys() + for tt in ListImagingServerAssociated: + for z in keyvaleur: + distinct_loc[z][0]=tt + synchroTargetsSecondPart(ctx, distinct_loc, target_type, pid, macs = macs) + return synchroTargetsSecondPart(ctx, distinct_locs, target_type, pid, macs = macs) else: def sendResult(results, distinct_loc = distinct_loc, target_type = target_type, pid = pid, db = db): for result, uuids in results: db.delProfileMenuTarget(uuids) - return synchroTargetsSecondPart(ctx, distinct_loc, target_type, pid, macs = macs) + distinct_locs = distinct_loc + keyvaleur = distinct_loc.keys() + for tt in ListImagingServerAssociated: + for z in keyvaleur: + distinct_loc[z][0]=tt + synchroTargetsSecondPart(ctx, distinct_loc, target_type, pid, macs = macs) + return synchroTargetsSecondPart(ctx, distinct_locs, target_type, pid, macs = macs) defer_list = defer.DeferredList(defer_list) defer_list.addCallback(sendResult) return defer_list diff --git a/pulse2/services/pulse2/apis/clients/imaging.py b/pulse2/services/pulse2/apis/clients/imaging.py index 1c9a03bc5..8bfa4e19f 100644 --- a/pulse2/services/pulse2/apis/clients/imaging.py +++ b/pulse2/services/pulse2/apis/clients/imaging.py @@ -350,6 +350,56 @@ def imagingServerISOCreate(self, image_uuid, size, title): d.addErrback(self.onErrorRaise, "Imaging:imagingServerISOCreate", image_uuid, size, title) return d + def imagingServermenuMulticast(self, objmenu): + """ + create bootmenu multicast from the imaging server + """ + d = self.callRemote("imagingServermenuMulticast", objmenu) + d.addErrback(self.onErrorRaise, "Imaging:imagingServermenuMulticast", objmenu) + return d + + def check_process_multicast(self,objprocess): + # controle execution process multicast + d = self.callRemote("check_process_multicast", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:check_process_multicast", objprocess) + return d + + def start_process_multicast(self, objprocess): + # controle execution process multicast + d = self.callRemote("start_process_multicast", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:start_process_multicast", objprocess) + return d + + def checkDeploymentUDPSender(self, objprocess): + # controle execution process multicast + d = self.callRemote("checkDeploymentUDPSender", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:checkDeploymentUDPSender", objprocess) + return d + + def muticast_script_exist(self, objprocess): + # controle execution process multicast + d = self.callRemote("muticast_script_exist", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:muticast_script_exist", objprocess) + return d + + def clear_script_multicast(self, objprocess): + # controle execution process multicast + d = self.callRemote("clear_script_multicast", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:clear_script_multicast", objprocess) + return d + + def stop_process_multicast(self, objprocess): + # controle execution process multicast + d = self.callRemote("stop_process_multicast", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:stop_process_multicast", objprocess) + return d + + def check_process_multicast_finish(self, objprocess): + # controle execution process multicast + d = self.callRemote("check_process_multicast_finish", objprocess) + d.addErrback(self.onErrorRaise, "Imaging:check_process_multicast_finish", objprocess) + return d + class ImagingApi(Imaging): # need to get a PackageApiManager, it will manage a PackageApi for each mirror # defined in the conf file. diff --git a/pulse2/services/pulse2/database/imaging/__init__.py b/pulse2/services/pulse2/database/imaging/__init__.py index 4a3de8d2c..3fef3f2e4 100644 --- a/pulse2/services/pulse2/database/imaging/__init__.py +++ b/pulse2/services/pulse2/database/imaging/__init__.py @@ -3152,6 +3152,17 @@ def unlinkImagingServerToEntity(self, is_uuid): session.close() return True + def getListImagingServerAssociated(self): + """ + method return list imaging server associated + @return: @return: list of imaging server associated + @rtype: list + """ + session = create_session() + q = session.query(ImagingServer).filter(self.imaging_server.c.associated == 1) + q = q.all() + session.close() + return q def __getLinkedImagingServerForEntity(self, session, loc_id): """ @@ -3529,8 +3540,6 @@ def setLocationPXEParams(self, uuid, params): session.close() return False - - def setLocationSynchroState(self, uuid, state): self.logger.debug(">>> setLocationSynchroState %s %s"%(uuid, str(state))) session = create_session() @@ -4168,9 +4177,15 @@ def addPostInstallScript(self, loc_id, params): session.flush() session.close() return True - + + def getLocationImagingServerByServerUUID(self,imaging_server_uuid ): + session = create_session() + ims = session.query(ImagingServer).filter(self.imaging_server.c.packageserver_uuid == imaging_server_uuid).first() + LocationServer = ims.fk_entity + session.close() + return LocationServer + # Computer basic inventory stuff - def injectInventory(self, imaging_server_uuid, computer_uuid, inventory): """ Inject a computer inventory into the dabatase. @@ -4207,6 +4222,9 @@ def injectInventory(self, imaging_server_uuid, computer_uuid, inventory): cp.start = int(part['start']) cd.partitions.append(cp) target.disks.append(cd) + locationServerImaging = self.getLocationImagingServerByServerUUID(imaging_server_uuid) + target.fk_entity = locationServerImaging + self.logger.debug("Attribution location %s for computer %s"%(target.fk_entity,target.name )) session.add(target) session.commit() except InvalidRequestError, e: diff --git a/pulse2/services/pulse2/database/inventory/__init__.py b/pulse2/services/pulse2/database/inventory/__init__.py index d8e4b6a4b..3d67adb1f 100644 --- a/pulse2/services/pulse2/database/inventory/__init__.py +++ b/pulse2/services/pulse2/database/inventory/__init__.py @@ -40,7 +40,9 @@ Integer, ForeignKey, or_, desc, func, not_, distinct from sqlalchemy.orm import create_session, mapper import sqlalchemy.databases -from lxml import etree +from lxml import etree +# standard modules +import time import datetime import re import logging @@ -269,9 +271,13 @@ def __machinesOnlyQuery(self, ctx, pattern = None, session = None, count = False if set(['macAddress','ipHostNumber','subnetMask']) & requested_cols: join_query = join_query.outerjoin(self.table['hasNetwork'], self.table['hasNetwork'].c.machine == Machine.id).outerjoin(self.table['Network'], self.table['Network'].c.id == self.table['hasNetwork'].c.network) if set(['os','user','type','domain','fullname']) & requested_cols: - join_query = join_query.outerjoin(self.table['hasHardware'], self.table['hasHardware'].c.machine == Machine.id).outerjoin(self.table['Hardware'], self.table['Hardware'].c.id == self.table['hasHardware'].c.hardware) + join_query = join_query.outerjoin(self.table['hasHardware'], + and_(self.table['hasHardware'].c.machine == Machine.id, + self.table['hasHardware'].c.inventory == self.inventory.c.id)).outerjoin(self.table['Hardware'], self.table['Hardware'].c.id == self.table['hasHardware'].c.hardware) if "Registry" in self.config.content: - join_query = join_query.outerjoin(self.table['hasRegistry'], self.table['hasRegistry'].c.machine == Machine.id).outerjoin(self.table['Registry'], self.table['Registry'].c.id == self.table['hasRegistry'].c.registry) + join_query = join_query.outerjoin(self.table['hasRegistry'], + and_( self.table['hasRegistry'].c.machine == Machine.id, + self.table['hasRegistry'].c.inventory == self.inventory.c.id)).outerjoin(self.table['Registry'], self.table['Registry'].c.id == self.table['hasRegistry'].c.registry) if count: query = session.query(func.count(Machine.id)).select_from(join_query).filter(query_filter) @@ -514,6 +520,17 @@ def getComputersOptimized(self, ctx, filt): for inv in row[1]: computers[uuid][1][inv["Path"]] = inv["Value"] # Build the result + ret1={} + result = self.getMachinesOnly(ctx, filt) + for m in result: # glpi mapping + if m.uuid() in uuids: + attributcomputer = m.toDN(ctx)[1] + keycomputer =attributcomputer.keys() + for ky in keycomputer: + computers[m.uuid()][1][ky] = attributcomputer[ky] + + + ret = [] for uuid in uuids: ret.append(computers[uuid]) @@ -1802,6 +1819,44 @@ def delUser(self, uidUser): #clear entitie of deleted user if fkuser != -1: self.delUserEntitiesbyfkUser(fkuser) + + def updateNameWithHardwareHost(self, uuid, name): + """ + name machine est synchronisée avec le host du hardware + """ + session = create_session() + query = session.query(Machine) + query = query.select_from(self.machine + .join(self.table['hasHardware'], self.machine.c.id == self.table['hasHardware'].c.machine) + .join(self.table['Hardware'], self.table['Hardware'].c.id == self.table['hasHardware'].c.hardware) + .join(self.table['Inventory'], self.table['Inventory'].c.id == self.table['hasHardware'].c.inventory) + ) + query = query.filter( + and_( + self.machine.c.id == fromUUID(uuid), + self.inventory.c.Last == 1, + ) + ) + ret = query.all() + session1 = create_session() + query1 = session1.query(Hardware) + query1 = query1.select_from(self.hardware + .join(self.table['hasHardware'], self.table['Hardware'].c.id == self.table['hasHardware'].c.hardware) + .join(self.machine, self.machine.c.id == self.table['hasHardware'].c.machine) + .join(self.table['Inventory'], self.table['Inventory'].c.id == self.table['hasHardware'].c.inventory) + ) + query1 = query1.filter( + and_( + self.machine.c.id == fromUUID(uuid), + self.inventory.c.Last == 1, + ) + ) + ret1 = query1.all() + session1.close() + if ret1[0].Host != ret[0].Name : + ret[0].Name=ret1[0].Host + session.flush() + session.close() def deleteEntities(self, id, Label, parentId): session = create_session() @@ -2154,7 +2209,7 @@ def addEntityRule(self, ruleobj): #self.logger.debug('add %s' % (ref1)) ref['count'] = nb_ligne + nblignerule numreglemodifier = int(ruleobj['numRuleadd']) - if numreglemodifier > nb_regle : + if numreglemodifier > nb_regle : ref['nb_regle']=int(ref['nb_regle'])+1 self.rewritte_file_rule_obj(ref) return True @@ -2560,6 +2615,7 @@ def getUsersInSameLocations(self, userid, locations = None): return ret def __getInventoryHistory(self, session, days, only_new, pattern, max = 10, min = 0): + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") if only_new: only_new_filter = self.inventory.c.Last == 1 else: @@ -2568,7 +2624,7 @@ def __getInventoryHistory(self, session, days, only_new, pattern, max = 10, min return session.query(self.klass['Inventory']).add_entity(Machine). \ select_from(self.table['hasInventory'].join(self.machine). \ join(self.table['Inventory'])). \ - filter(and_((func.to_days(func.now()) - func.to_days(self.klass['Inventory'].Date)) <= days, \ + filter(and_((func.to_days(nowsystem) - func.to_days(self.klass['Inventory'].Date)) <= days, \ Machine.Name.like('%' + pattern + '%'), only_new_filter)). \ order_by(self.klass['Inventory'].id.desc()).group_by(self.klass['Inventory'].id). \ offset(min) diff --git a/pulse2/services/pulse2/database/msc/__init__.py b/pulse2/services/pulse2/database/msc/__init__.py index 419bba5db..5348b2373 100644 --- a/pulse2/services/pulse2/database/msc/__init__.py +++ b/pulse2/services/pulse2/database/msc/__init__.py @@ -888,7 +888,7 @@ def getAllCommandsOnHost(self, ctx, uuid, min, max, filt): return [] def getAllCommandsConsult(self, ctx, min, max, filt, expired = True): - + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") session = create_session() # ====== GENERATING FILTERS ============================ @@ -908,9 +908,9 @@ def getAllCommandsConsult(self, ctx, min, max, filt, expired = True): #filters = filters & (self.commands.c.fk_bundle == self.bundle.c.id) if expired: - filters = and_(filters, (self.commands.c.end_date <= func.now())) + filters = and_(filters, (self.commands.c.end_date <= nowsystem)) else: - filters = and_(filters, (self.commands.c.end_date > func.now())) + filters = and_(filters, (self.commands.c.end_date > nowsystem)) # Adding command type filtering # Show default commands type=0 and convegence commands type=2 @@ -1043,6 +1043,7 @@ def getAllCommandsConsult(self, ctx, min, max, filt, expired = True): ################### def __displayLogsQuery(self, ctx, params, session): + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") query = session.query(Commands).select_from(self.commands.join(self.commands_on_host).join(self.target)) if params['gid'] != None: query = query.filter(self.target.c.id_group == params['gid']) @@ -1062,9 +1063,9 @@ def __displayLogsQuery(self, ctx, params, session): # Finished param if 'finished' in params and params['finished'] == '1': - query = query.filter(self.commands.c.end_date <= func.now()) + query = query.filter(self.commands.c.end_date <= nowsystem) elif 'finished' in params and params['finished'] == '0': - query = query.filter(self.commands.c.end_date > func.now()) + query = query.filter(self.commands.c.end_date > nowsystem) return query.group_by(self.commands.c.id).order_by(desc(params['order_by'])) @@ -1083,6 +1084,7 @@ def __doneBundle(self, params, session): return True def __displayLogsQuery2(self, ctx, params, session, count = False): + nowsystem = time.strftime("%Y-%m-%d %H:%M:%S") filter = [] group_by = False group_clause = False @@ -1117,9 +1119,9 @@ def __displayLogsQuery2(self, ctx, params, session, count = False): # Finished param if 'finished' in params and params['finished'] == '1': - filter.append(self.commands.c.end_date <= func.now()) + filter.append(self.commands.c.end_date <= nowsystem) elif 'finished' in params and params['finished'] == '0': - filter.append(self.commands.c.end_date > func.now()) + filter.append(self.commands.c.end_date > nowsystem) # Filtering on COH State if 'state' in params and params['state']: diff --git a/pulse2/services/pulse2/package_server/config.py b/pulse2/services/pulse2/package_server/config.py index 00df96aeb..ff15c69e5 100644 --- a/pulse2/services/pulse2/package_server/config.py +++ b/pulse2/services/pulse2/package_server/config.py @@ -162,7 +162,10 @@ def setup(self, config_file): self.public_ip = self.cp.get("main", 'public_ip') else: self.public_ip = self.bind - + if self.cp.has_option('main', 'public_mask'): + self.public_mask = self.cp.get("main", 'public_mask') + else: + self.public_mask = '255.255.255.0' if sys.platform != "win32": if self.cp.has_section('daemon'): if self.cp.has_option('daemon', 'pidfile'): @@ -314,11 +317,11 @@ def setup(self, config_file): # will contain the boot menus, served by tftp bootmenus_folder = 'bootmenus' # will contain diskless stuff (kernel, initramfs, additional tools), served by tftp - diskless_folder = 'diskless' + diskless_folder = 'davos' # diskless kernel - diskless_kernel = 'kernel' + diskless_kernel = 'vmlinuz' # diskless initrd - diskless_initrd = 'initrd' + diskless_initrd = 'initrd.img' # diskless initrd for CD-ROM diskless_initrdcd = 'initrdcd' # diskless memtest tool diff --git a/pulse2/services/pulse2/package_server/imaging/api/__init__.py b/pulse2/services/pulse2/package_server/imaging/api/__init__.py index e9112a35c..b1b448b50 100644 --- a/pulse2/services/pulse2/package_server/imaging/api/__init__.py +++ b/pulse2/services/pulse2/package_server/imaging/api/__init__.py @@ -105,6 +105,41 @@ def xmlrpc_imagingServerImageDelete(self, imageUUID): def xmlrpc_imagingServerISOCreate(self, imageUUID, size, title): return self.api.imagingServerISOCreate(imageUUID, size, title) + def xmlrpc_imagingServermenuMulticast(self, objmenu): + """ + """ + return self.api.imagingServermenuMulticast(objmenu) + + ## Imaging server configuration + def xmlrpc_check_process_multicast(self, objprocess): + # controle execution process multicast + return self.api.check_process_multicast(objprocess) + + def xmlrpc_check_process_multicast_finish(self, objprocess): + return self.api.check_process_multicast_finish(objprocess) + + def xmlrpc_start_process_multicast(self,objprocess): + # controle execution process multicast + self.logger.debug("start %s" % objprocess) + return self.api.start_process_multicast(objprocess) + + def xmlrpc_muticast_script_exist(self,objprocess): + # controle execution process multicast + return self.api.muticast_script_exist(objprocess) + + def xmlrpc_clear_script_multicast(self,objprocess): + # controle execution process multicast + return self.api.clear_script_multicast(objprocess) + + def xmlrpc_checkDeploymentUDPSender(self,objprocess): + # check transfert starting multicast + return self.api.checkDeploymentUDPSender(objprocess) + + def xmlrpc_stop_process_multicast(self,objprocess): + # controle execution process multicast + self.logger.debug("stop %s" % objprocess) + return self.api.stop_process_multicast(objprocess) + def xmlrpc_imagingServerConfigurationSet(self, conf): return self.api.imagingServerConfigurationSet(conf) diff --git a/pulse2/services/pulse2/package_server/imaging/api/functions.py b/pulse2/services/pulse2/package_server/imaging/api/functions.py index 0e9f6ec53..1e65e03d1 100644 --- a/pulse2/services/pulse2/package_server/imaging/api/functions.py +++ b/pulse2/services/pulse2/package_server/imaging/api/functions.py @@ -26,7 +26,8 @@ import logging import os import shutil - +import re +import subprocess from time import gmtime import uuid @@ -37,13 +38,13 @@ from pulse2.package_server.imaging.api.client import ImagingXMLRPCClient from pulse2.package_server.imaging.cache import UUIDCache from pulse2.package_server.imaging.api.status import Status -from pulse2.package_server.imaging.menu import isMenuStructure, ImagingDefaultMenuBuilder, ImagingComputerMenuBuilder, changeDefaultMenuItem, ImagingBootServiceItem +from pulse2.package_server.imaging.menu import isMenuStructure, ImagingDefaultMenuBuilder, ImagingComputerMenuBuilder, changeDefaultMenuItem, ImagingBootServiceItem, ImagingMulticastMenuBuilder from pulse2.package_server.imaging.computer import ImagingComputerConfiguration from pulse2.package_server.imaging.iso import ISOImage from pulse2.package_server.imaging.archiver import Archiver from pulse2.package_server.imaging.rpcreplay import RPCReplay -from pulse2.utils import isMACAddress, splitComputerPath, macToNode, isUUID, rfc3339Time, humanReadable, SingletonN +from pulse2.utils import isMACAddress, splitComputerPath, macToNode, isUUID, rfc3339Time, humanReadable, SingletonN, check_process, start_process, stop_process from pulse2.apis import makeURL from pulse2.imaging.image import Pulse2Image @@ -1000,6 +1001,104 @@ def imagingServerISOCreate(self, imageUUID, size, title): return ret ## Imaging server configuration + def imagingServermenuMulticast(self, objmenu): + # create menu multicast + m = ImagingMulticastMenuBuilder(objmenu) + ret = m.make() + return [ret] + + def _checkProcessDrblClonezilla(self): + """ check server dbrl running""" + s = subprocess.Popen("ps cax | grep drbl-ocs", + shell=True, + stdout=subprocess.PIPE + ) + returnprocess = False + for x in s.stdout: + if re.search("drbl-ocs", x): + returnprocess = True + s.stdout.close() + return returnprocess + + ## Imaging server configuration + def check_process_multicast(self, objprocess): + # check execution process multicast + return self._checkProcessDrblClonezilla() + + def check_process_multicast_finish(self, objprocess): + # check process multicast terminat + return os.path.exists("/tmp/processmulticast") and not self._checkProcessDrblClonezilla() + + def muticast_script_exist(self, objprocess): + # controle script existance script multicast + return os.path.exists(objprocess['process']) + + def clear_script_multicast(self, objprocess): + ## suppression commande multicast + # renvoi le groupe a regenerer bootmenu pour unicast + if os.path.exists("/tmp/processmulticast"): + os.remove("/tmp/processmulticast") + if os.path.exists("/tmp/multicast.sh"): + f = open("/tmp/multicast.sh",'r') + lignes = f.readlines() + f.close() + s=[x.split("=")[1].strip(' \t\n\r') for x in lignes if x.startswith( 'groupuuid' ) ] + if len(s)== 0: + return -1 + os.remove("/tmp/multicast.sh") + return s[0] + else: + return -1 + + def start_process_multicast(self, objprocess): + # start execution process multicast + start_process(objprocess['process']) + return self._checkProcessDrblClonezilla() + + def checkDeploymentUDPSender(self, objprocess): + result = {} + result['data']="" + result['tranfert'] = False + self.logger.info('verify exist file /tmp/udp-sender.log') + if os.path.isfile("/tmp/udp-sender.log"): + self.logger.info('file /tmp/udp-sender.log exist') + self.logger.info("exec : grep 'Starting transfer' /tmp/udp-sender.log") + s = subprocess.Popen("grep 'Starting transfer' /tmp/udp-sender.log", + shell=True, + stdout=subprocess.PIPE) + result['tranfert'] = False + for x in s.stdout: + result['tranfert'] = True + break; + s.stdout.close() + s.wait() + if result['tranfert'] == True: + self.logger.info("Starting transfer exist in the file") + else: + self.logger.info("Starting transfer no exist in the file") + self.logger.info("exec : tail -n 1 /tmp/udp-sender.log -> for next bar progression") + r = subprocess.Popen("tail -n 1 /tmp/udp-sender.log", + shell=True, + stdout=subprocess.PIPE) + for x in r.stdout: + result['data']= x + r.wait() + self.logger.info("last line of /tmp/udp-sender.log: %s"%result['data']) + r.stdout.close() + else: + self.logger.info('file /tmp/udp-sender.log no exist') + self.logger.info("return function checkDeploymentUDPSender on imaging server: %s"%result ) + return result + + + def stop_process_multicast(self, objprocess): + # stop execution process multicast + s = subprocess.Popen("/usr/sbin/drbl-ocs -h 127.0.0.1 stop", + shell=True, + stdout=subprocess.PIPE + ) + stop_process(objprocess['process']) + return self._checkProcessDrblClonezilla() def imagingServerConfigurationSet(self, conf): """ diff --git a/pulse2/services/pulse2/package_server/imaging/menu.py b/pulse2/services/pulse2/package_server/imaging/menu.py index 408def55f..6023565cf 100644 --- a/pulse2/services/pulse2/package_server/imaging/menu.py +++ b/pulse2/services/pulse2/package_server/imaging/menu.py @@ -791,7 +791,7 @@ def write(self, config): f = file(postinst, 'w+') f.write('#!/bin/sh\n') f.write('\n') - f.write('. /opt/lib/libpostinst.sh') + f.write('. /usr/lib/libpostinst.sh') f.write('\n') f.write('echo "==> postinstall script #%d : %s"\n' % (order, script['name'].encode('utf-8'))) f.write('set -v\n') @@ -875,3 +875,180 @@ def changeDefaultMenuItem(macaddress, value): % (backupname, filename, e)) return True return False + + + +class ImagingMulticastMenuBuilder: + """ + Class that builds an imaging menu according to its dict structure. + """ + + def __init__(self, menu): + """ + The object builder Menu multicast + @param config : the imaging server config + @param menu : the menu dict + + @return the object + """ + + self.pathBootMenu = os.path.join(PackageServerConfig().imaging_api['base_folder'], + PackageServerConfig().imaging_api['bootmenus_folder']) + self.logger = logging.getLogger('imaging') + self.logger.debug('creation commande et menu [%s] '%(menu)) + self.menu = menu + self.public_ip = PackageServerConfig().public_ip + self.server_address = self.ipV4toDecimal(self.public_ip) + self.public_mask = PackageServerConfig().public_mask + self.mask_server = self.ipV4toDecimal(self.public_mask) + self.networkserver = self.server_address & self.mask_server + self.ipPart=self.public_ip.split(".") + #self.listnameinterface=os.listdir("/sys/class/net/") + #for interface in self.listnameinterface: + #if pulse2.utils.get_ip_address(interface)==self.public_ip: + #self.nameinterface=interface + #break + #self.logger.info('interface [%s] ip [%s]'%(self.nameinterface,self.public_ip)) + self.action = "startdisk" + diskfile = os.path.join(self.menu['path'], "disk") + #load disk restore + fid = file(diskfile, 'r') + lines = fid.readlines() + fid.close() + self.disk=[ x.strip(' \t\n\r"') for x in lines if x.strip(' \t\n\r"')!= ""] + #self.templatecmdline = """#!/bin/bash +#mastername="%s" +#localisationmaster="%s" +#masteruuid=%s +#mastersize=%s +#groupuuid=%s +#waitting=%s +#locationuuid=%s +#cat /var/lib/pulse2/imaging/masters/%s/sda1.ntfs-ptcl-img.uncomp.aa |udp-sender --full-duplex --min-clients %s --interface %s --nokbd --mcast-all-addr 224.0.0.1 --portbase 2232 --ttl 1"""%( + #self.menu['description'] , + #self.menu['path'] , + #self.menu['master'] , + #self.menu['size'] , + #self.menu['group'] , + #self.menu['nbcomputer'], + #self.menu['location'], + #self.menu['master'] , + #self.menu['nbcomputer'], + #self.nameinterface ) + + self.templatecmdline = """#!/bin/bash +echo -e "NE PAS EFFACER\nDO NOT DELETE" > /tmp/processmulticast +echo "" > /tmp/udp-sender.log +mastername="%s" +localisationmaster="%s" +masteruuid=%s +mastersize=%s +groupuuid=%s +waitting=%s +locationuuid=%s +drbl-ocs -b -g auto -e1 auto -e2 -x -j2 --clients-to-wait %s -l en_US.UTF-8 -h "127.0.0.1" %s multicast_restore %s %s &>> /tmp/%s.log"""%( + self.menu['description'] , + self.menu['path'] , + self.menu['master'] , + self.menu['size'] , + self.menu['group'] , + self.menu['nbcomputer'], + self.menu['location'], + self.menu['nbcomputer'], + self.action, + self.menu['master'] , + self.disk[0], + self.menu['master']) + self.template=""" +timeout 10 +default 0 +splashimage /bootloader/bootsplash.xpm +color 7/1 15/3 + +title Restore Multicast + +desc %s + +kernel (nd)/davos/vmlinuz boot=live config noswap edd=on nomodeset nosplash noprompt vga=788 fetch=tftp://%s/davos/fs.squashfs mac=%s revorestorenfs image_uuid=%s davos_action=RESTORE_IMAGE_MULTICAST + +initrd (nd)/davos/initrd.img +""" + + def ipV4toDecimal(self, ipv4): + d = ipv4.split('.') + return (int(d[0])*256*256*256) + (int(d[1])*256*256) + (int(d[2])*256) +int(d[3]) + + def isValidIPv4Address(self, adressmachine): + self.logger.info("controle of the machine address %s in network %s"%(adressmachine,self.networkserver)) + adressmachine = adressmachine.split(":")[0] + reseaumachine = self.ipV4toDecimal(adressmachine) & self.mask_server + if self.networkserver == reseaumachine : + self.logger.info("machine address %s in network %s"%(adressmachine,self.networkserver)) + return True + return False + + def chooseMacAddress(self): + rest = True + for k, v in self.menu['computer'].iteritems(): + if self.isValidIPv4Address(v): + mac = pulse2.utils.reduceMACAddress(k) + self.logger.debug("create bootMenu [%s] Computer ip [%s]"%(k,v)) + menuval= self.template%( self.menu['description'], + self.public_ip, + k, #mac + self.menu['master'] + ) + self.logger.debug("bootMenu [%s]\n%s"%(mac, menuval)) + if self.writeMenuMulticast( mac, menuval) == False: + rest = False + else: + self.logger.debug("mac [%s] ip [%s] non selected"%(k,v)) + return rest + + def writeMenuMulticast(self,filename,content): + backupname = os.path.join(self.pathBootMenu,"%s.backup" % filename) + fichier = os.path.join(self.pathBootMenu,filename) + try: + os.rename(fichier, backupname) + except OSError, e: # can make a backup : give up ! + self.logger.error("While backuping boot menu %s as %s : %s" + % (fichier, backupname, e)) + + # Write new boot menu + try: + fid = file(fichier, 'w+b') + fid.write(content) + fid.close() + self.logger.debug('Successfully wrote boot menu for computer MAC %s into file %s' % (filename, fichier)) + except IOError, e: + self.logger.error("While writing boot menu for %s : %s" + % (filename, e)) + return False + # Remove boot menu backup + try: + os.unlink(backupname) + except OSError, e: + self.logger.warn("While removing backup %s of %s : %s" + % (backupname, filename, e)) + return True + + def make(self): + """ + """ + ##generation bootmenu for multicast + if not self.chooseMacAddress(): + return False + ##generation command line in tmp + fichier = os.path.join("/tmp","multicast.sh") + try: + fid = file(fichier, 'w+b') + fid.write(self.templatecmdline) + fid.close() + os.chmod(fichier, stat.S_IXUSR| stat.S_IWUSR |stat.S_IRUSR) + self.logger.debug('Successfully wrote multicast command into file %s' % ( fichier)) + return True + except IOError, e: + self.logger.error("While writing commande for multicast command" + % (filename, e)) + return False + return True diff --git a/pulse2/services/pulse2/pull_client/win32/artwork/header.bmp b/pulse2/services/pulse2/pull_client/win32/artwork/header.bmp index 134a3a061..dbdcbbf8e 100644 Binary files a/pulse2/services/pulse2/pull_client/win32/artwork/header.bmp and b/pulse2/services/pulse2/pull_client/win32/artwork/header.bmp differ diff --git a/pulse2/services/pulse2/pull_client/win32/artwork/wizard.bmp b/pulse2/services/pulse2/pull_client/win32/artwork/wizard.bmp index 7d838e7d8..07590ade4 100644 Binary files a/pulse2/services/pulse2/pull_client/win32/artwork/wizard.bmp and b/pulse2/services/pulse2/pull_client/win32/artwork/wizard.bmp differ diff --git a/pulse2/services/pulse2/pulse_update_manager/win32/artwork/header.bmp b/pulse2/services/pulse2/pulse_update_manager/win32/artwork/header.bmp index 134a3a061..dbdcbbf8e 100644 Binary files a/pulse2/services/pulse2/pulse_update_manager/win32/artwork/header.bmp and b/pulse2/services/pulse2/pulse_update_manager/win32/artwork/header.bmp differ diff --git a/pulse2/services/pulse2/pulse_update_manager/win32/artwork/wizard.bmp b/pulse2/services/pulse2/pulse_update_manager/win32/artwork/wizard.bmp index 7d838e7d8..07590ade4 100644 Binary files a/pulse2/services/pulse2/pulse_update_manager/win32/artwork/wizard.bmp and b/pulse2/services/pulse2/pulse_update_manager/win32/artwork/wizard.bmp differ diff --git a/pulse2/services/pulse2/utils.py b/pulse2/services/pulse2/utils.py index 1f978cb29..40575382a 100644 --- a/pulse2/services/pulse2/utils.py +++ b/pulse2/services/pulse2/utils.py @@ -61,6 +61,7 @@ import posixpath import psutil import logging +import sys # python 2.3 fallback for set() in xmlrpcleanup try: @@ -571,6 +572,42 @@ def get_ip_address(ifname): struct.pack('256s', ifname) )[20:24]) +def start_process(processname): + """ """ + import subprocess + subprocess.Popen([processname], shell=True) + return check_process(processname) + +def stop_process(processname): + """ + """ + import subprocess + import signal + proc = subprocess.Popen(["pgrep", processname], stdout=subprocess.PIPE)# Kill process. + for pid in proc.stdout: + logging.getLogger().debug("kill pid %d "%int(pid)) + os.kill(int(pid), signal.SIGTERM) + # Check if the process that we killed is alive. + try: + os.kill(int(pid), 0) + except OSError as ex: + logging.getLogger().warn("wasn't able to kill the process %s HINT:use signal.SIGKILL or signal.SIGABORT"% processname) + raise Exception("""wasn't able to kill the process %s + HINT:use signal.SIGKILL or signal.SIGABORT"""% processname) + return not check_process(processname) + +def check_process(processname): + """ + """ + import re + import subprocess + returnprocess = False + s = subprocess.Popen(["ps", "ax"],stdout=subprocess.PIPE) + for x in s.stdout: + if re.search(processname, x): + returnprocess = True + return returnprocess + def get_default_netif(): """ Read the default interface directly from /proc. """ diff --git a/pulse2/web/modules/backuppc/img/navbar/bpc.png b/pulse2/web/modules/backuppc/img/navbar/bpc.png index 80bde1792..e7cf6355b 100644 Binary files a/pulse2/web/modules/backuppc/img/navbar/bpc.png and b/pulse2/web/modules/backuppc/img/navbar/bpc.png differ diff --git a/pulse2/web/modules/backuppc/img/navbar/bpc_hl.png b/pulse2/web/modules/backuppc/img/navbar/bpc_hl.png index 4867b66b5..77b2711ae 100644 Binary files a/pulse2/web/modules/backuppc/img/navbar/bpc_hl.png and b/pulse2/web/modules/backuppc/img/navbar/bpc_hl.png differ diff --git a/pulse2/web/modules/backuppc/img/navbar/bpc_select.png b/pulse2/web/modules/backuppc/img/navbar/bpc_select.png index 5765c4de0..bd5ff73be 100644 Binary files a/pulse2/web/modules/backuppc/img/navbar/bpc_select.png and b/pulse2/web/modules/backuppc/img/navbar/bpc_select.png differ diff --git a/pulse2/web/modules/dyngroup/dyngroup/add_groups.php b/pulse2/web/modules/dyngroup/dyngroup/add_groups.php index 2bb11c17b..8fa1a8a5e 100644 --- a/pulse2/web/modules/dyngroup/dyngroup/add_groups.php +++ b/pulse2/web/modules/dyngroup/dyngroup/add_groups.php @@ -23,7 +23,9 @@ require_once("modules/pulse2/includes/utilities.php"); # for quickGet method require("modules/dyngroup/includes/groups.inc.php"); - +if (in_array("imaging", $_SESSION["modulesList"])) { + require_once('modules/imaging/includes/xmlrpc.inc.php'); + } $name = quickGet('name', $p_first = True, $urldecode = False); $id = quickGet('id'); $visibility = quickGet('visible'); @@ -147,6 +149,28 @@ new NotifyWidgetSuccess(_T("Group successfully modified", "dyngroup")); } else { // Imaging group // Synchro Profile + // Synchro Profile + if (in_array("imaging", $_SESSION["modulesList"])) { + // Get Current Location + //include('modules/imaging/includes/xmlrpc.inc.php'); + $location = xmlrpc_getProfileLocation($group->id); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location'] = $location; + $objprocess['process'] = $path.$scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The bootmenus cannot be generated as a multicast deployment is currently running.", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $ret = xmlrpc_synchroProfile($group->id); + xmlrpc_clear_script_multicast($objprocess); + } + } + $ret = xmlrpc_synchroProfile($group->id); if (count($dontAddedToProfile) > 0) { diff --git a/pulse2/web/modules/dyngroup/dyngroup/ajaxListGroups.php b/pulse2/web/modules/dyngroup/dyngroup/ajaxListGroups.php index 9a527d11f..e98121ec4 100644 --- a/pulse2/web/modules/dyngroup/dyngroup/ajaxListGroups.php +++ b/pulse2/web/modules/dyngroup/dyngroup/ajaxListGroups.php @@ -21,6 +21,7 @@ * along with MMC. If not, see . */ +require_once('modules/imaging/includes/xmlrpc.inc.php'); require("modules/pulse2/includes/profiles_xmlrpc.inc.php"); global $conf; @@ -52,7 +53,6 @@ } $filter = $_GET["filter"]; - $ids = array(); $name = array(); $type = array(); @@ -66,7 +66,13 @@ $empty = new EmptyActionItem(); foreach ($list as $group) { - $ids[]= array("id"=>$group->id, "gid"=>$group->id, "groupname"=> $group->name, 'type'=>$is_gp); + if($is_gp == 1){ + $profile = xmlrpc_getProfileLocation($group->id); + $ids[] = array("id"=>$group->id, "gid"=>$group->id, "groupname"=> $group->name, 'type'=>$is_gp,'profile'=>$profile); + }else{ + $ids[]= array("id"=>$group->id, "gid"=>$group->id, "groupname"=> $group->name, 'type'=>$is_gp); + } + $name[]= $group->getName(); if ($group->isDyn()) { $type[]= (!$group->isRequest() ? sprintf(_T('result (%s)', 'dyngroup'), $group->countResult()) : _T('query', 'dyngroup')); diff --git a/pulse2/web/modules/dyngroup/dyngroup/delete_group.php b/pulse2/web/modules/dyngroup/dyngroup/delete_group.php index c09701b08..36e0c075c 100644 --- a/pulse2/web/modules/dyngroup/dyngroup/delete_group.php +++ b/pulse2/web/modules/dyngroup/dyngroup/delete_group.php @@ -21,7 +21,11 @@ * along with MMC. If not, see . */ require_once("modules/dyngroup/includes/includes.php"); - +if (in_array("imaging", $_SESSION["modulesList"])) { + // Get Current Location + require_once('modules/imaging/includes/xmlrpc.inc.php'); + } +$location =""; $id = quickGet('gid'); $group = new Group($id, False); $type = quickGet('type'); @@ -39,14 +43,29 @@ $delete = _T("Delete group", "dyngroup"); } -if (quickGet('valid')) { if ($type == 1) { // Imaging group if (in_array("imaging", $_SESSION["modulesList"])) { // Get Current Location - include('modules/imaging/includes/xmlrpc.inc.php'); + require_once('modules/imaging/includes/xmlrpc.inc.php'); $location = xmlrpc_getProfileLocation($id); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The group cannot be deleted as a multicast deployment is currently running.", "imaging"); + echo'
+

'.$msg.'

+ +
'; + exit; + } } } + +if (quickGet('valid')) { + $group->delete(); if ($type == 1) { // Imaging group if (in_array("imaging", $_SESSION["modulesList"])) { @@ -71,7 +90,6 @@ -

" onClick="closePopup(); diff --git a/pulse2/web/modules/dyngroup/dyngroup/localImagingSidebar.php b/pulse2/web/modules/dyngroup/dyngroup/localImagingSidebar.php index 39f8fecdf..aa9aa1f4d 100644 --- a/pulse2/web/modules/dyngroup/dyngroup/localImagingSidebar.php +++ b/pulse2/web/modules/dyngroup/dyngroup/localImagingSidebar.php @@ -28,7 +28,7 @@ if (isProfilesEnable() && areProfilesPossible()) { $sidemenu->addSideMenuItem( - new SideMenuItem(_T("All imaging groups", "dyngroup"), "imaging", "manage", "list_profiles") + new SideMenuItem(_T("All imaging groups", "dyngroup"), "imaging", "manage", "list_profiles","img/machines/icn_allGroups_active.gif", "img/machines/icn_allGroups_ro.gif") ); $sidemenu->addSideMenuItem( new SideMenuItem(_T("Add an imaging group", "dyngroup"), "imaging", "manage", "computersprofilecreator", "img/machines/icn_addMachines_active.gif", "img/machines/icn_addMachines_ro.gif") diff --git a/pulse2/web/modules/dyngroup/dyngroup/remove_machine.php b/pulse2/web/modules/dyngroup/dyngroup/remove_machine.php index 8e0ff41e9..7bed18608 100644 --- a/pulse2/web/modules/dyngroup/dyngroup/remove_machine.php +++ b/pulse2/web/modules/dyngroup/dyngroup/remove_machine.php @@ -29,7 +29,7 @@ if (quickGet('valid')) { if (in_array("imaging", $_SESSION["modulesList"])) { - include('modules/imaging/includes/xmlrpc.inc.php'); + require_once('modules/imaging/includes/xmlrpc.inc.php'); if (xmlrpc_isProfileRegistered($gid)) { // Get Current Location $location = xmlrpc_getProfileLocation($gid); diff --git a/pulse2/web/modules/dyngroup/includes/groups.inc.php b/pulse2/web/modules/dyngroup/includes/groups.inc.php index 9320cccff..af0685f3f 100644 --- a/pulse2/web/modules/dyngroup/includes/groups.inc.php +++ b/pulse2/web/modules/dyngroup/includes/groups.inc.php @@ -22,7 +22,7 @@ */ if(in_array("imaging", $_SESSION["modulesList"])) - require('modules/imaging/includes/xmlrpc.inc.php'); + require_once('modules/imaging/includes/xmlrpc.inc.php'); require_once('modules/dyngroup/includes/dyngroup.php'); // for getPGobject method diff --git a/pulse2/web/modules/glpi/glpi/localSidebar.php b/pulse2/web/modules/glpi/glpi/localSidebar.php index a42c0401f..94cee0df5 100644 --- a/pulse2/web/modules/glpi/glpi/localSidebar.php +++ b/pulse2/web/modules/glpi/glpi/localSidebar.php @@ -22,12 +22,12 @@ */ /* Add new sidemenu item */ - +/* $sidemenu->addSideMenuItem(new SideMenuItem(_T("Entities", "glpi"), "base", "computers", "entityList", "", "")); $sidemenu->addSideMenuItem(new SideMenuItem(_T("Add an entity", "glpi"), "base", "computers", "addEntity", "", "")); $sidemenu->addSideMenuItem(new SideMenuItem(_T("Locations", "glpi"), "base", "computers", "locationList", "", "")); $sidemenu->addSideMenuItem(new SideMenuItem(_T("Add a location", "glpi"), "base", "computers", "addLocation", "", "")); $sidemenu->addSideMenuItem(new SideMenuItem(_T("Entity rules", "glpi"), "base", "computers", "entityRules", "", "")); $sidemenu->addSideMenuItem(new SideMenuItem(_T("Add entity rule", "glpi"), "base", "computers", "addEntityRule", "", "")); - +*/ ?> diff --git a/pulse2/web/modules/glpi/glpi/tabs.php b/pulse2/web/modules/glpi/glpi/tabs.php index 95f67a82b..406cf548b 100644 --- a/pulse2/web/modules/glpi/glpi/tabs.php +++ b/pulse2/web/modules/glpi/glpi/tabs.php @@ -49,10 +49,6 @@ $glpi_link = 'GLPI'; } -// JM 20141209 removed GLPI link -unset($glpi_link); -// endof JM 20141209 - $p = new TabbedPageGenerator(); $p->setSideMenu($sidemenu); if (isset($_SESSION['pull_targets']) && in_array($uuid, $_SESSION['pull_targets'])) { diff --git a/pulse2/web/modules/imaging/graph/manage/index.css b/pulse2/web/modules/imaging/graph/manage/index.css index 23ccc12fd..f8439eda5 100644 --- a/pulse2/web/modules/imaging/graph/manage/index.css +++ b/pulse2/web/modules/imaging/graph/manage/index.css @@ -1,5 +1,5 @@ div.membarfree { - border-right: 1px solid #27537C; + border-right: 1px solid #2295D2; height: 12px; background: url("img/main/bg_status_blue.gif") repeat-x left top transparent; padding: 0; @@ -27,7 +27,7 @@ div.membarcache { div.status { float: left; - width: 49%; + width: 50%; } div.status_block { @@ -50,8 +50,9 @@ div.status_block h3 { } div.status_block p { - padding-top: 0; + padding-top: 15px; padding-bottom: 3px; + font-size: 12px; } div.status_block p.stat { diff --git a/pulse2/web/modules/imaging/imaging/addimage.php b/pulse2/web/modules/imaging/imaging/addimage.php index 731509854..6d4d4c306 100644 --- a/pulse2/web/modules/imaging/imaging/addimage.php +++ b/pulse2/web/modules/imaging/imaging/addimage.php @@ -55,7 +55,26 @@ // Synchronize boot menu if ($type == 'group') { - $ret = xmlrpc_synchroProfile($target_uuid); + $location = getCurrentLocation(); + if ($location == "UUID1") + $location_name = _T("root", "pulse2"); + else + $location_name = xmlrpc_getLocationName($location); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The bootmenus cannot be generated as a multicast deployment is currently running.", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $ret = xmlrpc_synchroProfile($target_uuid); + xmlrpc_clear_script_multicast($objprocess); + } } else { $ret = xmlrpc_synchroComputer($target_uuid); diff --git a/pulse2/web/modules/imaging/imaging/addservice.php b/pulse2/web/modules/imaging/imaging/addservice.php index 281b2673b..d14e8bde6 100644 --- a/pulse2/web/modules/imaging/imaging/addservice.php +++ b/pulse2/web/modules/imaging/imaging/addservice.php @@ -54,7 +54,26 @@ /* insert notification code here if needed */ // Synchronize boot menu if ($type == 'group') { - $ret = xmlrpc_synchroProfile($target_uuid); + $location = getCurrentLocation(); + if ($location == "UUID1") + $location_name = _T("root", "pulse2"); + else + $location_name = xmlrpc_getLocationName($location); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The bootmenus cannot be generated as a multicast deployment is currently running.", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $ret = xmlrpc_synchroProfile($target_uuid); + xmlrpc_clear_script_multicast($objprocess); + } } else { $ret = xmlrpc_synchroComputer($target_uuid); diff --git a/pulse2/web/modules/imaging/imaging/ajaxImages.php b/pulse2/web/modules/imaging/imaging/ajaxImages.php index fd5775616..4b3144b70 100644 --- a/pulse2/web/modules/imaging/imaging/ajaxImages.php +++ b/pulse2/web/modules/imaging/imaging/ajaxImages.php @@ -32,6 +32,7 @@ require("../../../includes/PageGenerator.php"); require("../includes/includes.php"); require_once('../includes/xmlrpc.inc.php'); +require_once("../../pulse2/includes/locations_xmlrpc.inc.php"); global $conf; $maxperpage = $conf["global"]["maxperpage"]; @@ -55,6 +56,8 @@ if ($type == 'group') { $all = xmlrpc_getProfileImages($_GET['gid'], $start, $end, $filter); + + } else { $all = xmlrpc_getComputerImages($_GET['uuid'], $start, $end, $filter); } @@ -64,13 +67,22 @@ } else { list($count, $images) = $all['images']; } + + + $params = getParams(); $addActions = array(); + + $addAction = new ActionPopupItem(_T("Add image to boot menu", "imaging"), "addimage", "addbootmenu", "image", "base", "computers", null, 300, "add"); $delAction = new ActionPopupItem(_T("Remove from boot menu", "imaging"), "bootmenu_remove", "delbootmenu", "item", "base", "computers", $type."tabbootmenu", 300, "delete"); + + $emptyAction = new EmptyActionItem(); $destroyAction = new ActionPopupItem(_T("Delete the image", "imaging"), "images_delete", "delete", "image", "base", "computers", $type."tabimages", 300, "delete"); + + $showImAction = new ActionPopupItem(_T("Show target using that image", "imaging"), "showtarget", "showtarget", "image", "base", "computers"); $editActions = array(); @@ -92,13 +104,16 @@ $a_logs = array(); $a_info = array(); $l_im = array(); + foreach ($images as $image) { $name = $image['name']; $l_params = $params; + $l_params['is_master'] = $image['is_master']; + $l_params["uuidmaster"] = $image['uuid']; $l_params["itemid"] = $image['imaging_uuid']; $l_params["itemlabel"] = urlencode($name); $l_params["target_uuid"] = $_GET['target_uuid']; - + $l_params["target_name"] = $_GET['target_name']; if (isset($image['read_only']) && $image['read_only']) $is_in_profile = True; if (in_array("dyngroup", $_SESSION["modulesList"])) { @@ -150,7 +165,6 @@ } } } - // show images list $l = new OptimizedListInfos($a_label, _T("Label", "imaging")); $l->setParamInfo($list_params); @@ -161,7 +175,6 @@ if ($is_in_profile) { $l->addExtraInfo($a_fromprofile, _T("From profile", "imaging")); } - $l->addActionItemArray($addActions); $l->addActionItem( @@ -170,6 +183,25 @@ ); // if not in boot menu +if ($type == 'group') { + $location = getCurrentLocation(); + if ($location == "UUID1") + $location_name = _T("root", "pulse2"); + else + $location_name = xmlrpc_getLocationName($location); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + + if (!xmlrpc_muticast_script_exist($objprocess)){ + $l->addActionItem( + new ActionPopupItem(_T("Multicast init", "imaging")." ".$location_name, + "multicast", "imaging", "image", "base", "computers") + ); + } +} if ($actions) { $l->addActionItem( new ActionItem(_T("Edit image", "imaging"), diff --git a/pulse2/web/modules/imaging/imaging/bootmenu_remove.php b/pulse2/web/modules/imaging/imaging/bootmenu_remove.php index 6ba144420..944909723 100644 --- a/pulse2/web/modules/imaging/imaging/bootmenu_remove.php +++ b/pulse2/web/modules/imaging/imaging/bootmenu_remove.php @@ -64,7 +64,27 @@ // Synchronize boot menu if ($type == 'group') { - $ret = xmlrpc_synchroProfile($target_uuid); + $location = getCurrentLocation(); + if ($location == "UUID1") + $location_name = _T("root", "pulse2"); + else + $location_name = xmlrpc_getLocationName($location); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The bootmenus cannot be generated as a multicast deployment is currently running.", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $ret = xmlrpc_synchroProfile($target_uuid); + xmlrpc_clear_script_multicast($objprocess); + } } else { $ret = xmlrpc_synchroComputer($target_uuid); } diff --git a/pulse2/web/modules/imaging/imaging/configure.php b/pulse2/web/modules/imaging/imaging/configure.php index eb399af5d..d9a38dc54 100644 --- a/pulse2/web/modules/imaging/imaging/configure.php +++ b/pulse2/web/modules/imaging/imaging/configure.php @@ -458,6 +458,15 @@ function expertModeDisplay($f, $has_profile, $type, $menu, $opts, $target, $real $profileNetworks = xmlrpc_getProfileNetworks($target_uuid); foreach ($profileNetworks as $networks) { $networks = $networks[1]; + foreach (range(0, count($networks['ipHostNumber']) - 1) as $i) { + $ip=explode(":", $networks['ipHostNumber'][$i] ); + if(filter_var($ip[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) == ""){ + unset($networks['ipHostNumber'][$i]); + unset($networks['macAddress'][$i]); + unset($networks['networkUuids'][$i]); + unset($networks['domain'][$i]); + } + } if (is_array($networks) && count($networks) > 1 and isset($networks['macAddress'])) { if (count($networks['macAddress']) > 1) { $f->push(new Table()); @@ -582,7 +591,6 @@ function expertModeDisplay($f, $has_profile, $type, $menu, $opts, $target, $real $f->pop(); } } - /* * Network card selection * If more than one network card, display a select form to select the one to use with imaging @@ -590,7 +598,15 @@ function expertModeDisplay($f, $has_profile, $type, $menu, $opts, $target, $real if ($is_registering && $type == '') { $networks = xmlCall('base.getComputersNetwork', array(array('uuid'=>$_GET["target_uuid"]))); $networks = $networks[0][1]; - + foreach (range(0, count($networks['ipHostNumber']) - 1) as $i) { + $ip = explode(":", $networks['ipHostNumber'][$i]); + if(filter_var($ip[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) == ""){ + unset($networks['ipHostNumber'][$i]); + unset($networks['macAddress'][$i]); + unset($networks['networkUuids'][$i]); + unset($networks['domain'][$i]); + } + } if (is_array($networks) && count($networks) > 1 and isset($networks['macAddress'])) { if (count($networks['macAddress']) > 1) { $f->push(new Table()); diff --git a/pulse2/web/modules/imaging/imaging/multicast.php b/pulse2/web/modules/imaging/imaging/multicast.php new file mode 100644 index 000000000..86cda895b --- /dev/null +++ b/pulse2/web/modules/imaging/imaging/multicast.php @@ -0,0 +1,196 @@ + $gid, 'hostname'=> '', 'location'=> $location), False); + list($count, $masters) = xmlrpc_getLocationImages($location); + if (count($list) == 0 ) + { + $msg = _T("Multicast menu has not been created : there are no computers in the group", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } + if (!isset($numbercomputer)){ + $msg = sprintf( _T("Multicast menu has not been created : number of computers missing")); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } else + { + $numbercomputer = intval($numbercomputer); + } + if (!(gettype ( $numbercomputer ) == "integer")){ + $msg = sprintf( _T("Multicast menu has not been created : number of computers missing")); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } + if ( count($list) < intval($numbercomputer)){ + $msg = sprintf( _T("Multicast menu has not been created : the imaging group contains %d computers and you have entered %d"),count($list),intval($numbercomputer)); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + }; + if (intval($numbercomputer)==0 ){ + $msg = sprintf( _T("Multicast menu has not been created : the imaging group contains %d computers and you have entered %d"),count($list),intval($numbercomputer)); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } + $objval=array(); + $objval['computer']=array(); + if ( count($list) < intval($numbercomputer)){ + $msg = sprintf( _T("Multicast menu has not been created : the imaging group contains %d computers and you have entered %d"),count($list),intval($numbercomputer)); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + }; + + $objval['location']=$location; + $objval['nbcomputer'] = intval($numbercomputer); + foreach($masters as $val){ + if ($val['uuid'] == $_POST['uuidmaster']){ + $objval['size'] = $val['size']; + $objval['description'] =$val['name']; + $objval['path'] =$val['path']; + $objval['master'] =$_POST['uuidmaster']; + } + } + + $objval['group'] = $target_uuid; + $profileNetworks1 = xmlrpc_getProfileNetworks($target_uuid); + + $mach=array(); + foreach($profileNetworks1 as $net){ + for ($t=0;$t",$net[1]['macAddress'][$t],$ip[0]); + } + } + } + // list machine sans ipv4 + $machine = array(); + foreach($profileNetworks1 as $net){ + $recherche = False; + foreach($net[1]['ipHostNumber'] as $ip){ + $ip1 = explode(":", $ip); + if (filter_var($ip1[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + $recherche = True; + break; + } + } + if ($recherche == False ){ + $machine[]=$net[1]['objectUUID'][0]; + }; + } + $nbmachine = count($machine); + if($nbmachine !=0 ){ + $msg = $nbmachine." "._T("computers have a [IPV6] interfaces address exclusively in the group", "imaging")."\n". + "list machines : [".implode(" ",$machine)."]"; + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } + + + $objval['computer']= $mach; + + + if (count($objval['computer']) == 0 ) + { + $msg = _T("Multicast menu has not been created : there are no computers in the group", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } + if (!isset($objval['path']) || $objval['path']=="" ){ + $msg = _T("Multicast menu has not been created : the selected master is missing on disk", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/list_profiles")); + exit; + } +// echo "
";
+//     print_r ($objval);
+//     echo "
"; +// exit; + $list = xmlrpc_imagingServermenuMulticast($objval); + if($list[0] == 1){ + $msg = _T("Multicast menu has been successfully created.", "imaging"); + new NotifyWidgetSuccess($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $msg = _T("Multicast menu has not been created : check that the imaging server is running", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } +} +?> +

+%s to this group %s in multicast", "imaging"), $label,$_GET[target_name]) ?> +

+
" method="post"> + + + + + +
+ + + +
+ + + + + + + + + + + + + " /> + " onclick="closePopup(); + return false;" /> +
\ No newline at end of file diff --git a/pulse2/web/modules/imaging/imaging/tabs.php b/pulse2/web/modules/imaging/imaging/tabs.php index 5e7ece2da..276304a8c 100644 --- a/pulse2/web/modules/imaging/imaging/tabs.php +++ b/pulse2/web/modules/imaging/imaging/tabs.php @@ -82,8 +82,30 @@ function resetDefaultMenu($uuid) { if (isset($_POST['bsync'])) { if (isset($params['uuid'])) { $ret = xmlrpc_synchroComputer($params['uuid']); - } else { - $ret = xmlrpc_synchroProfile($params['gid']); + } + else { + $location = getCurrentLocation(); + if ($location == "UUID1") + $location_name = _T("root", "pulse2"); + else + $location_name = xmlrpc_getLocationName($location); + $objprocess=array(); + $scriptmulticast = 'multicast.sh'; + $path="/tmp/"; + $objprocess['location']=$location; + $objprocess['process'] = $path.$scriptmulticast; + //if (xmlrpc_muticast_script_exist($objprocess)){ + + if (xmlrpc_check_process_multicast($objprocess)){ + $msg = _T("The bootmenus cannot be generated as a multicast deployment is currently running.", "imaging"); + new NotifyWidgetFailure($msg); + header("Location: " . urlStrRedirect("imaging/manage/index")); + exit; + } + else{ + $ret = xmlrpc_synchroProfile($params['gid']); + xmlrpc_clear_script_multicast($objprocess); + } } // goto images list if ($ret[0] and !isXMLRPCError()) { @@ -193,7 +215,9 @@ function resetDefaultMenu($uuid) { } $p->addTab("tabbootmenu", _T("Boot menu", 'imaging'), _T("Current boot menu", "imaging"), "modules/imaging/imaging/bootmenu.php", $params); - $p->addTab("tabimages", _T("Images and Masters", 'imaging'), "", "modules/imaging/imaging/images.php", $params); + $ddd=$params; + $ddd['namee'] = "llllllllll"; + $p->addTab("tabimages", _T("Images and Masters", 'imaging'), "", "modules/imaging/imaging/images.php", $ddd); $p->addTab("tabservices", _T("Boot services", 'imaging'), _T("Available boot menu services", "imaging"), "modules/imaging/imaging/services.php", $params); $p->addTab("tabimlogs", _T("Imaging log", 'imaging'), "", "modules/imaging/imaging/logs.php", $params); $p->addTab("tabconfigure", _T("Menu configuration", 'imaging'), "", "modules/imaging/imaging/configure.php", $params); diff --git a/pulse2/web/modules/imaging/img/imaging.png b/pulse2/web/modules/imaging/img/imaging.png index 859239cb7..2e34f5cfc 100644 Binary files a/pulse2/web/modules/imaging/img/imaging.png and b/pulse2/web/modules/imaging/img/imaging.png differ diff --git a/pulse2/web/modules/imaging/img/imaging_hl.png b/pulse2/web/modules/imaging/img/imaging_hl.png index 56bfc6ad6..2b3f8845b 100644 Binary files a/pulse2/web/modules/imaging/img/imaging_hl.png and b/pulse2/web/modules/imaging/img/imaging_hl.png differ diff --git a/pulse2/web/modules/imaging/img/imaging_select.png b/pulse2/web/modules/imaging/img/imaging_select.png index 04c4a415f..1329ae412 100644 Binary files a/pulse2/web/modules/imaging/img/imaging_select.png and b/pulse2/web/modules/imaging/img/imaging_select.png differ diff --git a/pulse2/web/modules/imaging/includes/xmlrpc.inc.php b/pulse2/web/modules/imaging/includes/xmlrpc.inc.php index 96e7e94fd..8ca73bc05 100644 --- a/pulse2/web/modules/imaging/includes/xmlrpc.inc.php +++ b/pulse2/web/modules/imaging/includes/xmlrpc.inc.php @@ -21,6 +21,47 @@ * You should have received a copy of the GNU General Public License * along with MMC. If not, see . */ + + //check process +function xmlrpc_check_process($process) { + return xmlCall("imaging.check_process", array($process)); +} + +function xmlrpc_imagingServermenuMulticast($obj){ + return xmlCall("imaging.imagingServermenuMulticast", $obj); +} + +function xmlrpc_check_process_multicast ($objprocess){ + // check process running + return xmlCall("imaging.check_process_multicast", array($objprocess)); +} + +function xmlrpc_stop_process_multicast ($objprocess){ + + return xmlCall("imaging.stop_process_multicast", array($objprocess)); +} + +function xmlrpc_checkDeploymentUDPSender ($objprocess){ + // $objprocess idem que pour xmlrpc_imagingServermenuMulticast + return xmlCall("imaging.checkDeploymentUDPSender", array($objprocess)); +} + +function xmlrpc_check_process_multicast_finish ($objprocess){ + return xmlCall("imaging.check_process_multicast_finish", array($objprocess)); +} + +function xmlrpc_start_process_multicast ($objprocess){ + return xmlCall("imaging.start_process_multicast", array($objprocess)); +} + +function xmlrpc_muticast_script_exist ($objprocess){ + return xmlCall("imaging.muticast_script_exist", array($objprocess)); +} + +function xmlrpc_clear_script_multicast ($objprocess){ + return xmlCall("imaging.clear_script_multicast", array($objprocess)); +} + function xmlrpc_isProfileRegistered($profile_uuid) { # we call as long as it's not registered, but once it is, # we can store that information in the session. @@ -38,6 +79,9 @@ function xmlrpc_getProfileLocation($target_uuid) { return xmlCall("imaging.getProfileLocation", array($target_uuid)); } + + + function xmlrpc_getMyMenuProfile($target_uuid) { return xmlCall("imaging.getMyMenuProfile", array($target_uuid)); } @@ -184,6 +228,11 @@ function xmlrpc_moveItemUpInMenu4Location($loc_id, $item_uuid) { return xmlCall("imaging.moveItemUpInMenu4Location", array($loc_id, $item_uuid)); } + +function xmlrpc_setMethod4location($location, $method) { + return xmlCall("imaging.setMethod4location", array($location, $method)); +} + /* Images */ function xmlrpc_imagingServerISOCreate($image_uuid, $size, $title) { diff --git a/pulse2/web/modules/imaging/infoPackage.inc.php b/pulse2/web/modules/imaging/infoPackage.inc.php index 405cc67c1..2c6f55fa8 100644 --- a/pulse2/web/modules/imaging/infoPackage.inc.php +++ b/pulse2/web/modules/imaging/infoPackage.inc.php @@ -49,6 +49,15 @@ $submod->addPage($page); +$page = new Page("multicastaction"); +$page->setFile("modules/imaging/manage/multicastaction.php"); +$submod->addPage($page); + + +$page = new Page("ajaxcheckstatusmulticast"); +$page->setFile("modules/imaging/manage/ajaxcheckstatusmulticast.php"); +$submod->addPage($page); + $page = new Page("index", _T("Server status", "imaging")); $submod->addPage($page); @@ -390,7 +399,11 @@ $page->setFile("modules/imaging/imaging/images_iso.php"); $page->setOptions(array("visible" => False, "noHeader" => True)); $submod->addPage($page); - + $page = new Page("multicast", _T("init multicast", "imaging")); + $page->setFile("modules/imaging/imaging/multicast.php"); + $page->setOptions(array("visible" => False, "noHeader" => True)); + $submod->addPage($page); + unset($submod); } ?> diff --git a/pulse2/web/modules/imaging/manage/ajaxStatus.php b/pulse2/web/modules/imaging/manage/ajaxStatus.php index 27b2239be..93843e176 100644 --- a/pulse2/web/modules/imaging/manage/ajaxStatus.php +++ b/pulse2/web/modules/imaging/manage/ajaxStatus.php @@ -61,11 +61,131 @@

( )

/

- - + + + '; ?> +

+ + '; +echo ' +var locations = "'.$_GET['location'].'";'; +echo 'var path = "'.$path.'";'; +echo 'var scriptmulticast = "'.$scriptmulticast.'";'; +echo' +var interval = setInterval(function() { + var request = jQuery.ajax({ + url: "modules/imaging/manage/ajaxcheckstatusmulticast.php", + type: "GET", + data: {"location" :locations,"path": path,"scriptmulticast" : scriptmulticast} + }); + request.done(function(msg) { + if(msg==1){ jQuery("#checkprocess").hide(); } + }); +},1000); + '; + echo ' +
+
'; + // fichier /tmp/multicast.sh n'existe pas "ne pas afficher cadre Multicast Current Location" + $objprocess['process'] = $scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + // script /tmp/multicast.sh run + // "affichage bouton arrêt" + // voir apres pour bar de progression + echo'

'; + echo _T('STOP Multicast Current Location', 'imaging'); + echo'

'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ' + +
'; + } + else{ + // script arreter afficher bouton start + echo'

'; + echo _T('START Multicast Current Location', 'imaging'); + echo'

'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ' + +
'; + echo "
"; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ' + +
'; + } + echo' +
+
'; +}else{ + $objprocess['process'] = $scriptmulticast; + if (xmlrpc_check_process_multicast($objprocess)){ + // if /tmp/multicast.sh is running then stoping + $objprocess['process'] = $scriptmulticast; + xmlrpc_stop_process_multicast ($objprocess); + $objprocess['process'] = $path.$scriptmulticast; + $gr = xmlrpc_clear_script_multicast($objprocess); + if ($gr != -1) xmlrpc_synchroProfile($gr); + } +} +?> +

diff --git a/pulse2/web/modules/imaging/manage/ajaxcheckstatusmulticast.php b/pulse2/web/modules/imaging/manage/ajaxcheckstatusmulticast.php new file mode 100644 index 000000000..00e04d454 --- /dev/null +++ b/pulse2/web/modules/imaging/manage/ajaxcheckstatusmulticast.php @@ -0,0 +1,47 @@ +. + */ + +require("../../../includes/config.inc.php"); +require("../../../includes/i18n.inc.php"); +require("../../../includes/acl.inc.php"); +require("../../../includes/session.inc.php"); +require("../../../includes/PageGenerator.php"); +require("../includes/includes.php"); +require('../includes/xmlrpc.inc.php'); +require("../../base/includes/edit.inc.php"); +require_once("../../pulse2/includes/locations_xmlrpc.inc.php"); +extract($_GET); +$objprocess=array(); +$objprocess['location']=$location; +$objprocess['process'] = $path.$scriptmulticast; +if( xmlrpc_check_process_multicast_finish($objprocess)){ + $objprocess['process'] = $path.$scriptmulticast; + $gr = xmlrpc_clear_script_multicast($objprocess); + if ($gr != -1) xmlrpc_synchroProfile($gr); + echo "1"; +} +else{ + echo "0"; +} +?> \ No newline at end of file diff --git a/pulse2/web/modules/imaging/manage/localSidebar.php b/pulse2/web/modules/imaging/manage/localSidebar.php index 805cbc741..43b6e0742 100644 --- a/pulse2/web/modules/imaging/manage/localSidebar.php +++ b/pulse2/web/modules/imaging/manage/localSidebar.php @@ -42,7 +42,11 @@ $sidemenu->addSideMenuItem( new SideMenuItem(_T("Imaging Configuration","imaging"), "imaging", "manage", "configuration", "modules/imaging/graph/images/imaging-configuration-active.png", "modules/imaging/graph/images/imaging-configuration-inactive.png") ); - +// $sidemenu->addSideMenuItem( +// new SideMenuItem(_T("Windows Sysprep Answer File","imaging"), "imaging", "manage", "unattended", +// "modules/imaging/graph/images/imaging-configuration-active.png", +// "modules/imaging/graph/images/imaging-configuration-inactive.png") +// ); if (in_array("dyngroup", $_SESSION["modulesList"])) { require("modules/dyngroup/dyngroup/localImagingSidebar.php"); } diff --git a/pulse2/web/modules/imaging/manage/multicastaction.php b/pulse2/web/modules/imaging/manage/multicastaction.php new file mode 100644 index 000000000..49c437260 --- /dev/null +++ b/pulse2/web/modules/imaging/manage/multicastaction.php @@ -0,0 +1,81 @@ +. + */ + +require("modules/imaging/manage/localSidebar.php"); +require("graph/navbar.inc.php"); +require_once('modules/imaging/includes/includes.php'); +require_once('modules/imaging/includes/xmlrpc.inc.php'); +require_once('modules/imaging/includes/web_def.inc.php'); + + + + // fichier /tmp/multicast.sh existe + // multicast lancer "affichage seulement bouton arrêt" voir aprés pour bar de progression + // multicast non lancer "affichage seulement bouton stop" + + // cas extreme + // cas si fichier /tmp/multicast.sh n'existe plus et /tmp/multicast.sh lancer normalement possible + // stoper /tmp/multicast.sh + + // action bouton arret + // 1) stoper /tmp/multicast.sh + // 2) supprimer le fichier /tmp/multicast.sh + // 3) regénéré les menus unicast + + // action bouton marche + // 1) start /tmp/multicast.sh + +extract($_POST); + +$objprocess=array(); +if ( isset($multicast) && + isset($location) && + isset($process)&& + isset($path) && + $location !="" && + $process !=""){ + + $objprocess['location']=$location; + + switch ($multicast) { + case "start": + $objprocess['process'] = $path.$process; + xmlrpc_start_process_multicast($objprocess); + break; + case "stop": + $objprocess['process'] = $process; + xmlrpc_stop_process_multicast($objprocess); + $objprocess['process'] = $path.$process; + $gr = xmlrpc_clear_script_multicast($objprocess); + if ($gr != -1) xmlrpc_synchroProfile($gr); + break; + case "clear": + $objprocess['process'] = $path.$process; + $gr = xmlrpc_clear_script_multicast($objprocess); + if ($gr != -1) xmlrpc_synchroProfile($gr); + break; + } +} + +redirectTo(urlStrRedirect("imaging/manage/index/")); +?> diff --git a/pulse2/web/modules/imaging/manage/save_configuration.php b/pulse2/web/modules/imaging/manage/save_configuration.php index 70838ddd0..e34cc3ba6 100644 --- a/pulse2/web/modules/imaging/manage/save_configuration.php +++ b/pulse2/web/modules/imaging/manage/save_configuration.php @@ -30,7 +30,7 @@ require_once("includes/session.inc.php"); require_once("includes/PageGenerator.php"); require("modules/imaging/includes/includes.php"); -require("modules/imaging/includes/xmlrpc.inc.php"); +require_once("modules/imaging/includes/xmlrpc.inc.php"); $location = getCurrentLocation(); $params = getParams(); diff --git a/pulse2/web/modules/msc/img/navbar/msc.png b/pulse2/web/modules/msc/img/navbar/msc.png index 26d888041..318969eea 100644 Binary files a/pulse2/web/modules/msc/img/navbar/msc.png and b/pulse2/web/modules/msc/img/navbar/msc.png differ diff --git a/pulse2/web/modules/msc/img/navbar/msc_hl.png b/pulse2/web/modules/msc/img/navbar/msc_hl.png index cfe3053fb..93ba9c402 100644 Binary files a/pulse2/web/modules/msc/img/navbar/msc_hl.png and b/pulse2/web/modules/msc/img/navbar/msc_hl.png differ diff --git a/pulse2/web/modules/msc/img/navbar/msc_select.png b/pulse2/web/modules/msc/img/navbar/msc_select.png index 8adf44920..b25103099 100644 Binary files a/pulse2/web/modules/msc/img/navbar/msc_select.png and b/pulse2/web/modules/msc/img/navbar/msc_select.png differ diff --git a/pulse2/web/modules/msc/msc/ajaxPackageFilter.php b/pulse2/web/modules/msc/msc/ajaxPackageFilter.php index d4eaaec97..d62bba81c 100644 --- a/pulse2/web/modules/msc/msc/ajaxPackageFilter.php +++ b/pulse2/web/modules/msc/msc/ajaxPackageFilter.php @@ -45,7 +45,7 @@ $label = new RenderedLabel(3, sprintf(_T('These packages can be installed on group "%s"', 'msc'), $group->getName())); } $label->display(); - +echo "

"; function getConvergenceStatus($mountpoint, $pid, $group_convergence_status, $associateinventory) { $return = 0; if ($associateinventory) { diff --git a/pulse2/web/modules/msc/msc/vnc_client_java.php b/pulse2/web/modules/msc/msc/vnc_client_java.php index 7c1cd198b..6842fee59 100644 --- a/pulse2/web/modules/msc/msc/vnc_client_java.php +++ b/pulse2/web/modules/msc/msc/vnc_client_java.php @@ -35,9 +35,8 @@ echo " - Mandriva Management Console - - + Siveo Pulse +
@@ -46,7 +45,7 @@

"._T("Connection Failed !", "msc") . "


"._T("Connection was refused by the other side.", "msc") . "
- +
@@ -61,7 +60,7 @@ echo " - Mandriva Management Console + Siveo Pulse diff --git a/pulse2/web/modules/msc/msc/vnc_client_no_vnc.php b/pulse2/web/modules/msc/msc/vnc_client_no_vnc.php index 3204f1948..f21557ebc 100644 --- a/pulse2/web/modules/msc/msc/vnc_client_no_vnc.php +++ b/pulse2/web/modules/msc/msc/vnc_client_no_vnc.php @@ -46,7 +46,7 @@ echo " - Mandriva Management Console + Siveo Pulse diff --git a/pulse2/web/modules/pkgs/img/navbar/pkgs.png b/pulse2/web/modules/pkgs/img/navbar/pkgs.png index a80ba2ec7..6609ecf70 100644 Binary files a/pulse2/web/modules/pkgs/img/navbar/pkgs.png and b/pulse2/web/modules/pkgs/img/navbar/pkgs.png differ diff --git a/pulse2/web/modules/pkgs/img/navbar/pkgs_hl.png b/pulse2/web/modules/pkgs/img/navbar/pkgs_hl.png index dd9a74240..2a43347bb 100644 Binary files a/pulse2/web/modules/pkgs/img/navbar/pkgs_hl.png and b/pulse2/web/modules/pkgs/img/navbar/pkgs_hl.png differ diff --git a/pulse2/web/modules/pkgs/img/navbar/pkgs_select.png b/pulse2/web/modules/pkgs/img/navbar/pkgs_select.png index 07c57d434..4b7140455 100644 Binary files a/pulse2/web/modules/pkgs/img/navbar/pkgs_select.png and b/pulse2/web/modules/pkgs/img/navbar/pkgs_select.png differ diff --git a/pulse2/web/modules/pkgs/lib/fileuploader/fileuploader.css b/pulse2/web/modules/pkgs/lib/fileuploader/fileuploader.css index 9f67db4ae..c947d365f 100644 --- a/pulse2/web/modules/pkgs/lib/fileuploader/fileuploader.css +++ b/pulse2/web/modules/pkgs/lib/fileuploader/fileuploader.css @@ -109,7 +109,7 @@ padding: 5px; width: 190px; text-align: center; - background-color: #21449C; + background-color: #2295D2; color: white; cursor: pointer; z-index: 1000; diff --git a/pulse2/web/modules/pkgs/pkgs/ajaxPackageList.php b/pulse2/web/modules/pkgs/pkgs/ajaxPackageList.php index c84a11d5c..9815b08b6 100644 --- a/pulse2/web/modules/pkgs/pkgs/ajaxPackageList.php +++ b/pulse2/web/modules/pkgs/pkgs/ajaxPackageList.php @@ -72,6 +72,7 @@ $params[] = array('p_api' => $_GET['location'], 'pid' => base64_encode($p['id'])); } } +echo "
"; if ($err) { new NotifyWidgetFailure(implode('
', array_merge($err, array(_T("Please contact your administrator.", "pkgs"))))); } diff --git a/pulse2/web/modules/pulse2/includes/menu_group_action.php b/pulse2/web/modules/pulse2/includes/menu_group_action.php index 682d9b859..1251b7d7c 100644 --- a/pulse2/web/modules/pulse2/includes/menu_group_action.php +++ b/pulse2/web/modules/pulse2/includes/menu_group_action.php @@ -51,13 +51,6 @@ if ($is_gp != 1) { // Simple group $actions['displayGroup'] = new ActionItem(_T("Display this group's content", 'dyngroup'), "display", "display", "id", "base", "computers"); - - if (in_array("inventory", $_SESSION["supportModList"])) { - $actions['inventory'] = new ActionItem(_T("Inventory on this group", "dyngroup"),"groupinvtabs","inventory","inventory", "base", "computers"); - } else { - # TODO implement the glpi inventory on groups - # $n->addActionItem(new ActionItem(_T("Inventory on this group", "dyngroup"),"groupglpitabs","inventory","inventory", "base", "computers")); - } $actions['edit'] = new ActionItem(_T("Edit this group", 'dyngroup'), "computersgroupedit", "edit", "id", "base", "computers"); $actions['share'] = new ActionItem(_T("Share this group", 'dyngroup'), "edit_share", "groupshare", "id", "base", "computers"); if (in_array("msc", $_SESSION["supportModList"])) { diff --git a/pulse2/web/modules/update/graph/navbar/update.png b/pulse2/web/modules/update/graph/navbar/update.png index c40f488b1..89d0d2a65 100644 Binary files a/pulse2/web/modules/update/graph/navbar/update.png and b/pulse2/web/modules/update/graph/navbar/update.png differ diff --git a/pulse2/web/modules/update/graph/navbar/update_hl.png b/pulse2/web/modules/update/graph/navbar/update_hl.png index c8824edd9..8533c94e3 100644 Binary files a/pulse2/web/modules/update/graph/navbar/update_hl.png and b/pulse2/web/modules/update/graph/navbar/update_hl.png differ diff --git a/pulse2/web/modules/update/graph/navbar/update_select.png b/pulse2/web/modules/update/graph/navbar/update_select.png index c78c911e6..f0005de40 100644 Binary files a/pulse2/web/modules/update/graph/navbar/update_select.png and b/pulse2/web/modules/update/graph/navbar/update_select.png differ