13
13
from ConfigParser import ConfigParser, Error as ConfigParserError
14
14
from StringIO import StringIO
16
from dbus.exceptions import DBusException
18
16
from landscape.lib.tag import is_valid_tag
20
18
from landscape.sysvconfig import SysVConfig, ProcessError
21
from landscape.lib.dbus_util import (
22
get_bus, NoReplyError, ServiceUnknownError, SecurityError)
19
from landscape.lib.amp import MethodCallError
23
20
from landscape.lib.twisted_util import gather_results
24
21
from landscape.lib.fetch import fetch, FetchError
22
from landscape.reactor import TwistedReactor
26
23
from landscape.broker.registration import InvalidCredentialsError
27
from landscape.broker.deployment import BrokerConfiguration
28
from landscape.broker.remote import RemoteBroker
24
from landscape.broker.config import BrokerConfiguration
25
from landscape.broker.amp import RemoteBrokerConnector
31
28
class ConfigurationError(Exception):
32
29
"""Raised when required configuration values are missing."""
34
32
class ImportOptionError(ConfigurationError):
35
33
"""Raised when there are issues with handling the --import option."""
120
118
parser.add_option("--import", dest="import_from",
121
119
metavar="FILENAME_OR_URL",
122
120
help="Filename or URL to import configuration from. "
123
"Imported options behave as if they were passed "
124
"in the command line, with precedence being "
125
"given to real command line options.")
121
"Imported options behave as if they were "
122
"passed in the command line, with precedence "
123
"being given to real command line options.")
126
124
parser.add_option("--script-users", metavar="USERS",
127
125
help="A comma-separated list of users to allow "
128
126
"scripts to run. To allow scripts to be run "
513
513
"The landscape client will continue to try and contact "
514
514
"the server periodically.",
518
518
def handle_registration_errors(failure):
519
519
# We'll get invalid credentials through the signal.
520
error = failure.trap(InvalidCredentialsError, NoReplyError)
521
# This event is fired here so we can catch this case where
522
# there is no reply in a test. In the normal case when
523
# running the client there is no trigger added for this event
524
# and it is essentially a noop.
525
reactor.fireSystemEvent("landscape-registration-error")
520
failure.trap(InvalidCredentialsError, MethodCallError)
521
connector.disconnect()
527
523
def catch_all(failure):
528
524
# We catch SecurityError here too, because on some DBUS configurations
529
525
# if you try to connect to a dbus name that doesn't have a listener,
530
526
# it'll try auto-starting the service, but then the StartServiceByName
531
527
# call can raise a SecurityError.
532
if failure.check(ServiceUnknownError, SecurityError):
533
print_text("Error occurred contacting Landscape Client. "
534
"Is it running?", error=True)
536
print_text(failure.getTraceback(), error=True)
537
print_text("Unknown error occurred.", error=True)
538
reactor.callLater(0, reactor.stop)
528
print_text(failure.getTraceback(), error=True)
529
print_text("Unknown error occurred.", error=True)
540
532
print_text("Please wait... ", "")
544
remote = RemoteBroker(get_bus(config.bus), retry_timeout=0)
545
except DBusException:
546
print_text("There was an error communicating with the Landscape client "
547
"via DBus.", error=True)
536
def got_connection(remote):
537
handlers = {"registration-done": success,
538
"registration-failed": failure,
539
"exchange-failed": exchange_failure}
541
remote.reload_configuration(),
542
remote.call_on_event(handlers),
543
remote.register().addErrback(handle_registration_errors)]
544
# We consume errors here to ignore errors after the first one.
545
# catch_all will be called for the very first deferred that fails.
546
results = gather_results(deferreds, consume_errors=True)
547
return results.addErrback(catch_all)
549
def got_error(failure):
550
print_text("There was an error communicating with the Landscape "
551
"client.", error=True)
548
552
print_text("This machine will be registered with the provided "
549
553
"details when the client runs.", error=True)
551
if config.ok_no_register:
554
# This is a bit unfortunate. Every method of remote returns a deferred,
555
# even stuff like connect_to_signal, because the fetching of the DBus
556
# object itself is asynchronous. We can *mostly* fire-and-forget these
557
# things, except that if the object isn't found, *all* of the deferreds
558
# will fail. To prevent unhandled errors, we need to collect them all up
559
# and add an errback.
561
remote.reload_configuration(),
562
remote.connect_to_signal("registration_done", success),
563
remote.connect_to_signal("registration_failed", failure),
564
remote.connect_to_signal("exchange_failed", exchange_failure),
565
remote.register().addErrback(handle_registration_errors)]
566
# We consume errors here to ignore errors after the first one. catch_all
567
# will be called for the very first deferred that fails.
568
gather_results(deferreds, consume_errors=True).addErrback(catch_all)
554
if not config.ok_no_register:
555
exit_with_error.append(2)
558
connector = RemoteBrokerConnector(reactor, config)
559
result = connector.connect(max_retries=0, quiet=True)
560
result.addCallback(got_connection)
561
result.addErrback(got_error)
566
sys.exit(exit_with_error[0])
572
571
def fetch_import_url(url):
573
572
"""Handle fetching of URLs passed to --url.