source: genappalpha/languages/docker/build_docker_footer.pl

Last change on this file was 1696, checked in by ehb, 2 years ago

Added run, env dependency support

File size: 7.8 KB
Line 
1# process each module with dependencies
2
3foreach my $mod ( keys %dependencies ) {
4    my $menu = $menus{ $mod };
5    print "checking $menu:$mod\n";
6    if ( $dependencies{ $mod } =~ /^_{2}dependencies__/ ) {
7        print "no dependencies\n";
8        $error .= "Module '$mod' : no dependencies defined, can not create docker container.\n";
9        next;
10    }
11    $depjson = decode_json( $dependencies{ $mod } );
12    $modjson = decode_json( $module_json{ $mod } );
13    if ( !$$modjson{'executable'} ) {
14        $error .= "Module '$mod' has no 'executable' defined.\n";
15        next;
16    }
17    print "executable is $$modjson{'executable'}\n";
18
19
20    # build up and output docker file based upon dependencies
21    # executable needs copying
22    my $out;
23    my $has_error;
24    my $has_base;
25    my @copys;
26    my %copymap;
27    my $has_cpanm;
28   
29    for ( my $i = 0; $i < @$depjson; ++$i ) {
30        my $entry = $$depjson[$i];
31        if ( scalar ( keys %$entry ) != 1 ) {
32            $has_error++;
33            $error .= "Module '$mod' : dependencies entry " . ( $i + 1 ) . " '" . encode_json( $entry ) . "' does not have exactly 1 key\n";
34            break;
35        }
36
37        my $k = (keys %$entry)[0];
38        my $v = $$entry{$k};
39        $k = lc( $k );
40        if ( ref( $v ) ne 'ARRAY' ) {
41            my @v = ( $v );
42            $v = \@v;
43        }
44        # create command to build and post (?) dockerfile
45
46        for ( my $j = 0; $j < @$v; ++$j ) {
47            my $val = $$v[$j];
48            if ( length( ref( $val ) ) ) {
49                $error .= "Module '$mod' : dependencies entry " . ( $i + 1 ) . " '" . encode_json( $entry ) . "' improper value in list entry number " . ( $j + 1 ) . "\n";
50                $has_error++;
51                next;
52            }
53            if ( $k eq 'base' ) {
54                if ( $hasbase ) {
55                    $error .= "Module '$mod' : dependencies entry " . ( $i + 1 ) . " '" . encode_json( $entry ) . "' multiple 'base' tags found, only one allowed\n";
56                    $has_error;
57                    last;
58                }
59                $out .= "FROM $val\n";
60                $out .= "WORKDIR $bindir\n";
61                $has_base++;
62                next;
63            }
64            if ( !$has_base ) {
65                $warn .= "No 'base' entry found in first position, defaulting to 'ubuntu'\n";
66                $out .= "FROM ubuntu\n";
67                $out .= "WORKDIR $bindir\n";
68                $has_base++;
69                next;
70            }               
71            if ( $k eq 'cpan' ) {
72                if ( !$has_cpanm ) {
73                    $out .= "RUN curl -L http://cpanmin.us | perl - App::cpanminus\n";
74                    $out .= "RUN mv /usr/bin/perl /usr/bin/perl.save\n";
75                    $out .= "RUN ln -s /usr/local/bin/perl /usr/bin/perl\n";
76                    $has_cpanm++;
77                }
78                $out .= "RUN cpanm $val\n";
79                next;
80            }
81
82            if ( $k eq 'file' ) {
83                my $dest = $val;
84                $dest =~ s/^.*\///g;
85                $out .= "COPY $dest $dest\n";
86                $val = "$executable_path/$val" if $val !~ /^\//;
87                push @copys, $val;
88                $copymap{ $val }++;
89                next;
90            }
91
92            if ( $k eq 'run' ) {
93                my $cmd = $val;
94                $out .= "RUN $cmd\n";
95                next;
96            }
97
98            if ( $k eq 'env' ) {
99                my $env = $val;
100                $env =~ s/\=/ /;
101                $out .= "ENV $env\n";
102                next;
103            }
104
105            $error .= "Module '$mod' : dependencies entry " . ( $i + 1 ) . " '" . encode_json( $entry ) . "' unknown tag '$k'\n";
106            $has_error++;
107            last;
108        }
109    }
110
111    # add executable
112
113    $out .= "COPY $$modjson{'executable'} $$modjson{'executable'}\n";
114    push @copys, "$executable_path/$$modjson{'executable'}";
115
116    ## if executable is not equal to module name, create symlink to enable appconfig:resource:docker*
117    if ( $$modjson{'executable'} ne $mod ) {
118        ### check if there is a clobber first, this is an error!
119        if ( $copymap{ $mod } ) {
120            $error .= "Module '$mod' : executable name does not match module id, yet there is a dependency of the same name\n";
121            $has_error++;
122        } else {
123            $out .= "RUN ln -s $$modjson{'executable'} $mod\n";
124        }
125    }
126   
127    next if $has_error;
128
129    # add CMD
130
131    ## always run in $rundir ?
132    $out .= "WORKDIR $rundir\n";
133
134    ## straight form:
135    ## $out .= "CMD [\"$bindir/$$modjson{'executable'}\"]\n";
136
137    ## abaco MSG form:
138    $out .= "CMD $bindir/$$modjson{'executable'} `echo \$MSG`\n";
139
140    # write dockerfile
141    if ( !-d $menu ) {
142        if ( -e $menu ) {
143            $error .= "File $menu exists in output folder, but is not a directory\n";
144            next;
145        }
146        if ( !mkdir $menu ) {
147            $error .= "Could not create subdir $menu $!\n";
148            next;
149        }
150    }
151
152    my $destdir = "$menu/$mod";
153    if ( !-d $destdir ) {
154        if ( -e $destdir ) {
155            $error .= "File $destdir exists in output folder, but is not a directory\n";
156            next;
157        }
158        if ( !mkdir $destdir ) {
159            $error .= "Could not create subdir $destdir $!\n";
160            next;
161        }
162    }
163       
164    my $df = "$destdir/Dockerfile";
165    my $fh;
166    if ( !( open $fh, ">$df" ) ) {
167        $error .= "Could not create file $df for writing\n";
168        next;
169    }
170    print $fh $out;
171    close $fh;
172
173    # do copies
174    $cmd = "cp " . ( join " ", @copys ) . " $destdir/";
175    print "$cmd\n";
176    system( $cmd );
177
178    # in dockerhub mode? (i.e. push and name appropriately)
179    # name needs to match in html5/abacolib.php
180   
181    $dhmode = "__dockerhub:user__" ne '_' . '_dockerhub:user__';
182    $dhtag = "";
183    if ( $dhmode ) {
184        if ( "__dockerhub:id__" ne '_' . '_dockerhub:id__' ) {
185            $dhtag = "__dockerhub:id__";
186            $dhtag =~ s/ //g;
187        } else {
188            $dhtag = lc( `hostname` );
189            chomp $dhtag;
190            $dhtag =~ s/[^a-z0-9_.-]/_/g;
191        }
192        if ( length( $dhtag ) ) {
193            $dhtag .= "_";
194        }
195        $dhnopush = "__dockerhub:nopush__" ne '_' . '_dockerhub:nopush__';
196        if ( $dhnopush ) {
197            $warn .= "No push to dockerhub flag set!\n";
198        }
199    }
200
201    # make container name
202
203    # current docker:local resource specifier
204    $cname = lc( "genapp_${dhtag}__application__" );
205    if ( length( $cname ) > 30 ) {
206        $warn .= "truncating docker image name '$cname' to leftmost 30 characters\n";
207        $cname = substr( $cname, 0, 30 );
208    }
209    $tname = "${menu}-${mod}";
210
211    if ( length( $tname ) > 128 ) {
212        $warn .= "truncating docker image tag '$tname' to leftmost 128 characters\n";
213        $tname = substr( $tname, 0, 128 );
214    }
215   
216    $uname = "$cname:$tname";
217
218    if ( $dhmode ) {
219        $uname = "__dockerhub:user__/$uname";
220    }
221
222    # build containers
223    $cmd = "cd $destdir && docker build -t $uname .";
224    print "$cmd\n";
225    system( $cmd );
226
227    # push to dockerhub
228
229    if ( $dhmode && !$dhnopush ) {
230        $cmd = "docker push $uname 2>&1";
231        print "$cmd\n";
232        my $result = `$cmd`;
233        if ( $result =~ /denied:/ ) {
234            $error .= "You must $ docker login -u __dockerhub:user__\n";
235        }
236    }
237}
238   
239print "================================================================================
240Warnings:
241--------------------------------------------------------------------------------
242${warn}================================================================================
243" if $warn;
244
245die "================================================================================
246Errors:
247--------------------------------------------------------------------------------
248${error}================================================================================
249
250" if $error;
Note: See TracBrowser for help on using the repository browser.