Line data Source code
1 : //
2 : // specials.c
3 : // oc-runner
4 : //
5 : // Created by Danny Goossen on 16/10/17.
6 : // Copyright (c) 2017 Danny Goossen. All rights reserved.
7 : //
8 :
9 : #include "deployd.h"
10 : #include "specials.h"
11 : #include "wordexp_var.h"
12 :
13 : /*------------------------------------------------------------------------
14 : * slug a null or non Null terminated string:
15 : * replace all non (a-zA-Z0-9) with -
16 : * no - at beginning or end, no subsequent dashes
17 : *
18 : * return a null terminated string, caller is responsible for freeing it!
19 : *------------------------------------------------------------------------*/
20 12 : char * slug_it(const char * input_str, size_t len)
21 : {
22 12 : if (!input_str) return NULL;
23 : regex_t regex;
24 : int reti;
25 12 : size_t prev_end=0;
26 12 : char * output=NULL;
27 12 : char * instr=NULL;
28 12 : char regex_str[]= "[^a-zA-Z0-9]";
29 12 : int regex_match_cnt=1+1;
30 :
31 : regmatch_t ovector[2];
32 : //regmatch_t * ovector= calloc(sizeof(regmatch_t),regex_match_cnt);
33 :
34 :
35 :
36 : // prepare input and output buffer
37 12 : if (len)
38 : {
39 1 : output=calloc(1, len+1);
40 1 : instr=calloc(1, len+1);
41 1 : memcpy(instr, input_str, len);
42 : }
43 : else
44 : {
45 11 : len=strlen(input_str);
46 11 : output=calloc(1, strlen(input_str)+1);
47 11 : instr=strdup(input_str);
48 : }
49 : // should not happen!
50 12 : if (!output || !instr){ error("Out of memory\n");if (output) free(output);if (instr) free(instr);return NULL;}
51 : /* Compile regular expression */
52 :
53 12 : reti = regcomp(®ex, regex_str, REG_EXTENDED);
54 : // should not happen, regex is fixed, not variable
55 12 : if (reti) { error("Could not compile regex\n");regfree(®ex);if (instr) free(instr);if (output) free(output);return NULL;}
56 :
57 : /* Execute regular expression in loop */
58 :
59 : for (;;)
60 : {
61 : size_t len_subject;
62 34 : reti = regexec(®ex, instr+prev_end, regex_match_cnt, ovector, 0);
63 34 : if (!reti)
64 : {
65 22 : if (ovector[0].rm_so !=-1 && (ovector[0].rm_eo-ovector[0].rm_so) == 1)
66 : {
67 22 : if (!prev_end )
68 7 : memcpy(output,instr,ovector[0].rm_so);
69 : else
70 15 : memcpy(output+strlen(output),instr+prev_end,ovector[0].rm_so);
71 :
72 22 : len_subject=strlen(output);
73 22 : if ( len_subject>0 && output[len_subject-1]!='-' ) output[len_subject]='-';
74 22 : prev_end=prev_end+ovector[0].rm_eo;
75 : }
76 : else break;
77 : }
78 12 : else if (reti == REG_NOMATCH)
79 : {
80 : // copy rest from lastmatch end to end of subject
81 12 : memcpy(output+strlen(output),(instr+ prev_end), len-prev_end);
82 12 : break;
83 : }
84 : else
85 0 : { char errmsg[1024];regerror(reti, ®ex,(char *) errmsg, 1024);error( "Regex match failed: %s\n", errmsg);break;}
86 22 : }
87 :
88 : //remove trailing -
89 1 : while(strlen(output) && output[strlen(output)-1]=='-') output[strlen(output)-1]='\0';
90 :
91 12 : regfree(®ex);
92 12 : if (strlen(output)==0)
93 : {
94 1 : if (output) free(output);
95 1 : if (instr) free(instr);
96 : return NULL;
97 : }
98 11 : if (instr) free(instr);
99 : // we only want lowercase
100 11 : lower_string(output);
101 : // chop anything longer then 63
102 11 : if (strlen(output)>63) output[63]=0;
103 : // we cant end with -
104 11 : if (len>61 && output[62]=='-') output[62]=0;
105 11 : return output;
106 : }
107 5 : char * resolve_const_vars(const char * s,const cJSON * env_vars)
108 : {
109 5 : if (!s) return NULL;
110 4 : char * res=NULL;
111 : char we_result[1024];
112 4 : int e_result=word_exp_var(we_result, 1024, s, env_vars);
113 4 : if (e_result)
114 : {
115 1 : debug("error resolve image\n");
116 : }
117 : else
118 : {
119 3 : res=strdup(we_result);
120 3 : debug("Resolved variable %s to %s\n", s,res);
121 : }
122 4 : return res;
123 : }
124 :
125 : int resolve_vars(char ** image,const cJSON * env_vars);
126 :
127 10 : int resolve_vars(char ** image,const cJSON * env_vars)
128 : {
129 10 : if(!image || !*image) return -1;
130 9 : int res=0;
131 : char image_result[1024];
132 9 : int e_result=word_exp_var(image_result, 1024, *image, env_vars);
133 9 : if (e_result)
134 : {
135 1 : res=-1;
136 1 : free(*image);
137 1 : debug("error resolve image\n");
138 1 : *image=NULL;
139 : }
140 : else
141 : {
142 8 : free(*image);
143 8 : *image=strdup(image_result);
144 8 : debug("Resolved image %s\n",*image);
145 : }
146 9 : return res;
147 : }
148 :
149 12 : int change_image_tag(char ** image, const char *new_tag)
150 : {
151 12 : if (!image || !*image || strlen(*image)==0) return -1;
152 9 : char *p_ddot=strchr(*image,':');
153 9 : char *p_at=strchr(*image,'@');
154 9 : char *p_slash=strchr(*image,'/');
155 :
156 9 : char * start_ref=NULL;
157 9 : if (image && *image && strlen(*image)>0 )
158 : {
159 9 : char * tag_sep=p_ddot;
160 9 : if (p_at) tag_sep=p_at;
161 9 : if (tag_sep)
162 : {
163 8 : char *p_ddot2=strchr(p_ddot+1,':');
164 8 : if (p_at)
165 : {
166 : start_ref=p_at;
167 : }
168 5 : else if (p_ddot2)
169 : {
170 : start_ref=p_ddot2;
171 : }
172 3 : else if (p_slash && p_ddot >p_slash)
173 : {
174 : start_ref=p_ddot;
175 : }
176 3 : else if (!p_slash)
177 2 : start_ref=p_ddot;
178 : }
179 : }
180 9 : char* new_image=NULL;
181 9 : if (start_ref)
182 : {
183 7 : if (new_tag && strlen(new_tag)>0)
184 : {
185 4 : size_t len_2ddot=start_ref-(*image);
186 4 : new_image=calloc(1,(start_ref-(*image))+1+strlen(new_tag)+1 );
187 4 : if (new_image)
188 4 : sprintf(new_image,"%.*s:%s",(int)len_2ddot,*image,new_tag );
189 : }
190 : else
191 : {
192 3 : size_t len_2tag_sep=start_ref-(*image);
193 3 : new_image=calloc(1,(start_ref-(*image))+1 );
194 3 : if (new_image)
195 3 : sprintf(new_image,"%.*s",(int)len_2tag_sep,*image );
196 : }
197 :
198 : }
199 : else
200 : {
201 2 : if (new_tag && strlen(new_tag)>0)
202 : {
203 2 : new_image=calloc(1,(strlen(*image))+1+strlen(new_tag)+1 );
204 2 : if(new_image)
205 2 : sprintf(new_image,"%s:%s",*image,new_tag );
206 : }
207 : else
208 : {
209 0 : new_image=calloc(1,(strlen(*image))+1 );
210 0 : if (new_image)
211 0 : sprintf(new_image,"%s",*image );
212 : }
213 :
214 : }
215 9 : if (new_image)
216 : {
217 9 : free(*image);
218 9 : *image=new_image;
219 9 : return 0;
220 : }
221 : else
222 : return -1;
223 :
224 : }
225 :
226 : /*
227 : int process_executor_image_nick(char ** image,const char * Imagestream_ip, const char * oc_name_space)
228 : {
229 : if (!image || !*image || strlen(*image)==0) return -1;
230 : if (strstr(*image,"ImageStream")==*image)
231 : {
232 : // it's imageStream
233 : char image_check[1024];
234 : char * p=NULL;
235 : if (strstr(*image,"ImageStream/")==*image)
236 : p=(*image)+strlen("ImageStream/");
237 : else
238 : p=*(image)+strlen("ImageStream");
239 :
240 : if (strlen(p)==0)
241 : return -1;
242 : else
243 : {
244 : char *p_ddot_nick=strchr(p,':');
245 : char * slugged_nick=NULL;
246 : if (p_ddot_nick && p_ddot_nick != p) // slug till :
247 : {
248 : slugged_nick=slug_it(p, p_ddot_nick-p);
249 : if (slugged_nick) snprintf(image_check,1024 ,"%s/%s/is-%s%s",Imagestream_ip,oc_name_space,slugged_nick,p_ddot_nick);
250 : }
251 : else if (!p_ddot_nick)
252 : {
253 : if (slugged_nick)free(slugged_nick);
254 : return -1;
255 : }
256 : else
257 : {
258 : if (slugged_nick)free(slugged_nick);
259 : return -1;
260 : }
261 : if (slugged_nick)free(slugged_nick);
262 : }
263 : free(*image);
264 : *image=strdup(image_check);
265 : }
266 : return 0;
267 : }
268 :
269 : */
270 :
271 17 : char * process_image_nick(char ** image,const cJSON * env_vars,const char * Imagestream_ip, const char * oc_name_space,const char * docker_registry)
272 : {
273 17 : if (!image || !*image || strlen(*image)==0) return NULL;
274 17 : char *result=NULL;
275 :
276 17 : resolve_image_var(image, env_vars);
277 :
278 17 : char *p_dot=strchr(*image,'.');
279 17 : char *p_ddot=strchr(*image,':');
280 17 : char *p_slash=strchr(*image,'/');
281 :
282 :
283 17 : if (strstr(*image,"ImageStream")==*image)
284 : {
285 : // it's imageStream
286 : char image_check[1024];
287 6 : char * p=NULL;
288 6 : if (strstr(*image,"ImageStream/")==*image)
289 3 : p=(*image)+strlen("ImageStream/");
290 : else
291 3 : p=*(image)+strlen("ImageStream");
292 :
293 6 : if (p && strlen(p)==0)
294 1 : snprintf(image_check,1024 ,"%s/%s/is-%s",Imagestream_ip,oc_name_space,cJSON_get_key(env_vars,"CI_PROJECT_PATH_SLUG"));
295 : else
296 : {
297 5 : char *p_ddot_nick=strchr(p,':');
298 5 : char *p_at_nick=strchr(p,'@');
299 5 : char * slugged_nick=NULL;
300 5 : char*tag_sep=p_ddot_nick;
301 5 : if (p_at_nick)
302 : {
303 2 : tag_sep=p_at_nick;
304 :
305 : }
306 5 : if (tag_sep && tag_sep != p ) // slug till :
307 : {
308 :
309 1 : slugged_nick=slug_it(p, tag_sep-p);
310 1 : if (slugged_nick) snprintf(image_check,1024 ,"%s/%s/is-%s-%s%s",Imagestream_ip,oc_name_space,cJSON_get_key(env_vars,"CI_PROJECT_PATH_SLUG"),slugged_nick,tag_sep);
311 :
312 : }
313 4 : else if (!tag_sep )
314 : {
315 2 : slugged_nick=slug_it(p, 0);
316 :
317 2 : if (slugged_nick)
318 2 : snprintf(image_check,1024 ,"%s/%s/is-%s-%s",Imagestream_ip,oc_name_space,cJSON_get_key(env_vars,"CI_PROJECT_PATH_SLUG"),slugged_nick);
319 : }
320 : else
321 2 : snprintf(image_check,1024 ,"%s/%s/is-%s%s",Imagestream_ip,oc_name_space,cJSON_get_key(env_vars,"CI_PROJECT_PATH_SLUG"),p);
322 :
323 5 : if (slugged_nick)free(slugged_nick);
324 : }
325 :
326 :
327 6 : result=strdup(image_check);
328 :
329 : }
330 11 : else if ( strstr(*image,"Gitlab")==*image)
331 : {
332 : // it's gitlab
333 6 : debug("image is Gitlab registry\n");
334 6 : if (!cJSON_get_key(env_vars,"CI_REGISTRY_IMAGE"))
335 : {
336 1 : debug("image is Gitlab, but no CI_REGISTRY_IMAGE in env \n");
337 1 : result=NULL; // not needed just for clarity
338 : }
339 : else
340 : {
341 : char image_check[1024];
342 5 : snprintf(image_check,1024 ,"%s%s",cJSON_get_key(env_vars,"CI_REGISTRY_IMAGE"),(*image)+strlen("Gitlab"));
343 5 : result=strdup(image_check);
344 : }
345 : }
346 : else
347 : {
348 : // check if docker
349 5 : if ((p_dot && !p_ddot) || (p_dot && p_ddot && (p_dot < p_ddot) ))
350 : { // image contains a registry_domain
351 3 : result=strdup(*image);
352 : }
353 : else
354 2 : { debug("image does not contain registry so prepend %s\n",docker_registry);
355 2 : if (docker_registry && *image)
356 : {
357 2 : size_t len_dock_regi=strlen(docker_registry);
358 2 : size_t len_image=strlen(*image);
359 2 : if ( !p_slash )
360 : { // add library/ if no /
361 1 : debug("add library/\n");
362 1 : len_image=len_image+strlen("library/");
363 1 : result=calloc(1,len_dock_regi+1+len_image+1);
364 1 : sprintf(result,"%s/library/%s",docker_registry,*image);
365 : }
366 : else
367 : {
368 1 : result=calloc(1,len_dock_regi+1+len_image+1);
369 1 : sprintf(result,"%s/%s",docker_registry,*image);
370 : }
371 :
372 : }
373 : else return NULL;
374 : }
375 : }
376 :
377 17 : return result;
378 : }
379 :
380 : /*
381 :
382 : // TODO remove this, use above function!!!
383 : int prep_image(char ** image,const cJSON * env_vars, const char * ImageStream_domain , const char * oc_name_space)
384 : {
385 : int res=0;
386 : res=resolve_image_var(image, env_vars);
387 : if (!res && image && *image && strstr(*image,"ImageStream/")==*image)
388 : {
389 : char image_check[1024];
390 : snprintf(image_check,1024 ,"%s/%s/%s",ImageStream_domain,oc_name_space,*image+strlen("ImageStream/"));
391 : free(*image);
392 : *image=strdup(image_check);
393 : }
394 : return res;
395 : }
396 : */
397 :
398 :
399 :
400 :
401 17 : int resolve_image_var(char ** image,const cJSON * env_vars)
402 : {
403 17 : int res=0;
404 17 : int work=0;
405 17 : if (image && *image && strchr(*image, '$')!=NULL)
406 : {
407 : int cnt=0;
408 : do
409 : {
410 3 : cnt ++;
411 3 : char * p=NULL;
412 3 : if ((p=strchr(*image,':')))
413 : {
414 : // split it
415 2 : char * image_name=strdup(*image);
416 2 : image_name[p-(*image)]=0;
417 2 : resolve_vars(&image_name,env_vars);
418 2 : char * tag=strdup(p+1);
419 2 : res=resolve_vars(&tag,env_vars);
420 2 : free(*image);
421 2 : *image=NULL;
422 2 : if (image_name && tag)
423 : {
424 2 : *image=calloc(1,strlen(image_name)+1+strlen(tag)+1);
425 : //and put it back together
426 2 : sprintf(*image, "%s:%s",image_name,tag);
427 : }
428 2 : if (tag)free(tag);
429 2 : if(image_name)free(image_name);
430 2 : tag=NULL;
431 2 : image_name=NULL;
432 : }
433 : else
434 1 : res=resolve_vars(image,env_vars);
435 :
436 3 : if (*image)
437 3 : work=(strchr(*image,'$')!=NULL );
438 : else
439 : work=0;
440 : }
441 3 : while (work && cnt<5);
442 : }
443 17 : return res;
444 : }
445 :
446 :
447 : //TODO: add , int * IsDigest
448 38 : int chop_image(const char *image,char ** registry_name,char **namespace,char **reference)
449 : {
450 38 : if (!image) return -1;
451 38 : if (namespace && *namespace) free(*namespace);
452 38 : if(reference && *reference) free(*reference);
453 38 : if (registry_name && *registry_name) free(*registry_name);
454 38 : if(reference) *reference=NULL;
455 38 : if (namespace) *namespace=NULL;
456 38 : if (registry_name) *registry_name=NULL;
457 :
458 38 : const char * start=image;
459 38 : char *fs=strchr(image,'/');
460 38 : char *pt=strchr(image,'.');
461 38 : char *pdd=strchr(image,':');
462 38 : char * tmp_image_name=NULL;
463 38 : if (fs && pt && pt<fs)
464 : {
465 : // we got registry, move start
466 26 : start=fs+1; // name space should not start with /
467 26 : tmp_image_name=cJSON_strdup_n((const unsigned char*)image, fs-image);
468 : }
469 12 : else if (!pt || (pt && pdd && pt>pdd))
470 : {
471 : // no registry=> take default
472 12 : tmp_image_name=strdup(DOCKER_REGISTRY);
473 : }
474 0 : else if (!fs && pt)
475 : {
476 0 : tmp_image_name=strdup(image);
477 0 : start=NULL;
478 : }
479 :
480 38 : if (start)
481 : {
482 38 : char *dd=strchr(start,':');
483 38 : char *at=strchr(start,'@');
484 38 : if (dd && !at)
485 : {
486 :
487 25 : if (namespace) *namespace=cJSON_strdup_n((const unsigned char*)start, dd-start);
488 :
489 25 : if (reference) *reference=strdup(dd+1);
490 : }
491 13 : else if( at) // image refered with @DIGEST
492 : {
493 6 : if (namespace) *namespace=cJSON_strdup_n((const unsigned char*)start, at-start);
494 :
495 6 : if (reference) *reference=strdup(at+1);
496 : }
497 : else
498 : {
499 7 : if (namespace) *namespace=strdup(start);
500 : }
501 : }
502 : //TODO remove, image should be complete
503 38 : if ( tmp_image_name && strcmp(tmp_image_name,DOCKER_REGISTRY)==0)
504 : {
505 12 : if (namespace && *namespace &&!strchr(*namespace,'/'))
506 : {
507 6 : char * tmp=calloc(1,strlen(*namespace)+1+strlen("library/"));
508 6 : sprintf(tmp, "library/%s",*namespace);
509 6 : free(*namespace);
510 6 : *namespace=tmp;
511 : }
512 : }
513 38 : if (registry_name)
514 : {
515 38 : *registry_name=tmp_image_name;
516 38 : tmp_image_name=NULL;
517 : }
518 38 : if (tmp_image_name) free(tmp_image_name);
519 : return 0;
520 : }
521 :
522 5 : char * name_space_rev(const char * namespace)
523 : {
524 5 : if (!namespace) return NULL;
525 5 : char* result=NULL;
526 5 : size_t len_ns=strlen(namespace)+1;
527 5 : size_t len_left=len_ns;
528 5 : char* temp=calloc(1, len_ns);
529 5 : char *p=NULL;
530 5 : char *pp=NULL;
531 : do
532 : {
533 10 : p=memrchr(namespace, '/',len_left);
534 10 : if (p||pp)
535 : {
536 10 : if ( strlen(temp)>0)
537 : {
538 5 : char * ns_1=NULL;
539 5 : if (p)
540 : {
541 2 : if (strncmp(temp, p+1, strlen(temp))!=0)
542 1 : asprintf(&ns_1,"%.*s",(int)(pp-p)-1,p+1);
543 : }
544 : else
545 : {
546 3 : if (strncmp(temp, namespace, strlen(temp))!=0)
547 : {
548 3 : int len=(int)(pp-namespace);
549 3 : asprintf(&ns_1,"%.*s",len,namespace);
550 : }
551 : }
552 5 : if (ns_1 && (strncmp("library", ns_1, strlen("library"))!=0))
553 : {
554 3 : char *r=NULL;
555 3 : asprintf(&r, "%s %s",temp,ns_1);
556 3 : if (temp) free(temp);
557 3 : free(ns_1);
558 3 : temp=r;
559 : }
560 : break;
561 : }
562 5 : else if(p)
563 : { // name of namesapce
564 5 : snprintf(temp, len_ns, "%s",p+1);
565 5 : len_left=len_ns-strlen(temp)-2;
566 : }
567 5 : pp=p;
568 : }
569 5 : } while(p);
570 5 : if (temp && strlen(temp)>0)result=strdup(temp);
571 5 : if (temp) free(temp);
572 5 : return result;
573 : }
574 :
575 5 : char * name_space_rev_slug(const char * namespace)
576 : {
577 5 : if (!namespace) return NULL;
578 5 : char* result=NULL;
579 5 : char * temp=name_space_rev(namespace);
580 5 : if (temp)
581 : {
582 5 : result=slug_it(temp, 0);
583 5 : free(temp);
584 : }
585 5 : return result;
586 : }
587 :
588 :
589 :
590 7 : void recursive_dir_extract(const char * file, size_t len, cJSON * list, void(*fn)(void * userp,char *path),void * userp )//struct archive *a_content,struct archive *a_compressed)
591 : {
592 7 : const char * p=memrchr(file,'/', len);
593 7 : if (p)
594 : {
595 7 : size_t newlen=p-file;
596 7 : if (newlen>0)
597 : {
598 6 : int res=cJSON_findinstringarry_n(list, file, newlen);
599 6 : if (res!=0)
600 : {
601 3 : recursive_dir_extract(file,newlen,list,(fn),userp);
602 3 : cJSON* tmp=cJSON_CreateObject();
603 3 : tmp->type=cJSON_String;
604 3 : tmp->valuestring=strndup(file, newlen);
605 3 : fn(userp,tmp->valuestring); // callback action
606 3 : cJSON_AddItemToBeginArray(list, tmp);
607 :
608 : }
609 : }
610 : }
611 7 : }
612 :
613 :
614 :
615 4 : cJSON * comma_sep_list_2_json_array(const char * list)
616 : {
617 4 : cJSON *result=NULL;
618 4 : char *input=NULL;
619 :
620 4 : if (list) input=strdup(list);
621 : else return NULL;
622 :
623 : char *token;
624 : char *state;
625 :
626 19 : for (token = strtok_r(input, ",", &state);
627 : token != NULL;
628 14 : token = strtok_r(NULL, ",", &state))
629 : {
630 7 : if (!result) result=cJSON_CreateArray();
631 7 : if (result)
632 : {
633 5 : while (strlen(token)>1 && token[strlen(token)-1]==' ') token[strlen(token)-1]='\0';
634 : size_t c=0;
635 3 : while (strlen(token+c)>1 && token[c]==' ') c++;
636 7 : cJSON_add_Array_string(result,token+c);
637 : }
638 : else break;
639 : }
640 : //print_json(result);
641 4 : return result;
642 : }
643 :
644 14 : int env_var_is_false(const char *name)
645 : {
646 14 : int result=0;
647 14 : const char* cvar=getenv(name);
648 14 : char *var=NULL;
649 14 : if (cvar) var=strdup(cvar);
650 14 : if (var) lower_string(var);
651 14 : if (var)
652 : {
653 13 : if (strcmp(var, "false")==0 || strcmp(var, "no")==0 || strcmp(var, "off")==0 || strcmp(var, "0")==0 ) result=1;
654 13 : free(var);
655 : }
656 14 : return result;
657 : }
658 :
659 14 : int env_var_is_true(const char *name)
660 : {
661 14 : int result=0;
662 14 : const char* cvar=getenv(name);
663 14 : char *var=NULL;
664 14 : if (cvar) var=strdup(cvar);
665 14 : if (var) lower_string(var);
666 14 : if (var)
667 : {
668 13 : if (strcmp(var, "true")==0 || strcmp(var, "yes")==0 || strcmp(var, "on")==0 || strcmp(var, "1")==0 ) result=1;
669 13 : free(var);
670 : }
671 14 : return result;
672 : }
|