class PluginsPlugin (SectionPlugin): def init(self): self.title = _('Plugins') self.icon = 'cogs' self.category = '' self.order = 60 # In case you didn't notice it yet, this is the Plugins Plugin Plugin self.append(self.ui.inflate('plugins:main')) def post_plugin_bind(object, collection, item, ui): if not item.crash: ui.find('crash').visible = False def post_dep_bind(object, collection, item, ui): if not item.satisfied(): installer = ui.find('fix') if item.__class__ == ModuleDependency: installer.package = 'python-module-' + item.module_name if item.__class__ == BinaryDependency: installer.package = item.binary_name installer.recheck() self.find('plugins').post_item_bind = post_plugin_bind self.find('dependencies').post_item_bind = post_dep_bind self.binder = Binder(None, self.find('bind-root')) def on_page_load(self): self.context.endpoint.send_progress(_('Gathering plugin list')) self.plugins = sorted(manager.get_all().values()) self.binder.setup(self).populate()
class Netatalk (SectionPlugin): config_path = '/etc/afp.conf' def init(self): self.title = 'Netatalk' self.icon = 'folder-close' self.category = _('Software') self.append(self.ui.inflate('netatalk:main')) if not os.path.exists(self.config_path): open(self.config_path, 'w').write("[Global]") self.binder = Binder(None, self.find('config')) self.find('shares').new_item = lambda c: ShareData() self.config = NetatalkConfig(path=self.config_path) def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def on_save(self): self.binder.update() self.config.save() self.refresh()
class Squid (SectionPlugin): def init(self): self.title = 'Squid' self.icon = 'exchange' self.category = _('Software') self.append(self.ui.inflate('squid:main')) self.find('servicebar').name = platform_select( debian='squid3', centos='squid', default='squid', ) self.find('servicebar').reload() self.binder = Binder(None, self.find('config')) self.find('acl').new_item = lambda c: ACLData(name='new') self.find('http_access').new_item = lambda c: HTTPAccessData() self.find('http_port').new_item = lambda c: HTTPPortData() self.find('https_port').new_item = lambda c: HTTPSPortData() for e in self.nearest(lambda x: x.id == 'options'): e.new_item = lambda c: ArgumentData() self.config = SquidConfig(path='/etc/squid3/squid.conf') def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def on_save(self): self.binder.update() self.config.save() self.refresh()
class Exports (SectionPlugin): config_path = '/etc/exports' def init(self): self.title = _('NFS Exports') self.icon = 'hdd' self.category = _('Software') self.append(self.ui.inflate('exports:main')) if not os.path.exists(self.config_path): open(self.config_path, 'w').close() self.config = ExportsConfig(path=self.config_path) self.binder = Binder(None, self) self.find('exports').new_item = lambda c: ExportData() self.find('clients').new_item = lambda c: ClientData() def on_page_load(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save() self.context.notify('info', _('Saved'))
class Supervisor (SectionPlugin): def init(self): self.title = 'Supervisor' self.icon = 'play' self.category = _('Software') self.append(self.ui.inflate('supervisor:main')) self.mgr = SupervisorServiceManager.get() self.binder = Binder(None, self.find('main')) self.find('programs').new_item = lambda c: ProgramData() self.config = SupervisorConfig(path=platform_select( default='/etc/supervisor/supervisord.conf', centos='/etc/supervisord.conf', )) self.find('servicebar').name = platform_select( centos='supervisord', default='supervisor', ) self.find('servicebar').reload() def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.mgr.fill(self.config.tree.programs) self.binder.setup(self.config.tree).populate() @on('save', 'click') def on_save(self): self.binder.update() self.config.save() self.refresh()
class DHCPDPlugin (SectionPlugin): def init(self): self.title = _('DHCP Server') self.icon = 'sitemap' self.category = _('Software') self.append(self.ui.inflate('dhcpd:main')) self.config = DHCPDConfig(path='/etc/dhcp/dhcpd.conf') self.binder = Binder(None, self) for x in self.nearest(lambda x: x.bind == 'ranges'): x.new_item = lambda c: RangeData() for x in self.nearest(lambda x: x.bind == 'options'): x.new_item = lambda c: OptionData() self.find('subnets').new_item = lambda c: SubnetData() def on_page_load(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save()
class PureFTPDExtension (BaseExtension): default_config = { 'created': False, 'password': None, } name = 'FTP' def init(self): self.append(self.ui.inflate('vh-pureftpd:ext')) self.binder = Binder(self, self) if not 'username' in self.config: self.config['username'] = self.website.slug if not 'system_user' in self.config: self.config['system_user'] = "" if not 'system_group' in self.config: self.config['system_group'] = "" if not self.config['created']: self.config['password'] = str(uuid.uuid4()) self.config['path'] = self.website.root self.config['created'] = True self.refresh() def refresh(self): self.binder.setup().populate() def update(self): self.binder.update()
class VSFTPDExtension (BaseExtension): default_config = { 'created': False, 'user': None, 'password': None, } name = 'FTP' def init(self): self.append(self.ui.inflate('vh-vsftpd:ext')) self.binder = Binder(self, self) self.config['username'] = self.website.slug if not self.config['created']: self.config['password'] = str(uuid.uuid4()) self.config['created'] = True self.refresh() def refresh(self): self.binder.setup().populate() def update(self): pass
class TaskManager (SectionPlugin): def init(self): self.title = _('Processes') self.icon = 'th-list' self.category = _('System') self.append(self.ui.inflate('taskmgr:main')) def post_item_bind(object, collection, item, ui): ui.find('term').on('click', self.on_term, item) ui.find('kill').on('click', self.on_kill, item) self.find('processes').post_item_bind = post_item_bind self.binder = Binder(None, self) self.sorting = '_cpu' self.sorting_reverse = True for x in ['_cpu', 'pid', '_sort_ram', '_sort_name']: self.find('sort-by-' + x).on('click', self.sort, x) def on_page_load(self): self.refresh() def sort(self, by): if self.sorting == by: self.sorting_reverse = not self.sorting_reverse else: self.sorting_reverse = by in ['_cpu', '_ram'] self.sorting = by self.refresh() def refresh(self): self.processes = list(psutil.process_iter()) for p in self.processes: try: p._name = p.name p._cmd = ' '.join(p.cmdline) p._cpu = p.get_cpu_percent(interval=0) p._ram = '%i K' % int(p.get_memory_info()[0] / 1024) p._ppid = p.ppid p._sort_ram = p.get_memory_info()[0] p._sort_name = p.name.lower() try: p._username = p.username except: p._username = '******' except psutil.NoSuchProcess: self.processes.remove(p) self.processes = sorted(self.processes, key=lambda x: getattr(x, self.sorting), reverse=self.sorting_reverse) self.binder.setup(self).populate() def on_term(self, p): os.kill(p.pid, 15) self.refresh() def on_kill(self, p): os.kill(p.pid, 9) self.refresh()
class NSDPlugin (SectionPlugin): def init(self): self.title = 'NSD' self.icon = 'globe' self.category = _('Software') self.append(self.ui.inflate('nsd:main')) self.config = NSDConfig(path='/etc/nsd3/nsd.conf') self.binder = Binder(None, self) self.find('zones').new_item = lambda c: ZoneData() def post_zone_bind(o, c, i, u): path = i.file if not path.startswith('/'): path = '/etc/nsd3/' + path exists = os.path.exists(path) u.find('no-file').visible = not exists u.find('file').visible = exists if exists: u.find('editor').value = open(path).read() def on_save_zone(): open(path, 'w').write(u.find('editor').value) self.context.notify('info', _('Zone saved')) def on_create_zone(): open(path, 'w').write("""$TTL 604800 @ IN SOA ns. root.ns. ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns. example.com. IN A 127.0.0.1 example.com. IN AAAA ::1 """) post_zone_bind(o, c, i, u) u.find('save-zone').on('click', on_save_zone) u.find('create-zone').on('click', on_create_zone) self.find('zones').post_item_bind = post_zone_bind def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save() self.refresh() self.context.notify('info', _('Saved'))
class MySQLExtension (BaseExtension): default_config = { 'created': False, 'name': None, 'user': None, 'password': None, } name = 'MySQL' def init(self): self.append(self.ui.inflate('vh-mysql:ext')) self.binder = Binder(self, self) self.refresh() self.db = MySQLDB.get() @staticmethod def selftest(): try: MySQLDB.get().query_databases() except: pass def refresh(self): self.binder.setup().populate() self.find('db-name').value = self.website.slug def update(self): self.binder.update() def on_destroy(self): if self.config['created']: self.on_delete() @on('create', 'click') def on_create(self): try: self.db.query_databases() except Exception, e: self.context.notify('error', str(e)) self.context.launch('configure-plugin', plugin=self.db) return dbname = self.find('db-name').value for db in self.db.query_databases(): if db.name == dbname: self.context.notify('error', 'This DB name is already used') return self.config['username'] = self.website.slug self.config['password'] = str(uuid.uuid4()) self.config['name'] = dbname try: self.db.query_create(self.config['name']) except Exception, e: self.context.notify('error', str(e)) return
class Filesystems (SectionPlugin): def init(self): self.title = _('Filesystems') self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('fstab:main')) self.find('type').labels = ['Auto', 'EXT2', 'EXT3', 'EXT4', 'NTFS', 'FAT', 'ZFS', 'ReiserFS', 'Samba', 'None', 'Loop'] self.find('type').values = ['auto', 'ext2', 'ext3', 'ext4', 'ntfs', 'vfat', 'zfs', 'reiser', 'smb', 'none', 'loop'] self.fstab_config = FSTabConfig(path='/etc/fstab') self.mounts = MountsBackend.get() self.binder = Binder(None, self) self.find('fstab').find('filesystems').new_item = lambda c: FilesystemData() def post_mount_bind(object, collection, item, ui): ui.find('umount').on('click', self.on_umount, item) self.find('mounts').find('filesystems').post_item_bind = post_mount_bind def on_page_load(self): self.refresh() def on_umount(self, mount): subprocess.call(['umount', mount.mountpoint]) self.context.notify('info', _('Unmounted')) self.refresh() @on('mount-all', 'click') def on_mount_all(self): self.save() if subprocess.call(['mount', '-a']): self.context.notify('error', _('mount -a failed')) self.refresh() @on('refresh', 'click') def refresh(self): self.binder.unpopulate() self.reload_disks() self.fstab_config.load() self.fstab = self.fstab_config.tree self.mounts.reload() self.binder.setup(self).populate() def reload_disks(self): lst = disks.list_devices(by_uuid=True, by_id=True, by_label=True) self.find('device').labels = [x[0] for x in lst] self.find('device').values = [x[1] for x in lst] @on('save', 'click') def save(self): self.binder.update() self.fstab_config.save() self.context.notify('info', _('Saved'))
class SNMPDPlugin (SectionPlugin): service_name = platform_select( default='snmpd', ) def init(self): self.title = 'SNMP' self.icon = 'exchange' self.category = _('Software') self.append(self.ui.inflate('snmpd:main')) self.find('servicebar').name = self.service_name self.find('servicebar').reload() self.snmp_config = SNMPConfig(path=platform_select( default='/etc/snmp/snmp.conf', )) self.binder = Binder(None, self) def on_page_load(self): self.refresh() def refresh(self): self.snmp_config.load() enabled_mibs = [] for mib in self.snmp_config.tree.mibs: for x in mib.name.strip('-+:').split(':'): enabled_mibs.append(x) self.mibs = [] for dirpath, dirname, filenames in os.walk('/usr/share/mibs', followlinks=True): for x in filenames: if not x.startswith('.'): mib = MIBData() mib.name = x mib.selected = x in enabled_mibs self.mibs.append(mib) self.mibs = sorted(self.mibs, key=lambda x: x.name) self.binder.setup(self).populate() @on('save', 'click') def save(self): self.binder.update() mib = MIBData() mib.name = ':'.join([x.name for x in self.mibs if x.selected]) for x in list(self.snmp_config.tree.mibs): self.snmp_config.tree.mibs.remove(x) self.snmp_config.tree.mibs.append(mib) self.snmp_config.save() self.refresh() self.context.notify('info', _('Saved')) ServiceMultiplexor.get().get_one(self.service_name).restart()
class Cron(SectionPlugin): def init(self): self.title = "Cron" self.icon = "time" self.category = _("System") self.append(self.ui.inflate("cron:main")) def create_task(cls): logging.info("[cron] created a %s" % cls.__name__) return cls() def remove_task(i, c): c.remove(i) logging.info("[cron] removed %s" % getattr(i, "command", None)) self.binder = Binder(None, self.find("config")) self.find("normal_tasks").new_item = lambda c: create_task(CrontabNormalTaskData) self.find("special_tasks").new_item = lambda c: create_task(CrontabSpecialTaskData) self.find("env_settings").new_item = lambda c: create_task(CrontabEnvSettingData) self.find("normal_tasks").delete_item = remove_task self.find("special_tasks").delete_item = remove_task self.find("env_settings").delete_item = remove_task self.current_user = "******" def on_page_load(self): self.refresh() @on("user-select", "click") def on_user_select(self): self.current_user = self.find("users").value logging.info("[cron] selected user %s" % self.current_user) self.refresh() def refresh(self): users_select = self.find("users") users_select.value = self.current_user users = [ x.name for x in PasswdConfig(path="/etc/passwd").load().tree.users if int(x.uid) >= 500 or x.name == "root" ] users_select.values = users_select.labels = users self.config = CronManager.get().load_tab(self.current_user) self.binder.setup(self.config.tree).populate() @on("save", "click") def on_save(self): self.binder.update() logging.info("[cron] edited tasks") try: CronManager.get().save_tab(self.current_user, self.config) self.refresh() except Exception, e: self.context.notify("error", e.message)
class NTPDPlugin(SectionPlugin): service_name = platform_select(default="ntp", centos="ntpd") def init(self): self.title = _("Date & Time") self.icon = "time" self.category = _("Software") self.append(self.ui.inflate("ntpd:main")) self.find("servicebar").name = self.service_name self.find("servicebar").reload() self.config = NTPDConfig(path=platform_select(default="/etc/ntp.conf")) self.binder = Binder(None, self) self.find("servers").new_item = lambda c: ServerData() def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.now = int(time.time()) self.binder.setup(self).populate() @on("set", "click") def on_set(self): self.binder.update() d = datetime.fromtimestamp(self.now) s = d.strftime("%m%d%H%M%Y") subprocess.call(["date", s]) self.refresh() @on("sync", "click") def on_sync(self): self.binder.update() if len(self.config.tree.servers) == 0: self.context.notify("error", _("No servers defined")) return server = self.config.tree.servers[0].address output = subprocess.check_output(["ntpdate", "-u", server]) self.context.notify("info", _("Done")) self.context.notify("info", output) self.refresh() @on("save", "click") def save(self): self.binder.update() self.config.save() self.refresh() self.context.notify("info", _("Saved")) ServiceMultiplexor.get().get_one(self.service_name).restart()
class Cron (SectionPlugin): def init(self): self.title = 'Cron' self.icon = 'time' self.category = _('System') self.append(self.ui.inflate('cron:main')) def create_task(cls): logging.info('[cron] created a %s' % cls.__name__) return cls() def remove_task(i, c): c.remove(i) logging.info('[cron] removed %s' % getattr(i, 'command', None)) self.binder = Binder(None, self.find('config')) self.find('normal_tasks').new_item = lambda c: create_task(CrontabNormalTaskData) self.find('special_tasks').new_item = lambda c: create_task(CrontabSpecialTaskData) self.find('env_settings').new_item = lambda c: create_task(CrontabEnvSettingData) self.find('normal_tasks').delete_item = remove_task self.find('special_tasks').delete_item = remove_task self.find('env_settings').delete_item = remove_task self.current_user = '******' def on_page_load(self): self.refresh() @on('user-select', 'click') def on_user_select(self): self.current_user = self.find('users').value logging.info('[cron] selected user %s' % self.current_user) self.refresh() def refresh(self): users_select = self.find('users') users_select.value = self.current_user users = [x.name for x in PasswdConfig(path='/etc/passwd').load().tree.users] users_select.values = users_select.labels = users self.config = CronManager.get().load_tab(self.current_user) self.binder.setup(self.config.tree).populate() @on('save', 'click') def on_save(self): self.binder.update() logging.info('[cron] edited tasks') try: CronManager.get().save_tab(self.current_user, self.config) self.refresh() except Exception as e: self.context.notify('error', e.message)
class LinuxIfUpDownNetworkConfigSet (NetworkConfigBit): cls = 'linux-ifupdown' title = 'Scripts' def init(self): self.append(self.ui.inflate('network:bit-linux-ifupdown')) self.binder = Binder(None, self) def refresh(self): self.binder.setup(self.iface).populate() def apply(self): self.binder.update()
class LinuxDHCPNetworkConfigSet (NetworkConfigBit): cls = 'linux-dhcp' title = 'DHCP' def init(self): self.append(self.ui.inflate('network:bit-linux-dhcp')) self.binder = Binder(None, self) def refresh(self): self.binder.setup(self.iface).populate() def apply(self): self.binder.update()
class Test (SectionPlugin): def init(self): self.title = 'Test' self.icon = 'question' self.category = 'Demo' self.append(self.ui.inflate('test:main')) alice = Person('Alice', [Phone('123')]) bob = Person('Bob', [Phone('234'), Phone('345')]) book = AddressBook([alice, bob]) self.find('persons-collection').new_item = lambda c: Person('New person', []) self.find('phones-collection').new_item = lambda c: Phone('123') self.binder = Binder(None, self.find('addressbook')) self.binder.setup(book).populate()
class RAID (SectionPlugin): def init(self): self.title = 'LSI MegaRAID' self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('megaraid:main')) self.mgr = RAIDManager.get() self.binder = Binder(None, self) def on_page_load(self): self.refresh() def refresh(self): self.mgr.refresh() self.binder.setup(self.mgr).populate()
class Munin (SectionPlugin): def init(self): self.title = 'Munin' self.icon = 'stethoscope' self.category = _('Software') self.append(self.ui.inflate('munin:main')) def post_graph_bind(o, c, i, u): for plot in u.nearest(lambda x: x.typeid == 'munin:plot'): plot.on('widget', self.on_add_widget, i) self.find('graphs').post_item_bind = post_graph_bind self.munin_client = MuninClient.get() self.binder = Binder(None, self) def on_page_load(self): self.refresh() def on_add_widget(self, graph, url=None, period=None): self.context.launch('dashboard-add-widget', cls=MuninWidget, config={'url': url, 'period': period}) def refresh(self): self.munin_client.reset() try: self.munin_client.fetch_domains() except requests.ConnectionError as e: self.find_type('tabs').active = 1 self.context.notify('error', _('Couldn\'t connect to Munin: %s') % e.message) except Exception as e: self.find_type('tabs').active = 1 if e.message == 'auth': self.context.notify('error', _('Munin HTTP authentication failed')) else: raise self.binder.setup(self.munin_client).populate() @on('save-button', 'click') def save(self): self.binder.update() self.munin_client.save_classconfig() self.refresh() self.find_type('tabs').active = 0
class ProcessesExtension (BaseExtension): default_config = { 'processes': [], } name = _('Processes') def init(self): self.append(self.ui.inflate('vh:ext-processes')) self.binder = Binder(self, self) self.find('processes').new_item = lambda c: WebsiteProcess() self.refresh() def refresh(self): self.processes = [WebsiteProcess(x) for x in self.config['processes']] self.binder.setup().populate() def update(self): self.binder.update() self.config['processes'] = [x.save() for x in self.processes]
class Hosts (SectionPlugin): def init(self): self.title = _('Hosts') self.icon = 'sitemap' self.category = _('System') self.append(self.ui.inflate('hosts:main')) self.config = HostsConfig(path='/etc/hosts') self.binder = Binder(None, self.find('hosts-config')) self.find('aliases').new_item = lambda c: AliasData() self.find('hosts').new_item = lambda c: HostData() def on_page_load(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save()
class Services (SectionPlugin): def init(self): self.title = _('Services') self.icon = 'play' self.category = _('Software') self.append(self.ui.inflate('services:main')) self.mgr = ServiceMultiplexor.get() self.binder = Binder(None, self.find('main')) def post_item_bind(object, collection, item, ui): ui.find('stop').on('click', self.on_stop, item) ui.find('restart').on('click', self.on_restart, item) ui.find('start').on('click', self.on_start, item) ui.find('stop').visible = item.running ui.find('restart').visible = item.running ui.find('start').visible = not item.running self.find('services').post_item_bind = post_item_bind def on_page_load(self): self.refresh() def refresh(self): self.services = sorted(self.mgr.get_all(), key=lambda x: x.name) self.binder.setup(self).populate() def on_start(self, item): item.start() self.refresh() self.context.notify('info', _('%s started') % item.name) def on_stop(self, item): item.stop() self.refresh() self.context.notify('info', _('%s stopped') % item.name) def on_restart(self, item): item.restart() self.refresh() self.context.notify('info', _('%s restarted') % item.name)
class PureFTPDExtension(BaseExtension): default_config = {"created": False, "password": None} name = "FTP" def init(self): self.append(self.ui.inflate("vh-pureftpd:ext")) self.binder = Binder(self, self) if not "username" in self.config: self.config["username"] = self.website.slug if not self.config["created"]: self.config["password"] = str(uuid.uuid4()) self.config["created"] = True self.refresh() def refresh(self): self.binder.setup().populate() def update(self): self.binder.update()
class RAID (SectionPlugin): def init(self): self.title = _('RAID') self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('raid:main')) def post_array_bind(o, c, i, u): u.find('recovery').visible = i.recovery self.find('arrays').post_item_bind = post_array_bind self.mgr = RAIDManager.get() self.binder = Binder(None, self) def on_page_load(self): self.refresh() def refresh(self): self.mgr.refresh() self.binder.setup(self.mgr).populate()
class Cron (SectionPlugin): def init(self): self.title = 'Cron' self.icon = 'time' self.category = _('System') self.append(self.ui.inflate('cron:main')) self.binder = Binder(None, self.find('config')) self.find('normal_tasks').new_item = lambda c: CrontabNormalTaskData() self.find('special_tasks').new_item = lambda c: CrontabSpecialTaskData() self.find('env_settings').new_item = lambda c: CrontabEnvSettingData() self.current_user = '******' def on_page_load(self): self.refresh() @on('user-select', 'click') def on_user_select(self): self.current_user = self.find('users').value self.refresh() def refresh(self): users_select = self.find('users') users_select.value = self.current_user users = [x.name for x in PasswdConfig(path='/etc/passwd').load().tree.users if int(x.uid) >= 500 or x.name == 'root'] users_select.values = users_select.labels = users self.config = CronManager.get().load_tab(self.current_user) self.binder.setup(self.config.tree).populate() @on('save', 'click') def on_save(self): self.binder.update() try: CronManager.get().save_tab(self.current_user, self.config) self.refresh() except Exception, e: self.context.notify('error', e.message)
class Resolv (SectionPlugin): def init(self): self.title = _('Nameservers') self.icon = 'globe' self.category = _('System') self.append(self.ui.inflate('resolv:main')) self.find('name-box').labels = [_('DNS nameserver'), _('Local domain name'), _('Search list'), _('Sort list'), _('Options')] self.find('name-box').values = ['nameserver', 'domain', 'search', 'sortlist', 'options'] self.config = ResolvConfig(path='/etc/resolv.conf') self.binder = Binder(None, self.find('resolv-config')) self.find('items').new_item = lambda c: ItemData() def on_page_load(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save()
class CTDB(SectionPlugin): nodes_file = "/etc/ctdb/nodes" addresses_file = "/etc/ctdb/public_addresses" def init(self): self.title = _("Samba Cluster") self.icon = "folder-close" self.category = _("Software") self.append(self.ui.inflate("ctdb:main")) self.config_path = {"debian": "/etc/default/ctdb", "centos": "/etc/sysconfig/ctdb"}[ajenti.platform] self.config = CTDBConfig(path=self.config_path) self.config.load() self.binder = Binder(None, self.find("main-config")) self.n_binder = Binder(None, self.find("nodes-config")) self.a_binder = Binder(None, self.find("addresses-config")) self.find("nodes").new_item = lambda c: NodeData() self.find("addresses").new_item = lambda c: PublicAddressData() def on_page_load(self): n_path = self.config.tree.nodes_file self.nodes_config = CTDBNodesConfig(path=n_path) if not os.path.exists(n_path): open(n_path, "w").close() self.nodes_config.load() a_path = self.config.tree.public_addresses_file self.addresses_config = CTDBPublicAddressesConfig(path=a_path) if not os.path.exists(a_path): open(a_path, "w").close() self.addresses_config.load() self.config.load() self.binder.setup(self.config.tree).populate() self.n_binder.setup(self.nodes_config.tree).populate() self.a_binder.setup(self.addresses_config.tree).populate() self.refresh() @on("refresh", "click") def refresh(self): try: self.find("status").value = subprocess.check_output(["ctdb", "status"]) self.find("status-ip").value = subprocess.check_output(["ctdb", "ip"]) except: self.find("status").value = _("Failed to obtain CTDB status") @on("save", "click") def save(self): self.binder.update() self.n_binder.update() self.a_binder.update() self.config.save() self.nodes_config.save() self.addresses_config.save() self.context.notify("info", _("Saved"))
class Samba(SectionPlugin): def init(self): self.title = 'Samba' self.icon = 'folder-close' self.category = _('Software') self.append(self.ui.inflate('samba:main')) self.find('servicebar').name = platform_select( debian='samba', ubuntu='smbd', mageia='smbd', centos='smb', default='samba', ) self.find('servicebar').reload() self.binder = Binder(None, self.find('config')) self.find('shares').new_item = lambda c: ShareData() self.config = SambaConfig(path=platform_select( default='/etc/samba/smb.conf', freebsd='/usr/local/etc/smb.conf', )) def post_item_bind(object, collection, item, ui): ui.find('disconnect').on('click', self.on_disconnect, item) self.find('connections').post_item_bind = post_item_bind def post_user_bind(object, collection, item, ui): def delete_user(): self.usermgr.delete(item.username) self.refresh() ui.find('delete').on('click', delete_user) def set_password(): if self.usermgr.set_password(item.username, ui.find('password').value): self.context.notify('info', _('Password updated')) ui.find('password').value = '' else: self.context.notify('error', _('Password update failed')) ui.find('password-set').on('click', set_password) self.find('user-list').post_item_bind = post_user_bind self.usermgr = SambaUsers() self.binder_u = Binder(self.usermgr, self.find('users')) self.monitor = SambaMonitor() self.binder_m = Binder(self.monitor, self.find('status')) def on_page_load(self): self.refresh() def on_disconnect(self, connection): connection.disconnect() self.refresh() def refresh(self): self.config.load() self.monitor.refresh() self.usermgr.load() self.binder.setup(self.config.tree).populate() self.binder_m.setup(self.monitor).populate() self.binder_u.setup(self.usermgr).populate() users_dropdown = self.find('add-user-list') users = [ x.name for x in PasswdConfig(path='/etc/passwd').load().tree.users ] for u in self.usermgr.users: if u.username in users: users.remove(u.username) users_dropdown.values = users_dropdown.labels = users @on('add-user', 'click') def on_add_user(self): self.usermgr.create(self.find('add-user-list').value) self.refresh() @on('save', 'click') def on_save(self): self.binder.update() self.config.save() self.refresh()
class NSDPlugin(SectionPlugin): def init(self): self.title = 'NSD' self.icon = 'globe' self.category = _('Software') self.append(self.ui.inflate('nsd:main')) self.config = NSDConfig(path='/etc/nsd3/nsd.conf') self.binder = Binder(None, self) self.find('zones').new_item = lambda c: ZoneData() def post_zone_bind(o, c, i, u): path = i.file if not path.startswith('/'): path = '/etc/nsd3/' + path exists = os.path.exists(path) u.find('no-file').visible = not exists u.find('file').visible = exists if exists: u.find('editor').value = open(path).read() def on_save_zone(): open(path, 'w').write(u.find('editor').value) self.context.notify('info', _('Zone saved')) def on_create_zone(): open(path, 'w').write("""$TTL 604800 @ IN SOA ns. root.ns. ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns. example.com. IN A 127.0.0.1 example.com. IN AAAA ::1 """) post_zone_bind(o, c, i, u) u.find('save-zone').on('click', on_save_zone) u.find('create-zone').on('click', on_create_zone) self.find('zones').post_item_bind = post_zone_bind def on_page_load(self): self.refresh() def refresh(self): if not os.path.exists(self.config.origin): self.context.notify('error', _('%s does not exist') % self.config.origin) return self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save() self.refresh() self.context.notify('info', _('Saved'))
class CTDB(SectionPlugin): nodes_file = '/etc/ctdb/nodes' addresses_file = '/etc/ctdb/public_addresses' def init(self): self.title = _('Samba Cluster') self.icon = 'folder-close' self.category = _('Software') self.append(self.ui.inflate('ctdb:main')) self.config_path = { 'debian': '/etc/default/ctdb', 'centos': '/etc/sysconfig/ctdb' }[ajenti.platform] self.config = CTDBConfig(path=self.config_path) self.config.load() self.binder = Binder(None, self.find('main-config')) self.n_binder = Binder(None, self.find('nodes-config')) self.a_binder = Binder(None, self.find('addresses-config')) self.find('nodes').new_item = lambda c: NodeData() self.find('addresses').new_item = lambda c: PublicAddressData() def on_page_load(self): n_path = self.config.tree.nodes_file self.nodes_config = CTDBNodesConfig(path=n_path) if not os.path.exists(n_path): open(n_path, 'w').close() self.nodes_config.load() a_path = self.config.tree.public_addresses_file self.addresses_config = CTDBPublicAddressesConfig(path=a_path) if not os.path.exists(a_path): open(a_path, 'w').close() self.addresses_config.load() self.config.load() self.binder.setup(self.config.tree).populate() self.n_binder.setup(self.nodes_config.tree).populate() self.a_binder.setup(self.addresses_config.tree).populate() self.refresh() @on('refresh', 'click') def refresh(self): try: self.find('status').value = subprocess.check_output( ['ctdb', 'status']) self.find('status-ip').value = subprocess.check_output( ['ctdb', 'ip']) except: self.find('status').value = _('Failed to obtain CTDB status') @on('save', 'click') def save(self): self.binder.update() self.n_binder.update() self.a_binder.update() self.config.save() self.nodes_config.save() self.addresses_config.save() self.context.notify('info', _('Saved'))
class NetworkPlugin (SectionPlugin): platforms = ['debian', 'centos', 'mageia'] def init(self): self.title = _('Network') self.icon = 'globe' self.category = _('System') self.net_config = INetworkConfig.get() self.append(self.ui.inflate('network:main')) def post_interface_bind(o, c, i, u): i.add_bits(self.ui) for bit in i.bits: u.find('bits').append(self.ui.create( 'tab', children=[bit], title=bit.title, )) u.find('up').on('click', self.on_up, i) u.find('down').on('click', self.on_down, i) u.find('restart').on('click', self.on_restart, i) u.find('ip').text = self.net_config.get_ip(i) def post_interface_update(o, c, i, u): for bit in i.bits: bit.apply() self.find('interfaces').post_item_bind = post_interface_bind self.find('interfaces').post_item_update = post_interface_update self.binder = Binder(None, self) def on_page_load(self): self.refresh() def refresh(self): self.net_config.rescan() sensor = Sensor.find('traffic') for i in self.net_config.interface_list: i.tx, i.rx = sensor.value(i.name) self.binder.setup(self.net_config).populate() return def on_up(self, iface=None): self.save() self.net_config.up(iface) self.refresh() def on_down(self, iface=None): self.save() self.net_config.down(iface) self.refresh() def on_restart(self, iface=None): self.save() self.on_down(iface) self.on_up(iface) @on('save', 'click') def save(self): self.binder.update() self.net_config.save() self.refresh() self.context.notify('info', _('Saved'))
class WebsitesWebsiteEditorPlugin(SectionPlugin): uses_access_permission_of = WebsitesPlugin def init(self): self.title = 'Website editor' self.icon = 'globe' self.category = 'Web' self.order = 2 self.hidden = True self.manager = VHManager.get() self.binder = Binder(None, self) self.append(self.ui.inflate('vh:main-website')) self.find( 'domains').new_item = lambda c: WebsiteDomain.create('example.com') self.find('ports').new_item = lambda c: WebsitePort.create(80) def post_location_bind(object, collection, item, ui): ui.find('backend-params').empty() ui.find('backend-params').append( self.ui.inflate('vh:main-backend-params-%s' % item.backend.type)) item.backend.__binder = Binder(item.backend, ui.find('backend-params')) item.backend.__binder.populate() def post_location_update(object, collection, item, ui): item.backend.__binder.update() self.find('locations').post_item_bind = post_location_bind self.find('locations').post_item_update = post_location_update self.find('create-location-type').labels = [] self.find('create-location-type').values = [] for g in sorted(ApplicationGatewayComponent.get_classes(), key=lambda x: x.title): self.find('create-location-type').labels.append(g.title) self.find('create-location-type').values.append(g.id) @intent('v:manage-website') def on_launch(self, website=None): self.activate() self.website = website self.binder.setup(self.website) self.binder.populate() for ext in BaseExtension.get_classes(): ext.selftest() extensions = BaseExtension.get_classes() def create_location(): self.binder.update() t = self.find('create-location-type').value l = WebsiteLocation.create(self.website, template=t) l.backend.type = t self.website.locations.append(l) self.refresh() self.find('create-location').on('click', create_location) # Extensions for tab in list(self.find('tabs').children): if hasattr(tab, '-is-extension'): tab.delete() self.website.extensions = [] for ext in extensions: ext = ext.new(self.ui, self.website, config=self.website.extension_configs.get( ext.classname, None)) ext.editor_ui = self ext._ui_container = self.ui.create('tab', children=[ext], title=ext.name) setattr(ext._ui_container, '-is-extension', True) self.website.extensions.append(ext) self.find('tabs').append(ext._ui_container) # Root creator self.find('root-not-created').visible = not os.path.exists( self.website.root) def create_root(): self.binder.update() if not os.path.exists(self.website.root): os.makedirs(self.website.root) subprocess.call(['chown', '-R', 'www-data:', self.website.root]) self.save() self.find('create-root-directory').on('click', create_root) self.find('fix-root-permissions').on('click', create_root) self.find('set-path').on('click', self.save) # Downloader def download(): url = self.find('download-url').value self.save() tmppath = '/tmp/ajenti-v-download' script = 'wget "%s" -O "%s" ' % (url, tmppath) if url.lower().endswith( ('tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2')): script += '&& tar xf "%s" -C "%s"' % (tmppath, self.website.root) elif url.lower().endswith('.rar'): script += '&& unrar x "%s" "%s"' % (tmppath, self.website.root) elif url.lower().endswith('.zip'): script += '&& unzip "%s" -d "%s"' % (tmppath, self.website.root) script += ' && chown www-data: -R "%s"' % self.website.root script += ' && find "%s" -type d -exec chmod 775 {} ";"' % self.website.root script += ' && find "%s" -type f -exec chmod 644 {} ";"' % self.website.root def callback(): self.save() self.activate() if os.path.exists(tmppath): os.unlink(tmppath) self.context.notify('info', _('Download complete')) self.context.launch('terminal', command=script, callback=callback) self.find('download').on('click', download) @on('go-back', 'click') def on_go_back(self): WebsitesPlugin.get().activate() @on('destroy', 'click') def on_destroy(self): for ext in self.website.extensions: try: ext.on_destroy() except Exception, e: logging.error(str(e)) self.manager.config.websites.remove(self.website) self.save() self.on_go_back()
class ScriptInstaller(BaseExtension): default_config = { 'databases': [], 'users': [], } name = 'Script Installer' def init(self): self.append(self.ui.inflate('vh-script-installer:main')) self.binder = Binder(self, self) self.refresh() self.db = MySQLDB.get() @staticmethod def selftest(): try: MySQLDB.get().query_databases() except: pass def refresh(self): if not 'databases' in self.config: if self.config['created']: self.config['databases'] = [{ 'name': self.config['name'], }] self.config['users'] = [{ 'name': self.config['user'], 'password': self.config['password'], }] else: self.config['databases'] = [] self.config['users'] = [] del self.config['created'] del self.config['name'] del self.config['user'] del self.config['password'] self.binder.setup().populate() self.find('wp-path').value = self.website.root self.find('wp-db-name').value = self.website.slug + '_wp' self.find('wp-db-user').value = self.website.slug + '_wp' self.find('wp-db-pass').value = str(uuid.uuid4()) self.find('wp-db-name').delete_item = lambda i, c: self.on_delete_db(i) self.find( 'wp-db-user').delete_item = lambda i, c: self.on_delete_user(i) def update(self): self.binder.update() def on_destroy(self): pass @on('wp-install', 'click') def on_install_wp(self): # Define User, Pass and DB Name db_user = self.find('wp-db-user').value db_pass = self.find('wp-db-pass').value db_name = self.find('wp-db-name').value # Download Latest Wordpress url = 'http://wordpress.org/latest.tar.gz' tmpfile = '/tmp/wp.tar.gz' with open(tmpfile, 'wb') as f: f.write( urllib2.urlopen('http://wordpress.org/latest.tar.gz').read()) f.close() with closing(tarfile.open('/tmp/wp.tar.gz', 'r')) as tar: tar.extractall(path="/tmp/wp") for f in os.listdir('/tmp/wp/wordpress/'): src = '/tmp/wp/wordpress/' + f dst = self.website.root + '/' + f shutil.move(src, dst) if os.path.isfile(tmpfile): os.remove(tmpfile) if os.path.exists("/tmp/wp"): shutil.rmtree("/tmp/wp") self.context.notify('info', _('Wordpress Downloaded !')) # Generate Databases self.generate_db(db_name, db_user, db_pass) # Configure Wordpress config_string = "" if os.path.isfile(self.website.root + '/wp-config-sample.php'): if not os.path.isfile(self.website.root + '/wp-config.php'): salt = urllib2.urlopen( 'https://api.wordpress.org/secret-key/1.1/salt/').read() with open(self.website.root + '/wp-config-sample.php', 'r') as sample_file: config_string = sample_file.read() config_string = config_string.replace( """define('AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', 'put your unique phrase here'); define('NONCE_KEY', 'put your unique phrase here'); define('AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', 'put your unique phrase here'); define('NONCE_SALT', 'put your unique phrase here');""", salt) config_string = config_string.replace( 'database_name_here', db_name) config_string = config_string.replace( 'username_here', db_user) config_string = config_string.replace( 'password_here', db_pass) sample_file.close() with open(self.website.root + '/wp-config.php', 'wb') as wp_config: wp_config.write(config_string) wp_config.close() else: self.context.notify('error', _('Config file already exists!')) return else: self.context.notify('error', _('File wp-config-sample.php\nNot Found!')) return self.context.notify('info', _('Wordpress Installed !')) self.refresh() self.try_save() def generate_db(self, db_name, db_user, db_pass): # Create Database try: self.db.query_databases() except Exception, e: self.context.notify('error', str(e)) self.context.launch('configure-plugin', plugin=self.db) return dbname = db_name for db in self.db.query_databases(): if db.name == dbname: self.context.notify('error', _('This database name is already used')) return db_cfg = {'name': dbname} try: self.db.query_create(db_cfg['name']) except Exception, e: self.context.notify('error', str(e)) return
class TaskManager(SectionPlugin): def init(self): self.title = _('Processes') self.icon = 'th-list' self.category = _('System') self.append(self.ui.inflate('taskmgr:main')) def post_item_bind(object, collection, item, ui): ui.find('term').on('click', self.on_term, item) ui.find('kill').on('click', self.on_kill, item) self.find('processes').post_item_bind = post_item_bind self.binder = Binder(None, self) self.sorting = '_cpu' self.sorting_reverse = True for x in ['_cpu', 'pid', '_sort_ram', '_sort_name']: self.find('sort-by-' + x).on('click', self.sort, x) def on_page_load(self): self.refresh() def sort(self, by): if self.sorting == by: self.sorting_reverse = not self.sorting_reverse else: self.sorting_reverse = by in ['_cpu', '_ram'] self.sorting = by self.refresh() def refresh(self): self.processes = list(psutil.process_iter()) for p in self.processes: try: p._name = get(p.name) p._cmd = ' '.join(get(p.cmdline)) p._cpu = p.get_cpu_percent(interval=0) p._ram = '%i K' % int(p.get_memory_info()[0] / 1024) p._ppid = get(p.ppid) p._sort_ram = p.get_memory_info()[0] p._sort_name = get(p.name).lower() try: p._username = get(p.username) except: p._username = '******' except psutil.NoSuchProcess: self.processes.remove(p) self.processes = sorted(self.processes, key=lambda x: getattr(x, self.sorting, None), reverse=self.sorting_reverse) self.binder.setup(self).populate() def on_term(self, p): os.kill(p.pid, 15) self.refresh() def on_kill(self, p): os.kill(p.pid, 9) self.refresh()
class MailPlugin (SectionPlugin): def init(self): self.title = _('Mail') self.icon = 'envelope' self.category = 'Web' self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate('vh-mail:not-configured')) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh-mail:main')) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find('size').text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find('password').value: item.password = ui.find('password').value self.find('mailboxes').post_item_bind = post_mb_bind self.find('mailboxes').post_item_update = post_mb_update self.find('mailboxes').filter = \ lambda mb: self.context.session.identity in ['root', mb.owner] self.find('targets').new_item = lambda c: ForwardingTarget.create() self.binder.setup(self.manager.config) def _fetch_new_mailbox_name(self, cls): mb = cls.create() mb.local = self.find('new-mailbox-local').value mb.domain = self.find('new-mailbox-domain').value or \ self.find('new-mailbox-domain-custom').value if not mb.local: self.context.notify('error', _('Invalid mailbox name')) return if not mb.domain: self.context.notify('error', _('Invalid mailbox domain')) return if cls == ForwardingMailbox: for existing in self.manager.config.forwarding_mailboxes: if existing.name == mb.name: self.context.notify( 'error', _('This address is already taken') ) return else: for existing in self.manager.config.mailboxes: if existing.name == mb.name: self.context.notify( 'error', _('This address is already taken') ) return self.find('new-mailbox-local').value = '' return mb @on('new-mailbox', 'click') def on_new_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(Mailbox) if not mb: return mb.owner = self.context.session.identity mb.password = '' self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() @on('new-forwarding-mailbox', 'click') def on_new_forwarding_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(ForwardingMailbox) if not mb: return mb.owner = self.context.session.identity self.manager.config.forwarding_mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if not self.manager.is_configured: return domains = [] for ws in VHManager.get().config.websites: if self.context.session.identity in ['root', ws.owner]: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) if self.find('new-mailbox-domain'): self.find('new-mailbox-domain').labels = \ domains + [_('Custom domain')] self.find('new-mailbox-domain').values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() if os.path.exists(self.manager.config.dkim_private_key): pubkey = subprocess.check_output([ 'openssl', 'rsa', '-in', self.manager.config.dkim_private_key, '-pubout' ]) pubkey = filter(None, pubkey.split('-'))[1].replace('\n', '') dns = '@\t\t\t\t10800 IN TXT "v=spf1 a -all"\n' dns += '_domainkey\t\t10800 IN TXT "o=~; r=postmaster@<domain>"\n' dns += '%s._domainkey\t10800 IN TXT "v=DKIM1; k=rsa; p=%s"\n' % ( self.manager.config.dkim_selector, pubkey ) dns += '_dmarc\t\t\t10800 IN TXT "v=DMARC1; p=quarantine"\n' self.find('dkim-domain-entry').value = dns else: self.find('dkim-domain-entry').value = _('No valid key exists') @on('generate-dkim-key', 'click') def on_generate_dkim_key(self): self.binder.update() self.manager.generate_dkim_key() self.binder.populate() self.save() @on('generate-tls-cert', 'click') def on_generate_tls_cert(self): self.binder.update() self.manager.generate_tls_cert() self.binder.populate() self.save() @on('save', 'click') def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify('info', _('Saved'))
class Configurator(SectionPlugin): def init(self): self.title = _('Configure') self.icon = 'wrench' self.category = '' self.order = 50 self.append(self.ui.inflate('configurator:main')) self.binder = Binder(ajenti.config.tree, self.find('ajenti-config')) self.ccmgr = ClassConfigManager.get() self.classconfig_binding = Binder(self.ccmgr, self.find('classconfigs')) def post_classconfig_bind(object, collection, item, ui): def configure(): self.configure_plugin(item, notify=False) ui.find('configure').on('click', configure) self.find('classconfigs').find( 'classes').post_item_bind = post_classconfig_bind self.find('users').new_item = lambda c: UserData() def post_user_bind(object, collection, item, ui): provider = UserManager.get(manager.context).get_sync_provider() editable = item.name != 'root' renameable = editable and provider.allows_renaming deletable = renameable ui.find('name-edit').visible = renameable ui.find('name-label').visible = not renameable ui.find('delete').visible = deletable box = ui.find('permissions') box.empty() p = PermissionProvider.get_all() for prov in p: line = self.ui.create('tab', title=prov.get_name()) box.append(line) for perm in prov.get_permissions(): line.append( self.ui.create('checkbox', id=perm[0], text=perm[1], value=(perm[0] in item.permissions))) def copy(): self.save() newuser = deepcopy(item) newuser.name += '_' collection[newuser.name] = newuser self.refresh() ui.find('copy').on('click', copy) self.find('users').post_item_bind = post_user_bind def post_user_update(object, collection, item, ui): box = ui.find('permissions') for prov in PermissionProvider.get_all(): for perm in prov.get_permissions(): has = box.find(perm[0]).value if has and not perm[0] in item.permissions: item.permissions.append(perm[0]) if not has and perm[0] in item.permissions: item.permissions.remove(perm[0]) if ui.find('password').value: item.password = ui.find('password').value self.find('users').post_item_update = post_user_update def on_page_load(self): self.refresh() @on('sync-users-button', 'click') def on_sync_users(self): self.save() prov = UserManager.get(manager.context).get_sync_provider() try: prov.test() prov.sync() except Exception as e: self.context.notify('error', str(e)) self.refresh() @on('configure-sync-button', 'click') def on_configure_sync(self): self.save() self.configure_plugin(UserManager.get( manager.context).get_sync_provider(), notify=False) self.refresh() def refresh(self): self.binder.unpopulate() self.find('sync-providers').labels = [ x.title for x in UserSyncProvider.get_classes() ] self.find('sync-providers').values = [ x.id for x in UserSyncProvider.get_classes() ] provider = UserManager.get(manager.context).get_sync_provider() self.find('sync-providers').value = provider.id self.find('add-user-button').visible = provider.id == '' self.find('sync-users-button').visible = provider.id != '' self.find('password').visible = provider.id == '' self.find('configure-sync-button' ).visible = provider.classconfig_editor is not None try: provider.test() sync_ok = True except Exception as e: self.context.notify('error', str(e)) sync_ok = False self.find('sync-status-ok').visible = sync_ok self.find('sync-status-fail').visible = not sync_ok languages = sorted(ajenti.locales.list_locales()) self.find('language').labels = [_('Auto'), 'en_US'] + languages self.find('language').values = ['', 'en_US'] + languages self.binder.setup().populate() self.ccmgr.reload() self.classconfig_binding.setup().populate() @on('save-button', 'click') @restrict('configurator:configure') def save(self): self.binder.update() UserManager.get(manager.context).set_sync_provider( self.find('sync-providers').value) for user in ajenti.config.tree.users.values(): if not '|' in user.password: user.password = UserManager.get(manager.context).hash_password( user.password) self.refresh() ajenti.config.save() self.context.notify( 'info', _('Saved. Please restart Ajenti for changes to take effect.')) @on('fake-ssl', 'click') def on_gen_ssl(self): host = self.find('fake-ssl-host').value if host == '': self.context.notify('error', _('Please supply hostname')) else: self.gen_ssl(host) @on('restart-button', 'click') def on_restart(self): ajenti.restart() @intent('configure-plugin') def configure_plugin(self, plugin=None, notify=True): self.find('tabs').active = 1 self.refresh() if plugin and notify: self.context.notify( 'info', _('Please configure %s plugin!') % plugin.classconfig_editor.title) self.activate() dialog = self.find('classconfigs').find('dialog') dialog.find('container').empty() dialog.visible = True editor = plugin.classconfig_editor.new(self.ui) dialog.find('container').append(editor) binder = DictAutoBinding(plugin, 'classconfig', editor.find('bind')) binder.populate() def save(button=None): dialog.visible = False binder.update() plugin.save_classconfig() self.save() dialog.on('button', save) @intent('setup-fake-ssl') def gen_ssl(self, host): self.save() subprocess.call(['ajenti-ssl-gen', host, '-f']) ajenti.config.load() self.refresh()
class BIND9Plugin(SectionPlugin): config_root = platform_select( debian='/etc/bind/', centos='/etc/named/', ) config_path = platform_select( debian='/etc/bind/named.conf', centos='/etc/named.conf', ) def init(self): self.title = 'BIND9' self.icon = 'globe' self.category = _('Software') self.append(self.ui.inflate('bind9:main')) self.config = BIND9Config(path=self.config_path) self.binder = Binder(None, self) self.find('zones').new_item = lambda c: ZoneData() def post_zone_bind(o, c, i, u): path = i.file if path is not None: if not path.startswith('/'): path = self.config_root + path exists = os.path.exists(path) else: exists = False u.find('no-file').visible = not exists u.find('file').visible = exists if exists: u.find('editor').value = open(path).read() def on_save_zone(): open(path, 'w').write(u.find('editor').value) self.context.notify('info', _('Zone saved')) def on_create_zone(): open(path, 'w').write("""$TTL 604800 @ IN SOA ns. root.ns. ( 1 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS ns. example.com. IN A 127.0.0.1 example.com. IN AAAA ::1 """) post_zone_bind(o, c, i, u) u.find('save-zone').on('click', on_save_zone) u.find('create-zone').on('click', on_create_zone) self.find('zones').post_item_bind = post_zone_bind def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.binder.setup(self.config.tree).populate() @on('save', 'click') def save(self): self.binder.update() self.config.save() self.refresh() self.context.notify('info', _('Saved'))
class Users(SectionPlugin): def init(self): self.title = _('Users') self.icon = 'group' self.category = _('System') self.append(self.ui.inflate('users:main')) def _filterOnlyUsers(x): u = int(x.uid) return u >= 500 def _filterOnlySystemUsers(x): u = int(x.uid) return u < 500 def _sorter(x): g = int(x.gid) if g >= 500: return g - 10000 return g self.find('users').filter = _filterOnlyUsers self.find('system-users').filter = _filterOnlySystemUsers self.find('groups').sorting = _sorter self.config = PasswdConfig(path='/etc/passwd') self.config_g = GroupConfig(path='/etc/group') self.binder = Binder(None, self.find('passwd-config')) self.binder_system = Binder(None, self.find('passwd-config-system')) self.binder_g = Binder(None, self.find('group-config')) self.mgr = UsersBackend.get() def post_item_bind(object, collection, item, ui): ui.find('change-password').on('click', self.change_password, item, ui) ui.find('remove-password').on('click', self.remove_password, item) if not os.path.exists(item.home): ui.find('create-home-dir').on('click', self.create_home_dir, item, ui) ui.find('create-home-dir').visible = True self.find('users').post_item_bind = post_item_bind self.find('system-users').post_item_bind = post_item_bind def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.config_g.load() self.binder.setup(self.config.tree).populate() self.binder_system.setup(self.config.tree).populate() self.binder_g.setup(self.config_g.tree) self.find('group-members').labels = self.find( 'group-members').values = [x.name for x in self.config.tree.users] self.binder_g.populate() @on('add-user', 'click') def on_add_user(self): self.find('input-username').visible = True @on('input-username', 'submit') def on_add_user_done(self, value): self.mgr.add_user(value) self.refresh() @on('add-group', 'click') def on_add_group(self): self.find('input-groupname').visible = True @on('input-groupname', 'submit') def on_add_group_done(self, value): self.mgr.add_group(value) self.refresh() @on('save-users', 'click') def save_users(self): self.binder.update() self.config.save() @on('save-system-users', 'click') def save_system_users(self): self.binder_system.update() self.config.save() @on('save-groups', 'click') def save_groups(self): self.binder_g.update() self.config_g.save() def create_home_dir(self, user, ui): self.mgr.make_home_dir(user) self.context.notify('info', _('Home dir for %s was created') % user.name) ui.find('create-home-dir').visible = False def change_password(self, user, ui): new_password = ui.find('new-password').value if new_password: try: self.mgr.change_password(user, new_password) self.context.notify( 'info', _('Password for %s was changed') % user.name) ui.find('new-password').value = '' except Exception, e: self.context.notify('error', _('Error: "%s"') % e.message) else:
class FileManager (SectionPlugin): default_classconfig = {'root': '/', 'start': '/'} classconfig_editor = FileManagerConfigEditor classconfig_root = True def init(self): self.title = _('Файлов мениджър') self.category = _('Tools') self.icon = 'folder-open' self.backend = FMBackend().get() self.append(self.ui.inflate('fm:main')) self.controller = Controller() def post_item_bind(object, collection, item, ui): ui.find('name').on('click', self.on_item_click, object, item) ui.find('edit').on('click', self.edit, item.fullpath) self.find('items').post_item_bind = post_item_bind def post_bc_bind(object, collection, item, ui): ui.find('name').on('click', self.on_bc_click, object, item) self.find('breadcrumbs').post_item_bind = post_bc_bind self.clipboard = [] self.tabs = self.find('tabs') def on_first_page_load(self): self.new_tab() self.binder = Binder(self.controller, self.find('filemanager')).populate() self.binder_c = Binder(self, self.find('bind-clipboard')).populate() def on_page_load(self): self.refresh() def refresh_clipboard(self): self.binder_c.setup().populate() @on('tabs', 'switch') def on_tab_switch(self): if self.tabs.active == (len(self.controller.tabs) - 1): self.new_tab() self.refresh() @intent('fm:browse') def new_tab(self, path=None): dir = path or self.classconfig.get('start', None) or '/' if not dir.startswith(self.classconfig['root']): dir = self.classconfig['root'] self.controller.new_tab(dir) if not self.active: self.activate() @on('close', 'click') def on_tab_close(self): if len(self.controller.tabs) > 2: self.controller.tabs.pop(self.tabs.active) self.tabs.active = 0 self.refresh() @on('new-file', 'click') def on_new_file(self): destination = self.controller.tabs[self.tabs.active].path logging.info('[fm] new file in %s' % destination) path = os.path.join(destination, 'new file') try: open(path, 'w').close() self._chown_new(path) except OSError as e: self.context.notify('error', str(e)) self.refresh() @on('new-dir', 'click') def on_new_directory(self): destination = self.controller.tabs[self.tabs.active].path logging.info('[fm] new directory in %s' % destination) path = os.path.join(destination, 'new directory') if not os.path.exists(path): try: os.mkdir(path) os.chmod(path, 0755) self._chown_new(path) except OSError as e: self.context.notify('error', str(e)) self.refresh() def _chown_new(self, path): uid = self.classconfig.get('new_owner', 'root') or 'root' gid = self.classconfig.get('new_group', 'root') or 'root' try: uid = int(uid) except: uid = pwd.getpwnam(uid)[2] try: gid = int(gid) except: gid = grp.getgrnam(gid)[2] os.chown(path, uid, gid) def upload(self, name, file): destination = self.controller.tabs[self.tabs.active].path logging.info('[fm] uploading %s to %s' % (name, destination)) try: output = open(os.path.join(destination, name), 'w') while True: data = file.read(1024 * 1024) if not data: break gevent.sleep(0) output.write(data) output.close() except OSError as e: self.context.notify('error', str(e)) self.refresh() @on('mass-cut', 'click') def on_cut(self): l = self._get_checked() for i in l: i.action = 'cut' self.clipboard += l self.refresh_clipboard() @on('mass-copy', 'click') def on_copy(self): l = self._get_checked() for i in l: i.action = 'copy' self.clipboard += l self.refresh_clipboard() @on('mass-delete', 'click') def on_delete(self): def callback(task): self.context.notify('info', _('Files deleted')) self.refresh() self.backend.remove(self._get_checked(), cb=callback) @on('paste', 'click') def on_paste(self): tab = self.controller.tabs[self.tabs.active] for_move = [] for_copy = [] for i in self.clipboard: if i.action == 'cut': for_move.append(i) else: for_copy.append(i) try: if for_move: def callback(task): self.context.notify('info', _('Files moved')) self.refresh() self.backend.move(for_move, tab.path, callback) if for_copy: def callback(task): self.context.notify('info', _('Files copied')) self.refresh() self.backend.copy(for_copy, tab.path, callback) self.clipboard = [] except Exception as e: self.context.notify('error', str(e)) self.refresh_clipboard() @on('select-all', 'click') def on_select_all(self): self.binder.update() tab = self.controller.tabs[self.tabs.active] for item in tab.items: item.checked = not item.checked self.binder.populate() self.context.notify('info', _('Selected %i items') % len(tab.items)) def _get_checked(self): self.binder.update() tab = self.controller.tabs[self.tabs.active] r = [] for item in tab.items: if item.checked: r.append(item) item.checked = False self.refresh() return r @on('clear-clipboard', 'click') def on_clear_clipboard(self): self.clipboard = [] self.refresh_clipboard() def on_item_click(self, tab, item): path = os.path.join(tab.path, item.name) if not os.path.isdir(path): self.edit(path) if not path.startswith(self.classconfig['root']): return tab.navigate(path) self.refresh() def edit(self, path): self.find('dialog').visible = True self.item = Item(path) self.item.read() self.binder_d = Binder(self.item, self.find('dialog')).populate() # Unpack u = Unpacker.find(self.item.fullpath.lower()) unpack_btn = self.find('dialog').find('unpack') unpack_btn.visible = u is not None def cb(): self.context.notify('info', _('Unpacked')) self.refresh() def unpack(): u.unpack(self.item.fullpath, cb=cb) logging.info('[fm] unpacking %s' % self.item.fullpath) unpack_btn.on('click', lambda: unpack()) # Edit edit_btn = self.find('dialog').find('edit') if self.item.size > 1024 * 1024 * 5: edit_btn.visible = False def edit(): self.context.launch('notepad', path=self.item.fullpath) edit_btn.on('click', lambda: edit()) @on('dialog', 'button') def on_close_dialog(self, button): self.find('dialog').visible = False if button == 'save': self.binder_d.update() try: self.item.write() except Exception as e: self.context.notify('error', str(e)) self.refresh() if self.find('chmod-recursive').value: cmd = 'chown -Rv "%s:%s" "%s"; chmod -Rv %o "%s"' % ( self.item.owner, self.item.group, self.item.fullpath, self.item.mode, self.item.fullpath, ) self.context.launch('terminal', command=cmd) logging.info('[fm] modifying %s: %o %s:%s' % (self.item.fullpath, self.item.mode, self.item.owner, self.item.group)) def on_bc_click(self, tab, item): if not item.path.startswith(self.classconfig['root']): return tab.navigate(item.path) self.refresh() def refresh(self, _=None): for tab in self.controller.tabs: tab.refresh() self.binder.populate()
class NTPDPlugin(SectionPlugin): def get_tz_debian(self): return open('/etc/timezone').read().strip() def get_tz_nondebian(self): return os.path.realpath( '/etc/localtime')[len('/usr/share/zoneinfo/'):] if os.path.islink( '/etc/localtime') else '' def set_tz_debian(self, timezone): open('/etc/timezone', 'w').write(timezone + '\n') def set_tz_nondebian(self, timezone): tz = os.path.join('/usr/share/zoneinfo/', timezone) if os.path.exists('/etc/localtime'): os.unlink('/etc/localtime') os.symlink(tz, '/etc/localtime') openntpd = isopenntpd() service_name = platform_select( default='openntpd' if openntpd else 'ntp', centos='openntpd' if openntpd else 'ntpd', mageia='ntpd', ) get_tz = platform_select( debian=get_tz_debian, default=get_tz_nondebian, ) set_tz = platform_select( debian=set_tz_debian, default=set_tz_nondebian, ) def init(self): self.title = _('Date & Time') self.icon = 'time' self.category = _('System') self.append(self.ui.inflate('ntpd:main')) self.find('servicebar').name = self.service_name self.find('servicebar').reload() self.config = NTPDConfig(path=platform_select( default=open_ntpd_conf if self.openntpd else ntpd_conf, centos='/usr/local/etc/ntpd.conf' if self.openntpd else ntpd_conf, freebsd='/usr/local/etc/ntpd.conf' if self.openntpd else ntpd_conf, )) self.binder = Binder(None, self) self.available_zones = [] for d, dirs, files in os.walk('/usr/share/zoneinfo', followlinks=False): for f in files: if f != 'zone.tab': self.available_zones.append(os.path.join(d, f)) self.available_zones = [ x[len('/usr/share/zoneinfo/'):] for x in self.available_zones ] self.available_zones.sort() self.find('servers').new_item = lambda c: ServerData() def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.now = int(time.time()) self.timezone = self.get_tz() self.binder.setup(self).populate() @on('set', 'click') def on_set(self): self.binder.update() d = datetime.fromtimestamp(self.now) s = d.strftime('%m%d%H%M%Y') self.set_tz(self.timezone) subprocess.call(['date', s]) self.refresh() @on('sync', 'click') def on_sync(self): self.binder.update() if len(self.config.tree.servers) == 0: self.context.notify('error', _('No servers defined')) return server = self.config.tree.servers[0].address output = subprocess.check_output(['ntpdate', '-u', server]) self.context.notify('info', _('Done')) self.context.notify('info', output) self.refresh() @on('save', 'click') def save(self): self.binder.update() self.config.save() self.refresh() self.context.notify('info', _('Saved')) ServiceMultiplexor.get().get_one(self.service_name).restart()
class MailPlugin(SectionPlugin): def init(self): self.title = _('Mail') self.icon = 'envelope' self.category = 'Web' self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate('vh-mail:not-configured')) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh-mail:main')) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find('size').text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find('password').value: item.password = ui.find('password').value self.find('mailboxes').post_item_bind = post_mb_bind self.find('mailboxes').post_item_update = post_mb_update self.binder.setup(self.manager.config) @on('new-mailbox', 'click') def on_new_mailbox(self): self.binder.update() mb = Mailbox.create() mb.local = self.find('new-mailbox-local').value mb.domain = self.find('new-mailbox-domain').value or self.find( 'new-mailbox-domain-custom').value mb.password = '' self.find('new-mailbox-local').value = '' if not mb.local: self.context.error(_('Invalid mailbox name')) if not mb.domain: self.context.error(_('Invalid mailbox domain')) self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): domains = [] for ws in VHManager.get().config.websites: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) self.find('new-mailbox-domain').labels = domains + [_('Custom domain')] self.find('new-mailbox-domain').values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify('info', _('Saved'))
class GitPlugin (SectionPlugin): def init(self): self.title = _('Git') self.icon = 'folder-close' self.category = 'Software' self.append(self.ui.inflate('git:main')) self.binder = Binder(None, self) self.user = None # Find User for user in ['gitolite3', 'gitolite2', 'gitolite']: try: pwn = getpwnam(user) self.user = pwn break except: pass if self.user == None: exit(-1) # Set Conf & Key Directory self.confdir = os.path.join(self.user.pw_dir, '.gitolite/conf/') self.keydir = os.path.join(self.user.pw_dir, '.gitolite/keydir/') # Event for new items self.find('usercollection').new_item = lambda c: User('newuser', '') self.find('repocollection').new_item = lambda c: Repository('newrepo') # Remove old Gitolite.conf and replace our version os.remove(self.confdir + 'gitolite.conf') with open((self.confdir + 'gitolite.conf'), 'w+') as file: file.write('include "*.conf"') def on_page_load(self): self.refresh() def refresh(self): self.refresh_users() self.refresh_repositories() self.binder.setup(self).populate() def reload(self): subprocess.call('su -c "gitolite compile" ' + self.user.pw_name, shell=True) self.context.notify('info', _('Saved')) # # Repositories # def refresh_repositories(self): self.repositories = [] userlist = [] for user in self.users: userlist.append(user.name) self.find('rwusers').values = userlist self.find('rwusers').labels = userlist self.find('rousers').values = userlist self.find('rousers').labels = userlist for file in os.listdir(self.confdir): if os.path.isfile(self.confdir + file) and not 'gitolite.conf' in file: with open(self.confdir + file) as content: content = content.read() repo = Repository('') # Repository Name match = re.search(r'repo[\s]+([A-z0-9]+)', content, re.I) repo.name = match.group(1) #Repository Users(read-write) match = re.search(r'RW\+[\s]+\=[\s]+([^\n]+)', content, re.I) repo.rwusers = match is not None and match.group(1) or '' #Repository Users(read-only) match = re.search(r'R[\s]+\=[\s]+([^\n]+)', content, re.I) repo.rousers = match is not None and match.group(1) or '' self.repositories.append(repo) @on('save-repositories', 'click') def save_repositories(self): self.binder.update() files = [] for file in os.listdir(self.confdir): if os.path.isfile(self.confdir + file) and not "gitolite.conf" in file: files.append(file) for repo in self.repositories: with open((self.confdir + repo.name + '.conf'), 'w+') as file: content = 'repo ' content += repo.name content += '\n' rwusers = repo.rwusers.strip() if len(rwusers) > 0: content += '\tRW+\t=\t' + rwusers + '\n' rousers = repo.rousers.strip() if len(rousers) > 0: content += '\tR\t=\t' + rousers + '\n' file.write(content) if (repo.name + '.conf') in files: files.remove(repo.name + '.conf') for file in files: os.remove(self.confdir + file) self.reload() # # Users # def refresh_users(self): self.users = [] for file in os.listdir(self.keydir): with open(self.keydir + file) as content: username = file.replace('.pub', '') pubkey = content.read() self.users.append(User(username, pubkey)) @on('save-users', 'click') def save_users(self): self.binder.update() files = [] for file in os.listdir(self.keydir): files.append(file) for user in self.users: with open((self.keydir + user.name + '.pub'), 'w+') as file: file.write(user.pubkey) if (user.name + '.pub') in files: files.remove(user.name + '.pub') for file in files: os.remove(self.keydir + file) self.reload();
class WebserverPlugin(SectionPlugin): service_name = '' service_buttons = [] hosts_available_dir = '' hosts_enabled_dir = '' hosts_dir = None template = '' supports_host_activation = True configurable = False main_conf_files = [] configurations = [] def log(self, msg): logging.info('[%s] %s' % (self.service_name, msg)) def init(self): self.append(self.ui.inflate('webserver_common:main')) self.binder = Binder(None, self) self.find_type('servicebar').buttons = self.service_buttons # Hosts preperation self.hosts_dir = AvailabilitySymlinks(self.hosts_available_dir, self.hosts_enabled_dir, self.supports_host_activation) def delete_host(host, c): self.log('removed host %s' % host.name) c.remove(host) self.hosts_dir.delete(host.name) def on_host_bind(o, c, host, u): host.__old_name = host.name def on_host_update(o, c, host, u): if host.__old_name != host.name: self.log('renamed host %s to %s' % (host.__old_name, host.name)) self.hosts_dir.rename(host.__old_name, host.name) host.save() def new_host(c): name = 'untitled' while os.path.exists(self.hosts_dir.get_path(name)): name += '_' self.log('created host %s' % name) self.hosts_dir.open(name, 'w').write(self.template) return WebserverConf(self, self.hosts_dir, name) self.find('hosts').delete_item = delete_host self.find('hosts').new_item = new_host self.find('hosts').post_item_bind = on_host_bind self.find('hosts').post_item_update = on_host_update self.find('header-active-checkbox').visible = \ self.find('body-active-line').visible = \ self.supports_host_activation def on_conf_bind(o, c, conf, u): conf.__old_name = conf.name def on_conf_update(o, c, conf, u): conf.save() self.find('configurations').post_item_bind = on_conf_bind self.find('configurations').post_item_update = on_conf_update self.tabs = self.find('tabs') def on_page_load(self): self.refresh() @on('save-button', 'click') def save(self): self.log('saving hosts') self.binder.update() self.refresh() self.context.notify('info', 'Saved') def refresh(self): self.hosts = [ WebserverConf(self, self.hosts_dir, x) for x in self.hosts_dir.list_available() ] self.configurations = [ WebserverMainConf(y).update() for y in self.main_conf_files ] if self.configurable else [] self.binder.setup(self).populate() self.find_type('servicebar').reload()
class CSFSection(SectionPlugin): def init(self): self.title = _('CSF Firewall') self.icon = 'fire' self.category = _('System') self.backend = CSFBackend.get() self.append(self.ui.inflate('csf:main')) self.config = CSFConfig(path='/etc/csf/csf.conf') self.list_allow = [] self.list_deny = [] self.list_tempallow = [] self.list_tempban = [] def delete_rule(csf_option, i): self.save() subprocess.call(['csf', csf_option, i.value.split('#')[0]]) self.refresh() self.find('list_allow').on_delete = lambda i, c: delete('-ar', i) self.find('list_deny').on_delete = lambda i, c: delete('-dr', i) self.find('list_tempallow').on_delete = lambda i, c: delete('-tr', i) self.find('list_tempban').on_delete = lambda i, c: delete('-tr', i) def add_rule(csf_option, address): self.save() p = subprocess.Popen(['csf', csf_option, address], stdout=subprocess.PIPE) o, e = p.communicate() self.context.notify('info', o) self.refresh() self.find('list_allow-add').on( 'click', lambda: add_rule('-a', self.find('permanent-lists-add-address').value)) self.find('list_deny-add').on( 'click', lambda: add_rule('-d', self.find('permanent-lists-add-address').value)) self.find('list_tempallow-add').on( 'click', lambda: add_rule('-ta', self.find('temporary-lists-add-address').value)) self.find('list_tempban-add').on( 'click', lambda: add_rule('-td', self.find('temporary-lists-add-address').value)) self.binder = Binder(None, self) self.binder_lists = Binder(self, self.find('lists')) def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.list_allow = self.backend.read_list('allow') self.list_deny = self.backend.read_list('deny') self.list_tempallow = self.backend.read_list('tempallow') self.list_tempban = self.backend.read_list('tempban') self.binder.setup(self.config.tree).populate() self.binder_lists.populate() @on('apply', 'click') def on_apply(self): self.backend.apply() self.context.notify('info', _('Applied')) @on('save', 'click') def save(self): self.binder.update() self.config.save() self.backend.write_list('allow', self.list_allow) self.backend.write_list('deny', self.list_deny) self.backend.write_list('tempallow', self.list_tempallow) self.backend.write_list('tempban', self.list_tempban) self.binder.setup(self.config.tree).populate() self.context.notify('info', _('Saved')) try: self.backend.test_config() self.context.notify('info', _('Self-test OK')) except Exception as e: self.context.notify('error', str(e))
class WebsitesPlugin(SectionPlugin): def init(self): self.title = _('Websites') self.icon = 'globe' self.category = 'Web' self.order = 1 self.manager = VHManager.get() if not self.manager.is_configured: from ajenti.plugins.vh import destroyed_configs self.append(self.ui.inflate('vh:not-configured')) self.find('destroyed-configs').text = ', '.join(destroyed_configs) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh:main')) self.binder = Binder(None, self) def post_ws_bind(object, collection, item, ui): def manage(): self.context.launch('v:manage-website', website=item) ui.find('manage').on('click', manage) self.find('websites').post_item_bind = post_ws_bind self.find( 'websites').filter = lambda ws: self.context.session.identity in [ 'root', ws.owner ] self.binder.setup(self.manager) @on('new-website', 'click') def on_new_website(self): self.binder.update() name = self.find('new-website-name').value self.find('new-website-name').value = '' if not name: name = '_' slug = slugify(name) slugs = [x.slug for x in self.manager.config.websites] while slug in slugs: slug += '_' w = Website.create(name) w.slug = slug w.owner = self.context.session.identity self.manager.config.websites.append(w) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if self.manager.is_configured: self.manager.config.websites = sorted(self.manager.config.websites, key=lambda x: x.name) self.binder.setup().populate() @on('recheck', 'click') def on_recheck(self): self.binder.update() self.context.endpoint.send_progress(_('Testing configuration')) try: self.manager.run_checks() finally: self.context.endpoint.send_progress(None) self.refresh() @on('save', 'click') def save(self): self.context.endpoint.send_progress(_('Saving changes')) self.binder.update() self.manager.save() self.context.endpoint.send_progress(_('Applying changes')) self.manager.update_configuration() self.context.endpoint.send_progress(_('Restarting web services')) self.manager.restart_services() gevent.spawn(self.on_recheck) self.refresh() self.context.notify('info', _('Saved'))
class SNMPDPlugin(SectionPlugin): service_name = platform_select(default='snmpd', ) def init(self): self.title = 'SNMP' self.icon = 'exchange' self.category = _('Software') self.append(self.ui.inflate('snmpd:main')) self.find('servicebar').name = self.service_name self.find('servicebar').reload() self.snmp_config = SNMPConfig( path=platform_select(default='/etc/snmp/snmp.conf', )) self.snmpd_config = SNMPDConfig( path=platform_select(default='/etc/snmp/snmpd.conf', )) self.find('rocommunities').new_item = lambda c: ROCommunityData() self.find('rwcommunities').new_item = lambda c: RWCommunityData() self.find('sinks1').new_item = lambda c: Sink1Data() self.find('sinks2').new_item = lambda c: Sink2Data() self.find('sinks2c').new_item = lambda c: Sink2cData() self.binder = Binder(None, self) def on_page_load(self): self.refresh() def refresh(self): self.snmp_config.load() self.snmpd_config.load() self.rocommunities = self.snmpd_config.tree.rocommunities self.rwcommunities = self.snmpd_config.tree.rwcommunities self.sinks1 = self.snmpd_config.tree.sinks1 self.sinks2 = self.snmpd_config.tree.sinks2 self.sinks2c = self.snmpd_config.tree.sinks2c enabled_mibs = [] for mib in self.snmp_config.tree.mibs: for x in mib.name.strip('-+:').split(':'): enabled_mibs.append(x) self.mibs = [] for dirpath, dirname, filenames in os.walk('/usr/share/mibs', followlinks=True): for x in filenames: if not x.startswith('.'): mib = MIBData() mib.name = x mib.selected = x in enabled_mibs self.mibs.append(mib) self.mibs = sorted(self.mibs, key=lambda x: x.name) self.binder.setup(self).populate() @on('save', 'click') def save(self): self.binder.update() mib = MIBData() mib.name = ':'.join([x.name for x in self.mibs if x.selected]) for x in list(self.snmp_config.tree.mibs): self.snmp_config.tree.mibs.remove(x) self.snmp_config.tree.mibs.append(mib) self.snmp_config.save() self.snmpd_config.save() self.refresh() self.context.notify('info', _('Saved')) ServiceMultiplexor.get().get_one(self.service_name).restart()
class WebsitesPlugin(SectionPlugin): def init(self): self.title = _('Websites') self.icon = 'globe' self.category = 'Web' self.manager = VHManager.get() if not self.manager.is_configured: from ajenti.plugins.vh import destroyed_configs self.append(self.ui.inflate('vh:not-configured')) self.find('destroyed-configs').text = ', '.join(destroyed_configs) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh:main')) self.binder = Binder(None, self) def post_ws_bind(object, collection, item, ui): def manage(): self.context.launch('v:manage-website', website=item) ui.find('manage').on('click', manage) self.find('websites').post_item_bind = post_ws_bind self.binder.setup(self.manager.config) @on('new-website', 'click') def on_new_website(self): self.binder.update() name = self.find('new-website-name').value self.find('new-website-name').value = '' if not name: name = '_' slug = slugify(name) slugs = [x.slug for x in self.manager.config.websites] while slug in slugs: slug += '_' w = Website.create(name) w.slug = slug self.manager.config.websites.append(w) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.context.endpoint.send_progress(_('Saving changes')) self.manager.save() self.context.endpoint.send_progress(_('Applying changes')) self.manager.update_configuration() self.refresh() self.context.notify('info', _('Saved'))
class Test(SectionPlugin): def init(self): self.title = 'Instance Manager' self.icon = 'th-list' self.category = 'System' self.mgr = lxc.lxcman() #change 'dialogging:..' to match the name of directory self.append(self.ui.inflate('dialogging:main')) def post_item_bind(object, collection, item, ui): ui.find('btnStart').on('click', self.on_start, item) ui.find('btnRestart').on('click', self.on_restart, item) ui.find('btnStop').on('click', self.on_stop, item) ui.find('btnRemove').on('click', self.on_remove, item) #ui.find('btnSnapshot').on('click', self.on_snapshot, item) running = True if item.name in self.mgr.get_running() else False frozen = True if item.name in self.mgr.get_frozen() else False ui.find('btnStart').visible = not running ui.find('btnRestart').visible = running ui.find('btnStop').visible = running ui.find('btnFreeze').visible = not frozen ui.find('btnUnfreeze').visible = frozen self.find('collection').post_item_bind = post_item_bind self.obj_collection = self.mgr.get_all() self.binder = Binder(self, self) self.find('btnSnapshot').visible = False self.refresh() def refresh(self): self.populate() self.binder.update() def populate(self): self.obj_collection = self.mgr.get_all() for i in self.obj_collection: i._status = get(i.status) i._name = i.name self.binder.setup(self).populate() @on('btnCreateDialog', 'click') def on_apply(self): self.find('dialog').visible = True self.created = Instance() self.binder_d = Binder(self.created, self.find('dialog')).populate() @on('dialog', 'button') def on_close_dialog(self, button): self.find('dialog').visible = False if button == 'save': self.binder_d.update() self.created.name = self.created.name.replace(' ', '-') self.mgr.create(self.created.name) if self.mgr.exists(self.created.name): self.context.notify('info', "%s created" % self.created.name) self.refresh() def on_start(self, container): self.mgr.start(container.name.strip()) self.populate() running = self.mgr.get_running() if container.name in running: self.context.notify('info', "%s started successfully" % container.name) self.refresh() def on_stop(self, container): self.mgr.stop(container.name.strip()) self.populate() stopped = self.mgr.get_stopped() if container.name in stopped: self.context.notify('info', "%s stopped successfully" % container.name) self.refresh() def on_restart(self, container): self.mgr.restart(container.name.strip()) self.populate() running = self.mgr.get_running() if container.name in running: self.context.notify('info', "%s restarted successfully" % container.name) self.refresh() def on_remove(self, container): self.find('confirmDialog').visible = True self.conf = confirmDialog() self.conf.name = container.name.strip() self.conf.message = 'Really delete %s ?' % self.conf.name self.binder_r = Binder(self.conf, self.find('confirmDialog')).populate() @on('confirmDialog', 'button') def on_remove_close(self, button): self.find('confirmDialog').visible = False if button == 'confirm': self.mgr.destroy(self.conf.name) self.populate() running = self.mgr.get_running() if self.conf.name not in running: self.context.notify('info', "%s removed successfully" % self.conf.name) self.refresh()
class LetsEncryptPlugin (SectionPlugin): pwd = os.path.join(os.path.dirname(os.path.realpath(__file__)), '') has_domains = False def init(self): self.title = 'LetsEncrypt' # those are not class attributes and can be only set in or after init() self.icon = 'lock' self.category = 'Security' self.append(self.ui.inflate('letsencrypt:main')) self.settings = Settings() self.binder = Binder(self.settings, self) def delete_domain(domain, c): logging.debug('removed domain %s' % domain.name) c.remove(domain) logging.debug("domain info: %s %s" % (domain.subdomains, domain.name)) self.save() def delete_cert(cert, c): logging.debug('removed cert %s' % cert.name) c.remove(cert) logging.debug("cert info: %s %s" % (cert.dir, cert.name)) shutil.rmtree(cert.dir) def on_domain_bind(o, c, domain, u): domain.__old_name = domain.name def on_cert_bind(o, c, cert, u): cert.__old_name = cert.name def new_domain(c): name = 'domain.com' subdomains = 'www.domain.com\nblog.domain.com' return DomainsInfo(self, name, subdomains) self.find('certs').delete_item = delete_cert self.find('certs').post_item_bind = on_cert_bind self.find('domains').new_item = new_domain self.find('domains').delete_item = delete_domain self.find('domains').post_item_bind = on_domain_bind def fix_dependencies(self): if self.settings.dependencies_met is True: return changes = False # Install dehyrated (this is how we communicate with letsencrpyt) if not os.path.isfile(self.settings.basedir + self.settings.scriptname): self.context.notify('info', 'Fixing dehydrated dependency') changes = True if self.git_clone('https://github.com/lukas2511/dehydrated.git', self.settings.basedir): logging.debug("cloning of dehydrated successful") changes = False # Install nginxparser (this is how we edit nginx config files) installed_mods = sorted(["%s==%s" % (i.key, i.version) for i in pip.get_installed_distributions()]) if "nginxparser" not in str(installed_mods): self.context.notify('info', 'Fixing nginxparser dependency') changes = True if self.git_clone('https://github.com/fatiherikli/nginxparser', '~/'): logging.debug("cloning of nginxparser successful.. installing..") command = ['python', 'setup.py', 'install']; p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='/root/nginxparser/') out, err = p.communicate() installed_mods = sorted(["%s==%s" % (i.key, i.version) for i in pip.get_installed_distributions()]) if "nginxparser" not in str(installed_mods): logging.debug("Something went wrong with installing nginxparser..") else: logging.debug("Installed nginxparser correctly.. importing modules..") from nginxparser import load from nginxparser import dumps changes = False if changes is False: self.settings.dependencies_met = True logging.debug("SUCCESSFULLY MET ALL DEPENDENCIES") def start_thread(self, target, *my_args, **my_keyword_args): thr = threading.Thread(target=target, args=my_args, kwargs=my_keyword_args) thr.daemon = True thr.start() return thr def on_page_load(self): self.refresh() def refresh(self): self.fix_dependencies() filepath = self.settings.basedir + self.settings.domainfile domains_file_read = '' if os.path.isfile(filepath): with open(filepath) as f: domains_file_read = f.readlines() domains_file_read = [x.strip() for x in domains_file_read] domains_file_read = "\n".join(domains_file_read) else: domains_file_read = "" cron = self.check_cron() mysplit = domains_file_read.split("\n") tmp = [] for lines in mysplit: mysecondsplit = lines.split(" ") main_domain = mysecondsplit.pop(0) sub_domains = "" if len(mysecondsplit) >= 1: sub_domains = mysecondsplit tmp.append(DomainsInfo(self, main_domain, "\n".join(sub_domains))) self.settings.domains = tmp self.find('cronjob').value = cron available_domains = self.list_available_certs() available_files = self.list_enabled_nginx_confs() temp_obj = [] if available_domains: for x in available_domains: #expiration date my_date = self.settings.basedir + '/certs/' + x + '/expiration.date' if os.path.isfile(my_date): with open(my_date, 'r') as myfile: my_date=myfile.read().replace('\n', '') else: my_date = "NONE" #cert chain my_ssl_chain = self.settings.basedir + '/certs/' + x + '/chain.pem' if os.path.isfile(my_ssl_chain): with open(my_ssl_chain, 'r') as myfile: my_ssl_chain=myfile.read().replace('\n', '') else: my_ssl_chain = "MISSING" #public key my_ssl_cert = self.settings.basedir + '/certs/' + x + '/cert.pem' if os.path.isfile(my_ssl_cert): with open(my_ssl_cert, 'r') as myfile: my_ssl_cert=myfile.read().replace('\n', '') else: my_ssl_cert = "MISSING" #public key and cert chain my_ssl_fullcert = self.settings.basedir + '/certs/' + x + '/fullchain.pem' if os.path.isfile(my_ssl_fullcert): with open(my_ssl_fullcert, 'r') as myfile: my_ssl_fullcert=myfile.read().replace('\n', '') else: my_ssl_fullcert = "MISSING" #private key my_ssl_key = self.settings.basedir + '/certs/' + x + '/privkey.pem' if os.path.isfile(my_ssl_key): with open(my_ssl_key, 'r') as myfile: my_ssl_key=myfile.read().replace('\n', '') else: my_ssl_key = "MISSING" temp_obj.append(CertificateInfo(self, self.settings.basedir + 'certs/' + x + '/', x, my_date, my_ssl_chain, my_ssl_cert, my_ssl_fullcert, my_ssl_key)) self.settings.certs = temp_obj else: logging.debug("NO DOMAINS AVAILABLE") self.binder.setup(self.settings).populate() def list_enabled_nginx_confs(self): if not os.path.isdir(self.settings.nginx_sites_enabled): return False return [x for x in sorted(os.listdir(self.settings.nginx_sites_enabled)) if os.path.isfile(os.path.join(self.settings.nginx_sites_enabled, x))] def list_available_certs(self): if not os.path.isdir(self.settings.basedir + "certs"): return False return [x for x in sorted(os.listdir(self.settings.basedir + "certs")) if os.path.isdir(os.path.join(self.settings.basedir + "certs", x))] def write_domain_file(self): filepath = self.settings.basedir + self.settings.domainfile if len(self.settings.domains) < 1: self.context.notify('info', 'No domains specified') self.has_domains = False return final_str = '' for domains in self.settings.domains: final_str = final_str + domains.name + " " if domains.subdomains: tmp = domains.subdomains.split("\n") tmp = " ".join(tmp) final_str = final_str + tmp final_str = final_str + "\n" logging.debug("final string %s " % final_str) file = open(filepath, 'w') if file.write(final_str) is None: self.has_domains = True else: self.context.notify('error', 'Domain file write error') file.close() def read_domain_file(self): filepath = self.settings.basedir + self.settings.domainfile if not open(filepath): self.context.notify('error', 'Domain file could not be read') file = open(filepath) with file as f: lines = f.readlines() return lines def create_folders(self): uid = pwd.getpwnam("www-data").pw_uid gid = grp.getgrnam("www-data").gr_gid if not os.path.exists(self.settings.basedir): os.makedirs(self.settings.basedir) os.chown(self.settings.basedir, uid, gid) if not os.path.exists(self.settings.wellknown): os.makedirs(self.settings.wellknown) os.chown(self.settings.wellknown, uid, gid) def create_dehydrated_config_file(self): template = """ BASEDIR=$basedir WELLKNOWN=$wellknown """ dict = { 'basedir': self.settings.basedir, 'wellknown': self.settings.wellknown } filepath = self.settings.basedir + self.settings.configname file = open(filepath, 'w') src = Template( template ) if file.write(src.safe_substitute(dict)) is not None: self.context.notify('info', 'Letsencrypt error') file.close() def cleanup_oldfiles(self): filepath1 = self.settings.nginx_sites_enabled + self.settings.nginx_config filepath2 = self.settings.nginx_sites_available + self.settings.nginx_config filepath3 = self.settings.basedir + self.settings.configname filepath4 = self.settings.basedir + self.settings.domainfile if os.path.isfile(filepath1): os.remove(filepath1) if os.path.isfile(filepath2): os.remove(filepath2) if os.path.isfile(filepath3): os.remove(filepath3) if os.path.isfile(filepath4): os.remove(filepath4) self.context.notify('info', 'removed all local files') def create_nginx_wellknown_config(self): if not self.check_nginx_dir_exists(): self.context.notify('info', 'nginx_custom_dir() is not valid: %s') return False template = """ server { server_name $domains; listen *:80; location $location { alias $alias; } } """ dict = { 'location': '/.well-known/acme-challenge', 'alias': self.settings.wellknown, 'domains': " ".join(self.read_domain_file()) } filepath = self.settings.nginx_sites_available + self.settings.nginx_config filepath2 = self.settings.nginx_sites_enabled + self.settings.nginx_config file = open(filepath, 'w') src = Template( template ) if file.write(src.safe_substitute(dict)) is not None: self.context.notify('info', 'WELLKNOWN config write error') file.close() if os.path.isfile(filepath2): return True os.symlink(filepath, filepath2) def create_cron(self): file = open(self.settings.crontab_dir + self.settings.cronfile, 'w') template = "0 0 1 * * " + self.pwd + 'libs/letsencrypt.sh/letsencrypt.sh -c' if not file.write(template): self.context.notify('info', 'Cron job error') file.close() def remove_cron(self): if os.path.isfile(self.settings.crontab_dir + self.settings.cronfile): if os.remove(self.settings.crontab_dir + self.settings.cronfile): return True else: self.context.notify('info', 'Cron remove error') return False def check_cron(self): if os.path.isfile(self.settings.crontab_dir + self.settings.cronfile): return True return False # Update Nginx config files to use SSL def update_nginx_confs(self): available_domains = self.list_available_certs() filepath = self.settings.basedir + self.settings.domainfile domains = '' if os.path.isfile(filepath): with open(filepath) as f: domains = f.readlines() domains = [x.strip() for x in domains] domains = "\n".join(domains) mysplit = domains.split("\n") # Gets all enabled sites available_nginx_files = self.list_enabled_nginx_confs() for curr_domain in available_domains: for curr_nginx_file in available_nginx_files: logging.debug("## Use Certs: Checking config file - %s ##" % curr_nginx_file) if self.settings.nginx_config in curr_nginx_file: logging.debug("Skipping file: %s" % curr_nginx_file) continue # Path is to the sites_available directory filepath = self.settings.nginx_sites_available + curr_nginx_file if not os.path.isfile(filepath): logging.debug("File not in sites_available directory.. continuing") continue loaded_conf = load(open(filepath)) for servers in loaded_conf: server_conf = servers[1] ssl_true = False listen_position = None server_name_position = None ssl_cert_position = None ssl_cert_key_position = None curr_pos = 0 for lines in server_conf: if isinstance(lines[0], str): if 'server_name' in lines[0] and len(lines) > 1: if server_name_position is not None: logging.debug("There must be more than one server_name_position.. skipping this file because we don't know how to handle it.") print("CONF %s" % loaded_conf) break server_name_position = curr_pos if 'listen' in lines[0] and len(lines) > 1: if listen_position is not None: listen_position = [listen_position] listen_position.append(curr_pos) print("There are multiple listen positions: %s" % listen_position) else: listen_position = curr_pos if 'ssl_certificate' in lines[0] and 'ssl_certificate_key' not in lines[0] and len(lines) > 1: if ssl_cert_position is not None: logging.debug("There must be more than one ssl_certificate.. skipping this file because we don't know how to handle it.") print("CONF %s" % lines[0]) break ssl_cert_position = curr_pos if 'ssl_certificate_key' in lines[0] and len(lines) > 1: if ssl_cert_key_position is not None: logging.debug("There must be more than one ssl_certificate_key.. skipping this file because we don't know how to handle it.") print("CONF %s" % lines[0]) break ssl_cert_key_position = curr_pos curr_pos += 1 if listen_position is not None and server_name_position is not None: logging.debug("We have both listen and server name positions: listen position: %s | server_name_position: %s" % (listen_position, server_name_position)) found_it = False for domain_list_line in mysplit: if found_it is True: break secondsplit = domain_list_line.split(" ") for domains in secondsplit: logging.debug("CHECKING DOMAIN %s with: %s" % (server_conf[server_name_position][1], domains)) if server_conf[server_name_position][1] in domains: logging.debug("found our domain: %s in the list of domains" % server_conf[server_name_position][1]) found_it = True break if found_it is False: logging.debug("Server Config does not have any of our domains with SSL certs in the 'server_name' position.. skipping this config.") continue # Check if SSL is already setup if ssl_cert_key_position is not None and ssl_cert_position is not None: # Check if ports are setup too if isinstance(listen_position, list): already_setup = False for listens in listen_position: if "443" in server_conf[listens][1]: already_setup = True break if already_setup is True: logging.debug("This server is already setup for SSL") continue elif isinstance(listen_position, str): if "443" in server_conf[listens][1]: continue # Lets setup SSL now... logging.debug("Attempting to setup SSL for domain: %s" % curr_domain) # Multiple listen calls.. if isinstance(listen_position, list): already_setup = False for listens in listen_position: if "443" in server_conf[listens][1]: already_setup = True break # Check if ssl port is already set if already_setup is True: logging.debug("Server port already setup for SSL") # 443 not set... set one of the listen calls to 443 else: server_conf[listen_position[0]][1] # ssl port set already if "443 ssl" in server_conf[listen_position[0]][1]: logging.debug("Server port already setup for SSL") # ssl port not set yet.. else: if ":" in server_conf[listen_position[0]][1]: tmp = server_conf[listen_position[0]][1].split(":") if tmp[1]: logging.debug("old port value %s" % server_conf[listen_position[0]][1]) r = re.compile(r"\d{2,5}") tmp[1] = r.sub("443 ssl", tmp[1]) server_conf[listen_position[0]][1] = ':'.join(tmp) logging.debug("new port value: %s" % server_conf[listen_position[0]][1]) else: logging.debug("old port value: %s" % server_conf[listen_position[0]][1]) r = re.compile(r"\d{2,5}") tmp = r.sub("443 ssl", server_conf[listen_position[0]][1]) server_conf[listen_position[0]][1] = tmp logging.debug("new port value: %s" % server_conf[listen_position[0]][1]) # Single listen call.. else: # ssl port set already if "443 ssl" in server_conf[listen_position][1]: logging.debug("Server port already setup for SSL") # ssl port not set yet.. else: if ":" in server_conf[listen_position][1]: tmp = server_conf[listen_position][1].split(":") if tmp[1]: logging.debug("old port value %s" % server_conf[listen_position][1]) r = re.compile(r"\d{2,5}") tmp[1] = r.sub("443 ssl", tmp[1]) server_conf[listen_position][1] = ':'.join(tmp) logging.debug("new port value: %s" % server_conf[listen_position][1]) else: logging.debug("old port value: %s" % server_conf[listen_position][1]) r = re.compile(r"\d{2,5}") tmp = r.sub("443 ssl", server_conf[listen_position][1]) server_conf[listen_position][1] = tmp logging.debug("new port value: %s" % server_conf[listen_position][1]) cert_path = self.settings.basedir + '/certs/' + curr_domain + '/fullchain.pem' cert_key_path = self.settings.basedir + '/certs/' + curr_domain + '/privkey.pem' if ssl_cert_position is None: server_conf.insert(0, ["ssl_certificate", cert_path]) else: server_conf[ssl_cert_position][1] = cert_path if ssl_cert_key_position is None: server_conf.insert(1, ["ssl_certificate_key", cert_key_path]) else: server_conf[ssl_cert_key_position][1] = cert_key_path file = open(filepath,"w") file.write(dumps(loaded_conf)) file.close() logging.debug("## FINISHED WITH SETTING UP NGINX WITH CERTS ##") self.context.notify('info', 'Nginx is now using your valid certs.') def check_nginx_dir_exists(self): if not os.path.exists(self.settings.nginx_sites_available): os.makedirs(self.settings.nginx_sites_available) if not os.path.exists(self.settings.nginx_sites_enabled): os.makedirs(self.settings.nginx_sites_enabled) if os.path.exists(self.settings.nginx_sites_available) and os.path.exists(self.settings.nginx_sites_enabled): return True self.context.notify('error', 'One or more nginx directories is incorrect') def request_certs_helper(self): self.save() time.sleep(5) if not os.path.exists(self.settings.basedir + "accounts"): self.context.notify('error', 'No accounts directory found, Registering before requesting certs..') self.request_certificates(True) if os.path.exists(self.settings.basedir + "accounts"): self.request_certificates(False) def request_certificates(self, register): filepath = self.settings.basedir + self.settings.scriptname params = [filepath, '-c'] out = "" if self.find('renewal').value: params.append('--force') if register: params = [filepath, '--register', '--accept-terms'] self.settings.output = "Disabling currently active SYMLINKS\n" self.binder.setup(self.settings).populate() available_files = self.list_enabled_nginx_confs() for curr_nginx_file in available_files: if self.settings.nginx_config in curr_nginx_file: logging.debug("Skipping file: %s" % curr_nginx_file) continue logging.debug("Disabling SYMLINK: %s" % curr_nginx_file) filepath = self.settings.nginx_sites_enabled + curr_nginx_file os.unlink(filepath) p = subprocess.Popen(params, stdout=subprocess.PIPE, stderr=subprocess.PIPE) success = False while p.poll() is None: output = p.stdout.readline() logging.debug("%s" % output) self.settings.output = output + self.settings.output self.binder.setup(self.settings).populate() if "Creating fullchain.pem" in output or "Skipping renew!" in output: success = True self.settings.output = "Re-enabling SYMLINKS...\n" + self.settings.output self.binder.setup(self.settings).populate() for curr_nginx_file in available_files: if not os.path.isfile(self.settings.nginx_sites_enabled + curr_nginx_file): filepath1 = self.settings.nginx_sites_available + curr_nginx_file filepath2 = self.settings.nginx_sites_enabled + curr_nginx_file os.symlink(filepath1, filepath2) self.settings.output = "Restarting NGINX once more...\n" + self.settings.output self.binder.setup(self.settings).populate() self.restart_nginx() if success is True: self.settings.output = "Success creating certificates! Congratulations!\n" + self.settings.output self.binder.setup(self.settings).populate() else: self.settings.output = "Something went wrong. Read logs below.\n" + self.settings.output self.binder.setup(self.settings).populate() def restart_nginx(self): self.context.notify('info', 'Restarting Nginx') command = ['/usr/sbin/service', 'nginx', 'restart']; p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() def git_clone(self, repo, dir): logging.debug("Cloning REPO: %s into directory: %s" % (repo, dir)) # GIT automatically makes directories command = ['/usr/bin/git', 'clone', repo, dir]; p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() command = ['/usr/bin/git', 'remote', '-v']; p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=dir) out, err = p.communicate() if repo in out: return True else: return False def helper(self): installed_mods = sorted(["%s==%s" % (i.key, i.version) for i in pip.get_installed_distributions()]) if "nginxparser" not in str(installed_mods): if self.git_clone('https://github.com/fatiherikli/nginxparser', '~/'): logging.debug("cloning of nginxparser successful.. installing..") command = ['python', 'setup.py', 'install']; p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='/root/nginxparser/') out, err = p.communicate() installed_mods = sorted(["%s==%s" % (i.key, i.version) for i in pip.get_installed_distributions()]) if "nginxparser" not in str(installed_mods): logging.debug("Something went wrong with installing nginxparser..") def save(self): self.binder.update() self.binder.populate() self.create_folders() self.write_domain_file() if not self.has_domains: self.cleanup_oldfiles() self.restart_nginx() return self.create_dehydrated_config_file() self.create_nginx_wellknown_config() if self.settings.cronjob: self.create_cron() else: self.remove_cron() self.restart_nginx() @on('done', 'click') def on_output_done(self): self.find('hidden_output').visible = False @on('tabs', 'switch') def tab_switched(self): self.refresh() @on('save', 'click') def save_button(self): self.save() @on('updatenginx', 'click') def updatenginx_button(self): self.update_nginx_confs() self.restart_nginx() @on('helperbutton', 'click') def helper_button(self): self.helper() @on('request', 'click') def request_button(self): self.settings.output = "Saving configuration... Waiting 5 seconds..." self.binder.setup(self.settings).populate() self.find('hidden_output').visible = True self.start_thread(self.request_certs_helper)
class MySQLExtension(BaseExtension): default_config = { 'databases': [], 'users': [], } name = 'MySQL' def init(self): self.append(self.ui.inflate('vh-mysql:ext')) self.binder = Binder(self, self) self.refresh() self.db = MySQLDB.get() @staticmethod def selftest(): try: MySQLDB.get().query_databases() except: pass def refresh(self): if not 'databases' in self.config: if self.config['created']: self.config['databases'] = [{ 'name': self.config['name'], }] self.config['users'] = [{ 'name': self.config['user'], 'password': self.config['password'], }] else: self.config['databases'] = [] self.config['users'] = [] del self.config['created'] del self.config['name'] del self.config['user'] del self.config['password'] def post_db_bind(object, collection, item, ui): ui.find('detach').on('click', self.on_detach_db, item) self.find('databases').post_item_bind = post_db_bind def post_user_bind(object, collection, item, ui): ui.find('detach').on('click', self.on_detach_user, item) self.find('users').post_item_bind = post_user_bind self.binder.setup().populate() self.find('db-name').value = self.website.slug self.find('db-username').value = self.website.slug self.find('db-password').value = str(uuid.uuid4()) self.find('databases').delete_item = lambda i, c: self.on_delete_db(i) self.find('users').delete_item = lambda i, c: self.on_delete_user(i) def update(self): self.binder.update() def on_destroy(self): pass @on('create-db', 'click') def on_create_db(self): try: self.db.query_databases() except Exception, e: self.context.notify('error', str(e)) self.context.launch('configure-plugin', plugin=self.db) return dbname = self.find('db-name').value for db in self.db.query_databases(): if db.name == dbname: self.context.notify('error', _('This database name is already used')) return db_cfg = {'name': dbname} try: self.db.query_create(db_cfg['name']) except Exception, e: self.context.notify('error', str(e)) return
class Packages(SectionPlugin): platforms = ['debian', 'centos', 'freebsd', 'arch', 'mageia'] def init(self): self.title = _('Packages') self.icon = 'gift' self.category = _('System') self.mgr = PackageManager.get() self.append(self.ui.inflate('packages:main')) def post_item_bind(object, collection, item, ui): ui.find('install').on('click', self.on_install, item) ui.find('remove').on('click', self.on_remove, item) ui.find('cancel').on('click', self.on_cancel, item) ui.find('install').visible = item.action is None ui.find( 'remove').visible = item.action is None and item.state == 'i' ui.find('cancel').visible = item.action is not None self.find('upgradeable').post_item_bind = post_item_bind self.find('search').post_item_bind = post_item_bind self.find('pending').post_item_bind = post_item_bind self.binder = Binder(None, self.find('bind-root')) self.binder_p = Binder(self, self.find('bind-pending')) self.binder_s = CollectionAutoBinding([], None, self.find('search')).populate() self.pending = {} self.installation_running = False self.action_queue = [] def refresh(self): self.fill(self.mgr.upgradeable) self.binder.setup(self.mgr).populate() self.binder_s.unpopulate().populate() self._pending = self.pending.values() self.binder_p.setup(self).populate() def run(self, tasks): if self.installation_running: self.action_queue += tasks self.context.notify('info', _('Enqueueing package installation')) return self.installation_running = True def callback(): self.installation_running = False if self.action_queue: self.run(self.action_queue) self.action_queue = [] return self.context.notify('info', _('Installation complete!')) self.mgr.do(tasks, callback=callback) @intent('install-package') @restrict('packages:modify') def intent_install(self, package): p = PackageInfo() p.name, p.action = package, 'i' self.run([p]) def on_page_load(self): self.context.endpoint.send_progress(_('Querying package manager')) self.mgr.refresh() self.refresh() @restrict('packages:modify') def on_install(self, package): package.action = 'i' self.pending[package.name] = package self.refresh() @restrict('packages:modify') def on_cancel(self, package): package.action = None if package.name in self.pending: del self.pending[package.name] self.refresh() @restrict('packages:modify') def on_remove(self, package): package.action = 'r' self.pending[package.name] = package self.refresh() @on('get-lists-button', 'click') @restrict('packages:refresh') def on_get_lists(self): self.mgr.get_lists() @on('apply-button', 'click') @restrict('packages:modify') def on_apply(self): self.run(self.pending.values()) self.pending = {} self.refresh() @on('upgrade-all-button', 'click') @restrict('packages:modify') def on_upgrade_all(self): for p in self.mgr.upgradeable: p.action = 'i' self.pending[p.name] = p self.refresh() @on('cancel-all-button', 'click') @restrict('packages:modify') def on_cancel_all(self): self.pending = {} self.refresh() def fill(self, packages): for p in packages: if p.name in self.pending: p.action = self.pending[p.name].action @on('search-button', 'click') def on_search(self): query = self.find('search-box').value results = self.mgr.search(query) if self.binder_s: self.binder_s.unpopulate() if len(results) > 100: self.find('search-counter' ).text = _('%i found, 100 shown') % len(results) results = results[:100] else: self.find('search-counter').text = _('%i found') % len(results) self.fill(results) self.binder_s = CollectionAutoBinding(results, None, self.find('search')).populate()
class OpenVPN (SectionPlugin): def init(self): self.title = _('OpenVPN') self.icon = 'globe' self.category = _('Software') self.append(self.ui.inflate('openvpn:main')) def disconnect(u, c): try: self.backend.killbyaddr(u.raddress) time.sleep(1) except Exception as e: self.context.notify('error', e.message) self.refresh() self.find('clients').delete_item = disconnect self.binder = Binder(None, self) self.backend = OpenVPNBackend.get() def on_page_load(self): self.refresh() @on('hard-restart', 'click') def on_hard_restart(self): self.backend.restarthard() time.sleep(2) @on('soft-restart', 'click') def on_soft_restart(self): self.backend.restartcond() time.sleep(2) def refresh(self): try: self.backend.setup() except Exception as e: self.context.notify('error', e.message) self.context.launch('configure-plugin', plugin=self.backend) return self.state = State() try: self.backend.connect() self.state.stats = self.backend.getstats() self.state.status = self.backend.getstatus() self.state.messages = [] self.state.clients = [] for d in self.state.status['clients']: c = Client() c.__dict__.update(d) self.state.clients.append(c) for d in self.backend.getmessages(): m = Message() m.timestamp, m.flags, m.text = d[:3] self.state.messages.append(m) except Exception as e: self.context.notify('error', e.message) self.binder.setup(self.state).populate()
class Firewall(SectionPlugin): platforms = ['centos', 'debian', 'arch', 'mageia'] manager_class = FirewallManager def init(self): self.title = _('Firewall') self.icon = 'fire' self.category = _('System') self.append(self.ui.inflate('iptables:main')) self.fw_mgr = self.manager_class.get() self.config = IPTablesConfig(path=self.fw_mgr.config_path_ajenti) self.binder = Binder(None, self.find('config')) self.find('tables').new_item = lambda c: TableData() self.find('chains').new_item = lambda c: ChainData() self.find('rules').new_item = lambda c: RuleData() self.find('options').new_item = lambda c: OptionData() self.find('options').binding = OptionsBinding self.find('options').filter = lambda i: not i.name in ['j', 'jump'] def post_rule_bind(o, c, i, u): u.find('add-option').on('change', self.on_add_option, c, i, u) action = '' j_option = i.get_option('j', 'jump') if j_option: action = j_option.arguments[0].value u.find('action').text = action u.find('action').style = 'iptables-action iptables-%s' % action u.find('action-select').value = action u.find('title').text = i.comment if i.comment else i.summary def post_rule_update(o, c, i, u): action = u.find('action-select').value j_option = i.get_option('j', 'jump') if j_option: j_option.arguments[0].value = action else: if action: o = OptionData.create_destination() o.arguments[0].value = action i.options.append(o) self.find('rules').post_item_bind = post_rule_bind self.find('rules').post_item_update = post_rule_update self.find('add-option').values = self.find('add-option').labels = [ _('Add option') ] + sorted(OptionData.templates.keys()) def on_page_load(self): if not os.path.exists(self.fw_mgr.config_path_ajenti): if not os.path.exists(self.fw_mgr.config_path): open(self.fw_mgr.config_path, 'w').write(""" *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT *filter :INPUT DROP [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 8000 -j ACCEPT COMMIT """) open(self.fw_mgr.config_path_ajenti, 'w').write(open(self.fw_mgr.config_path).read()) self.config.load() self.refresh() @on('load-current', 'click') def on_load_current(self): subprocess.call( '%s > %s' % (self.fw_mgr.iptables_save_binary, self.fw_mgr.config_path_ajenti), shell=True) self.config.load() self.refresh() def refresh(self): self.find('autostart').text = (_('Disable') if self.fw_mgr.get_autostart_state() else _('Enable')) + _(' autostart') actions = ['ACCEPT', 'DROP', 'REJECT', 'LOG', 'MASQUERADE', 'DNAT', 'SNAT'] + \ list(set(itertools.chain.from_iterable([[c.name for c in t.chains] for t in self.config.tree.tables]))) self.find('action-select').labels = actions self.find('action-select').values = actions self.find('chain-action-select').labels = actions self.find('chain-action-select').values = actions self.binder.setup(self.config.tree).populate() @on('autostart', 'click') def on_autostart_change(self): self.fw_mgr.set_autostart_state(not self.fw_mgr.get_autostart_state()) self.refresh() def on_add_option(self, options, rule, ui): self.binder.update() o = OptionData.create(ui.find('add-option').value) ui.find('add-option').value = '' rule.options.append(o) self.binder.populate() @on('save', 'click') def save(self): self.binder.update() for t in self.config.tree.tables: for c in t.chains: for r in c.rules: r.verify() self.config.save() open(self.fw_mgr.config_path, 'w').write(''.join( l.split('#')[0] + '\n' for l in open(self.fw_mgr.config_path_ajenti).read().splitlines())) self.refresh() self.context.notify('info', _('Saved')) @on('edit', 'click') def raw_edit(self): self.context.launch('notepad', path=self.fw_mgr.config_path_ajenti) @on('apply', 'click') def apply(self): self.save() cmd = 'cat %s | %s' % (self.fw_mgr.config_path, self.fw_mgr.iptables_restore_binary) if subprocess.call(cmd, shell=True) != 0: self.context.launch('terminal', command=cmd) else: self.context.notify('info', _('Applied successfully'))
class fail2ban(SectionPlugin): def init(self): self.title = 'fail2ban' self.icon = 'shield' self.category = _('Software') self.f2b_v = subprocess.check_output(['fail2ban-client', '--version']).splitlines()[0] self.append(self.ui.inflate('fail2ban:main')) self.binder = Binder(self, self) self.update_status = True def on_config_update(o, c, config, u): if config.__old_name != config.name: if os.path.exists(os.path.join(c.path, config.name)): self.context.notify('error', _( 'File with name {0} already exists in {1}.').format(config.name, c.path)) self.update_status = False config.name = config.__old_name return logging.debug('renamed config file %s to %s' % (config.__old_name, config.name)) os.unlink(config.configfile) config.save() self.update_status = True def on_config_bind(o, c, config, u): config.__old_name = config.name def new_config(c): new_fn = 'untitled{0}.conf' s_fn = new_fn.format('') filename = os.path.join(c.path, s_fn) i = 1 while os.path.exists(filename): s_fn = new_fn.format('_' + str(i)) filename = os.path.join(c.path, s_fn) i += 1 try: logging.debug('add config %s' % filename) conf = f2b_Config(s_fn, c.path) conf.config = config_templates[c.type] return conf.save() except IOError as e: print('Error writing file {0} in {1}'.format(filename, c.path)) def delete_config(config, c): filename = config.configfile logging.debug('removed config %s' % config.configfile) c.remove(config) os.unlink(filename) self.find('configlist').post_item_update = on_config_update self.find('configlist').post_item_bind = on_config_bind self.find('configlist').new_item = new_config self.find('configlist').delete_item = delete_config def on_page_load(self): self.refresh() def refresh(self): self.configurations = [ f2b_Configs(k, d).update() for k, d in config_dirs.iteritems() if os.path.isdir(d) ] self.binder.setup(self).populate() @on('save-button', 'click') def save(self): self.binder.update() if self.update_status: self.context.notify('info', _('Saved')) self.update_status = True self.binder.setup(self).populate() @on('check-regex', 'click') def check_regex(self): self.find('check-status').text = '' log_fname = self.find('log-filename').value filter_fname = self.find('filter-filename').value log_as_text = self.find('log-file').value filter_as_text = self.find('filter-file').value if not (log_fname or log_as_text) or not (filter_fname or filter_as_text): logging.debug('Filter checker. Some parameters are empty.') self.context.notify('error', _('Some parameters are empty.')) return with open(filter_fname + '.tmp', 'w') as rt: rt.write(self.find('filter-file').value) rt_name = rt.name rt.close() p = subprocess.Popen(['fail2ban-regex', '--full-traceback', log_fname, rt_name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, err = p.communicate() self.find('check-status').text = out os.unlink(rt_name) @on('open-filter-button', 'click') def open_filter(self): self.find('openfilterdialog').show() @on('openfilterdialog', 'button') def on_open_filter_dialog(self, button): self.find('openfilterdialog').visible = False @on('openfilterdialog', 'select') def on_filter_file_select(self, path=None): if not path: return self.find('openfilterdialog').visible = False self.find('filter-filename').value = path self.find('filter-file').value = ''.join(open(path).readlines()) @on('open-log-button', 'click') def open_log(self): self.find('openlogdialog').show() @on('openlogdialog', 'button') def on_open_log_dialog(self, button): self.find('openlogdialog').visible = False @on('openlogdialog', 'select') def on_log_file_select(self, path=None): if not path: return self.find('openlogdialog').visible = False self.find('log-filename').value = path self.find('log-file').value = ''.join(open(path).readlines()) @on('save-filter-button', 'click') def save_filter(self): try: open(self.find('filter-filename').value, 'w').write(self.find('filter-file').value) except IOError as e: self.context.notify('error', _('Could not save config file. %s') % str(e)) logging.error(e.message)
class DBPlugin(SectionPlugin): service_name = '' service_buttons = [] has_users = True def init(self): self.append(self.ui.inflate('db_common:main')) self.binder = Binder(None, self) self.find_type('servicebar').buttons = self.service_buttons def delete_db(db, c): self.query_drop(db) self.refresh() self.find('databases').delete_item = delete_db def delete_user(user, c): self.query_drop_user(user) self.refresh() self.find('users').delete_item = delete_user def on_page_load(self): self.refresh() @on('sql-run', 'click') def on_sql_run(self): try: result = self.query_sql( self.find('sql-db').value, self.find('sql-input').value) self.context.notify('info', _('Query finished')) except Exception as e: self.context.notify('error', str(e)) return tbl = self.find('sql-output') tbl.empty() if len(result) > 200: self.context.notify( 'info', _('Output cut from %i rows to 200') % len(result)) result = result[:200] for row in result: erow = self.ui.create('dtr') tbl.append(erow) for cell in row: ecell = self.ui.create('dtd') ecell.append(self.ui.create('label', text=str(cell))) erow.append(ecell) @on('add-db', 'click') def on_add_db(self): self.find('db-name-dialog').value = '' self.find('db-name-dialog').visible = True @on('add-user', 'click') def on_add_user(self): self.find('add-user-dialog').visible = True def refresh(self): self.binder.setup(self).populate() self.databases = [] self.users = [] try: self.databases = self.query_databases() if self.has_users: self.users = self.query_users() except Exception as e: import traceback traceback.print_exc() self.context.notify('error', str(e)) if hasattr(self, 'config_class'): self.context.launch('configure-plugin', plugin=self.config_class.get()) return self.binder.unpopulate() self.find('sql-db').labels = self.find('sql-db').values = [ x.name for x in self.databases ] self.binder.populate() self.find_type('servicebar').reload() @on('db-name-dialog', 'submit') def on_db_name_dialog_submit(self, value=None): try: self.query_create(value) except Exception as e: self.context.notify('error', str(e)) return self.refresh() @on('add-user-dialog', 'button') def on_add_user_dialog(self, button=None): d = self.find('add-user-dialog') d.visible = False if button == 'ok': u = User() u.name = d.find('name').value u.host = d.find('host').value u.password = d.find('password').value try: self.query_create_user(u) except Exception as e: self.context.notify('error', str(e)) return self.refresh() def query_sql(self, db, sql): raise NotImplementedError() def query_databases(self): raise NotImplementedError() def query_drop(self, db): raise NotImplementedError() def query_create(self, name): raise NotImplementedError() def query_users(self): raise NotImplementedError() def query_create_user(self, user): raise NotImplementedError() def query_drop_user(self, user): raise NotImplementedError()
class Tasks(SectionPlugin): def init(self): self.title = _('Tasks') self.icon = 'cog' self.category = _('Tools') self.append(self.ui.inflate('tasks:main')) self.manager = TaskManager.get(manager.context) self.binder = Binder(None, self) def post_td_bind(object, collection, item, ui): if item.get_class(): params_ui = self.ui.inflate(item.get_class().ui) item.binder = DictAutoBinding(item, 'params', params_ui.find('bind')) item.binder.populate() ui.find('slot').empty() ui.find('slot').append(params_ui) def post_td_update(object, collection, item, ui): if hasattr(item, 'binder'): item.binder.update() def post_rt_bind(object, collection, item, ui): def abort(): item.abort() self.refresh() ui.find('abort').on('click', abort) self.find('task_definitions').post_item_bind = post_td_bind self.find('task_definitions').post_item_update = post_td_update self.find('running_tasks').post_item_bind = post_rt_bind self.find('job_definitions').new_item = lambda c: JobDefinition() def on_page_load(self): self.refresh() @on('refresh', 'click') def refresh(self): self.manager.refresh() self.binder.unpopulate() dd = self.find('task-classes') dd.labels = [] dd.values = [] for task in Task.get_classes(): if not task.hidden: dd.labels.append(task.name) dd.values.append(task.classname) dd = self.find('task-selector') dd.labels = [_.name for _ in self.manager.task_definitions] dd.values = [_.id for _ in self.manager.task_definitions] self.find('run-task-selector').labels = dd.labels self.find('run-task-selector').values = dd.values self.binder.setup(self.manager).populate() @on('run-task', 'click') def on_run_task(self): self.manager.run(task_id=self.find('run-task-selector').value, context=self.context) self.refresh() @on('create-task', 'click') def on_create_task(self): cls = self.find('task-classes').value td = TaskDefinition(task_class=cls) td.name = td.get_class().name self.manager.task_definitions.append(td) self.refresh() @on('save', 'click') def on_save(self): self.binder.update() self.manager.save() self.refresh()
class CSFSection (SectionPlugin): def init(self): self.title = _('CSF Firewall') self.icon = 'fire' self.category = _('System') self.backend = CSFBackend.get() self.append(self.ui.inflate('csf:main')) self.config = CSFConfig(path='/etc/csf/csf.conf') self.list_allow = [] self.list_deny = [] self.list_tempallow = [] self.list_tempban = [] def delete_rule(csf_option, i): self.save() subprocess.call(['csf', csf_option, i.value.split('#')[0]]) self.refresh() self.find('list_allow').on_delete = lambda i, c: delete('-ar', i) self.find('list_deny').on_delete = lambda i, c: delete('-dr', i) self.find('list_tempallow').on_delete = lambda i, c: delete('-tr', i) self.find('list_tempban').on_delete = lambda i, c: delete('-tr', i) def add_rule(csf_option, address): self.save() p = subprocess.Popen(['csf', csf_option, address], stdout=subprocess.PIPE) o, e = p.communicate() self.context.notify('info', o) self.refresh() self.find('list_allow-add').on('click', lambda: add_rule('-a', self.find('permanent-lists-add-address').value)) self.find('list_deny-add').on('click', lambda: add_rule('-d', self.find('permanent-lists-add-address').value)) self.find('list_tempallow-add').on('click', lambda: add_rule('-ta', self.find('temporary-lists-add-address').value)) self.find('list_tempban-add').on('click', lambda: add_rule('-td', self.find('temporary-lists-add-address').value)) self.binder = Binder(None, self) self.binder_lists = Binder(self, self.find('lists')) def on_page_load(self): self.refresh() def refresh(self): self.config.load() self.list_allow = self.backend.read_list('allow') self.list_deny = self.backend.read_list('deny') self.list_tempallow = self.backend.read_list('tempallow') self.list_tempban = self.backend.read_list('tempban') self.binder.setup(self.config.tree).populate() self.binder_lists.populate() @on('apply', 'click') def on_apply(self): self.backend.apply() self.context.notify('info', _('Applied')) @on('save', 'click') def save(self): self.binder.update() self.config.save() self.backend.write_list('allow', self.list_allow) self.backend.write_list('deny', self.list_deny) self.backend.write_list('tempallow', self.list_tempallow) self.backend.write_list('tempban', self.list_tempban) self.binder.setup(self.config.tree).populate() self.context.notify('info', _('Saved')) try: self.backend.test_config() self.context.notify('info', _('Self-test OK')) except Exception as e: self.context.notify('error', str(e))
class Filesystems(SectionPlugin): def init(self): self.title = _('Filesystems') self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('fstab:main')) self.find('type').labels = [ 'Auto', 'EXT2', 'EXT3', 'EXT4', 'NTFS', 'FAT', 'ZFS', 'ReiserFS', 'Samba', 'None', 'Loop' ] self.find('type').values = [ 'auto', 'ext2', 'ext3', 'ext4', 'ntfs', 'vfat', 'zfs', 'reiser', 'smb', 'none', 'loop' ] self.fstab_config = FSTabConfig(path='/etc/fstab') self.mounts = MountsBackend.get() self.binder = Binder(None, self) self.find('fstab').find( 'filesystems').new_item = lambda c: FilesystemData() def post_mount_bind(object, collection, item, ui): ui.find('umount').on('click', self.on_umount, item) self.find('mounts').find( 'filesystems').post_item_bind = post_mount_bind def on_page_load(self): self.refresh() def on_umount(self, mount): subprocess.call(['umount', mount.mountpoint]) self.context.notify('info', _('Unmounted')) self.refresh() @on('mount-all', 'click') def on_mount_all(self): self.save() if subprocess.call(['mount', '-a']): self.context.notify('error', _('mount -a failed')) self.refresh() @on('refresh', 'click') def refresh(self): self.binder.unpopulate() self.reload_disks() self.fstab_config.load() self.fstab = self.fstab_config.tree self.mounts.reload() self.binder.setup(self).populate() def reload_disks(self): lst = disks.list_devices(by_uuid=True, by_id=True, by_label=True) self.find('device').labels = [x[0] for x in lst] self.find('device').values = [x[1] for x in lst] @on('save', 'click') def save(self): self.binder.update() self.fstab_config.save() self.context.notify('info', _('Saved'))