blob: a248c60042caf7952749c2434c35aaa2b5ab08dc [file] [log] [blame]
Siobhan Tully4bc09f22013-04-10 21:15:21 -04001import os
2from django.db import models
Sapan Bhatia14356b72014-11-05 10:32:41 -05003from django.db.models import Q
Tony Mack2b241cf2013-04-16 21:57:55 -04004from django.core import exceptions
Sapan Bhatia14356b72014-11-05 10:32:41 -05005from core.models import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager
Tony Mack50e12212015-03-09 13:03:56 -04006from core.models.plcorebase import StrippedCharField
Siobhan Tully30fd4292013-05-10 08:59:56 -04007from core.models import Image
Scott Bakera115c1e2015-05-07 14:58:46 -07008from core.models import Slice, SlicePrivilege
Siobhan Tully30fd4292013-05-10 08:59:56 -04009from core.models import Node
10from core.models import Site
Siobhan Tullybf1153a2013-05-27 20:53:48 -040011from core.models import Deployment
Tony Mack68a1e422014-12-08 16:43:02 -050012from core.models import Controller
Tony Mackb0d97422013-06-10 09:57:45 -040013from core.models import User
Siobhan Tullyde5450d2013-06-21 11:35:33 -040014from core.models import Tag
Scott Baker7a61dc42014-09-02 17:08:20 -070015from core.models import Flavor
Siobhan Tullyde5450d2013-06-21 11:35:33 -040016from django.contrib.contenttypes import generic
Scott Baker86e132c2015-02-11 21:38:09 -080017from xos.config import Config
Sapan Bhatiaeec8acc2014-12-16 01:08:51 -050018from monitor import driver as monitor
Scott Bakerf41fe2c2015-07-09 19:06:08 -070019from django.core.exceptions import PermissionDenied, ValidationError
Sapan Bhatia14356b72014-11-05 10:32:41 -050020
21config = Config()
Siobhan Tully4bc09f22013-04-10 21:15:21 -040022
Tony Mack06c8e472014-11-30 15:53:08 -050023def get_default_flavor(controller = None):
Tony Mackd8515472015-08-19 11:58:18 -040024 # Find a default flavor that can be used for a instance. This is particularly
Scott Baker7a61dc42014-09-02 17:08:20 -070025 # useful in evolution. It's also intended this helper function can be used
26 # for admin.py when users
27
Tony Mack06c8e472014-11-30 15:53:08 -050028 if controller:
29 flavors = controller.flavors.all()
Scott Baker7a61dc42014-09-02 17:08:20 -070030 else:
31 flavors = Flavor.objects.all()
32
33 if not flavors:
Scott Baker7a61dc42014-09-02 17:08:20 -070034 return None
35
36 for flavor in flavors:
37 if flavor.default:
Scott Baker7a61dc42014-09-02 17:08:20 -070038 return flavor
39
Scott Baker7a61dc42014-09-02 17:08:20 -070040 return flavors[0]
41
Tony Mackd8515472015-08-19 11:58:18 -040042class InstanceDeletionManager(PlCoreBaseDeletionManager):
Sapan Bhatia14356b72014-11-05 10:32:41 -050043 def get_queryset(self):
Tony Mackd8515472015-08-19 11:58:18 -040044 parent=super(InstanceDeletionManager, self)
Sapan Bhatia14356b72014-11-05 10:32:41 -050045 try:
46 backend_type = config.observer_backend_type
47 except AttributeError:
48 backend_type = None
49
50 parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
51 if (backend_type):
Tony Mack51c4a7d2014-11-30 15:33:35 -050052 return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
Sapan Bhatia14356b72014-11-05 10:32:41 -050053 else:
54 return parent_queryset
55
56 # deprecated in django 1.7 in favor of get_queryset().
57 def get_query_set(self):
58 return self.get_queryset()
59
60
Tony Mackd8515472015-08-19 11:58:18 -040061class InstanceManager(PlCoreBaseManager):
Sapan Bhatia14356b72014-11-05 10:32:41 -050062 def get_queryset(self):
Tony Mackd8515472015-08-19 11:58:18 -040063 parent=super(InstanceManager, self)
Sapan Bhatia14356b72014-11-05 10:32:41 -050064
65 try:
66 backend_type = config.observer_backend_type
67 except AttributeError:
68 backend_type = None
69
70 parent_queryset = parent.get_queryset() if hasattr(parent, "get_queryset") else parent.get_query_set()
71
72 if backend_type:
Tony Mack51c4a7d2014-11-30 15:33:35 -050073 return parent_queryset.filter(Q(node__controller__backend_type=backend_type))
Sapan Bhatia14356b72014-11-05 10:32:41 -050074 else:
75 return parent_queryset
76
77 # deprecated in django 1.7 in favor of get_queryset().
78 def get_query_set(self):
79 return self.get_queryset()
80
Siobhan Tully4bc09f22013-04-10 21:15:21 -040081# Create your models here.
Tony Mackd8515472015-08-19 11:58:18 -040082class Instance(PlCoreBase):
83 objects = InstanceManager()
84 deleted_objects = InstanceDeletionManager()
Tony Mack50e12212015-03-09 13:03:56 -040085 instance_id = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance id")
86 instance_uuid = StrippedCharField(null=True, blank=True, max_length=200, help_text="Nova instance uuid")
Tony Mackd8515472015-08-19 11:58:18 -040087 name = StrippedCharField(max_length=200, help_text="Instance name")
Tony Mack50e12212015-03-09 13:03:56 -040088 instance_name = StrippedCharField(blank=True, null=True, max_length=200, help_text="OpenStack generated name")
Tony Mackd8515472015-08-19 11:58:18 -040089 ip = models.GenericIPAddressField(help_text="Instance ip address", blank=True, null=True)
90 image = models.ForeignKey(Image, related_name='instances')
91 #key = models.ForeignKey(Key, related_name='instances')
92 creator = models.ForeignKey(User, related_name='instances', blank=True, null=True)
93 slice = models.ForeignKey(Slice, related_name='instances')
94 deployment = models.ForeignKey(Deployment, verbose_name='deployment', related_name='instance_deployment')
95 node = models.ForeignKey(Node, related_name='instances')
96 numberCores = models.IntegerField(verbose_name="Number of Cores", help_text="Number of cores for instance", default=0)
Scott Baker7a61dc42014-09-02 17:08:20 -070097 flavor = models.ForeignKey(Flavor, help_text="Flavor of this instance", default=get_default_flavor)
Siobhan Tullyde5450d2013-06-21 11:35:33 -040098 tags = generic.GenericRelation(Tag)
Scott Baker9c7a1e12014-05-30 14:42:42 -070099 userData = models.TextField(blank=True, null=True, help_text="user_data passed to instance during creation")
Siobhan Tully4bc09f22013-04-10 21:15:21 -0400100
Scott Baker3015c762013-08-23 10:28:07 -0700101 def __unicode__(self):
Scott Bakerc1452212015-08-04 23:50:51 -0700102 if self.name and Slice.objects.filter(id=self.slice_id) and (self.name != self.slice.name):
103 # NOTE: The weird check on self.slice_id was due to a problem when
Tony Mackd8515472015-08-19 11:58:18 -0400104 # deleting the slice before the instance.
Scott Baker02f913f2015-08-04 16:05:18 -0700105 return u'%s' % self.name
106 elif self.instance_name:
Scott Baker3015c762013-08-23 10:28:07 -0700107 return u'%s' % (self.instance_name)
108 elif self.id:
109 return u'uninstantiated-%s' % str(self.id)
110 elif self.slice:
Tony Mackd8515472015-08-19 11:58:18 -0400111 return u'unsaved-instance on %s' % self.slice.name
Scott Baker3015c762013-08-23 10:28:07 -0700112 else:
Tony Mackd8515472015-08-19 11:58:18 -0400113 return u'unsaved-instance'
Scott Baker3015c762013-08-23 10:28:07 -0700114
Tony Mackcdec0902013-04-15 00:38:49 -0400115 def save(self, *args, **kwds):
Scott Baker02f913f2015-08-04 16:05:18 -0700116 if not self.name:
117 self.name = self.slice.name
Tony Mack2bd5b412013-06-11 21:05:06 -0400118 if not self.creator and hasattr(self, 'caller'):
119 self.creator = self.caller
Scott Baker2d599df2015-01-29 17:55:40 -0800120 if not self.creator:
Tony Mackd8515472015-08-19 11:58:18 -0400121 raise ValidationError('instance has no creator')
Scott Baker5380c522014-06-06 14:49:43 -0700122
Scott Bakerf41fe2c2015-07-09 19:06:08 -0700123 if (self.slice.creator != self.creator):
124 # Check to make sure there's a slice_privilege for the user. If there
125 # isn't, then keystone will throw an exception inside the observer.
126 slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
127 if not slice_privs:
Tony Mackd8515472015-08-19 11:58:18 -0400128 raise ValidationError('instance creator has no privileges on slice')
Scott Bakerf41fe2c2015-07-09 19:06:08 -0700129
Scott Bakerec06eba2014-06-20 18:03:04 -0700130# XXX smbaker - disabled for now, was causing fault in tenant view create slice
Tony Mack06c8e472014-11-30 15:53:08 -0500131# if not self.controllerNetwork.test_acl(slice=self.slice):
132# raise exceptions.ValidationError("Deployment %s's ACL does not allow any of this slice %s's users" % (self.controllerNetwork.name, self.slice.name))
Scott Baker5380c522014-06-06 14:49:43 -0700133
Tony Mackd8515472015-08-19 11:58:18 -0400134 super(Instance, self).save(*args, **kwds)
Tony Mack5b061472014-02-04 07:57:10 -0500135
136 def can_update(self, user):
Tony Mack3428e6e2015-02-08 21:38:41 -0500137 return user.can_update_slice(self.slice)
Tony Mack5b061472014-02-04 07:57:10 -0500138
Scott Baker434ca7e2014-08-15 12:29:20 -0700139 def all_ips(self):
140 ips={}
Tony Mackd8515472015-08-19 11:58:18 -0400141 for ns in self.networkinstances.all():
Scott Baker01907e92015-08-18 23:02:11 -0700142 if ns.ip:
143 ips[ns.network.name] = ns.ip
Scott Baker434ca7e2014-08-15 12:29:20 -0700144 return ips
145
146 def all_ips_string(self):
147 result = []
148 ips = self.all_ips()
149 for key in sorted(ips.keys()):
150 #result.append("%s = %s" % (key, ips[key]))
151 result.append(ips[key])
152 return ", ".join(result)
153 all_ips_string.short_description = "addresses"
154
Scott Baker7d7d8cd2015-03-16 17:13:58 -0700155 def get_public_ip(self):
Tony Mackd8515472015-08-19 11:58:18 -0400156 for ns in self.networkinstances.all():
Scott Bakerf8ec83d2015-03-16 16:44:41 -0700157 if (ns.ip) and (ns.network.template.visibility=="public") and (ns.network.template.translation=="none"):
158 return ns.ip
159 return None
160
Tony Mack5b061472014-02-04 07:57:10 -0500161 @staticmethod
162 def select_by_user(user):
163 if user.is_admin:
Tony Mackd8515472015-08-19 11:58:18 -0400164 qs = Instance.objects.all()
Tony Mack5b061472014-02-04 07:57:10 -0500165 else:
Tony Macke4be32f2014-03-11 20:45:25 -0400166 slices = Slice.select_by_user(user)
Tony Mackd8515472015-08-19 11:58:18 -0400167 qs = Instance.objects.filter(slice__in=slices)
Tony Mack5b061472014-02-04 07:57:10 -0500168 return qs
Sapan Bhatiaeec8acc2014-12-16 01:08:51 -0500169
170 def get_cpu_stats(self):
Tony Mackd8515472015-08-19 11:58:18 -0400171 filter = 'instance_id=%s'%self.instance_id
Sapan Bhatiaeec8acc2014-12-16 01:08:51 -0500172 return monitor.get_meter('cpu',filter,None)
173
174 def get_bw_stats(self):
Tony Mackd8515472015-08-19 11:58:18 -0400175 filter = 'instance_id=%s'%self.instance_id
Sapan Bhatiaeec8acc2014-12-16 01:08:51 -0500176 return monitor.get_meter('network.outgoing.bytes',filter,None)
177
178 def get_node_stats(self):
179 # Note sure what should go back here
180 return 1
Scott Baker7ccc6ad2015-01-25 22:16:13 -0800181
182 def get_ssh_command(self):
183 if (not self.instance_id) or (not self.node) or (not self.instance_name):
184 return None
185 else:
186 return 'ssh -o "ProxyCommand ssh -q %s@%s" ubuntu@%s' % (self.instance_id, self.node.name, self.instance_name)
Scott Bakera115c1e2015-05-07 14:58:46 -0700187
188 def get_public_keys(self):
189 slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
190 pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
191
192 if self.creator.public_key:
193 pubkeys.add(self.creator.public_key)
194
195 if self.slice.creator.public_key:
196 pubkeys.add(self.slice.creator.public_key)
197
198 if self.slice.service and self.slice.service.public_key:
199 pubkeys.add(self.slice.service.public_key)
200
201 return pubkeys
Sapan Bhatia52ba5422015-05-13 15:48:02 +0200202
203def controller_setter(instance, **kwargs):
204 try:
205 instance.controller = instance.node.site_deployment.controller
206 except:
207 instance.controller = None
208
Tony Mackd8515472015-08-19 11:58:18 -0400209models.signals.post_init.connect(controller_setter, Instance)