Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 1 | from core.models import Service, TenantWithContainer |
| 2 | from django.db import transaction |
| 3 | |
| 4 | HELLO_WORLD_KIND = "helloworldservice_complete" |
| 5 | |
| 6 | # The class to represent the service. Most of the service logic is given for us |
| 7 | # in the Service class but, we have some configuration that is specific for |
| 8 | # this example. |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 9 | class HelloWorldServiceComplete(Service): |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 10 | KIND = HELLO_WORLD_KIND |
| 11 | |
| 12 | class Meta: |
| 13 | # When the proxy field is set to True the model is represented as |
Jeremy Mowery | f4dea16 | 2015-12-01 09:24:27 -0700 | [diff] [blame] | 14 | # it's superclass in the database, but we can still change the python |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 15 | # behavior. In this case HelloWorldServiceComplete is a Service in the |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 16 | # database. |
| 17 | proxy = True |
| 18 | # The name used to find this service, all directories are named this |
| 19 | app_label = "helloworldservice_complete" |
| 20 | verbose_name = "Hello World Service" |
| 21 | |
| 22 | # This is the class to represent the tenant. Most of the logic is given to use |
| 23 | # in TenantWithContainer, however there is some configuration and logic that |
| 24 | # we need to define for this example. |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 25 | class HelloWorldTenantComplete(TenantWithContainer): |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 26 | |
| 27 | class Meta: |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 28 | # Same as a above, HelloWorldTenantComplete is represented as a |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 29 | # TenantWithContainer, but we change the python behavior. |
| 30 | proxy = True |
Jeremy Mowery | 12fd157 | 2015-12-01 12:31:43 -0700 | [diff] [blame] | 31 | verbose_name = "Hello World Tenant" |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 32 | |
| 33 | # The kind of the service is used on forms to differentiate this service |
| 34 | # from the other services. |
| 35 | KIND = HELLO_WORLD_KIND |
| 36 | |
| 37 | # Ansible requires that the sync_attributes field contain nat_ip and nat_mac |
| 38 | # these will be used to determine where to SSH to for ansible. |
| 39 | # Getters must be defined for every attribute specified here. |
| 40 | sync_attributes = ("nat_ip", "nat_mac",) |
| 41 | |
| 42 | # default_attributes is used cleanly indicate what the default values for |
| 43 | # the fields are. |
| 44 | default_attributes = {'display_message': 'Hello World!'} |
| 45 | |
| 46 | def __init__(self, *args, **kwargs): |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 47 | helloworld_services = HelloWorldServiceComplete.get_service_objects().all() |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 48 | # When the tenant is created the default service in the form is set |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 49 | # to be the first created HelloWorldServiceComplete |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 50 | if helloworld_services: |
| 51 | self._meta.get_field( |
| 52 | "provider_service").default = helloworld_services[0].id |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 53 | super(HelloWorldTenantComplete, self).__init__(*args, **kwargs) |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 54 | |
| 55 | def save(self, *args, **kwargs): |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 56 | super(HelloWorldTenantComplete, self).save(*args, **kwargs) |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 57 | # This call needs to happen so that an instance is created for this |
| 58 | # tenant is created in the slice. One instance is created per tenant. |
| 59 | model_policy_helloworld_tenant(self.pk) |
| 60 | |
| 61 | def delete(self, *args, **kwargs): |
| 62 | # Delete the instance that was created for this tenant |
| 63 | self.cleanup_container() |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 64 | super(HelloWorldTenantComplete, self).delete(*args, **kwargs) |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 65 | |
| 66 | # Getter for the message that will appear on the webpage |
| 67 | # By default it is "Hello World!" |
| 68 | @property |
| 69 | def display_message(self): |
| 70 | return self.get_attribute( |
| 71 | "display_message", |
| 72 | self.default_attributes['display_message']) |
| 73 | |
| 74 | # Setter for the message that will appear on the webpage |
| 75 | @display_message.setter |
| 76 | def display_message(self, value): |
| 77 | self.set_attribute("display_message", value) |
| 78 | |
| 79 | @property |
| 80 | def addresses(self): |
| 81 | if (not self.id) or (not self.instance): |
| 82 | return {} |
| 83 | |
| 84 | addresses = {} |
| 85 | # The ports field refers to networks for the instance. |
| 86 | # This loop stores the details for the NAT network that will be |
| 87 | # necessary for ansible. |
| 88 | for ns in self.instance.ports.all(): |
| 89 | if "nat" in ns.network.name.lower(): |
| 90 | addresses["nat"] = (ns.ip, ns.mac) |
| 91 | return addresses |
| 92 | |
| 93 | # This getter is necessary because nat_ip is a sync_attribute |
| 94 | @property |
| 95 | def nat_ip(self): |
| 96 | return self.addresses.get("nat", (None, None))[0] |
| 97 | |
| 98 | # This getter is necessary because nat_mac is a sync_attribute |
| 99 | @property |
| 100 | def nat_mac(self): |
| 101 | return self.addresses.get("nat", (None, None))[1] |
| 102 | |
| 103 | |
| 104 | def model_policy_helloworld_tenant(pk): |
| 105 | # This section of code is atomic to prevent race conditions |
| 106 | with transaction.atomic(): |
| 107 | # We find all of the tenants that are waiting to update |
Jeremy Mowery | b971a76 | 2015-11-29 19:46:05 -0700 | [diff] [blame] | 108 | tenant = HelloWorldTenantComplete.objects.select_for_update().filter(pk=pk) |
Jeremy Mowery | 1568734 | 2015-11-29 19:08:04 -0700 | [diff] [blame] | 109 | if not tenant: |
| 110 | return |
| 111 | # Since this code is atomic it is safe to always use the first tenant |
| 112 | tenant = tenant[0] |
| 113 | tenant.manage_container() |