1#################################################################################################################################### 2# ContainerTest.pm - Build containers for testing and documentation 3#################################################################################################################################### 4package pgBackRestTest::Common::ContainerTest; 5 6#################################################################################################################################### 7# Perl includes 8#################################################################################################################################### 9use strict; 10use warnings FATAL => qw(all); 11use Carp qw(confess longmess); 12use English '-no_match_vars'; 13 14use Cwd qw(abs_path); 15use Digest::SHA qw(sha1_hex); 16use Exporter qw(import); 17 our @EXPORT = qw(); 18use File::Basename qw(dirname); 19use Getopt::Long qw(GetOptions); 20 21use pgBackRestDoc::Common::Log; 22use pgBackRestDoc::Common::String; 23use pgBackRestDoc::ProjectInfo; 24 25use pgBackRestTest::Common::ExecuteTest; 26use pgBackRestTest::Common::VmTest; 27 28#################################################################################################################################### 29# User/group definitions 30#################################################################################################################################### 31use constant TEST_USER => getpwuid($UID) . ''; 32 push @EXPORT, qw(TEST_USER); 33use constant TEST_USER_ID => $UID; 34 push @EXPORT, qw(TEST_USER_ID); 35use constant TEST_GROUP => getgrgid((getpwnam(TEST_USER))[3]) . ''; 36 push @EXPORT, qw(TEST_GROUP); 37use constant TEST_GROUP_ID => getgrnam(TEST_GROUP) . ''; 38 push @EXPORT, qw(TEST_GROUP_ID); 39 40#################################################################################################################################### 41# Cert file constants 42#################################################################################################################################### 43use constant CERT_FAKE_PATH => '/etc/fake-cert'; 44use constant CERT_FAKE_CA => CERT_FAKE_PATH . '/ca.crt'; 45 push @EXPORT, qw(CERT_FAKE_CA); 46use constant CERT_FAKE_SERVER => CERT_FAKE_PATH . '/server.crt'; 47 push @EXPORT, qw(CERT_FAKE_SERVER); 48use constant CERT_FAKE_SERVER_KEY => CERT_FAKE_PATH . '/server.key'; 49 push @EXPORT, qw(CERT_FAKE_SERVER_KEY); 50 51#################################################################################################################################### 52# Container Debug - speeds container debugging by splitting each section into a separate intermediate container 53#################################################################################################################################### 54use constant CONTAINER_DEBUG => false; 55 56#################################################################################################################################### 57# Store cache container checksums 58#################################################################################################################################### 59my $hContainerCache; 60 61#################################################################################################################################### 62# Container repo - defines the Docker repository where the containers will be located 63#################################################################################################################################### 64sub containerRepo 65{ 66 return PROJECT_EXE . qw(/) . 'test'; 67} 68 69push @EXPORT, qw(containerRepo); 70 71#################################################################################################################################### 72# Section header 73#################################################################################################################################### 74sub sectionHeader 75{ 76 return (CONTAINER_DEBUG ? "\n\nRUN \\\n" : " && \\\n\n"); 77} 78 79#################################################################################################################################### 80# Write the Docker container 81#################################################################################################################################### 82sub containerWrite 83{ 84 my $oStorageDocker = shift; 85 my $strTempPath = shift; 86 my $strOS = shift; 87 my $strTitle = shift; 88 my $strImageParent = shift; 89 my $strImage = shift; 90 my $strCopy = shift; 91 my $strScript = shift; 92 my $bForce = shift; 93 94 my $strTag = containerRepo() . ":${strImage}"; 95 96 $strScript = 97 "# ${strTitle} Container\n" . 98 "FROM ${strImageParent}" . 99 (defined($strCopy) ? "\n\n${strCopy}" : '') . 100 (defined($strScript) && $strScript ne ''? 101 "\n\nRUN echo '" . (CONTAINER_DEBUG ? 'DEBUG' : 'OPTIMIZED') . " BUILD'" . $strScript : ''); 102 103 # Search for the image in the cache 104 my $strScriptSha1; 105 my $bCached = false; 106 107 if ($strImage =~ /\-base$/) 108 { 109 $strScriptSha1 = sha1_hex($strScript); 110 111 foreach my $strBuild (reverse(keys(%{$hContainerCache}))) 112 { 113 if (defined($hContainerCache->{$strBuild}{hostArch()}{$strOS}) && 114 $hContainerCache->{$strBuild}{hostArch()}{$strOS} eq $strScriptSha1) 115 { 116 &log(INFO, "Using cached ${strTag}-${strBuild} image (${strScriptSha1}) ..."); 117 118 $strScript = 119 "# ${strTitle} Container\n" . 120 "FROM ${strTag}-${strBuild}"; 121 122 $bCached = true; 123 } 124 } 125 } 126 127 if (!$bCached) 128 { 129 &log(INFO, "Building ${strTag} image" . (defined($strScriptSha1) ? " (${strScriptSha1})" : '') . ' ...'); 130 } 131 132 # Write the image 133 $oStorageDocker->put("${strTempPath}/${strImage}", trim($strScript) . "\n"); 134 executeTest('docker build' . (defined($bForce) && $bForce ? ' --no-cache' : '') . 135 " -f ${strTempPath}/${strImage} -t ${strTag} ${strTempPath}", 136 {bSuppressStdErr => true}); 137} 138 139#################################################################################################################################### 140# User/group creation 141#################################################################################################################################### 142sub groupCreate 143{ 144 my $strOS = shift; 145 my $strName = shift; 146 my $iId = shift; 147 148 return "groupadd -f -g${iId} ${strName}"; 149} 150 151sub userCreate 152{ 153 my $strOS = shift; 154 my $strName = shift; 155 my $iId = shift; 156 my $strGroup = shift; 157 158 my $oVm = vmGet(); 159 160 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 161 { 162 return "adduser -g${strGroup} -u${iId} -n ${strName}"; 163 } 164 elsif ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) 165 { 166 return "adduser --uid=${iId} --ingroup=${strGroup} --disabled-password --gecos \"\" ${strName}"; 167 } 168 169 confess &log(ERROR, "unable to create user for os '${strOS}'"); 170} 171 172#################################################################################################################################### 173# Setup SSH 174#################################################################################################################################### 175sub sshSetup 176{ 177 my $strOS = shift; 178 my $strUser = shift; 179 my $strGroup = shift; 180 my $bControlMaster = shift; 181 182 my $strUserPath = $strUser eq 'root' ? "/${strUser}" : "/home/${strUser}"; 183 184 my $strScript = sectionHeader() . 185 "# Setup SSH\n" . 186 " mkdir ${strUserPath}/.ssh && \\\n" . 187 " echo '-----BEGIN RSA PRIVATE KEY-----' > ${strUserPath}/.ssh/id_rsa && \\\n" . 188 " echo 'MIICXwIBAAKBgQDR0yJsZW5d5LcqteiOtv8d+FFeFFHDPI0VTcTOdMn1iDiIP1ou' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 189 " echo 'X3Q2OyNjsBaDbsRJd+sp9IRq1LKX3zsBcgGZANwm0zduuNEPEU94ajS/uRoejIqY' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 190 " echo '/XkKOpnEF6ZbQ2S7TaE4sWeGLvba7kUFs0QTOO+N+nV2dMbdqZf6C8lazwIDAQAB' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 191 " echo 'AoGBAJXa6xzrnFVmwgK5BKzYuX/YF5TPgk2j80ch0ct50buQXH/Cb0/rUH5i4jWS' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 192 " echo 'T6Hy/DFUehnuzpvV6O9auTOhDs3BhEKFRuRLn1nBwTtZny5Hh+cw7azUCEHFCJlz' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 193 " echo 'makCrVbgawtno6oU/pFgQm1FcxD0f+Me5ruNcLHqUZsPQwkRAkEA+8pG+ckOlz6R' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 194 " echo 'AJLIHedmfcrEY9T7sfdo83bzMOz8H5soUUP4aOTLJYCla1LO7JdDnXMGo0KxaHBP' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 195 " echo 'l8j5zDmVewJBANVVPDJr1w37m0FBi37QgUOAijVfLXgyPMxYp2uc9ddjncif0063' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 196 " echo '0Wc0FQefoPszf3CDrHv/RHvhHq97jXDwTb0CQQDgH83NygoS1r57pCw9chzpG/R0' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 197 " echo 'aMEiSPhCvz757fj+qT3aGIal2AJ7/2c/gRZvwrWNETZ3XIZOUKqIkXzJLPjBAkEA' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 198 " echo 'wnP799W2Y8d4/+VX2pMBkF7lG7sSviHEq1sP2BZtPBRQKSQNvw3scM7XcGh/mxmY' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 199 " echo 'yx0qpqfKa8SKbNgI1+4iXQJBAOlg8MJLwkUtrG+p8wf69oCuZsnyv0K6UMDxm6/8' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 200 " echo 'cbvfmvODulYFaIahaqHWEZoRo5CLYZ7gN43WHPOrKxdDL78=' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 201 " echo '-----END RSA PRIVATE KEY-----' >> ${strUserPath}/.ssh/id_rsa && \\\n" . 202 " echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDR0yJsZW5d5LcqteiOtv8d+FFeFFHDPI0VTcTOdMn1iDiIP1ouX3Q2OyNjsBaDbsRJd+sp9I" . 203 "Rq1LKX3zsBcgGZANwm0zduuNEPEU94ajS/uRoejIqY/XkKOpnEF6ZbQ2S7TaE4sWeGLvba7kUFs0QTOO+N+nV2dMbdqZf6C8lazw== " . 204 "user\@pgbackrest-test' > ${strUserPath}/.ssh/authorized_keys && \\\n" . 205 " echo 'Host *' > ${strUserPath}/.ssh/config && \\\n" . 206 " echo ' StrictHostKeyChecking no' >> ${strUserPath}/.ssh/config && \\\n"; 207 208 if ($bControlMaster) 209 { 210 $strScript .= 211 " echo ' ControlMaster auto' >> ${strUserPath}/.ssh/config && \\\n" . 212 " echo ' ControlPath /tmp/\%r\@\%h:\%p' >> ${strUserPath}/.ssh/config && \\\n" . 213 " echo ' ControlPersist 30' >> ${strUserPath}/.ssh/config && \\\n"; 214 } 215 216 $strScript .= 217 " chown -R ${strUser}:${strGroup} ${strUserPath}/.ssh && \\\n" . 218 " chmod 700 ${strUserPath}/.ssh && \\\n" . 219 " chmod 600 ${strUserPath}/.ssh/*"; 220 221 return $strScript; 222} 223 224#################################################################################################################################### 225# Cert Setup 226#################################################################################################################################### 227sub certSetup 228{ 229 my $strOS = shift; 230 231 my $strScript = 232 sectionHeader() . 233 "# Generate fake certs\n" . 234 " mkdir -p -m 755 /etc/fake-cert && \\\n" . 235 " cd /etc/fake-cert && \\\n" . 236 " openssl genrsa -out ca.key 2048 && \\\n" . 237 " openssl req -new -x509 -extensions v3_ca -key ca.key -out ca.crt -days 99999 \\\n" . 238 " -subj \"/C=US/ST=Country/L=City/O=Organization/CN=pgbackrest.org\" && \\\n" . 239 " openssl genrsa -out server.key 2048 && \\\n" . 240 " openssl req -new -key server.key -out server.csr \\\n" . 241 " -subj \"/C=US/ST=Country/L=City/O=Organization/CN=*.pgbackrest.org\" && \\\n" . 242 " openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 99999 \\\n" . 243 " -sha256 && \\\n" . 244 " chmod 644 /etc/fake-cert/* && \\\n"; 245 246 my $rhVm = vmGet(); 247 248 if ($rhVm->{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 249 { 250 $strScript .= 251 " cp /etc/fake-cert/pgbackrest-test-ca.crt /etc/pki/ca-trust/source/anchors && \\\n" . 252 " update-ca-trust extract"; 253 } 254 elsif ($rhVm->{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) 255 { 256 $strScript .= 257 " cp /etc/fake-cert/pgbackrest-test-ca.crt /usr/local/share/ca-certificates && \\\n" . 258 " update-ca-certificates"; 259 } 260 else 261 { 262 confess &log(ERROR, "unable to install certificate for $rhVm->{$strOS}{&VM_OS_BASE}"); 263 } 264 265 return $strScript; 266} 267 268#################################################################################################################################### 269# Entry point setup 270#################################################################################################################################### 271sub entryPointSetup 272{ 273 my $strOS = shift; 274 275 my $strScript = 276 "\n\n# Start SSH when container starts\n" . 277 'ENTRYPOINT '; 278 279 my $oVm = vmGet(); 280 281 if ($oVm->{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 282 { 283 $strScript .= '/usr/sbin/sshd -D'; 284 } 285 else 286 { 287 $strScript .= 'service ssh restart && bash'; 288 } 289 290 return $strScript; 291} 292 293#################################################################################################################################### 294# Build containers 295#################################################################################################################################### 296sub containerBuild 297{ 298 my $oStorageDocker = shift; 299 my $strVm = shift; 300 my $bVmForce = shift; 301 302 # Create temp path 303 my $strTempPath = $oStorageDocker->pathGet('test/result/docker'); 304 $oStorageDocker->pathCreate($strTempPath, {strMode => '0770', bIgnoreExists => true, bCreateParent => true}); 305 306 # Load container definitions from yaml 307 require YAML::XS; 308 YAML::XS->import(qw(Load)); 309 310 $hContainerCache = Load(${$oStorageDocker->get($oStorageDocker->pathGet('test/container.yaml'))}); 311 312 # Remove old images on force 313 if ($bVmForce) 314 { 315 my $strRegExp = '^' . containerRepo(); 316 317 if ($strVm ne 'all') 318 { 319 $strRegExp .= "\:${strVm}-"; 320 } 321 322 executeTest("rm -f ${strTempPath}/" . ($strVm eq 'all' ? '*' : "${strVm}-*")); 323 imageRemove("${strRegExp}.*"); 324 } 325 326 # VM Images 327 ################################################################################################################################ 328 my $oVm = vmGet(); 329 330 foreach my $strOS ($strVm eq 'all' ? VM_LIST : ($strVm)) 331 { 332 my $oOS = $oVm->{$strOS}; 333 my $bDocBuild = false; 334 335 # Deprecated OSs can only be used to build packages 336 my $bDeprecated = $oVm->{$strOS}{&VM_DEPRECATED} ? true : false; 337 338 # Base image 339 ########################################################################################################################### 340 my $strImageParent = "$$oVm{$strOS}{&VM_IMAGE}"; 341 my $strImage = "${strOS}-base"; 342 my $strCopy = undef; 343 344 #--------------------------------------------------------------------------------------------------------------------------- 345 my $strScript = sectionHeader() . 346 "# Install packages\n"; 347 348 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 349 { 350 if ($strOS eq VM_CO7) 351 { 352 $strScript .= 353 " yum -y install centos-release-scl-rh epel-release && \\\n"; 354 } 355 356 $strScript .= 357 " yum -y update && \\\n" . 358 " yum -y install openssh-server openssh-clients wget sudo valgrind git \\\n" . 359 " perl perl-Digest-SHA perl-DBD-Pg perl-YAML-LibYAML openssl \\\n" . 360 " gcc make perl-ExtUtils-MakeMaker perl-Test-Simple openssl-devel perl-ExtUtils-Embed rpm-build \\\n" . 361 " libyaml-devel zlib-devel libxml2-devel lz4-devel lz4 bzip2-devel bzip2 perl-JSON-PP"; 362 } 363 else 364 { 365 $strScript .= 366 " export DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_FRONTEND=noninteractive && \\\n" . 367 " apt-get update && \\\n" . 368 " apt-get install -y --no-install-recommends openssh-server wget sudo gcc make valgrind git \\\n" . 369 " libdbd-pg-perl libhtml-parser-perl libssl-dev libperl-dev \\\n" . 370 " libyaml-libyaml-perl tzdata devscripts lintian libxml-checker-perl txt2man debhelper \\\n" . 371 " libppi-html-perl libtemplate-perl libtest-differences-perl zlib1g-dev libxml2-dev pkg-config \\\n" . 372 " libbz2-dev bzip2 libyaml-dev libjson-pp-perl liblz4-dev liblz4-tool gnupg"; 373 } 374 375 # Add zst command-line tool and development libs when available 376 if (vmWithZst($strOS)) 377 { 378 if ($oVm->{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 379 { 380 $strScript .= ' zstd libzstd-devel'; 381 } 382 else 383 { 384 $strScript .= ' zstd libzstd-dev'; 385 } 386 } 387 388 # If no specific version of lcov is requested then install the default package 389 if (!defined($oVm->{$strOS}{&VMDEF_LCOV_VERSION})) 390 { 391 $strScript .= ' lcov'; 392 } 393 394 #--------------------------------------------------------------------------------------------------------------------------- 395 $strScript .= sectionHeader() . 396 "# Regenerate SSH keys\n" . 397 " rm -f /etc/ssh/ssh_host_rsa_key* && \\\n" . 398 " ssh-keygen -t rsa -b 1024 -f /etc/ssh/ssh_host_rsa_key"; 399 400 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) 401 { 402 $strScript .= sectionHeader() . 403 "# Fix root tty\n" . 404 " sed -i 's/^mesg n/tty -s \\&\\& mesg n/g' /root/.profile"; 405 406 $strScript .= sectionHeader() . 407 "# Suppress dpkg interactive output\n" . 408 " rm /etc/apt/apt.conf.d/70debconf"; 409 } 410 411 #--------------------------------------------------------------------------------------------------------------------------- 412 my $strCertPath = 'test/certificate'; 413 my $strCertName = 'pgbackrest-test'; 414 415 $strCopy = '# Copy Test Certificates'; 416 417 foreach my $strFile ('-ca.crt', '.crt', '.key') 418 { 419 $oStorageDocker->copy("${strCertPath}/${strCertName}${strFile}", "${strTempPath}/${strCertName}${strFile}"); 420 $strCopy .= "\nCOPY ${strCertName}${strFile} " . CERT_FAKE_PATH . "/${strCertName}${strFile}"; 421 } 422 423 $strScript .= certSetup($strOS); 424 425 #--------------------------------------------------------------------------------------------------------------------------- 426 if (defined($oVm->{$strOS}{&VMDEF_LCOV_VERSION})) 427 { 428 my $strLCovVersion = $oVm->{$strOS}{&VMDEF_LCOV_VERSION}; 429 my $strLCovPath = "/root/lcov-${strLCovVersion}"; 430 431 $strScript .= sectionHeader() . 432 "# Build lcov ${strLCovVersion}\n" . 433 " wget -q -O - https://github.com/linux-test-project/lcov/releases/download/v${strLCovVersion}/" . 434 "lcov-${strLCovVersion}.tar.gz | tar zx -C /root && \\\n" . 435 " make -C ${strLCovPath} install && \\\n" . 436 " rm -rf ${strLCovPath}"; 437 } 438 439 #--------------------------------------------------------------------------------------------------------------------------- 440 if (!$bDeprecated) 441 { 442 $strScript .= sectionHeader() . 443 "# Install PostgreSQL packages\n"; 444 445 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 446 { 447 $strScript .= 448 " rpm --import http://yum.postgresql.org/RPM-GPG-KEY-PGDG && \\\n"; 449 450 if ($strOS eq VM_CO7) 451 { 452 $strScript .= 453 " rpm -ivh \\\n" . 454 " https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-" . hostArch() . "/" . 455 "pgdg-redhat-repo-latest.noarch.rpm && \\\n"; 456 } 457 elsif ($strOS eq VM_F33) 458 { 459 $strScript .= 460 " rpm -ivh \\\n" . 461 " https://download.postgresql.org/pub/repos/yum/reporpms/F-33-" . hostArch() . "/" . 462 "pgdg-fedora-repo-latest.noarch.rpm && \\\n"; 463 } 464 465 $strScript .= " yum -y install postgresql-devel"; 466 } 467 else 468 { 469 $strScript .= 470 " echo 'deb http://apt.postgresql.org/pub/repos/apt/ " . 471 $$oVm{$strOS}{&VM_OS_REPO} . '-pgdg main' . ($strOS eq VM_U20 ? ' 14' : '') . 472 "' >> /etc/apt/sources.list.d/pgdg.list && \\\n" . 473 " wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \\\n" . 474 " apt-get update && \\\n" . 475 " apt-get install -y --no-install-recommends postgresql-common libpq-dev && \\\n" . 476 " sed -i 's/^\\#create\\_main\\_cluster.*\$/create\\_main\\_cluster \\= false/' " . 477 "/etc/postgresql-common/createcluster.conf"; 478 } 479 480 if (defined($oOS->{&VM_DB}) && @{$oOS->{&VM_DB}} > 0) 481 { 482 $strScript .= sectionHeader() . 483 "# Install PostgreSQL\n"; 484 485 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 486 { 487 $strScript .= " yum -y install"; 488 } 489 else 490 { 491 $strScript .= " apt-get install -y --no-install-recommends"; 492 } 493 494 # Construct list of databases to install 495 foreach my $strDbVersion (@{$oOS->{&VM_DB}}) 496 { 497 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 498 { 499 my $strDbVersionNoDot = $strDbVersion; 500 $strDbVersionNoDot =~ s/\.//; 501 502 $strScript .= " postgresql${strDbVersionNoDot}-server"; 503 504 # Add development package for the latest version of postgres 505 if ($strDbVersion eq @{$oOS->{&VM_DB}}[-1]) 506 { 507 $strScript .= " postgresql${strDbVersionNoDot}-devel"; 508 } 509 } 510 else 511 { 512 $strScript .= " postgresql-${strDbVersion}"; 513 } 514 } 515 } 516 } 517 518 # Add path to lastest version of postgres 519 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 520 { 521 $strScript .= 522 "\n\nENV PATH=/usr/pgsql-" . @{$oOS->{&VM_DB}}[-1] . "/bin:\$PATH\n"; 523 } 524 525 #--------------------------------------------------------------------------------------------------------------------------- 526 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_DEBIAN) 527 { 528 $strScript .= sectionHeader() . 529 "# Cleanup\n"; 530 531 $strScript .= 532 " apt-get autoremove -y && \\\n" . 533 " apt-get clean && \\\n" . 534 " rm -rf /var/lib/apt/lists/*"; 535 } 536 537 containerWrite( 538 $oStorageDocker, $strTempPath, $strOS, 'Base', $strImageParent, $strImage, $strCopy, $strScript, $bVmForce); 539 540 # Test image 541 ######################################################################################################################## 542 if (!$bDeprecated) 543 { 544 $strImageParent = containerRepo() . ":${strOS}-base"; 545 $strImage = "${strOS}-test"; 546 547 $strCopy = undef; 548 $strScript = ''; 549 550 #--------------------------------------------------------------------------------------------------------------------------- 551 $strScript .= sectionHeader() . 552 "# Create banner to make sure pgBackRest ignores it\n" . 553 " echo '***********************************************' > /etc/issue.net && \\\n" . 554 " echo 'Sample banner to make sure banners are skipped.' >> /etc/issue.net && \\\n" . 555 " echo '' >> /etc/issue.net && \\\n" . 556 " echo 'More banner after a blank line.' >> /etc/issue.net && \\\n" . 557 " echo '***********************************************' >> /etc/issue.net && \\\n" . 558 " echo 'Banner /etc/issue.net' >> /etc/ssh/sshd_config"; 559 560 $strScript .= sectionHeader() . 561 "# Create test user\n" . 562 ' ' . groupCreate($strOS, TEST_GROUP, TEST_GROUP_ID) . " && \\\n" . 563 ' ' . userCreate($strOS, TEST_USER, TEST_USER_ID, TEST_GROUP) . " && \\\n" . 564 ' mkdir -m 750 /home/' . TEST_USER . "/test && \\\n" . 565 ' chown ' . TEST_USER . ':' . TEST_GROUP . ' /home/' . TEST_USER . "/test"; 566 567 $strScript .= sectionHeader() . 568 "# Configure sudo\n"; 569 570 if ($$oVm{$strOS}{&VM_OS_BASE} eq VM_OS_BASE_RHEL) 571 { 572 $strScript .= 573 # Don't allow sudo to disable core dump (suppresses errors, see https://github.com/sudo-project/sudo/issues/42) 574 " echo \"Set disable_coredump false\" >> /etc/sudo.conf && \\\n" . 575 " echo '%" . TEST_GROUP . " ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/" . TEST_GROUP . 576 " && \\\n" . 577 " sed -i 's/^Defaults requiretty\$/\\# Defaults requiretty/' /etc/sudoers"; 578 } 579 else 580 { 581 $strScript .= 582 " echo '%" . TEST_GROUP . " ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"; 583 } 584 585 $strScript .= 586 sshSetup($strOS, TEST_USER, TEST_GROUP, $$oVm{$strOS}{&VM_CONTROL_MASTER}); 587 588 $strScript .= sectionHeader() . 589 "# Make " . TEST_USER . " home dir readable\n" . 590 ' chmod g+r,g+x /home/' . TEST_USER; 591 592 $strScript .= entryPointSetup($strOS); 593 594 containerWrite( 595 $oStorageDocker, $strTempPath, $strOS, 'Test', $strImageParent, $strImage, $strCopy, $strScript, $bVmForce); 596 } 597 } 598 599 &log(INFO, "Build Complete"); 600} 601 602push @EXPORT, qw(containerBuild); 603 604#################################################################################################################################### 605# containerRemove 606# 607# Remove containers that match a regexp. 608#################################################################################################################################### 609sub containerRemove 610{ 611 my $strRegExp = shift; 612 613 foreach my $strContainer (sort(split("\n", trim(executeTest('docker ps -a --format "{{.Names}}"'))))) 614 { 615 if ($strContainer =~ $strRegExp) 616 { 617 executeTest("docker rm -f ${strContainer}", {bSuppressError => true}); 618 } 619 } 620} 621 622push @EXPORT, qw(containerRemove); 623 624#################################################################################################################################### 625# imageRemove 626# 627# Remove images that match a regexp. 628#################################################################################################################################### 629sub imageRemove 630{ 631 my $strRegExp = shift; 632 633 foreach my $strImage (sort(split("\n", trim(executeTest('docker images --format "{{.Repository}}:{{.Tag}}"'))))) 634 { 635 if ($strImage =~ $strRegExp) 636 { 637 &log(INFO, "Removing ${strImage} image..."); 638 executeTest("docker rmi -f ${strImage}"); 639 } 640 } 641} 642 6431; 644