diff --git a/plans/hana/default.toml b/plans/hana/default.toml index 17788e341d..16161a55e4 100644 --- a/plans/hana/default.toml +++ b/plans/hana/default.toml @@ -4,3 +4,4 @@ password = "Password1234" sapadm-password = "Password1234" system-user-password = "Password1234" root-password = "Password1234" +role = "worker" diff --git a/plans/hana/hooks/init b/plans/hana/hooks/init new file mode 100644 index 0000000000..5b4ca6aa49 --- /dev/null +++ b/plans/hana/hooks/init @@ -0,0 +1,69 @@ +#!/bin/bash + +trim() { + local var="$*" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + echo "$var" +} + +latest_package() { + # Count the number of slashes, and use it to make a choice + # about what to return as the latest package. + latest_package_flags=$(echo $1 | grep -o '/' | wc -l) + case $(trim $latest_package_flags) in + "3") + echo "/opt/bldr/pkgs/$1" ;; + "2") + echo $(find /opt/bldr/pkgs/${1} -maxdepth 1 -type d | sort -r | head -n 1) ;; + "1") + echo $(find /opt/bldr/pkgs/${1} -maxdepth 2 -type d | sort -r | head -n 1) ;; + esac +} + +hana_path=$(latest_package sap/hana) + +# Because we like to party, we just put all the libraries in the lib cache. +find /opt/bldr/pkgs -name 'LD_RUN_PATH' | xargs cat | tr ':' '\n' > /etc/ld.so.conf +glibc_path=$(latest_package chef/glibc) +$glibc_path/sbin/ldconfig.real + +export LD_LIBRARY_PATH=$(find /opt/bldr/pkgs -name 'LD_RUN_PATH' | xargs cat | tr '\n' :) +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$hana_path/bin/instruntime +pkg_prefix=$hana_path +# This needs to have the path be correct for hana + +if [[ -d "/usr/sap" ]]; then + echo "HANA is already installed" +else + {{#census.me.leader}} + echo "Installing HANA runtime" + echo "return 0" > /bin/chkconfig + chmod a+x /bin/chkconfig + cat < /tmp/hana-passwords + + +{{password}} +{{sapadm-password}} +{{system-user-password}} +{{root-password}} + +EOT + env HDB_IGNORE_HANA_PLATFORM_CHECK=1 LD_LIBRARY_PATH=$LD_LIBRARY_PATH \ + cat /tmp/hana-passwords | $pkg_prefix/bin/hdblcm \ + --b \ + --components=all \ + --sid {{sid}} \ + --number={{instance-id}} \ + --userid=5150 \ + --groupid=5150 \ + --shell=/bin/bash \ + --batch \ + --read_password_from_stdin=xml \ + --hdbinst_server_ignore=check_min_mem,check_platform,check_diskspace \ + --ignore=check_signature_file + {{/census.me.leader}} + {{#census.me.follower}} + $pkg_prefix/bin/hdblcm --action=install --addhosts={{census.me.hostname}}:role={{role}} + {{/census.me.follower}} +fi diff --git a/plans/hana/hooks/run b/plans/hana/hooks/run index 3d63c9c75f..e18397eb7e 100644 --- a/plans/hana/hooks/run +++ b/plans/hana/hooks/run @@ -33,36 +33,6 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$hana_path/bin/instruntime pkg_prefix=$hana_path # This needs to have the path be correct for hana -if [[ -d "/usr/sap" ]]; then - echo "HANA is already installed" -else - echo "Installing HANA runtime" - echo "return 0" > /bin/chkconfig - chmod a+x /bin/chkconfig - cat < /tmp/hana-passwords - - -{{password}} -{{sapadm-password}} -{{system-user-password}} -{{root-password}} - -EOT - env HDB_IGNORE_HANA_PLATFORM_CHECK=1 LD_LIBRARY_PATH=$LD_LIBRARY_PATH \ - cat /tmp/hana-passwords | $pkg_prefix/bin/hdblcm \ - --b \ - --components=all \ - --sid {{sid}} \ - --number={{instance-id}} \ - --userid=5150 \ - --groupid=5150 \ - --shell=/bin/bash \ - --batch \ - --read_password_from_stdin=xml \ - --hdbinst_server_ignore=check_min_mem,check_platform,check_diskspace \ - --ignore=check_signature_file -fi - echo "Starting SAP HANA" /usr/sap/hostctrl/exe/sapcontrol -nr {{instance-id}} -function Start if [[ $? -ne 0 ]]; then diff --git a/src/bldr/census.rs b/src/bldr/census.rs index a43e3336a8..9184ea064e 100644 --- a/src/bldr/census.rs +++ b/src/bldr/census.rs @@ -62,6 +62,7 @@ pub struct CensusEntry { pub vote: Option, pub election: Option, pub needs_write: Option, + pub initialized: bool, keep_me: bool, } @@ -112,6 +113,7 @@ impl CensusEntry { vote: None, election: None, needs_write: None, + initialized: false, keep_me: true, } } @@ -147,6 +149,12 @@ impl CensusEntry { self.needs_write = Some(true); } + /// Set our application initialization status to true. + pub fn initialized(&mut self) { + self.initialized = true; + self.needs_write = Some(true); + } + /// Set our status on having initialzied data. pub fn data_init(&mut self, data_init: Option) { self.data_init = data_init; @@ -686,4 +694,3 @@ impl GenServer for CensusActor { } } } - diff --git a/src/bldr/pkg.rs b/src/bldr/pkg.rs index 53aa977fe8..b0b84ec59c 100644 --- a/src/bldr/pkg.rs +++ b/src/bldr/pkg.rs @@ -33,6 +33,7 @@ use health_check::{self, CheckResult}; use service_config::ServiceConfig; use util::{self, convert}; +const INIT_FILENAME: &'static str = "init"; const HEALTHCHECK_FILENAME: &'static str = "health_check"; const RECONFIGURE_FILENAME: &'static str = "reconfigure"; const RUN_FILENAME: &'static str = "run"; @@ -50,11 +51,13 @@ pub enum HookType { HealthCheck, Reconfigure, Run, + Init, } impl fmt::Display for HookType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + &HookType::Init => write!(f, "init"), &HookType::HealthCheck => write!(f, "health_check"), &HookType::Reconfigure => write!(f, "reconfigure"), &HookType::Run => write!(f, "run"), @@ -127,6 +130,7 @@ impl Hook { pub struct HookTable<'a> { pub package: &'a Package, + pub init_hook: Option, pub health_check_hook: Option, pub reconfigure_hook: Option, pub run_hook: Option, @@ -136,6 +140,7 @@ impl<'a> HookTable<'a> { pub fn new(package: &'a Package) -> Self { HookTable { package: package, + init_hook: None, health_check_hook: None, reconfigure_hook: None, run_hook: None, @@ -148,6 +153,7 @@ impl<'a> HookTable<'a> { match fs::metadata(path) { Ok(meta) => { if meta.is_dir() { + self.init_hook = self.load_hook(HookType::Init); self.reconfigure_hook = self.load_hook(HookType::Reconfigure); self.health_check_hook = self.load_hook(HookType::HealthCheck); self.run_hook = self.load_hook(HookType::Run); @@ -309,6 +315,7 @@ impl Package { pub fn hook_template_path(&self, hook_type: &HookType) -> PathBuf { let base = PathBuf::from(self.join_path("hooks")); match *hook_type { + HookType::Init => base.join(INIT_FILENAME), HookType::HealthCheck => base.join(HEALTHCHECK_FILENAME), HookType::Reconfigure => base.join(RECONFIGURE_FILENAME), HookType::Run => base.join(RUN_FILENAME), @@ -318,6 +325,7 @@ impl Package { pub fn hook_path(&self, hook_type: &HookType) -> PathBuf { let base = PathBuf::from(self.srvc_join_path("hooks")); match *hook_type { + HookType::Init => base.join(INIT_FILENAME), HookType::HealthCheck => base.join(HEALTHCHECK_FILENAME), HookType::Reconfigure => base.join(RECONFIGURE_FILENAME), HookType::Run => base.join(RUN_FILENAME), @@ -404,6 +412,19 @@ impl Package { Ok(files) } + /// Run iniitalization hook if present + pub fn initialize(&self, context: &ServiceConfig) -> BldrResult<()> { + if let Some(hook) = self.hooks().init_hook { + match hook.run(Some(context)) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } else { + Ok(()) + } + } + + /// Run reconfigure hook if present pub fn reconfigure(&self, context: &ServiceConfig) -> BldrResult<()> { if let Some(hook) = self.hooks().reconfigure_hook { match hook.run(Some(context)) { diff --git a/src/bldr/topology/initializer.rs b/src/bldr/topology/initializer.rs new file mode 100644 index 0000000000..0ba4a0a436 --- /dev/null +++ b/src/bldr/topology/initializer.rs @@ -0,0 +1,240 @@ +// +// Copyright:: Copyright (c) 2015 Chef Software, Inc. +// License:: Apache License, Version 2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//! This is the building block of complicated topologies which require a leader. It is +//! used when a single member of your cluster should perform additional applications +//! level initialization and/or if the other members of your cluster need to perform +//! additional initialization steps. +//! +//! We guarantee that the leader will perform it's initialization sequence before the +//! followers attempt to run thier initialization sequences. + +use config::Config; +use error::{BldrResult, BldrError}; +use state_machine::StateMachine; +use topology::{self, standalone, State, Worker}; +use pkg::Package; + +enum InitGate { + NoLeader, + Waiting, + Done, +} + +pub fn run(package: Package, config: &Config) -> BldrResult<()> { + let mut worker = try!(Worker::new(package, String::from("initializer"), config)); + let mut sm: StateMachine = StateMachine::new(State::DetermineViability); + sm.add_dispatch(State::DetermineViability, state_determine_viability); + sm.add_dispatch(State::StartElection, state_start_election); + sm.add_dispatch(State::InElection, state_in_election); + sm.add_dispatch(State::BecomeLeader, state_become_leader); + sm.add_dispatch(State::BecomeFollower, state_become_follower); + sm.add_dispatch(State::InitializingLeader, state_initializing_leader); + sm.add_dispatch(State::InitializingFollower, state_initializing_follower); + sm.add_dispatch(State::Leader, state_leader); + sm.add_dispatch(State::Follower, state_follower); + topology::run_internal(&mut sm, &mut worker) +} + +pub fn state_determine_viability(worker: &mut Worker) -> BldrResult<(State, u32)> { + println!(" {}: Determining viability as a leader", worker.preamble()); + worker.census.in_event = true; + { + let mut ce = try!(worker.census.me_mut()); + ce.follower(None); + ce.leader(None); + } + if worker.census.has_leader() { + Ok((State::BecomeFollower, 0)) + } else { + Ok((State::StartElection, 0)) + } +} + +pub fn state_start_election(worker: &mut Worker) -> BldrResult<(State, u32)> { + println!(" {}: Starting an election", worker.preamble()); + { + let mut ce = try!(worker.census.me_mut()); + ce.election = Some(true); + } + let candidate = worker.census.determine_vote().candidate_string(); + println!(" {}: My candidate is {:?}", worker.preamble(), candidate); + let mut ce = try!(worker.census.me_mut()); + ce.vote(Some(candidate)); + Ok((State::InElection, 0)) +} + +pub fn state_in_election(worker: &mut Worker) -> BldrResult<(State, u32)> { + let preamble = worker.preamble(); + let candidate = worker.census.determine_vote().candidate_string(); + { + let mut ce = try!(worker.census.me_mut()); + match ce.vote { + Some(ref c) if *c == candidate => {}, + Some(_) => { + println!(" {}: Switching my vote to {}", preamble, candidate); + ce.vote(Some(candidate)); + }, + None => { + println!(" {}: Switching my vote to {}", preamble, candidate); + ce.vote(Some(candidate)); + } + } + } + + if let Some(leader_ce) = worker.census.get_leader() { + println!(" {}: {} has already been elected; becoming a follower", preamble, leader_ce.candidate_string()); + return Ok((State::BecomeFollower, 0)); + } + + match worker.census.voting_finished() { + Some(winner) => { + let me = try!(worker.census.me()); + if me == winner { + println!(" {}: The votes are in! I won! I will serve with humility.", worker.preamble()); + Ok((State::BecomeLeader, 0)) + } else { + println!(" {}: The votes are in! I lost! I will serve with grace.", worker.preamble()); + Ok((State::BecomeFollower, 0)) + } + }, + None => Ok((State::InElection, 10)) + } +} + +pub fn state_become_leader(worker: &mut Worker) -> BldrResult<(State, u32)> { + if worker.census.has_leader() == false { + { + let mut ce = try!(worker.census.me_mut()); + ce.leader = Some(true); + } + } + + if worker.census.has_all_followers() { + println!(" {}: Starting my term as leader", worker.preamble()); + Ok((State::InitializingLeader, 0)) + } else { + println!(" {}: Waiting for all my followers to agree", worker.preamble()); + Ok((State::BecomeLeader, 0)) + } +} + +pub fn state_become_follower(worker: &mut Worker) -> BldrResult<(State, u32)> { + println!(" {}: Becoming a follower", worker.preamble()); + { + let mut ce = try!(worker.census.me_mut()); + if ce.follower.is_none() { + ce.follower(Some(true)); + } + } + + if worker.census.has_leader() { + println!(" {}: Becoming a follower for real", worker.preamble()); + Ok((State::InitializingFollower, 0)) + } else { + println!(" {}: Waiting for a leader", worker.preamble()); + Ok((State::BecomeFollower, 0)) + } +} + +pub fn state_initializing_leader(worker: &mut Worker) -> BldrResult<(State, u32)> { + try!(initialize(worker)); + Ok((State::Leader, 0)) +} + +pub fn state_initializing_follower(worker: &mut Worker) -> BldrResult<(State, u32)> { + let gate = { + if let Some(leader) = worker.census.get_leader() { + if leader.initialized { + InitGate::Done + } else { + InitGate::Waiting + } + } else { + InitGate::NoLeader + } + }; + + match gate { + InitGate::Done => { + try!(initialize(worker)); + Ok((State::Follower, 0)) + }, + InitGate::Waiting => Ok((State::InitializingFollower, 0)), + InitGate::NoLeader => Ok((State::DetermineViability, 0)), + } +} + +pub fn state_leader(worker: &mut Worker) -> BldrResult<(State, u32)> { + { + let me = try!(worker.census.me_mut()); + if me.election.is_some() { + me.election(None) + } + if me.vote.is_some() { + me.vote(None) + } + } + + if worker.census.in_event { + worker.census.in_event = false; + } + + if worker.supervisor_thread.is_none() { + try!(standalone::state_starting(worker)); + } + + Ok((State::Leader, 0)) +} + +pub fn state_follower(worker: &mut Worker) -> BldrResult<(State, u32)> { + { + let me = try!(worker.census.me_mut()); + if me.election.is_some() { + me.election(None); + } + if me.vote.is_some() { + me.vote(None); + } + } + + if worker.census.in_event { + worker.census.in_event = false; + } + + if worker.supervisor_thread.is_none() { + try!(standalone::state_starting(worker)); + } + + if ! worker.census.has_leader() { + Ok((State::DetermineViability, 0)) + } else { + Ok((State::Follower, 0)) + } +} + +fn initialize(worker: &mut Worker) -> BldrResult<()> { + let service_config = worker.service_config.read().unwrap(); + let package = worker.package.read().unwrap(); + match package.initialize(&service_config) { + Ok(()) => { + let mut me = try!(worker.census.me_mut()); + me.initialized(); + Ok(()) + }, + Err(e) => Err(e), + } +} diff --git a/src/bldr/topology/leader.rs b/src/bldr/topology/leader.rs index 2df24e33b8..f56434ab94 100644 --- a/src/bldr/topology/leader.rs +++ b/src/bldr/topology/leader.rs @@ -15,11 +15,10 @@ // limitations under the License. // -use topology::{self, State, Worker}; +use topology::{self, initializer, State, Worker}; use state_machine::StateMachine; use error::{BldrResult, BldrError}; use pkg::Package; -use topology::standalone; use config::Config; pub fn run(package: Package, config: &Config) -> BldrResult<()> { @@ -27,17 +26,19 @@ pub fn run(package: Package, config: &Config) -> BldrResult<()> { let mut sm: StateMachine = StateMachine::new(State::Init); sm.add_dispatch(State::Init, state_init); sm.add_dispatch(State::RestoreDataset, state_restore_dataset); - sm.add_dispatch(State::DetermineViability, state_determine_viability); - sm.add_dispatch(State::StartElection, state_start_election); - sm.add_dispatch(State::InElection, state_in_election); - sm.add_dispatch(State::BecomeLeader, state_become_leader); - sm.add_dispatch(State::BecomeFollower, state_become_follower); - sm.add_dispatch(State::Leader, state_leader); - sm.add_dispatch(State::Follower, state_follower); + sm.add_dispatch(State::DetermineViability, initializer::state_determine_viability); + sm.add_dispatch(State::StartElection, initializer::state_start_election); + sm.add_dispatch(State::InElection, initializer::state_in_election); + sm.add_dispatch(State::BecomeLeader, initializer::state_become_leader); + sm.add_dispatch(State::BecomeFollower, initializer::state_become_follower); + sm.add_dispatch(State::InitializingLeader, initializer::state_initializing_leader); + sm.add_dispatch(State::InitializingFollower, initializer::state_initializing_follower); + sm.add_dispatch(State::Leader, initializer::state_leader); + sm.add_dispatch(State::Follower, initializer::state_follower); topology::run_internal(&mut sm, &mut worker) } -fn state_init(worker: &mut Worker) -> Result<(State, u32), BldrError> { +fn state_init(worker: &mut Worker) -> BldrResult<(State, u32)> { if worker.census.dataset_initialized() { Ok((State::RestoreDataset, 0)) } else { @@ -51,152 +52,3 @@ fn state_restore_dataset(worker: &mut Worker) -> BldrResult<(State, u32)> { ce.data_init(Some(true)); Ok((State::DetermineViability, 0)) } - -fn state_determine_viability(worker: &mut Worker) -> BldrResult<(State, u32)> { - println!(" {}: Determining viability as a leader", worker.preamble()); - worker.census.in_event = true; - { - let mut ce = try!(worker.census.me_mut()); - ce.follower(None); - ce.leader(None); - } - if worker.census.has_leader() { - Ok((State::BecomeFollower, 0)) - } else { - Ok((State::StartElection, 0)) - } -} - -fn state_start_election(worker: &mut Worker) -> BldrResult<(State, u32)> { - println!(" {}: Starting an election", worker.preamble()); - { - let mut ce = try!(worker.census.me_mut()); - ce.election = Some(true); - } - let candidate = worker.census.determine_vote().candidate_string(); - println!(" {}: My candidate is {:?}", worker.preamble(), candidate); - let mut ce = try!(worker.census.me_mut()); - ce.vote(Some(candidate)); - Ok((State::InElection, 0)) -} - -fn state_in_election(worker: &mut Worker) -> BldrResult<(State, u32)> { - let preamble = worker.preamble(); - let candidate = worker.census.determine_vote().candidate_string(); - { - let mut ce = try!(worker.census.me_mut()); - match ce.vote { - Some(ref c) if *c == candidate => {}, - Some(_) => { - println!(" {}: Switching my vote to {}", preamble, candidate); - ce.vote(Some(candidate)); - }, - None => { - println!(" {}: Switching my vote to {}", preamble, candidate); - ce.vote(Some(candidate)); - } - } - } - - if let Some(leader_ce) = worker.census.get_leader() { - println!(" {}: {} has already been elected; becoming a follower", preamble, leader_ce.candidate_string()); - return Ok((State::BecomeFollower, 0)); - } - - match worker.census.voting_finished() { - Some(winner) => { - let me = try!(worker.census.me()); - if me == winner { - println!(" {}: The votes are in! I won! I will serve with humility.", worker.preamble()); - Ok((State::BecomeLeader, 0)) - } else { - println!(" {}: The votes are in! I lost! I will serve with grace.", worker.preamble()); - Ok((State::BecomeFollower, 0)) - } - }, - None => Ok((State::InElection, 10)) - } -} - -fn state_become_leader(worker: &mut Worker) -> BldrResult<(State, u32)> { - if worker.census.has_leader() == false { - { - let mut ce = try!(worker.census.me_mut()); - ce.leader = Some(true); - } - } - - if worker.census.has_all_followers() { - println!(" {}: Starting my term as leader", worker.preamble()); - Ok((State::Leader, 0)) - } else { - println!(" {}: Waiting for all my followers to agree", worker.preamble()); - Ok((State::BecomeLeader, 0)) - } -} - -fn state_become_follower(worker: &mut Worker) -> BldrResult<(State, u32)> { - println!(" {}: Becoming a follower", worker.preamble()); - { - let mut ce = try!(worker.census.me_mut()); - if ce.follower.is_none() { - ce.follower(Some(true)); - } - } - - if worker.census.has_leader() { - println!(" {}: Becoming a follower for real", worker.preamble()); - Ok((State::Follower, 0)) - } else { - println!(" {}: Waiting for a leader", worker.preamble()); - Ok((State::BecomeFollower, 0)) - } -} - -fn state_leader(worker: &mut Worker) -> BldrResult<(State, u32)> { - { - let me = try!(worker.census.me_mut()); - if me.election.is_some() { - me.election(None) - } - if me.vote.is_some() { - me.vote(None) - } - } - - if worker.census.in_event { - worker.census.in_event = false; - } - - if worker.supervisor_thread.is_none() { - try!(standalone::state_starting(worker)); - } - - Ok((State::Leader, 0)) -} - -fn state_follower(worker: &mut Worker) -> BldrResult<(State, u32)> { - { - let me = try!(worker.census.me_mut()); - if me.election.is_some() { - me.election(None); - } - if me.vote.is_some() { - me.vote(None); - } - } - - if worker.census.in_event { - worker.census.in_event = false; - } - - if worker.supervisor_thread.is_none() { - try!(standalone::state_starting(worker)); - } - - if ! worker.census.has_leader() { - Ok((State::DetermineViability, 0)) - } else { - Ok((State::Follower, 0)) - } -} diff --git a/src/bldr/topology/mod.rs b/src/bldr/topology/mod.rs index cb16c35122..aaa8bb7e39 100644 --- a/src/bldr/topology/mod.rs +++ b/src/bldr/topology/mod.rs @@ -27,6 +27,7 @@ pub mod standalone; pub mod leader; +pub mod initializer; use ansi_term::Colour::White; use std::thread; @@ -120,9 +121,11 @@ pub enum State { Leader, Follower, Configure, + Initializing, + InitializingLeader, + InitializingFollower, Starting, Running, - Finished, } /// The topology `Worker` is where everything our state machine needs between states lives. diff --git a/src/bldr/topology/standalone.rs b/src/bldr/topology/standalone.rs index d662377a15..3094bf7dd2 100644 --- a/src/bldr/topology/standalone.rs +++ b/src/bldr/topology/standalone.rs @@ -19,16 +19,10 @@ //! //! ![Standalone Topology](../../images/standalone.png) //! -//! * **Init**: Creates the paths needed for the service in `/opt/bldr/srvc`, and copies in the `run` file -//! from the package. -//! * **Configure**: Writes the `default.toml` from the package, followed by any `environment` -//! configuration (specified as toml in a `$BLDR_service` variable, where `service == redis`, or -//! whatever the name of your service is), data discovered from the system, data from the bldr -//! package iteslf, and if configured, from a discovery service. +//! * **Initializing**: Initializes the service by running the `init` hook if present. //! * **Starting**: Starts the service under `runsv`, and starts a thread to process output and //! handle errors. //! * **Running**: The state for the 'normal' operating condition. -//! * **Finished**: Does nothing; exists to handle cleanup. use std::thread; use error::{BldrResult, BldrError}; @@ -46,22 +40,21 @@ use config::Config; /// `topology::run_internal` function. pub fn run(package: Package, config: &Config) -> BldrResult<()> { let mut worker = try!(Worker::new(package, String::from("standalone"), config)); - let mut sm: StateMachine = StateMachine::new(State::Init); - sm.add_dispatch(State::Init, state_init); - sm.add_dispatch(State::Configure, state_configure); + let mut sm: StateMachine = StateMachine::new(State::Initializing); + sm.add_dispatch(State::Initializing, state_initializing); sm.add_dispatch(State::Starting, state_starting); sm.add_dispatch(State::Running, state_running); topology::run_internal(&mut sm, &mut worker) } /// Initialize the service. -pub fn state_init(_worker: &mut Worker) -> Result<(State, u32), BldrError> { - Ok((State::Configure, 0)) -} - -/// Configure the service. -pub fn state_configure(_worker: &mut Worker) -> Result<(State, u32), BldrError> { - Ok((State::Starting, 1)) +pub fn state_initializing(worker: &mut Worker) -> BldrResult<(State, u32)> { + let service_config = worker.service_config.read().unwrap(); + let package = worker.package.read().unwrap(); + match package.initialize(&service_config) { + Ok(()) => Ok((State::Starting, 0)), + Err(e) => Err(e), + } } /// Start the service. @@ -74,8 +67,9 @@ pub fn state_configure(_worker: &mut Worker) -> Result<(State, u32), BldrError> /// /// * If we cannot find the package /// * If we cannot start the supervisor -pub fn state_starting(worker: &mut Worker) -> Result<(State, u32), BldrError> { +pub fn state_starting(worker: &mut Worker) -> BldrResult<(State, u32)> { println!(" {}: Starting", worker.preamble()); + let package = worker.package_name.clone(); let runit_pkg = try!(Package::latest("runit", None)); let mut child = try!( Command::new(runit_pkg.join_path("bin/runsv")) @@ -86,7 +80,6 @@ pub fn state_starting(worker: &mut Worker) -> Result<(State, u32), BldrError> { .spawn() ); worker.supervisor_id = Some(child.id()); - let pkg = worker.package_name.clone(); let supervisor_thread = try!(thread::Builder::new().name(String::from("supervisor")).spawn(move|| -> BldrResult<()> { { let mut c_stdout = match child.stdout { @@ -94,7 +87,7 @@ pub fn state_starting(worker: &mut Worker) -> Result<(State, u32), BldrError> { None => return Err(BldrError::UnpackFailed) }; - let mut line = format!(" {}({}): ", pkg, White.bold().paint("O")); + let mut line = format!(" {}({}): ", package, White.bold().paint("O")); loop { let mut buf = [0u8; 1]; // Our byte buffer let len = try!(c_stdout.read(&mut buf)); @@ -108,7 +101,7 @@ pub fn state_starting(worker: &mut Worker) -> Result<(State, u32), BldrError> { line.push_str(&buf_string); if line.contains("\n") { print!("{}", line); - line = format!(" {}({}): ", pkg, White.bold().paint("O")); + line = format!(" {}({}): ", package, White.bold().paint("O")); } } } @@ -120,6 +113,6 @@ pub fn state_starting(worker: &mut Worker) -> Result<(State, u32), BldrError> { Ok((State::Running, 0)) } -pub fn state_running(_worker: &mut Worker) -> Result<(State, u32), BldrError> { +pub fn state_running(_worker: &mut Worker) -> BldrResult<(State, u32)> { Ok((State::Running, 0)) }