The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Операционные системы" / Оглавление документа

3. Более сложные понятия

Продолжаем знакомится с системой Cfengine

3.1. Классы

Понятие классов является основополагающей идее в работе cfengine. То, что работа cfengine основывается на понятии классов, означает, что он не принимает решений, используя конструкции ifthenelse так, как это делают другие языки.

Он выполняет действие только в том случае, если хост, на котором он запускается, принадлежит к тому же классу, что и само действие. Чтобы понять, что это значит, представим себе процесс выбора определённых хостов из общего списка всех хостов сайта. Допустим, что мы ищем такой класс хостов, которые принадлежали бы к вычислительному отделу, работали бы с операционной системой GNU/Linux и имели бы жёлтые пятна. Для того, чтобы определить удовлетворяет ли конкретный хост данным критериям, в первую очередь, нужно исключить из рассмотрения все хосты, работающие на операционных системах, отличных от GNU/Linux. Затем из числа оставшихся необходимо исключить не принадлежащие вычислительному отделу, а затем из оставшихся исключить хосты без жёлтых пятен. В оставшемся списке будут находиться хосты, удовлетворяющие всем критериям. Теперь над ними можно выполнять действия.

Cfengine работает подобным образом. Весь описанный выше процесс он сводит к проверке принадлежности хоста нескольким классам одновременно. Хотя определённая информация о хостах может быть получена напрямую (например, используемая операционная система), но очевидно, что для проверки остальных параметров необходимо иметь список хостов, принадлежащих к вычислительному отделу и список хостов с жёлтыми пятнами.

Как это осуществляется в программе cfengine? Программа или конфигурационный скрипт состоит из ряда объявлений, называемыми действиями (action), которые должны выполняться только для определённых классов хостов. Любой хост может запускать программу, но выполняться будет только то действие, которое соответствует данному конкретному хосту. Это происходит автоматически, поскольку cfengine создаёт список классов, которому принадлежит хост, в процессе работы, поэтому ему не приходиться снова и снова принимать большого числа решений.

Создание классов, которые классифицировали бы хосты системы неким простым для понимания путём, позволяет за один раз выполнять одно действие для нескольких хостов, причём только для тех, для которых нужно. Можно создавать классы, согласно определённому типу операционной системы, можно сгруппировать вместе кластеры и рабочие станции в зависимости от того, кто будет их использовать, также можно помечать их жёлтыми пятнами и многое многое другое.

Действие в cfengine выглядит примерно следующим образом:

action-type:     (тип действия)
      compound-class::        (классы)
              declaration        (объявления)

Класс может быть следующим:

Составной класс представляет собой последовательность простых классов, связанных точками или символом конвейеризации (вертикальные черточки). Наприме

myclass.sun4.Monday::
sun4|ultrix|osf::

Значение составного класса является истинным, если значение всех входящих в него простых классов является истинным. Таким образом, в рассмотренном примере действия, следующие после compound_class:: будут выполнены, если рассматриваемый хост принадлежит myclass, имеет тип sun4 и всё происходит в понедельник. Во втором примере, хост, на котором запущен файл, должен быть либо sun4, либо Ultrix, либо osf. Другими словами, составные классы поддерживают работу с двумя операторами AND (и) или OR (или), обозначаемыми . или | соответственно. Начиная cfengine версии 2.1.1. для оператора AND (и) также используется символ &. Cfengine не имеет ограничений на количество используемых операторов (поскольку он пропускает пустые имена классов), поэтому возможны разные формы записи:

     solaris|irix::
или
     solaris||irix::

в зависимости от желания. С другой стороны, важен порядок записи операторов AND и OR.

Правило состоит в том, что AND имеет более высокий приоритет, чем OR. Поэтому . тесно связывает классы, и операторы OR  будут исполнены только после того, как были выполнены  все операции AND. Это характерно для всех языков программирования. Для изменения такого порядка необходимо использовать круглые скобки.Cfengine предоставляет возможность определять активные и неактивные временные (dummy) классы, что позволяет выбрать определённое подмножество действий. В частности, стоит заметить, что определяя собственные классы, используя их для создания составных правил данного типа, а затем включая и выключая их,  также можно включить и выключить соответствующие действия контролируемым способом (in a controlled way). Для этого можно использовать опции командной строки D и N. См. addclasses в приложении к руководству.Оператор логического отрицания (NOT) был добавлен, чтобы позволить более удобным способом исключать определённые хосты. Оператор логического отрицания NOT, как и в C и C++, обозначается символом !. В следующем примере исключается хост с именем myhost:

action:
!myhost::
command

аналогичным образом, следующий пример разрешает все хосты определённой пользователем группы mygroup за исключением myhost:

action:
    mygroup.!myhost::
          command

что читается, как  mygroup AND NOT myhost. Оператор NOT также можно сочетать с оператором OR. В примере class1|!class2 будут выбраны хосты, которые либо принадлежат классу class1 или не принадлежат классу class2.

Наконец, существует ряд зарезервированных классов. Приведённые ниже классы являются жёсткими для различных архитектур операционных систем. Их не нужно определять, так как каждый хост знает, какая операционная система на нём установлена. Таким образом, для каждого хоста всегда будет выбран один из них. По тем же причинам, очевидно, не нужно определять день недели, за исключением случая, когда cfengine запускается из космоса. Зарезервированными классами являются:

ultrix, sun4, sun3, hpux, hpux10, aix, solaris, osf, irix4, irix, irix64 sco, freebsd, netbsd, openbsd, bsd4_3, newsos, solarisx86, aos, nextstep, bsdos, linux, debian, cray, unix_sv, GnU, NT

Если данных классов недостаточно для различения хостов сети, то cfengine имеет ряд более специальных классов, которые содержат имя и релиз операционной системы. Чтобы понять, как это выглядит для конкретной системы, можно запустить cfengine в режиме parse-only-verbose (анализ-только-диалог):

cfagent -p v

и эта информация будет выведена. Например, системы Solaris 2.4. создают дополнительные классы sunos_5_4 и sunos_sun4m, sunos_sun4m_5_4.

В качестве имён классов cfengine использует как неуточнённые, так и полные имена хостов. Некоторые сайты и операционные системы для своих хостов используют полностью уточнённые имена, то есть uname n вернётся к полному доменному уточнённому имени хоста. Это вызывает неполадки в алгоритмах сопоставления классов cfengine, поэтому он автоматически сокращает имена, содержащие точку .до первой, с которой он встретится. Если имя хоста содержит точки (которые не относятся к доменному имени), то cfengine запутается. Отсюда вывод: имена хостов не должны содержать точек! Внимание: для того, чтобы бы убедиться, что полностью уточнённое имя хоста становится классом, необходимо определить переменную домена. Точки в этой строке будут заменены символами подчёркивания.

Приведём список операторов, которые можно использовать при работе с классами в cfengine:

3.2. Замена переменных

При создании файла конфигурации очень удобно иметь возможность использовать переменные. Возможность определить конфигурацию с использованием некоторых ключевых переменных ключа, может упростить её редактирование в дальнейшем, сделать её более понятной для чтения, а также позволит по-разному определять переменные на различных типах систем. Другими словами, переменные в cfengine также принадлежат классам. В cfengine существует три направления использования переменных:

Переменные окружения получаются непосредственно из оболочки, на какой бы системе не запускалась программа. Примером специальной переменной является переменная domain предыдущего раздела. Прямая макро-замена позволяет определить символьное имя, которое следует заменить произвольной текстовой строкой. Все эти определения (естественно, за исключением переменных окружения shell) производятся в части control программы cfengine:

control:
myvar = ( /usr/local/mydir/lib/very/long/path ) # define macro
...
links:
$(myvar) -> /another/directory

В данном примере определяется макро под названием myvar, которая в дальнейшем используется, чтобы обозначить создание ссылки. Также можно определять переменные, зависимые от классов:

control:
sun4:: myvar = ( sun )
hpux:: myvar = ( HP )

Cfagent предоставляет доступ к переменным окружения shell и позволяет создавать собственные переменные. Он также имеет несколько специальных переменных, влияющих за его работу. При раскрытии переменной cfengine в первую очередь ищет такое имя в своём списке специальных переменных, затем в определённых пользователем макро-переменных и только потом среди переменных оболочки. Если соответствие так и не было установлено, он вернёт пустую строку. При вставке макро-переменных необходимо заключать правую часть в кавычки и убедиться, что значение уже определено:

control:
myvar = ( "$(othervar)" )

Значения также можно вставлять из выполнения команд shell. Для этого перед командой необходимо поставить exec. Этот метод резко осуждается в версии 2 и был заменён функцией.

control:
# old method
listing = ( "exec /bin/ls -l" )
# new method
listing = ( ExecResult(/bin/ls -l) )
Это задаёт листинг переменных в вывод команды в ковычках.

Некоторые другие внутренние функции:

RandomInt(a,b)
Выдаёт случайное число между a до b.
ExectResult(command)

Выполняет заданную команду shell и записывает результат в переменную. Например:

control:
variable2 = ( RandomInt(0,23) )
variable3 = ( ExecResult(/bin/ls -a /opt) )

В зависимости от желания к переменным можно обратиться двумя различными способами. Можно использовать формы $(переменная) или ${переменная}. Переменной в круглых или фигурных скобках может быть имя любого определённого пользователем макро, переменная окружения или одна из следующих специальных внутренних  переменных.

AllClasses Длинная строка вида CFALLCLASSES=class1:class2. Эта переменная является перечнем всех когда-либо определённых классов. Информация в ней постоянно обновляется для того, чтобы скрипты могли использовать данные о классах cfengine.
Arch Текущая детализироанная строка архитектуры, представляющая собой объединения всей информации из uname. Неопределяемая переменная.
Binserver Сервер, используемый по умолчанию, для двоичных данных. См. Раздел 4.6. [ресурсы NFS]. Неопределяемая переменная.
class Ныне определённый жёсткий класс системы (например, sun4, hpux). Неопределяемая переменная.
date Строка с текущей датой. Обратите внимание, что при её использовании в командах оболочки, она может быть проинтерпретирована как переменная списка, так как она по умолчанию содержит разделитель :.
domain Определённый в настоящее время домен
faculty Факультет или сайт, согласно определению в контроле (см. сайт)
fqhost Полностью уточнённое (DNS/BIND) хостимя системы, которое также включает доменное имя.
Host Хостимя машины, на которой запущена программа.
Ipaddress Интернет адрес хоста, на котором в данный момент работает cfengine, записанный в числовой форме.
MaxCfengines Максимальное число cfengine, которые могут одновременно сосуществовать в системе. Это позволяет предотвратить перегрузку из-за непреднамеренного спаминга в ситуации, когда несколько cfagent запускаются независимо друг от друга. Значение по умолчанию это количество неограниченно.
ostype Краткий вариант для $(arch)
OutPrefix Такую строку, записанную в двойных кавычках, можно использовать для смены cfengine по умолчанию: префикс в выходных строках на что-то другое. Возможно укоротить строку или установить разные префиксы для разных хостов. К значению данной переменной также прибавляется имя хоста. По умолчанию:
OutputPrefix = ( cfengine:$(host): )
RepChar Символьное значение строки, используемой файловым хранилищем в процессе создания уникальных файловых имён из имён пути. Такая строка заменяет символ /. (см. приложение к руководству)
site Эта переменная идентична $(faculty) и может употребляться вместо неё
split Признак, по которому разделяются переменные списка (см. приложение к руководству)
sysadm Имя или e-mail системного администратора
Timezone Текущая временная зона, определённая в control
UnderscoreClasses Если установлено значение on, то cfengine использует жёсткие классы, начинающиеся с символа нижнего подчёркивания, с целью избежать столкновения имён. Смотрите также опции Runtime в приложении к руководству.
year
текущий год

Данные переменные определены, как специальные, потому что они играют особую роль в создании конфигурации системы, см. главу 4 [Глобальная конфигурация]. Их очень полезно использовать для задания полностью обобщённых правил в программе. Переменные также могут использоваться при определении имён файлов и директорий, а также для передачи аргументов командам оболочки. Разумное использование переменных может помочь свести множество определений в одно при тщательном планировании.

Внимание: перечисленные выше переменные управления не чувствительны к регистрам, в отличие от пользовательских макросов. Поэтому нельзя определять пользовательские макросы с этими именами.

Следующие переменные также являются зарезервированными и могут быть использованы для включения в строки специальных сложных символов.

cr
символ возврата каретки
dblquote
символ двойных кавычек
dollar символ $
n символ начала строки
quote единичная кавычка
spc
пустой символ. Он может быть использован, например, для вставки пробелов в именя файлов и т.д.
tab единичная табуляция

Переменные модно использовать в следующих случаях:

links:
    osf::
          /$(site)/${host}/directory -> somefile
<!-- @page { size: 21cm 29.7cm; margin: 2cm } P { margin-bottom: 0.21cm } -->
shellcommands:
any::
"/bin/echo $(timezone) | /bin/mail $(sysadm)"
'/bin/echo "double quotes!"'

Переменные могут быть по-разному определены под разными классами, если перед определением поставить имя класса. Например:

control:
sun4:: my_macro = ( User_string_1 )
irix:: my_macro = ( User_string_2 )

В данном примере значение, присваиваемое $(my_macro) зависит от того, на каком из классов будет выдано значение истины. Такая возможность может быть эффективно использована для задания mail адреса нужного системного администратора для разных групп хостов.

control:
physics:: sysadm = ( mark,fred )
chemistry:: sysadm = ( localsys@domain )
Обратите внимание, что опция -a может быть использована, чтобы вывести mail адрес системного администратора для любого вложенного скрипта.

3.3. Неопределённые переменные

Обратите внимание, что неопределённые макро-переменные не развёртываются на версии 1.6 cfengine. В более ранних версиях неопределённые переменные заменялись пустой строкой, как в Perl. Начиная с версий 1.6.x строка с переменной не заменяется, если переменной не существует. Например,control:

actionsequence = ( shellcommands )
myvar = ( "test string " )
shellcommands:
"/bin/echo $(myvar) $(myvar2)"
results in:
cfengine:host: Executing script /bin/echo test string $(myvar2)
cfengine:host:/bin/echo test : sh: syntax error at line 1: `(' unexpected
cfengine:host: Finished script /bin/echo test string $(myvar2)
Это позволяет модулям определять переменные в процессе работы.

3.4. Определение классов и создание исключений

Cfengine говорит сам с собой, посылая сообщения в форме классов. Когда класс переходит во включенное или выключенное состояние, программа cfengine изменяется соответствующим образом. Существует несколько способов включения и выключения классов. Полное изучение этого механизма потребует времени, но только после этого станет возможным использовать в cfengine полную силу.

В связи с тем, что cfagent работает на очень высоком уровне, выполняя множество действий, соответствующих всего нескольким строкам кода, может показаться, что это сделано в ущерб гибкости. Когда некоторые действия приписываются специальным классам, то временами может оказаться удобным иметь возможность на время выключить классы, чтобы выключить специальные действия.

3.4.1 Классы командной строки

Можно самостоятельно определять классы, которые могут быть включены или выключены, как через командную строку, так и через последовательность действий action sequence. Например, определим класс include. Для этого используется addclasses.

addclasses = ( include что-то )

Целью такого создания позволить задавать действия, подлежащие исключению. Действия, определённые с помощью

any.include::
actions

будут выполняться при обычных обстоятельствах, поскольку с помощью addclasses мы определили значение include, как истинное. Но если cfagent запускается в ограниченном режиме, где значению include соответствует ложь, эти действия могут быть исключены.

Итак, присваивая символу include значение ложь, можно исключить все действия, которые в качестве своего члена содержат include. Это может быть сделано двумя способами. Один глобально проотрицать класс, используя

Cfagent N include.

Это исключает класс include на протяжении всей программы.

3.4.2. Классы последовательности действий actionsequence

Другим способом определить действия является использование классов, чтобы выбрать только подмножество всех действий, заданных в actionsequence. Это можно сделать, добавив имя класса к одному из действий в последовательности действий, используя точку . для разделения слов. В таком случае символу будет присвоено значение истины на протяжении только того действия, к которому он был присоединён. Например:

links.onlysome
shellcommands.othersymbols.onlysome

В первом случае onlysome будет истинным пока выполняется links. Это значит, что в результате такого задания выполняться будут только действия, отмеченные классом onlysome. В следующем примере как onlysome, так и othersymbols определены как истинные при выполнении shellcommands.

Такой синтаксис обычно используется для того, чтобы избежать определённых действий, требующих большого количества времени, например, чистка всех домашних папок. Также его можно использовать для синхронизации определённых действий, которые должны выполняться в определённом порядке.

3.4.3. Классы shellcommand

Для более широкого использования возможностей cfengine, может возникнуть потребность определять классы, исходя из успешного или неуспешного выполнения пользовательской программы, команды shell или пользовательского скрипта. Рассмотрим следующий пример:

groups:
have_cc = ( "/bin/test -f /usr/ucb/cc"
"/bin/test -f /local/gnu/cc" )

Обратите внимание, что в версии cfengine 1.4.0 слово classes можно использовать в качестве алиаса для groups. Каждый раз, когда cfagent встречает объект в списке классов или переменной, заключённой в двойные, одинарные или обратные кавычки, он пытается исполнить такую строку, как команду, переданную Bourne shell. Если результирующая команда возвращает код нуля (означающий выход), тогда классу стоящему по левую сторону знака равно (в данном примере have_cc) присваивается значение истины. В случае, если команда вернула любое другое значение (номер ошибки) результатом будет ложь. Так как группы получаются с помощью операции логического ИЛИ их членов (достаточно, чтобы только один член принадлежал текущей системе), то класс have_cc в рассмотренном примере будет определён, если существует или /usr/ucb/cc, или /local/gnu/cc, или оба сразу.

3.4.4. Классы feedback (обратной связи)

Классы могут представлять собой результат действий, выполняемых cfagent. Например, можно настроить cfagent так, что при копировании файла, его редактировании или при нехватке пространства на диске из-за существующего ограничения, он ответит активацией классов в течение рабочего цикла. Это позволяет создавать программы, которые способны динамично отвечать, реагируя на изменения среды. Такие классы задаются как часть других предложений с основами в форме

define=classlist

Подобные классы, как правило, должны быть определены в начале программы, если только define не всегда предшествует действиям, которые используют созданные классы, с addinstallable.

3.4.5. Создание вспомогательных (plugin) модулей

В том случае, когда обычные механизмы создания классов не приводят к требуемым для конфигурации результатам, то существует возможность писать собственные программы для создания классов, отвечающих всем желаниям. Вспомогательные модули добавляются в программы cfagent  внутри последовательности действий action sequence (см. приложение к руководству). Они позволяют создавать специальный код для решения задач, которые сложно решить с использованием других, рассмотренных ранее, механизмов. Это позволяет управлять классами, которые будут включены, и моментом, когда модуль будет пытаться оценить состояние системы.

Модули должны храниться в специальной папке, определённой переменной moduledirectory. Они должны иметь имя вида module:mymodule и должны следовать простому протоколу. Cfagent будет запускать модуль, принадлежащий либо корню, либо пользователю, запускающему cfagent, только если он находиться в специальной папке и под особым именем. Вспомогательный модуль может быть написан на любом языке и иметь любой вывод. Но строки, начинающиеся со знака + воспринимаются, как классы, которые должны быть определеными (как -D), тогда как начинающиеся с -, трактуются как классы, которые должны быть неопределёнными (как -N).

Строчки, начинающиеся с = являются переменными \ макросами, которые должны быть определёнными. Любые другие строки вывода размещаются cfagent, так что, как правило, модуль должен быть совершенно молчаливым. Ниже приведён пример модуля на Perl. В первую очередь определяется модуль в программе cfagent:

actionsequence = (
files
module:myplugin
"module:argplugin arg1 arg2"
copy
)
...
AddInstallables = ( specialclass )

Обратите внимание, что определения классов для модуля также должны быть заданы в AddInstallables, если так удобнее. Кроме того, необходимо запомнить, что классы необходимо объявлять до их использования в конфигурации cfagent, в противном случае такие действия будут пропущены. Теперь создаётся сам плагин:

#!/usr/bin/perl
#
# module:myplugin
#
# lots of computation....
if (special-condition)
{
print "+specialclass";
}

Модули получают переменные среды из cfagent и  воспринимают аргументы также как и обычная команда shell.

#!/bin/sh
#
# module:myplugin
#
/bin/echo $*

Cfagent определяет классы как переменную окружения, так что программы имеют к ним доступ. Например, следующий модуль:

#!/usr/bin/perl
print "Decoding $ENV{CFALLCLASSES}\n";
@allclasses = split (":","$ENV{CFALLCLASSES}");
while ($c=shift(@allclasses))
{
$classes{$c} = 1;
print "$c is set\n";
}

Модули могут определять макросы в cfagent, выводя строчки в форме

=variablename=value

Когда переменная $(allclasses) становиться слишком большой для удобной работы, доступ к списку всех созданных к текущему моменты классов можно получить в файле /var/cfengine/state/allclasses.

3.5. Общий класс any

Общий групповой символ any может обозначать любой класс. Таким образом, вместо описания действий только для класса sun4, можно определить действия для любой архетиктуры, записав:

any::
actions

Если никакого класса не определено, то cfengine устанавливает принятое для классов значение по умолчанию.

3.6. Подсказки по устранению ошибок

Полезный приём при устранении ошибок избегать нежелательных действий, путём изменения их классового имени. Так как cfengine воспринимает любое непонятное имя, как имя хоста, то он просто будет игнорировать неузнаваемые записи. Например:

Myclass:: можно заменить на Xmyclass::

Поскольку Xmyclass уже не соответствует ни одному из созданных классов и не является именем какого-либо хоста, то он будет просто проигнорирован. С этой же целью может также быть использована опция -N (см. приложение к руководству).

3.7. Контроль доступа

Иногда оказывается удобным иметь возможность ограничивать доступ к программе для определённого круга пользователей. Это можно сделать, добавив список доступа в секцию control: программы. Например,

control:
...
access = ( mark root )

приведёт к тому, что cfengine откажется запускать программу для любых пользователей за исключением mark и root. Такое ограничение может быть полезно, например, при желании создать скрипт, устанавливающий id пользователя(set-user-id), но так, что только определённые пользователи смогли бы его использовать. Если список доступа отсутствует, то все пользователи могут запускать программу.

Обратите внимание: при запуске cfagent через программу cfrun cfagent всегда начинается с одной и той же пользовательской личности, как и процесс cfservd на удалённом хосте. Как правило, это корневая пользовательская личность (главный пользователь). Это значит, что ключевое слово, по которому осуществляется доступ, никак не повлияет на использование команды cfrun.

3.8. Групповые символы в названиях папок

В двух действиях - files и tidy задаются имена папок, с которых должны начаться проверка или чистка файлов. Использование групповых символов даёт возможность существенно сэкономить время,  позволяя определять целую группу папок, где должны разом запускаться такие же процессы. Например, имена папок

/usr/*/*
/bla/*/ab?/bla

представляют все директории (и только директории), которые соответствуют обозначенным строкам групповых символов. Cfagent открывает каждую, удовлетворяющую такому определению папку, и выполняет действие над каждой такой директорией.

Символ ? соответствует любому одиночному символу, тогда как * соответствует любому числу символов, в соответствии с групповыми символами файловой подстановки, определёнными в shell.

Когда такая форма записи используется при задании имён папок, она всегда определяет точку, с которой начинается поиск. Она не выдаёт команд, как искать, а только задаёт место начала. Для задания моделей чистки файлов может быть использована папка pattern в tidy, а под files рассматриваются все файлы (см. приложение к руководству).

3.9. Рекурсивный обход файлов (file sweeps) \ обход директорий

Обход файлов представляет собой процесс поиска по всему дереву папок, при котором большое число фалов анализируется и обрабатывается каким-либо образом. Существует много случаев, когда cfagent используется для осуществления обхода файлов:

Проблема при обходе файлов может заключаться в излишней тщательности, так как зачастую нет необходимости анализировать каждый файл из дерева файлов. Возможно желание выполнять поиск

В этом отношении действие tidy немного отличается от прочих, так как  уже всегда предполагается, что оно выполняется согласно определённой модели. Как правило, никому не нужно осуществлять обход файлов, удаляя все, не соответствующие заданному образцу: это может оказаться слишком опасным. Именно поэтому синтаксис tidy запрещает использование ignore, include и exclude. Об этом можно прочитать в разделе про удаление файлов (см. приложение к руководству).

Объявления в глобальном разделе ignore затрагивают files, copy, links и tidy. Для обхода файлов внутри files, copy и links можно создать отдельные списки ignore, записав ignore=. Разница между exclude и ignore заключается в том, что последний может работать с абсолютными папками. Он исключает папки, тогда как exclude ищет файлы внутри папок.

Для обхода файлов внутри files и copy можно задавать специальные параметры поиска, используя ключевые слова include= и exclude=, а для версий 1.6.x ещё и filter=. Например,

files:
/usr/local/bin m=0755 exclude=*.ps action=fixall

В данном примере cfagent осуществляет поиск по всему файловому дереву (за исключение папок, описанных в списке ignore и фалов, оканчивающихся на .ps), (см. приложение к руководству).

Использование ключевого слова include= немного отличается от остальных, так как оно автоматически сводит поиск только к заданным (через * и ?) образцам, везде и в каких количествах оно бы не встречалось. Если задавать образцы таким способом, то cfagent будет игнорировать любые файлы, которые не соответствуют заданным образцам. Он также будет игнорировать все образцы, которые были определены в глобальном списке игнорирования, как и те, которые были исключены с помощью exclude=pattern. Другими словами, операция exclude всегда аннулирует операцию include.

В случае, если возникает необходимость особым образом обработать исключённый образец или папку, то для них нужно отдельно написать подробную проверку. Например, для того, чтобы обработать исключённые ранее файлы с расширением .ps, потребуется создать нечто подобное:

files:
/usr/local/bin m=0644 include=*.ps action=fixall

Важно никогда не заключать групповые символы в кавычки. Кавычки воспринимаются буквально и образец может трактоваться не так, как было задумано.

Для editfiles синтаксис немного отличен. Для редактирования строфы необходимо добавлять строчки:

editfiles:
{ /tmp/testdir
Include .*
Exclude bla.*
Ignore "."
Ignore ".."
Recurse 6
ReplaceAll "search" With "replace"
}

 

3.10.Безопасность рекурсивного обхода файлов

Рекурсивный обход папок с выполнением масштабных операций деструктивного характера может оказаться весьма опасным, если досконально не знать всей структуры папок.

Предположим, что пользователь, имеющий права доступа к файловой системе, добавил символическую ссылку на /etc/passwd, а затем происходит рекурсивное удаление. Таким образом, cfengine внезапно превращается в инструмент разрушительного действия. Именно поэтому, cfengine по умолчанию не переходит по символическим ссылкам при рекурсивном спуске. Для того, чтобы это поменять, можно установить значение true для параметра travlinks. Однако, как правило, менять значение этого параметра не следует, особенно если ненадёжные пользователи имеют доступ к частям файловой системы, тогда, например, можно рекурсивно удалить /tmp.

Cfagent выявляет атаки путём быстрого создания ссылок, при которых пользователи пытаются заменить папку на ссылку в промежутки между системными вызовами. Таким образом они пытаются обмануть cfagent, заставляя воспринимать ссылку за папку, как в версии 2.0.3.(и 1.6.4.)

Обратите внимание, что даже когда travlinks присвоено значение истины, cfagent не будет следовать по символической ссылке, созданной не владельцем ID пользователя агента. Это сделано для минимизации риска атак быстрыми ссылками, при которых пользователи с правами записи могут перенаправить cfagent в другую часть системы.

3.11. Журнал регистрации, cоздаваемый cfagent

Внутри себя cfagent хранит два вида журналов регистрации и позволяет протоколировать его деятельность в системном журнале. Такая функция активизируется с помощью переменной Syslog (см. приложение к руководству).

Первый протокол, хранящийся cfagent, предназначен для каждого пользователя (каждая поддиректория домашней директории файловой системы). Файл ~/.cfengine.rm хранит список всех файлов, удалённых в ходе последнего запуска функции tidy. Это может потребоваться пользователям, чтобы узнать, какие файлы были удалены без их ведома.Также такая функция поможет узнать, что происходит с системой в случае каких-либо сбоев.

Второй файл создаётся, когда cfagent просматривает дерево файлов в ходе действия files. Он представляет собой список всех программ, которые являются setuit root, или setgid root. Так как подобные файлы представляют потенциальную опасность безопасности, то cfagent всегда выдаёт предупреждение, когда встречает новый (т.е. который ещё не находится в списке). Это позволяет системному администратору своевременно отслеживать новые программы, которые появляются и предоставляют пользователям доступ к корню. Журнал регистрации cfagent называется /var/cfengine/cfengine.log. Этот файл не доступен для чтения обычным пользователям.

3.12. Строки в кавычках

В нескольких командах cfengine для того, чтобы задать количество текста, который может содержать пробелы,  используются строки в кавычках. Например:

control:
macro = ( "mycommand" )
editfiles:
{ $(HOME)/myfile
AppendIfNoSuchLine 'This text contains space'
}

Для того, чтобы разграничивать строки в каждом из случаев можно использовать любой из трёх видом кавычек или или .

При использовании, например, , такой же символ уже нельзя использовать внутри самой строки. То же самое относится и ко всем остальным типам кавычек.  В отличии от shell, cfengine воспринимает все три вида абсолютно одинаково между ними не существует никакой разницы. В версиях до 2.0.7. для того, чтобы процитировать строку, заключённую в кавычки, необходимо использовать тип, отличный от уже используемых. Начиная с версии 2.0.7. знаки кавычек можно опустить.

qstring = ( "One string\"with substring\" escaped" )

Обратите внимание, что для определённых символов в строке можно использовать специальные переменные (см. раздел 3.2. [Замена переменных]).

3.13. Регулярные выражения

В cfagent регулярные выражения могут использоваться в сочетании с editfiles и processes для поиска строк, которые удовлетворяют определённым условиям. Регулярное выражение это обобщённый групповой символ. В групповых символах cfagent * и ? могут использоваться для обозначения любого символа или нескольких символов. Работа с регулярными выражениями является более трудной, но зато они гораздо более гибкие в использовании.

Внимание: значение специальных символов * и ?, используемых в групповых символах, отличается от использования их в регулярных выражениях.

Некоторые регулярные выражения соответствуют только единственной строке. Например, каждая строка, не содержащая специальных символов, является регулярным выражением, соответствующим только строке, идентичной ему самому. То есть, регулярное выражение cfengine будет соответствовать только строке cfengine , а не Cfengine или cfengin и т.д. Другие регулярные выражения могут соответствовать и большему количеству срок. Например, регулярное выражение *c будет подходить для любого числа c (включая и одно). Таким образом, это выражение будет соответствовать пустой строке, c, ccc, cccccccc, но не cccx.

Ниже приведён список регулярных вырадений специальных символов и операторов:

 \
Как правило обратная косая черта имеет определённое предназначение: она либо вводит новую команду, либо выражение, поясняющее, что следующий символ не является специальным. Данный символ означает сам себя, только когда он заключён в квадратные скобки [\] или заключён в кавычки сам с собой \\.
\b
Определяет границы слова
\B
Ставиться внутри слова (оператора)
`\<' 
 Соответствует началу слова
`\>' 
Соответствует началу слова
`\w' Соответствует символу, который может являться частью слова
`\W' Соответствует символу, который не может являться частью слова
`any character' Соответствует сам себе
`.' Соответствует  любому символу
`*'  
Соответствует любому числу (в частности, нулю) вхождений предшествующего символа. Например, `c*'. Если перед ним не стоит никакого символа, то он представляет звёздочку в буквальном смысле.
`+' 
Соответствует любому числу (начиная с одного) вхождений  следующего за ним символа.
`?' 
Соответствует нулю или одному вхождению  следующего за ним символа.
`{ }'
Число вхождений оператора. `{5}' будет соответствовать именно 5 разам вхождения предыдущего символа. `{6,}' будет значить по меньшей мере 6 раз вхождения предыдущего символа. `{7,12}' будет соответствовать от 7 до 12 случаям вхождения последующего символа. Очевидно, что для того, чтобы выражение имело смысл, необходимо, чтобы первое число было меньше второго.
`|'  
Оператор логического ИЛИ, выполняет операцию логического сложения над двумя регулярными выражениями..
`[list]' Определяет набор символов, которые следует трактовать, как один объект (ORed).Например, `[a-z]'соответствует любому символу от a до z, `abcd' будет соответствовать либо a, либо b, либо c, либо  d. Большинство символов внутри списка являются обычными, но существуют исключения: `]' обозначает конец списка, только если не стоит на первом месте, , `\' заключает следующий символ в кавычки, `[:' и `:]' определяют оператор символьного типа (см. ниже), и `-' представляет ряд символов, только если не стоит на первом или последнем месте в списке.
`[^list]' определяет список символов, с которыми нельзя осуществлять сопоставление, то есть строка может совпадать с любыми символами за исключением находящихся в списке.    
``[:class:]'' определяет класс символов, используя ctype-library.
  alnum числовой знак начала
alpha  символ алфавита
blank  пробел или символ табуляции
cntrl управляющий символ
digit 0-9
graph print, но без пробелов
lower буква нижнего регистра
print  печатные символы(не управляющие символы)
punct символы не являющиеся ни управляющими, ни алфавитными
space пробел, символ возврата каретки, символ перевода строки, вертикальная табуляция, символ прогона листа.
upper буква верхнего регистра
xdigit шестнадцатеричная цифра 0-9, a-f
``( )'' группирует любое число операторов.
`\digit' оператор обратной ссылки (относится к GNU документации regex documentation).
`^' Соответствует  началу строки
`$' Соответствует концу строки

Ниже приведены несколько примеров. Следует помнить, что некоторые команды ищут регулярные выражения, совпадающие с частью строки, тогда как другим требуется полное совпадение строк (см. приложение к руководству).

^#  соответствует строке, начинающейся с символа #
^[^#] соответствует строке, начинающейся не с символа #
^[A-Z].+ соответствует строке, начинающейся с буквы верхнего регистра, следом за которой стоит по меньшей мере один символ.

3.14. Итерация в списках3.14.Итерация в списках

Переменные списка shell как правило определяются путём объединения списка папок с помощью символа конкатенации, такого как :. Типичным примером может быть переменна PATH:

PATH=/usr/bin:/usr/local/bin:/usr/sbin

Очень удобно иметь возможность использовать такие переменные для того, чтобы заставить cfagent делать итерацию в списках. Это даёт способ компактно записывать повторяющиеся операции и позволяет просто устанавливать взаимодействие со средой shell. В целях безопасности, итерация поддерживается только в следующих ситуациях:

Как правило, это предоставляет возможность взаимодействия в shell с переменными окружения типа PATH.

В приведённых ситуациях, любая переменная которая представляет собой список, объединённый с помощью двоеточия, будет повторяться в течении компиляции. Обратите внимание, что значение разделителя списка можно поменять с помощью переменной Split в секции управления control программы (см. приложение к руководству).
Например, для связи всех бинарных файлов в переменной окружения PATH в единую папку, стирая в ходе этого процесса уже мёртвые ссылки, необходимо написать:

control:
actionsequence = ( links tidy )
links:
/allbin +> $(PATH)
tidy:
# Hopefully no-match matches nothing
/allbin pattern=no-match age=0 links=tidy

Слово no-match не является зарезервированным в cfengine, это всего лишь строка, которая не должна соответствовать никакому файлу.
Для того, чтобы задать полный список, используя символ пробела в качестве разделителя, необходимо:

control:
Split = ( " " )
mylist = ( "mark ricky bad-dude" )
tidy:
/mnt/home1/$(mylist) pattern=*.cfsaved age=1

В данном примере действие tidy будет повторяться в директориях `/mnt/home1/mark', `/mnt/home1/ricky' и `/mnt/home1/bad-dude'.

Как правило, число переменных типа списка в любом пути или имени файла должно не превосходить одного или двух, так как случайная комбинация двух списков иногда может создать что-то значащий образец. Единственным очевидным исключением является осуществление итерации в подпапках типа bin, lib и т.д., находящихся в нескольких различных пакетных директориях (package directory).

 




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру