blob: fb54d627f62c32d3e2e7b1477f2f7bd41027763c [file] [log] [blame]
Matteo Scandolo35113f72017-08-08 13:05:25 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Scott Baker619de672016-06-20 12:49:38 -070017import os
18import sys
Scott Baker037ad242018-06-28 09:38:16 -070019import time
20from synchronizers.new_base.syncstep import SyncStep, DeferredException
21from synchronizers.new_base.ansible_helper import run_template_ssh
22from synchronizers.new_base.modelaccessor import ExampleServiceInstance
23from xosconfig import Config
24from multistructlog import create_logger
Scott Baker619de672016-06-20 12:49:38 -070025
Scott Baker037ad242018-06-28 09:38:16 -070026log = create_logger(Config().get('logging'))
Scott Baker619de672016-06-20 12:49:38 -070027
Scott Baker037ad242018-06-28 09:38:16 -070028# TODO(smbaker): Move this to the core
29class SyncServiceInstanceWithComputeUsingAnsible(SyncStep):
30 def __init__(self, *args, **kwargs):
31 SyncStep.__init__(self, *args, **kwargs)
Srikanth Vavilapalli974c9ce2017-01-25 01:50:27 +000032
Scott Baker037ad242018-06-28 09:38:16 -070033 def defer_sync(self, o, reason):
34 log.info("defer object", object = str(o), reason = reason, **o.tologdict())
35 raise DeferredException("defer object %s due to %s" % (str(o), reason))
36
37 def get_extra_attributes(self, o):
38 # This is a place to include extra attributes that aren't part of the
39 # object itself.
40
41 return {}
42
43 def run_playbook(self, o, fields, template_name=None):
44 if not template_name:
45 template_name = self.template_name
46 tStart = time.time()
47 run_template_ssh(template_name, fields, object=o)
48 log.info("playbook execution time", time=int(time.time() - tStart), **o.tologdict())
49
50 def get_ssh_ip(self, instance):
51 for port in instance.ports.all():
52 if port.network.template and port.network.template.vtn_kind == "MANAGEMENT_LOCAL":
53 return port.ip
54
55 for port in instance.ports.all():
56 if port.network.template and port.network.template.vtn_kind == "MANAGEMENT_HOST":
57 return port.ip
58
59 return None
60
61 def get_ansible_fields(self, instance):
62 # return all of the fields that tell Ansible how to talk to the context
63 # that's setting up the container.
64
65 # Cast to the leaf_model. For OpenStackServiceInstance, this will allow us access to fields like "node"
66 instance = instance.leaf_model
67
68 node = getattr(instance, "node")
69 if not node:
70 raise Exception("Instance has no node for instance %s" % str(instance))
71
72 if not instance.slice:
73 raise Exception("Instance has no slice for instance %s" % str(instance))
74
75 if not instance.slice.service:
76 raise Exception("Instance's slice has no service for instance %s" % str(instance))
77
78 if not instance.slice.service.private_key_fn:
79 raise Exception("Instance's slice's service has no private_key_fn for instance %s" % str(instance))
80
81 key_name = instance.slice.service.private_key_fn
82 if not os.path.exists(key_name):
83 raise Exception("Node key %s does not exist for instance %s" % (key_name, str(instance)))
84
85 ssh_ip = self.get_ssh_ip(instance)
86 if not ssh_ip:
87 raise Exception("Unable to determine ssh ip for instance %s" % str(instance))
88
89 key = file(key_name).read()
90
91 fields = {"instance_name": instance.name,
92 "hostname": node.name,
93 "username": "ubuntu",
94 "ssh_ip": ssh_ip,
95 "private_key": key,
96 "instance_id": "none", # is not used for proxy-ssh ansible connections
97 }
98
99 return fields
100
101 def sync_record(self, o):
102 log.info("sync'ing object", object=str(o), **o.tologdict())
103
104 compute_service_instance = o.compute_instance
105 if not compute_service_instance:
106 self.defer_sync(o, "waiting on instance")
107 return
108
109 if not compute_service_instance.backend_handle:
110 self.defer_sync(o, "waiting on instance.backend_handle")
111 return
112
113 fields = self.get_ansible_fields(compute_service_instance)
114
115 fields["ansible_tag"] = getattr(o, "ansible_tag", o.__class__.__name__ + "_" + str(o.id))
116
117 fields.update(self.get_extra_attributes(o))
118
119 self.run_playbook(o, fields)
120
121 o.save()
122
123class SyncExampleServiceInstance(SyncServiceInstanceWithComputeUsingAnsible):
Scott Baker619de672016-06-20 12:49:38 -0700124
Scott Bakerffac7182017-07-27 15:21:30 -0700125 provides = [ExampleServiceInstance]
Scott Baker619de672016-06-20 12:49:38 -0700126
Scott Bakerffac7182017-07-27 15:21:30 -0700127 observes = ExampleServiceInstance
Scott Baker619de672016-06-20 12:49:38 -0700128
129 requested_interval = 0
130
Scott Bakerffac7182017-07-27 15:21:30 -0700131 template_name = "exampleserviceinstance_playbook.yaml"
Scott Baker619de672016-06-20 12:49:38 -0700132
Scott Baker619de672016-06-20 12:49:38 -0700133 def __init__(self, *args, **kwargs):
Scott Bakerffac7182017-07-27 15:21:30 -0700134 super(SyncExampleServiceInstance, self).__init__(*args, **kwargs)
Scott Baker619de672016-06-20 12:49:38 -0700135
Scott Baker619de672016-06-20 12:49:38 -0700136 # Gets the attributes that are used by the Ansible template but are not
137 # part of the set of default attributes.
138 def get_extra_attributes(self, o):
139 fields = {}
140 fields['tenant_message'] = o.tenant_message
Scott Baker037ad242018-06-28 09:38:16 -0700141 exampleservice = o.owner.leaf_model
Scott Baker619de672016-06-20 12:49:38 -0700142 fields['service_message'] = exampleservice.service_message
Scott Baker7a916f72017-10-25 16:52:52 -0700143
144 if o.foreground_color:
145 fields["foreground_color"] = o.foreground_color.html_code
146
147 if o.background_color:
148 fields["background_color"] = o.background_color.html_code
149
Scott Baker037ad242018-06-28 09:38:16 -0700150 images = []
Scott Baker7a916f72017-10-25 16:52:52 -0700151 for image in o.embedded_images.all():
152 images.append({"name": image.name,
153 "url": image.url})
154 fields["images"] = images
155
Scott Baker619de672016-06-20 12:49:38 -0700156 return fields
157
Scott Baker9b1a3eb2017-01-23 14:46:27 -0800158 def delete_record(self, port):
159 # Nothing needs to be done to delete an exampleservice; it goes away
160 # when the instance holding the exampleservice is deleted.
161 pass
162