summaryrefslogtreecommitdiffstats
path: root/roles/lib_openshift/src/class/oc_process.py
blob: 9d29938aa51e00880751a725d333bc277245c2c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# pylint: skip-file
# flake8: noqa


# pylint: disable=too-many-instance-attributes
class OCProcess(OpenShiftCLI):
    ''' Class to wrap the oc command line tools '''

    # pylint allows 5. we need 6
    # pylint: disable=too-many-arguments
    def __init__(self,
                 namespace,
                 tname=None,
                 params=None,
                 create=False,
                 kubeconfig='/etc/origin/master/admin.kubeconfig',
                 tdata=None,
                 verbose=False):
        ''' Constructor for OpenshiftOC '''
        super(OCProcess, self).__init__(namespace, kubeconfig=kubeconfig, verbose=verbose)
        self.name = tname
        self.data = tdata
        self.params = params
        self.create = create
        self._template = None

    @property
    def template(self):
        '''template property'''
        if self._template is None:
            results = self._process(self.name, False, self.params, self.data)
            if results['returncode'] != 0:
                raise OpenShiftCLIError('Error processing template [%s].' % self.name)
            self._template = results['results']['items']

        return self._template

    def get(self):
        '''get the template'''
        results = self._get('template', self.name)
        if results['returncode'] != 0:
            # Does the template exist??
            if 'not found' in results['stderr']:
                results['returncode'] = 0
                results['exists'] = False
                results['results'] = []

        return results

    def delete(self, obj):
        '''delete a resource'''
        return self._delete(obj['kind'], obj['metadata']['name'])

    def create_obj(self, obj):
        '''create a resource'''
        return self._create_from_content(obj['metadata']['name'], obj)

    def process(self, create=None):
        '''process a template'''
        do_create = False
        if create != None:
            do_create = create
        else:
            do_create = self.create

        return self._process(self.name, do_create, self.params, self.data)

    def exists(self):
        '''return whether the template exists'''
        # Always return true if we're being passed template data
        if self.data:
            return True
        t_results = self._get('template', self.name)

        if t_results['returncode'] != 0:
            # Does the template exist??
            if 'not found' in t_results['stderr']:
                return False
            else:
                raise OpenShiftCLIError('Something went wrong. %s' % t_results)

        return True

    def needs_update(self):
        '''attempt to process the template and return it for comparison with oc objects'''
        obj_results = []
        for obj in self.template:

            # build a list of types to skip
            skip = []

            if obj['kind'] == 'ServiceAccount':
                skip.extend(['secrets', 'imagePullSecrets'])
            if obj['kind'] == 'BuildConfig':
                skip.extend(['lastTriggeredImageID'])
            if obj['kind'] == 'ImageStream':
                skip.extend(['generation'])
            if obj['kind'] == 'DeploymentConfig':
                skip.extend(['lastTriggeredImage'])

            # fetch the current object
            curr_obj_results = self._get(obj['kind'], obj['metadata']['name'])
            if curr_obj_results['returncode'] != 0:
                # Does the template exist??
                if 'not found' in curr_obj_results['stderr']:
                    obj_results.append((obj, True))
                    continue

            # check the generated object against the existing object
            if not Utils.check_def_equal(obj, curr_obj_results['results'][0], skip_keys=skip):
                obj_results.append((obj, True))
                continue

            obj_results.append((obj, False))

        return obj_results

    # pylint: disable=too-many-return-statements
    @staticmethod
    def run_ansible(params, check_mode):
        '''run the ansible idempotent code'''

        ocprocess = OCProcess(params['namespace'],
                              params['template_name'],
                              params['params'],
                              params['create'],
                              kubeconfig=params['kubeconfig'],
                              tdata=params['content'],
                              verbose=params['debug'])

        state = params['state']

        api_rval = ocprocess.get()

        if state == 'list':
            if api_rval['returncode'] != 0:
                return {"failed": True, "msg" : api_rval}

            return {"changed" : False, "results": api_rval, "state": "list"}

        elif state == 'present':
            if check_mode and params['create']:
                return {"changed": True, 'msg': "CHECK_MODE: Would have processed template."}

            if not ocprocess.exists() or not params['reconcile']:
            #FIXME: this code will never get run in a way that succeeds when
            #       module.params['reconcile'] is true. Because oc_process doesn't
            #       create the actual template, the check of ocprocess.exists()
            #       is meaningless. Either it's already here and this code
            #       won't be run, or this code will fail because there is no
            #       template available for oc process to use. Have we conflated
            #       the template's existence with the existence of the objects
            #       it describes?

            # Create it here
                api_rval = ocprocess.process()
                if api_rval['returncode'] != 0:
                    return {"failed": True, "msg": api_rval}

                if params['create']:
                    return {"changed": True, "results": api_rval, "state": "present"}

                return {"changed": False, "results": api_rval, "state": "present"}

        # verify results
        update = False
        rval = []
        all_results = ocprocess.needs_update()
        for obj, status in all_results:
            if status:
                ocprocess.delete(obj)
                results = ocprocess.create_obj(obj)
                results['kind'] = obj['kind']
                rval.append(results)
                update = True

        if not update:
            return {"changed": update, "results": api_rval, "state": "present"}

        for cmd in rval:
            if cmd['returncode'] != 0:
                return {"failed": True, "changed": update, "results": rval, "state": "present"}

        return {"changed": update, "results": rval, "state": "present"}