provision.help.inc 15.7 KB
Newer Older
1
<?php
2
// $Id$
3 4 5 6
/**
 * @file ProvisionHelp contains the bulk of the provision help system
 */

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

/**
 * Constants used to generate the requirement help documentation.
 */
/** Status is irrelevant. Can't be checked **/
define('PROVISION_STATUS_NONE', 0);
/** Requirement is met. **/
define('PROVISION_STATUS_SUCCESS', 1);
/** Requirement not met. Less severe than an error. */
define('PROVISION_STATUS_WARNING', 2);
/** Requirement failed. Fix before site will function. */
define('PROVISION_STATUS_ERROR', 4);

/**
 * Returns a class name for the output of the form element.
 */
function _provision_status_class($status)  {
  static $map;
 
  if (!sizeof($map)) {
   $map = array(
      PROVISION_STATUS_NONE => 'provision-status-none',
      PROVISION_STATUS_SUCCESS => 'provision-status-success',
      PROVISION_STATUS_WARNING => 'provision-status-warning',
      PROVISION_STATUS_ERROR => 'provision-status-error',
    );
  }

  return $map[$status];
}

/**
 * Constants used to configure contextual hosting help
 */
/** Display component of help **/
define('PROVISION_HELP_ENABLED', 1);
/** Don't show help component **/
define('PROVISION_HELP_DISABLED', ~PROVISION_HELP_ENABLED);
45 46 47 48 49

/** These are internally used to test against. Use the COLLAPSIBLE AND COLLAPSED instead **/
define('_PROVISION_HELP_CAN_COLLAPSE', 2);
define('_PROVISION_HELP_HAS_COLLAPSED', 4);

50 51 52 53
/**
 * Show help with the ability to collapse to save space. 
 * This automatically enables the help component
 **/
54
define('PROVISION_HELP_COLLAPSIBLE', PROVISION_HELP_ENABLED | _PROVISION_HELP_CAN_COLLAPSE);
55 56 57 58
/** 
 * Display help component with an initial collapsed state.
 * This automatically enables and sets the help component to be collapsible
 */
59 60
define('PROVISION_HELP_COLLAPSED', PROVISION_HELP_COLLAPSIBLE | _PROVISION_HELP_HAS_COLLAPSED);

61 62

/**
63
 * Returns a class name for the output of the form elementG
64 65 66 67 68 69 70 71 72 73 74 75 76 77
 */
function _provision_help_class($state) {
  static $map;
 
  if (!sizeof($map)) {
    $map = array(
      PROVISION_HELP_ENABLED => 'provision-help',
      PROVISION_HELP_COLLAPSIBLE => 'provision-help-collapsible',
      PROVISION_HELP_COLLAPSED => 'provision-help-collapsed'
    );
  }
  return $map[$state];
}

78 79 80
/**
 * Implementation of hook_help()
 */
81 82
function provision_help($path, $arg) {
  switch ($path) {
83 84 85 86 87 88
    case 'admin/help#provision':
      $output .= t('<p>The Provision framework is a powerful set of modules that lets you to accomplish a lot of maintenance tasks through the unix command line such as installing new sites, backing them up, rolling back to previous backups and facilitating upgrades.</p>');
      $output .= t('<p>Additionally, the Provision framework is one component of the distributed hosting infrastructure provided by the <code>hostmaster</code> install profile. 
                    The Hostmaster profile is capable of driving several provision backends, in a distributed manner, and provides an interface for the functionality of provision.</p>');
      $output .= t('<p>It is not required to run the hosting front end to use the Provision framework, but the system does not provide much in the way of a web accessible front end, by design.</p>');

89
      $output .= '<a name=\'requirements\'><h3>'. t('Requirements') .'</h3></a>';
90 91
      $output .= t('<p>For a more detailed breakdown of steps that need to be taken to configure Provisioning to run with your system, please read the <a href="@url">in depth requirement documentation</a></p>',
                  array('@url' => url('admin/help/provision/requirements')));
92
      $output .= '<a name=\'commands\'><h3>'. t('Commands') .'</h3></a>';
93 94 95 96 97
      $commands = module_invoke_all('drush_command');
      $output .= "<dl>";
      foreach ($commands as $command => $info) {
        if (preg_match('/^provision/', $command)) {
          if (sizeof($info['arguments'])) {
98
            $command .= ' '. implode(' ', (array) key($info['arguments']));            
99 100
          }
          if (sizeof($info['optional arguments'])) {
101
            $command .= ' ['. implode('] [', (array) key($info['optional arguments'])) .']';  
102
          }
103 104
          $output .= '<dt>'."<code>drush.php $command</code>".'</dt>';
          $output .= '<dd>'.  $info["description"] .'</dd>';
105 106 107 108
        }
      }
      $output .= "</dl>";

109
      $output .= '<a name=\'options\'><h3>'. t('Options') .'</h3></a>';
110 111 112 113 114 115

      
      $options = module_invoke_all('value_list');

      $output .= "<dl>";
      foreach ($options as $option => $description) {
116 117
        $output .= '<dt>'."<code>--$option</code>".'</dt>';
        $output .= '<dd>'.  $description .'</dd>';
118 119 120 121 122
      }
      $output .= "</dl>";
      
      return $output;
    case 'admin/help/provision#requirements' :
123 124
      $output .= _provision_requirements('group');
      $output .=  _provision_requirements('backup_path');
125 126 127 128 129 130 131 132
      return $output;
  }
}

/**
 * Page callback with in depth requirement documentation
 */
function provision_help_requirements() {
133 134 135
  $output .= _provision_requirements("basic_drupal");  
  $output .= _provision_requirements("basic_unix");  
  $output .= _provision_requirements("basic_server");  
136 137 138 139 140 141
  $modules = module_implements('provision_service');
  foreach ($modules as $module) {
    $service = module_invoke($module, 'provision_service');
    $name = current($service);
    $help = module_invoke($module, 'help', 'admin/help/provision#requirements');
    if ($name && $help) {
142
      $output .= "<a href='requirements-$module'></a><h3>". t($name) .'</h3>';
143 144 145 146 147 148
      $output .=  $help;
    }
  }
  return $output;
}

149 150 151
/**
 * Helper function for displaying contextual help when not used in a form.
 */
152
function _provision_requirements($req, $section = 'all') {
153
  $item = _element_info('requirement_help');
154 155
  $item['#requirement'] = $req;
  $item['#type'] = 'requirement_help';
156
/*
157 158
  foreach (array('#heading', '#summary', '#suggestion', '#configuration') as $key) {
    if (in_array($section, array('all', $key))) {
159
      $item['#'. $key] = PROVISION_HELP_ENABLED;
160
    }
161
    elseif ($section != 'all') {
162
      $item['#'. $key] = ($section == $key) ? PROVISION_HELP_ENABLED : PROVISION_HELP_DISABLED;
163 164
    }
  }
165
 */
166 167 168 169
  $item = provision_requirement_process($item);
  return theme("requirement_help", $item);
}

Adrian Rossouw's avatar
Adrian Rossouw committed
170 171 172 173 174 175 176 177 178
function provision_theme() {
  return array(
    'requirement_help' => array(
       'arguments' => array('element' => NULL)
     ),
  );

}

179
function provision_get_requirement($req) {
180
  $func = '_provision_'. $req .'_requirements';
181 182 183 184 185 186
  if (function_exists($func)) {
    $help = $func();
  }
  return $help;
}

187
function _provision_backup_path_requirements() {
188 189 190 191 192 193
    $username = PROVISION_SCRIPT_USER;
    $group = PROVISION_WEB_GROUP;
    $backup_path = PROVISION_BACKUP_PATH;
    $mkdir_cmd['@backup_path'] = $backup_path;      
    $mkdir_cmd['@provision_link'] = url('admin/settings/provision');
    $mkdir_cmd['@mkdir_cmd'] = <<<EOF
194 195 196 197
    [$username@hm2 ~]$ mkdir $backup_path
    [$username@hm2 ~]$ chown $username:$username $backup_path
    [$username@hm2 ~]$ chmod 0700 $backup_path
EOF;
198
  $help['title'] = t('Write access to a directory to store backups');
199
  $help['summary'] = t('The drush user (<a href="http://drupal.org/project/drush">http://drupal.org/project/drush</a>) needs to be able to maintain the backups repository to ensure that your site is backed up successfully. 
200 201
                        It is incredibly important that this path is not accessible via the web server, so that no undesirables can get their
                        hands on your database. The recommended path is directly above your platform path, but it can be anywhere.');
202

203
  $help['suggestion'] = t('Based on your server configuration we have determined that your path should be <code>@backup_path</code>, 
204
    but you can change this in the <a href="@provision_link">provisioning section</a>.', $mkdir_cmd);
205
  $help['configuration'] = t('Please enter the following commands : <pre>@mkdir_cmd</pre>', $mkdir_cmd);
206
  return $help;
207 208 209 210 211 212 213 214
}

function _provision_group_requirements() {

    $username = PROVISION_SCRIPT_USER;
    $group = PROVISION_WEB_GROUP;
      

215
    $vigr_cmd = <<<EOF
216
    [$username@hm2 ~]$ sudo adduser $username $group
217 218 219 220 221 222 223 224 225 226
EOF;
    $vigr1 = <<<EOF
    $group::99:
EOF;
    $vigr2 = <<<EOF
    $group::99:$username
EOF;
    $vigr3 = <<<EOF
    $group::99:anotheruser,$username
EOF;
227 228 229
  
  $help['title'] = t('The user account running the script, and the group of the httpd daemon.');
  $help['summary'] = t('The provision framework takes special care to make sure that the file permissions of the 
230
                          hosted sites are always as safe as can be, especially to make sure that the web server does 
231
                          not have the ability to modify the code of the site, therefore this information is required 
232
                          to assure that safety while keeping the sites accessible. This username needs to be a member
233
                          of the web server group, in order to be able to correctly set the file permissions.');
234

235 236 237 238
  $help['suggestion'] = t('Based on your server configuration we have determined that you should set the 
                        username to "<code>@username</code>" and the group to "<code>@group</code>", 
                        but you can change these in the <a href="@provision_link">provisioning section</a>.', 
                        array("@username" => $username, "@group" => $group, "@provision_link" => url('admin/settings/provision')));
239

240
  $help['configuration'] =t('If your user is not a member of the web group, you can add them by using the
241 242 243 244 245
                          <code>adduser</code> command:
                          <pre>@vigr_cmd</pre>
                          If that command is not available, you will need to edit the /etc/group file directly with
                          your vigr or your favorite editor.
                          Find the line that says : <pre>@vigr1</pre>
246
                          Then add the username to the end of the line, so that it looks like : <pre>@vigr2</pre>
247
                          If there were already users in the group, add your user to the group using a comma as separator :
248 249 250 251 252 253 254 255 256 257 258 259 260
                          <pre>@vigr3</pre>', array('@vigr_cmd' => $vigr_cmd, '@vigr1' => $vigr1, '@vigr2' => $vigr2, '@vigr3' => $vigr3));
  return $help;

}

/**
 * Implementation of hook_elements.
 *
 * Defines a number of form elements that are used for formatting the contextual help
 * in forms.
 */
function provision_elements() {
  $type['requirement_help'] = array(
261
    '#requirement' => NULL,
262
    '#status' => PROVISION_STATUS_NONE,
263 264
    '#heading' => PROVISION_HELP_ENABLED,
    '#summary' => PROVISION_HELP_ENABLED,
265 266 267 268 269 270 271
    '#summary_prefix' => t("What is this?"),
    '#configuration' => PROVISION_HELP_COLLAPSED,
    '#configuration_prefix' => t("How do I configure this?"),
    '#default_messages' => array(
      PROVISION_STATUS_SUCCESS => t("You have met this requirement."),
      PROVISION_STATUS_WARNING => t("This requirement has a non critical error."),
      PROVISION_STATUS_ERROR => t("This requirement has a critical error. This system will not operate until it has been fixed")),
272
    '#process' => array('provision_requirement_process'),
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
  );
  return $type;
}

/**
 * Places the various help components info the $element array
 */
function provision_requirement_process(&$element) {
  if (!$element['#requirement']) {
    return element;
  }

  $element['#help'] = provision_get_requirement($element['#requirement']);
  return $element;
}

/**
 * Theme function for displaying contextual help.
 *
 * Can control individual components of the help, for display in various places.
 */
function theme_requirement_help(&$element) {
295 296
  drupal_add_js(drupal_get_path('module', 'provision') .'/provision.js');
  drupal_add_css(drupal_get_path('module', 'provision') .'/provision.css');
297
  $req = $element['#requirement'];
298 299 300 301 302
  $help = $element['#help']; // this is just to make it easier to work with.

  //place anchor so user can be directed to right page.
  $output .= "<a name='provision-help-$req'></a>";

303 304
  $output .= '<div class="provision-'. form_clean_id($element["#type"]) . 
    ' '. _provision_status_class($element['#status']) .'">';
305 306

  if ($element['#status'] != PROVISION_STATUS_NONE) {
307
    $output .= "<div class='message'>". (($element['#message']) ? $element['#message'] : $element['#default_messages'][$element['#status']]) ."</div>";
308
  }
309 310 311 312 313 314 315 316 317 318

  $components = array('summary', 'suggestion', 'configuration');
  foreach ($components as $key) {
    if (($element["#$key"] & PROVISION_HELP_ENABLED) && !is_null($help[$key])) {
      $display_type = _provision_help_class($element["#$key"]);
      $output .= "<div class='provision-help-$key $display_type'>";
      if (!is_array($help[$key])) {
        // it is simpler if there's only one way to print the component
        $help[$key] = array($help[$key]);  
      }
319 320
      if ($element["#$key".'_prefix'] && ($element["#$key"] & _PROVISION_HELP_CAN_COLLAPSE)) {
        $output .= '<a href="javascript:void(0)" class="provision-help-toggle">'. $element["#$key".'_prefix'] .'</a>';
321 322
      }

323
      $output .= "<div class='provision-help'><p>". implode("</p><p>", $help[$key]) ."</p></div>"; 
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
      $output .= '</div>';
    } 
  }
  $output .= '</div>';
  if (($element['#heading'] & PROVISION_HELP_ENABLED) && $help['title'] && !$element['#title']) {
    $element['#title'] = $help['title'];
  }
  $element['#value'] = $output;
  return theme('item', $element);
}

/**
 * @TODO: handle element children for requirement help
function _provision_basic_requirements() {
  $help['drupal'] = _provision_basic_drupal_requirements();
  $help['unix'] = _provision_basic_unix_requirements();
  $help['server'] = _provision_basic_server_requirements();

342
  return $help;
343 344
}
 */
345

346 347 348 349 350 351 352 353 354 355
function _provision_basic_drupal_requirements() {
  $help['title'] = t('A system capable of running Drupal');
  $help['summary'] = t('If you are reading this via the inline help, this would be kind of obvious. This system is entirely Drupal based, and has the same base requirements that Drupal does.');
  return $help;
}

function _provision_basic_server_requirements() {
  $help['title'] = t('Your own server');
  $help['summary'] = t('The level of access required to be able to configure this system is very far beyond what is commonly available to users with shared hosting.');
  return $help;
356
}
357 358 359 360 361 362 363

function _provision_basic_unix_requirements() {
  $help['title'] = t('A unix based operating system');
  $help['summary'] = t('The majority of functionality in this system occurs in the back-end, through system level programming. There are several features (such as symlinks), that are not available to users on Windows. There are no plans currently to add windows support.</p>');
  return $help;
}

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
function _provision_provision_setup_requirements() {
  $docroot = PROVISION_DOCROOT_PATH;
  $uri = PROVISION_BASE_URL;
  $drush_path = rtrim(drupal_get_path('module', 'drush'), '/') . '/drush.php';
  $username = PROVISION_SCRIPT_USER;
  $setup_cmd = <<<EOF
    [$username@hm2 ~]$ cd $docroot
    [$username@hm2 ~]$ $drush_path provision setup
EOF;
  $help['title'] = t('Generate your configuration file using the <code>Provision Setup</code> command');

  $help['summary'][] = t('The provision setup command inspects your environment and creates an initial configuration file in <code>sites/default/provision.settings.php</code>.<br />This configuration file stores important settings such as paths, binary locations and database credentials.');

  $help['summary'][] = t('<strong>If you are using this platform as the back end to an existing Hostmaster installation: </strong><br /> you need to run this command before adding the platform node to your hosting site, to allow the hosting site to communicate with this platform.');
  $help['configuration'] = t('Ensure that you are logged into the shell as %script_user, and then execute the following commands :<pre>@setup_cmd</pre>', 
     array('%script_user' => $username, '@setup_cmd' => $setup_cmd));

  return $help;
}