""" SSH into infrastructure managed by touchdown """ name = "ssh" mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan("ssh") if not plan_class: plan_class = resource.meta.get_plan("describe") if not plan_class: plan_class = resource.meta.get_plan("null") return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( "box", metavar="BOX", type=str, help="The resource to ssh to", ) parser.add_argument('args', nargs=argparse.REMAINDER) def execute(self, box, args): boxes = self.collect_as_dict("ssh") if box not in boxes: raise errors.Error("No such host '{}'".format(box)) boxes[box].execute(args) register(Ssh)
def get_plan_class(self, resource): plan_class = resource.meta.get_plan('snapshot') if not plan_class: plan_class = resource.meta.get_plan('null') return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( 'target', metavar='TARGET', type=str, help='The resource to snapshot', ) parser.add_argument( 'snapshot_name', metavar='TO', type=str, help='The snapshot name', ) def execute(self, target, snapshot_name): snapshotable = self.collect_as_dict('snapshot') if target not in snapshotable: raise errors.Error('No such resource "{}"'.format(target)) snapshotable[target].snapshot(snapshot_name) register(Snapshot)
class GetSigninUrl(Goal): ''' Generate short-lived access urls ''' name = 'get-signin-url' mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan('get-signin-url') if not plan_class: plan_class = resource.meta.get_plan('null') return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( 'resource', metavar='RESOURCE', type=str, help='The resource to create a signin url for' ) def execute(self, resource): resources = self.collect_as_dict('get-signin-url') if resource not in resources: raise errors.Error('No such resource "{}"'.format(resource)) self.ui.echo(resources[resource].get_signin_url()) register(GetSigninUrl)
""" Replace a configuration variable with its default setting """ name = "refresh" mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan("refresh") if not plan_class: plan_class = resource.meta.get_plan("describe") if not plan_class: plan_class = resource.meta.get_plan("null") return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( "name", metavar="NAME", type=str, help="The setting to refresh", ) def execute(self, name): settings = self.collect_as_dict("refresh") if name not in settings: raise errors.Error("No such setting '{}'".format(name)) settings[name].execute() register(Refresh)
'-f', '--follow', default=False, action='store_true', help='Don\'t exit and continue to print new events in the stream' ) parser.add_argument( '-s', '--start', default='5m ago', action='store', type=datetime, help='The earliest event to retrieve' ) parser.add_argument( '-e', '--end', default=None, action='store', type=datetime, help='The latest event to retrieve' ) def execute(self, stream, start='5m ago', end=None, follow=False): tailers = self.collect_as_dict('tail') if stream not in tailers: raise errors.Error('No such log stream "{}"'.format(stream)) tailers[stream].tail(start, end, follow) register(Tail)
class Dot(Goal): ''' Generate a dot graph of all resources and their interconnections ''' name = 'dot' mutator = False def get_plan_class(self, resource): return plan.NullPlan def get_digraph(self): graph = ['digraph ast {'] for node, deps in self.get_plan_order().items(): if node.dot_ignore: continue graph.append('{} [label="{}"];'.format(id(node), node)) for dep in deps: if dep.dot_ignore: continue graph.append('{} -> {};'.format(id(node), id(dep))) graph.append('}') return '\n'.join(graph) def execute(self): self.ui.echo(self.get_digraph()) register(Dot)
def setup_argparse(cls, parser): parser.add_argument( 'target', metavar='TARGET', type=str, help='The resource to rollback', ) parser.add_argument( 'from_backup', metavar='FROM', type=str, help='When or what to rollback to', ) def pre_restore(self): pass def post_restore(self): pass def execute(self, target, from_backup): restorable = self.collect_as_dict('rollback') if target not in restorable: raise errors.Error('No such resource "{}"'.format(target)) restorable[target].check(from_backup) self.pre_restore() restorable[target].rollback(from_backup) self.post_restore() register(Rollback)
', '.join(sorted(services.keys())), )) try: local_port = int(local_port) except ValueError: raise errors.Error('Not a valid port number: "{}"'.format(p)) yield (services[service], local_port) def process_incoming_forever(self, servers): # This is broadly the same as a TCPServer.serve_forever, but we do it # for multiple ports/protocols at once try: while True: r, w, e = _eintr_retry(select.select, servers, [], [], 0.5) for server in r: server._handle_request_noblock() except KeyboardInterrupt: self.ui.echo('Interupted. Exiting...') def execute(self, *ports): mappings = self.get_services(ports) servers = [s.start(lp) for s, lp in mappings] self.ui.echo('All requested port forwards started. Waiting for connections...') self.process_incoming_forever(servers) register(PortForward)
# # 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. from touchdown.core.goals import Goal, register from touchdown.goals.action import ActionGoalMixin class Apply(ActionGoalMixin, Goal): ''' Converge infrastructure on the state defined ''' name = 'apply' def get_plan_class(self, resource): if 'destroy' in resource.ensure: return resource.meta.get_plan('destroy') if 'never-create' in resource.ensure: return resource.meta.get_plan('describe') return resource.meta.get_plan('apply') or resource.meta.get_plan('describe') or resource.meta.get_plan('null') register(Apply)
# 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. from touchdown.core.goals import Goal, register from touchdown.goals.action import ActionGoalMixin class Destroy(ActionGoalMixin, Goal): """ Tear down this infrastructure """ name = "destroy" execute_in_reverse = True def get_plan_class(self, resource): if "never-destroy" not in resource.ensure: return resource.meta.get_plan("destroy") or resource.meta.get_plan("describe") or resource.meta.get_plan("null") return resource.meta.get_plan("describe") or resource.meta.get_plan("null") register(Destroy)
@classmethod def setup_argparse(cls, parser): parser.add_argument( 'source', metavar='SOURCE', type=str, help='What to copy', ) parser.add_argument( 'destination', metavar='DESTINATION', type=str, help='Where to copy it', ) def execute(self, source, destination): for path in (source, destination): if ':' in path: server = path.split(':', 1)[0] break else: raise errors.Error('Either source or destination must contain a target server that touchdown knows about') boxes = self.collect_as_dict('scp') if server not in boxes: raise errors.Error('No such host "{}"'.format(server)) boxes[server].execute(source, destination) register(Scp)
mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan("get") if not plan_class: plan_class = resource.meta.get_plan("null") return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( "name", metavar="NAME", type=str, help="The setting to set", ) def execute(self, name): settings = self.collect_as_dict("get") if name not in settings: raise errors.Error("No such setting '{}'".format(name)) val, user_set = settings[name].execute() val = settings[name].to_string(val) if user_set: print("{} (overriden by user)".format(val)) else: print("{} (default value)".format(val)) register(Get)
def get_plan_class(self, resource): plan_class = resource.meta.get_plan("cost") if not plan_class: plan_class = resource.meta.get_plan("null") return plan_class def execute(self): headers = [("Resource", "Cost (per hour)")] data = [] def collect_costs(resource): coster = self.get_plan(resource) if coster.name == self.name: data.append((str(coster.resource), str(coster.cost()))) self.visit( "Collecting costs...", self.get_plan_order(), collect_costs, ) data.sort() if len(data) == 0: self.ui.echo("No costable items") return self.ui.table(headers + data) register(Cost)
""" Edit a file like object managed by Touchdown """ name = "edit" mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan("edit") if not plan_class: plan_class = resource.meta.get_plan("describe") if not plan_class: plan_class = resource.meta.get_plan("null") return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( "name", metavar="NAME", type=str, help="The file to edit", ) def execute(self, name): files = self.collect_as_dict("edit") if name not in files: raise errors.Error("No such file '{}'".format(name)) files[name].execute() register(Edit)
def get_plan_class(self, resource): plan_class = resource.meta.get_plan('set') if not plan_class: plan_class = resource.meta.get_plan('describe') if not plan_class: plan_class = resource.meta.get_plan('null') return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( 'name', metavar='NAME', type=str, help='The setting to set', ) parser.add_argument( 'value', metavar='VALUE', type=str, help='The new value to set', ) def execute(self, name, value): settings = self.collect_as_dict('set') if name not in settings: raise errors.Error('No such setting "{}"'.format(name)) settings[name].execute(settings[name].from_string(value)) register(Set)
class GetCredentials(Goal): ''' Get bash-sourcable temporary access credentials for a role ''' name = 'get-credentials' mutator = False def get_plan_class(self, resource): plan_class = resource.meta.get_plan('get-credentials') if not plan_class: plan_class = resource.meta.get_plan('null') return plan_class @classmethod def setup_argparse(cls, parser): parser.add_argument( 'resource', metavar='RESOURCE', type=str, help='The resource to get credentials for', ) def execute(self, resource): resources = self.collect_as_dict('get-credentials') if resource not in resources: raise errors.Error('No such resource "{}"'.format(resource)) self.ui.echo(resources[resource].get_credentials()) register(GetCredentials)