title: How to extend a Boto3 resource?
body: <p>On boto3, how can I extend <code>ResourceModel</code>? What I wan't to do is subclass <code>boto3.resources.factory.ec2.Instance</code> and add a <code>run</code> method to it. That method would be used to remotely run commands on the EC2 instance represented by the Python object, via SSH. I wish to do this in a clean way, i.e., without resorting to monkey patches or other obscure techniques.</p>
  
  <p><strong>Update</strong></p>
  
  <p>Based on <a href="https://stackoverflow.com/a/29637081">Daniel's answer</a>, I came up with the following code. Requires a recent version of Boto 3, and <a href="https://github.com/mwilliamson/spur.py" rel="nofollow noreferrer">Spur</a> for the SSH connection (<code>pip install spur boto3</code>).</p>
  
  <pre><code>from boto3 import session
  from shlex import split
  from spur import SshShell
  
  # Customize here.
  REGION = 'AWS-REGION'
  INSTID = 'AWS-INSTANCE-ID'
  USERID = 'SSH-USER'
  
  def hook_ssh(class_attributes, **kwargs):
      def run(self, command):
          '''Run a command on the EC2 instance via SSH.'''
  
          # Create the SSH client.
          if not hasattr(self, '_ssh_client'):
              self._ssh_client = SshShell(self.public_ip_address, USERID)
  
          print(self._ssh_client.run(split(command)).output.decode())
  
      class_attributes['run'] = run
  
  if __name__ == '__main__':
      b3s = session.Session()
      ec2 = b3s.resource('ec2', region_name=REGION)
  
      # Hook the "run" method to the "ec2.Instance" resource class.
      b3s.events.register('creating-resource-class.ec2.Instance', hook_ssh)
  
      # Run some commands.
      ec2.Instance(INSTID).run('uname -a')
      ec2.Instance(INSTID).run('uptime')
  </code></pre>