├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .fixtures.yml ├── .gitattributes ├── .github ├── CODEOWNERS └── workflows │ └── pdk-test-unit.yml ├── .gitignore ├── .gitlab-ci.yml ├── .pdkignore ├── .puppet-lint.rc ├── .rspec ├── .rubocop.yml ├── .travis.yml ├── .vscode └── extensions.json ├── .yardopts ├── Gemfile ├── LICENSE ├── README.md ├── REFERENCE.md ├── Rakefile ├── appveyor.yml ├── data └── common.yaml ├── hiera.yaml ├── manifests ├── init.pp └── instance.pp ├── metadata.json ├── spec ├── classes │ └── github_actions_runner_spec.rb ├── default_facts.yml └── spec_helper.rb └── templates ├── configure_install_runner.sh.epp ├── env.epp ├── github-actions-runner.service.epp └── path.epp /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM puppet/pdk:latest 2 | 3 | # [Optional] Uncomment this section to install additional packages. 4 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 5 | # && apt-get -y install --no-install-recommends 6 | 7 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet 3 | { 4 | "name": "Puppet Development Kit (Community)", 5 | "dockerFile": "Dockerfile", 6 | 7 | // Set *default* container specific settings.json values on container create. 8 | "settings": { 9 | "terminal.integrated.shell.linux": "/bin/bash" 10 | }, 11 | 12 | // Add the IDs of extensions you want installed when the container is created. 13 | "extensions": [ 14 | "puppet.puppet-vscode", 15 | "rebornix.Ruby" 16 | ] 17 | 18 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 19 | // "forwardPorts": [], 20 | 21 | // Use 'postCreateCommand' to run commands after the container is created. 22 | // "postCreateCommand": "pdk --version", 23 | } 24 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | # This file can be used to install module dependencies for unit testing 2 | # See https://github.com/puppetlabs/puppetlabs_spec_helper#using-fixtures for details 3 | --- 4 | fixtures: 5 | forge_modules: 6 | stdlib: "puppetlabs/stdlib" 7 | repositories: 8 | archive: 9 | repo: "https://github.com/voxpupuli/puppet-archive.git" 10 | ref: "v1.1.2" 11 | systemd: 12 | repo: "https://github.com/camptocamp/puppet-systemd.git" 13 | ref: "2.7.0" 14 | 15 | 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rb eol=lf 2 | *.erb eol=lf 3 | *.pp eol=lf 4 | *.sh eol=lf 5 | *.epp eol=lf 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default owners for everything in the repository 2 | * @Telefonica/lifecycle 3 | -------------------------------------------------------------------------------- /.github/workflows/pdk-test-unit.yml: -------------------------------------------------------------------------------- 1 | name: Run pdk test unit 2 | 3 | on: 4 | - push 5 | - pull_request 6 | - workflow_dispatch 7 | 8 | jobs: 9 | validating: 10 | runs-on: ubuntu-20.04 11 | strategy: 12 | matrix: 13 | puppet-version: [5, 6, 7] 14 | steps: 15 | - name: Clone repository 16 | uses: actions/checkout@v2 17 | 18 | - name: Run pdk validate 19 | uses: puppets-epic-show-theatre/action-pdk-validate@v1 20 | with: 21 | puppet-version: ${{ matrix.puppet-version }} 22 | 23 | testing: 24 | runs-on: ubuntu-20.04 25 | strategy: 26 | matrix: 27 | puppet-version: [5, 6, 7] 28 | steps: 29 | - name: Clone repository 30 | uses: actions/checkout@v2 31 | 32 | - name: Run unit tests 33 | uses: puppets-epic-show-theatre/action-pdk-test-unit@v1 34 | # added because there are open ended dependencies version requirements in metadata.json 35 | with: 36 | puppet-version: ${{ matrix.puppet-version }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/ 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | stages: 3 | - syntax 4 | - unit 5 | 6 | default: 7 | cache: 8 | paths: 9 | - vendor/bundle 10 | 11 | before_script: &before_script 12 | - bundle -v 13 | - rm Gemfile.lock || true 14 | - "# Update system gems if requested. This is useful to temporarily workaround troubles in the test runner" 15 | - "# Set `rubygems_version` in the .sync.yml to set a value" 16 | - "# Ignore exit code of SIGPIPE'd yes to not fail with shell's pipefail set" 17 | - '[ -z "$RUBYGEMS_VERSION" ] || (yes || true) | gem update --system $RUBYGEMS_VERSION' 18 | - gem --version 19 | - bundle -v 20 | - bundle install --without system_tests --path vendor/bundle --jobs $(nproc) 21 | 22 | syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.5.7-Puppet ~> 6: 23 | stage: syntax 24 | image: ruby:2.5.7 25 | script: 26 | - bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop 27 | variables: 28 | PUPPET_GEM_VERSION: '~> 6' 29 | 30 | parallel_spec-Ruby 2.5.7-Puppet ~> 6: 31 | stage: unit 32 | image: ruby:2.5.7 33 | script: 34 | - bundle exec rake parallel_spec 35 | variables: 36 | PUPPET_GEM_VERSION: '~> 6' 37 | 38 | syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop-Ruby 2.7.2-Puppet ~> 7: 39 | stage: syntax 40 | image: ruby:2.7.2 41 | script: 42 | - bundle exec rake syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop 43 | variables: 44 | PUPPET_GEM_VERSION: '~> 7' 45 | 46 | parallel_spec-Ruby 2.7.2-Puppet ~> 7: 47 | stage: unit 48 | image: ruby:2.7.2 49 | script: 50 | - bundle exec rake parallel_spec 51 | variables: 52 | PUPPET_GEM_VERSION: '~> 7' 53 | 54 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/ 20 | /tmp/ 21 | /vendor/ 22 | /convert_report.txt 23 | /update_report.txt 24 | .DS_Store 25 | .project 26 | .envrc 27 | /inventory.yaml 28 | /spec/fixtures/litmus_inventory.yaml 29 | /appveyor.yml 30 | /.editorconfig 31 | /.fixtures.yml 32 | /Gemfile 33 | /.gitattributes 34 | /.gitignore 35 | /.gitlab-ci.yml 36 | /.pdkignore 37 | /.puppet-lint.rc 38 | /Rakefile 39 | /rakelib/ 40 | /.rspec 41 | /.rubocop.yml 42 | /.travis.yml 43 | /.yardopts 44 | /spec/ 45 | /.vscode/ 46 | /.sync.yml 47 | /.devcontainer/ 48 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | --relative 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | require: 3 | - rubocop-performance 4 | - rubocop-rspec 5 | AllCops: 6 | DisplayCopNames: true 7 | TargetRubyVersion: '2.4' 8 | Include: 9 | - "**/*.rb" 10 | Exclude: 11 | - bin/* 12 | - ".vendor/**/*" 13 | - "**/Gemfile" 14 | - "**/Rakefile" 15 | - pkg/**/* 16 | - spec/fixtures/**/* 17 | - vendor/**/* 18 | - "**/Puppetfile" 19 | - "**/Vagrantfile" 20 | - "**/Guardfile" 21 | Layout/LineLength: 22 | Description: People have wide screens, use them. 23 | Max: 200 24 | RSpec/BeforeAfterAll: 25 | Description: Beware of using after(:all) as it may cause state to leak between tests. 26 | A necessary evil in acceptance testing. 27 | Exclude: 28 | - spec/acceptance/**/*.rb 29 | RSpec/HookArgument: 30 | Description: Prefer explicit :each argument, matching existing module's style 31 | EnforcedStyle: each 32 | RSpec/DescribeSymbol: 33 | Exclude: 34 | - spec/unit/facter/**/*.rb 35 | Style/BlockDelimiters: 36 | Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to 37 | be consistent then. 38 | EnforcedStyle: braces_for_chaining 39 | Style/ClassAndModuleChildren: 40 | Description: Compact style reduces the required amount of indentation. 41 | EnforcedStyle: compact 42 | Style/EmptyElse: 43 | Description: Enforce against empty else clauses, but allow `nil` for clarity. 44 | EnforcedStyle: empty 45 | Style/FormatString: 46 | Description: Following the main puppet project's style, prefer the % format format. 47 | EnforcedStyle: percent 48 | Style/FormatStringToken: 49 | Description: Following the main puppet project's style, prefer the simpler template 50 | tokens over annotated ones. 51 | EnforcedStyle: template 52 | Style/Lambda: 53 | Description: Prefer the keyword for easier discoverability. 54 | EnforcedStyle: literal 55 | Style/RegexpLiteral: 56 | Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 57 | EnforcedStyle: percent_r 58 | Style/TernaryParentheses: 59 | Description: Checks for use of parentheses around ternary conditions. Enforce parentheses 60 | on complex expressions for better readability, but seriously consider breaking 61 | it up. 62 | EnforcedStyle: require_parentheses_when_complex 63 | Style/TrailingCommaInArguments: 64 | Description: Prefer always trailing comma on multiline argument lists. This makes 65 | diffs, and re-ordering nicer. 66 | EnforcedStyleForMultiline: comma 67 | Style/TrailingCommaInArrayLiteral: 68 | Description: Prefer always trailing comma on multiline literals. This makes diffs, 69 | and re-ordering nicer. 70 | EnforcedStyleForMultiline: comma 71 | Style/SymbolArray: 72 | Description: Using percent style obscures symbolic intent of array's contents. 73 | EnforcedStyle: brackets 74 | RSpec/MessageSpies: 75 | EnforcedStyle: receive 76 | Style/Documentation: 77 | Exclude: 78 | - lib/puppet/parser/functions/**/* 79 | - spec/**/* 80 | Style/WordArray: 81 | EnforcedStyle: brackets 82 | Performance/AncestorsInclude: 83 | Enabled: true 84 | Performance/BigDecimalWithNumericArgument: 85 | Enabled: true 86 | Performance/BlockGivenWithExplicitBlock: 87 | Enabled: true 88 | Performance/CaseWhenSplat: 89 | Enabled: true 90 | Performance/ConstantRegexp: 91 | Enabled: true 92 | Performance/MethodObjectAsBlock: 93 | Enabled: true 94 | Performance/RedundantSortBlock: 95 | Enabled: true 96 | Performance/RedundantStringChars: 97 | Enabled: true 98 | Performance/ReverseFirst: 99 | Enabled: true 100 | Performance/SortReverse: 101 | Enabled: true 102 | Performance/Squeeze: 103 | Enabled: true 104 | Performance/StringInclude: 105 | Enabled: true 106 | Performance/Sum: 107 | Enabled: true 108 | Style/CollectionMethods: 109 | Enabled: true 110 | Style/MethodCalledOnDoEndBlock: 111 | Enabled: true 112 | Style/StringMethods: 113 | Enabled: true 114 | Bundler/InsecureProtocolSource: 115 | Enabled: false 116 | Gemspec/DuplicatedAssignment: 117 | Enabled: false 118 | Gemspec/OrderedDependencies: 119 | Enabled: false 120 | Gemspec/RequiredRubyVersion: 121 | Enabled: false 122 | Gemspec/RubyVersionGlobalsUsage: 123 | Enabled: false 124 | Layout/ArgumentAlignment: 125 | Enabled: false 126 | Layout/BeginEndAlignment: 127 | Enabled: false 128 | Layout/ClosingHeredocIndentation: 129 | Enabled: false 130 | Layout/EmptyComment: 131 | Enabled: false 132 | Layout/EmptyLineAfterGuardClause: 133 | Enabled: false 134 | Layout/EmptyLinesAroundArguments: 135 | Enabled: false 136 | Layout/EmptyLinesAroundAttributeAccessor: 137 | Enabled: false 138 | Layout/EndOfLine: 139 | Enabled: false 140 | Layout/FirstArgumentIndentation: 141 | Enabled: false 142 | Layout/HashAlignment: 143 | Enabled: false 144 | Layout/HeredocIndentation: 145 | Enabled: false 146 | Layout/LeadingEmptyLines: 147 | Enabled: false 148 | Layout/SpaceAroundMethodCallOperator: 149 | Enabled: false 150 | Layout/SpaceInsideArrayLiteralBrackets: 151 | Enabled: false 152 | Layout/SpaceInsideReferenceBrackets: 153 | Enabled: false 154 | Lint/BigDecimalNew: 155 | Enabled: false 156 | Lint/BooleanSymbol: 157 | Enabled: false 158 | Lint/ConstantDefinitionInBlock: 159 | Enabled: false 160 | Lint/DeprecatedOpenSSLConstant: 161 | Enabled: false 162 | Lint/DisjunctiveAssignmentInConstructor: 163 | Enabled: false 164 | Lint/DuplicateElsifCondition: 165 | Enabled: false 166 | Lint/DuplicateRequire: 167 | Enabled: false 168 | Lint/DuplicateRescueException: 169 | Enabled: false 170 | Lint/EmptyConditionalBody: 171 | Enabled: false 172 | Lint/EmptyFile: 173 | Enabled: false 174 | Lint/ErbNewArguments: 175 | Enabled: false 176 | Lint/FloatComparison: 177 | Enabled: false 178 | Lint/HashCompareByIdentity: 179 | Enabled: false 180 | Lint/IdentityComparison: 181 | Enabled: false 182 | Lint/InterpolationCheck: 183 | Enabled: false 184 | Lint/MissingCopEnableDirective: 185 | Enabled: false 186 | Lint/MixedRegexpCaptureTypes: 187 | Enabled: false 188 | Lint/NestedPercentLiteral: 189 | Enabled: false 190 | Lint/NonDeterministicRequireOrder: 191 | Enabled: false 192 | Lint/OrderedMagicComments: 193 | Enabled: false 194 | Lint/OutOfRangeRegexpRef: 195 | Enabled: false 196 | Lint/RaiseException: 197 | Enabled: false 198 | Lint/RedundantCopEnableDirective: 199 | Enabled: false 200 | Lint/RedundantRequireStatement: 201 | Enabled: false 202 | Lint/RedundantSafeNavigation: 203 | Enabled: false 204 | Lint/RedundantWithIndex: 205 | Enabled: false 206 | Lint/RedundantWithObject: 207 | Enabled: false 208 | Lint/RegexpAsCondition: 209 | Enabled: false 210 | Lint/ReturnInVoidContext: 211 | Enabled: false 212 | Lint/SafeNavigationConsistency: 213 | Enabled: false 214 | Lint/SafeNavigationWithEmpty: 215 | Enabled: false 216 | Lint/SelfAssignment: 217 | Enabled: false 218 | Lint/SendWithMixinArgument: 219 | Enabled: false 220 | Lint/ShadowedArgument: 221 | Enabled: false 222 | Lint/StructNewOverride: 223 | Enabled: false 224 | Lint/ToJSON: 225 | Enabled: false 226 | Lint/TopLevelReturnWithArgument: 227 | Enabled: false 228 | Lint/TrailingCommaInAttributeDeclaration: 229 | Enabled: false 230 | Lint/UnreachableLoop: 231 | Enabled: false 232 | Lint/UriEscapeUnescape: 233 | Enabled: false 234 | Lint/UriRegexp: 235 | Enabled: false 236 | Lint/UselessMethodDefinition: 237 | Enabled: false 238 | Lint/UselessTimes: 239 | Enabled: false 240 | Metrics/AbcSize: 241 | Enabled: false 242 | Metrics/BlockLength: 243 | Enabled: false 244 | Metrics/BlockNesting: 245 | Enabled: false 246 | Metrics/ClassLength: 247 | Enabled: false 248 | Metrics/CyclomaticComplexity: 249 | Enabled: false 250 | Metrics/MethodLength: 251 | Enabled: false 252 | Metrics/ModuleLength: 253 | Enabled: false 254 | Metrics/ParameterLists: 255 | Enabled: false 256 | Metrics/PerceivedComplexity: 257 | Enabled: false 258 | Migration/DepartmentName: 259 | Enabled: false 260 | Naming/AccessorMethodName: 261 | Enabled: false 262 | Naming/BlockParameterName: 263 | Enabled: false 264 | Naming/HeredocDelimiterCase: 265 | Enabled: false 266 | Naming/HeredocDelimiterNaming: 267 | Enabled: false 268 | Naming/MemoizedInstanceVariableName: 269 | Enabled: false 270 | Naming/MethodParameterName: 271 | Enabled: false 272 | Naming/RescuedExceptionsVariableName: 273 | Enabled: false 274 | Naming/VariableNumber: 275 | Enabled: false 276 | Performance/BindCall: 277 | Enabled: false 278 | Performance/DeletePrefix: 279 | Enabled: false 280 | Performance/DeleteSuffix: 281 | Enabled: false 282 | Performance/InefficientHashSearch: 283 | Enabled: false 284 | Performance/UnfreezeString: 285 | Enabled: false 286 | Performance/UriDefaultParser: 287 | Enabled: false 288 | RSpec/Be: 289 | Enabled: false 290 | RSpec/Capybara/CurrentPathExpectation: 291 | Enabled: false 292 | RSpec/Capybara/FeatureMethods: 293 | Enabled: false 294 | RSpec/Capybara/VisibilityMatcher: 295 | Enabled: false 296 | RSpec/ContextMethod: 297 | Enabled: false 298 | RSpec/ContextWording: 299 | Enabled: false 300 | RSpec/DescribeClass: 301 | Enabled: false 302 | RSpec/EmptyHook: 303 | Enabled: false 304 | RSpec/EmptyLineAfterExample: 305 | Enabled: false 306 | RSpec/EmptyLineAfterExampleGroup: 307 | Enabled: false 308 | RSpec/EmptyLineAfterHook: 309 | Enabled: false 310 | RSpec/ExampleLength: 311 | Enabled: false 312 | RSpec/ExampleWithoutDescription: 313 | Enabled: false 314 | RSpec/ExpectChange: 315 | Enabled: false 316 | RSpec/ExpectInHook: 317 | Enabled: false 318 | RSpec/FactoryBot/AttributeDefinedStatically: 319 | Enabled: false 320 | RSpec/FactoryBot/CreateList: 321 | Enabled: false 322 | RSpec/FactoryBot/FactoryClassName: 323 | Enabled: false 324 | RSpec/HooksBeforeExamples: 325 | Enabled: false 326 | RSpec/ImplicitBlockExpectation: 327 | Enabled: false 328 | RSpec/ImplicitSubject: 329 | Enabled: false 330 | RSpec/LeakyConstantDeclaration: 331 | Enabled: false 332 | RSpec/LetBeforeExamples: 333 | Enabled: false 334 | RSpec/MissingExampleGroupArgument: 335 | Enabled: false 336 | RSpec/MultipleExpectations: 337 | Enabled: false 338 | RSpec/MultipleMemoizedHelpers: 339 | Enabled: false 340 | RSpec/MultipleSubjects: 341 | Enabled: false 342 | RSpec/NestedGroups: 343 | Enabled: false 344 | RSpec/PredicateMatcher: 345 | Enabled: false 346 | RSpec/ReceiveCounts: 347 | Enabled: false 348 | RSpec/ReceiveNever: 349 | Enabled: false 350 | RSpec/RepeatedExampleGroupBody: 351 | Enabled: false 352 | RSpec/RepeatedExampleGroupDescription: 353 | Enabled: false 354 | RSpec/RepeatedIncludeExample: 355 | Enabled: false 356 | RSpec/ReturnFromStub: 357 | Enabled: false 358 | RSpec/SharedExamples: 359 | Enabled: false 360 | RSpec/StubbedMock: 361 | Enabled: false 362 | RSpec/UnspecifiedException: 363 | Enabled: false 364 | RSpec/VariableDefinition: 365 | Enabled: false 366 | RSpec/VoidExpect: 367 | Enabled: false 368 | RSpec/Yield: 369 | Enabled: false 370 | Security/Open: 371 | Enabled: false 372 | Style/AccessModifierDeclarations: 373 | Enabled: false 374 | Style/AccessorGrouping: 375 | Enabled: false 376 | Style/AsciiComments: 377 | Enabled: false 378 | Style/BisectedAttrAccessor: 379 | Enabled: false 380 | Style/CaseLikeIf: 381 | Enabled: false 382 | Style/ClassEqualityComparison: 383 | Enabled: false 384 | Style/ColonMethodDefinition: 385 | Enabled: false 386 | Style/CombinableLoops: 387 | Enabled: false 388 | Style/CommentedKeyword: 389 | Enabled: false 390 | Style/Dir: 391 | Enabled: false 392 | Style/DoubleCopDisableDirective: 393 | Enabled: false 394 | Style/EmptyBlockParameter: 395 | Enabled: false 396 | Style/EmptyLambdaParameter: 397 | Enabled: false 398 | Style/Encoding: 399 | Enabled: false 400 | Style/EvalWithLocation: 401 | Enabled: false 402 | Style/ExpandPathArguments: 403 | Enabled: false 404 | Style/ExplicitBlockArgument: 405 | Enabled: false 406 | Style/ExponentialNotation: 407 | Enabled: false 408 | Style/FloatDivision: 409 | Enabled: false 410 | Style/FrozenStringLiteralComment: 411 | Enabled: false 412 | Style/GlobalStdStream: 413 | Enabled: false 414 | Style/HashAsLastArrayItem: 415 | Enabled: false 416 | Style/HashLikeCase: 417 | Enabled: false 418 | Style/HashTransformKeys: 419 | Enabled: false 420 | Style/HashTransformValues: 421 | Enabled: false 422 | Style/IfUnlessModifier: 423 | Enabled: false 424 | Style/KeywordParametersOrder: 425 | Enabled: false 426 | Style/MinMax: 427 | Enabled: false 428 | Style/MixinUsage: 429 | Enabled: false 430 | Style/MultilineWhenThen: 431 | Enabled: false 432 | Style/NegatedUnless: 433 | Enabled: false 434 | Style/NumericPredicate: 435 | Enabled: false 436 | Style/OptionalBooleanParameter: 437 | Enabled: false 438 | Style/OrAssignment: 439 | Enabled: false 440 | Style/RandomWithOffset: 441 | Enabled: false 442 | Style/RedundantAssignment: 443 | Enabled: false 444 | Style/RedundantCondition: 445 | Enabled: false 446 | Style/RedundantConditional: 447 | Enabled: false 448 | Style/RedundantFetchBlock: 449 | Enabled: false 450 | Style/RedundantFileExtensionInRequire: 451 | Enabled: false 452 | Style/RedundantRegexpCharacterClass: 453 | Enabled: false 454 | Style/RedundantRegexpEscape: 455 | Enabled: false 456 | Style/RedundantSelfAssignment: 457 | Enabled: false 458 | Style/RedundantSort: 459 | Enabled: false 460 | Style/RescueStandardError: 461 | Enabled: false 462 | Style/SingleArgumentDig: 463 | Enabled: false 464 | Style/SlicingWithRange: 465 | Enabled: false 466 | Style/SoleNestedConditional: 467 | Enabled: false 468 | Style/StderrPuts: 469 | Enabled: false 470 | Style/StringConcatenation: 471 | Enabled: false 472 | Style/Strip: 473 | Enabled: false 474 | Style/SymbolProc: 475 | Enabled: false 476 | Style/TrailingBodyOnClass: 477 | Enabled: false 478 | Style/TrailingBodyOnMethodDefinition: 479 | Enabled: false 480 | Style/TrailingBodyOnModule: 481 | Enabled: false 482 | Style/TrailingCommaInHashLiteral: 483 | Enabled: false 484 | Style/TrailingMethodEndStatement: 485 | Enabled: false 486 | Style/UnpackFirst: 487 | Enabled: false 488 | Lint/DuplicateBranch: 489 | Enabled: false 490 | Lint/DuplicateRegexpCharacterClassElement: 491 | Enabled: false 492 | Lint/EmptyBlock: 493 | Enabled: false 494 | Lint/EmptyClass: 495 | Enabled: false 496 | Lint/NoReturnInBeginEndBlocks: 497 | Enabled: false 498 | Lint/ToEnumArguments: 499 | Enabled: false 500 | Lint/UnexpectedBlockArity: 501 | Enabled: false 502 | Lint/UnmodifiedReduceAccumulator: 503 | Enabled: false 504 | Performance/CollectionLiteralInLoop: 505 | Enabled: false 506 | Style/ArgumentsForwarding: 507 | Enabled: false 508 | Style/CollectionCompact: 509 | Enabled: false 510 | Style/DocumentDynamicEvalDefinition: 511 | Enabled: false 512 | Style/NegatedIfElseCondition: 513 | Enabled: false 514 | Style/NilLambda: 515 | Enabled: false 516 | Style/RedundantArgument: 517 | Enabled: false 518 | Style/SwapValues: 519 | Enabled: false 520 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | os: linux 3 | dist: xenial 4 | language: ruby 5 | cache: bundler 6 | before_install: 7 | - bundle -v 8 | - rm -f Gemfile.lock 9 | - "# Update system gems if requested. This is useful to temporarily workaround troubles in the test runner" 10 | - "# See https://github.com/puppetlabs/pdk-templates/commit/705154d5c437796b821691b707156e1b056d244f for an example of how this was used" 11 | - "# Ignore exit code of SIGPIPE'd yes to not fail with shell's pipefail set" 12 | - '[ -z "$RUBYGEMS_VERSION" ] || (yes || true) | gem update --system $RUBYGEMS_VERSION' 13 | - gem --version 14 | - bundle -v 15 | script: 16 | - 'bundle exec rake $CHECK' 17 | bundler_args: --without system_tests 18 | rvm: 19 | - 2.5.7 20 | stages: 21 | - static 22 | - spec 23 | - acceptance 24 | - 25 | if: tag =~ ^v\d 26 | name: deploy 27 | jobs: 28 | fast_finish: true 29 | include: 30 | - 31 | env: CHECK="check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop syntax lint metadata_lint" 32 | stage: static 33 | - 34 | env: PUPPET_GEM_VERSION="~> 6.0" CHECK=parallel_spec 35 | rvm: 2.5.7 36 | stage: spec 37 | - 38 | env: DEPLOY_TO_FORGE=yes 39 | stage: deploy 40 | branches: 41 | only: 42 | - master 43 | - /^v\d/ 44 | notifications: 45 | email: false 46 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "puppet.puppet-vscode", 4 | "rebornix.Ruby" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | def location_for(place_or_version, fake_version = nil) 4 | git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} 5 | file_url_regex = %r{\Afile:\/\/(?.*)} 6 | 7 | if place_or_version && (git_url = place_or_version.match(git_url_regex)) 8 | [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact 9 | elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) 10 | ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] 11 | else 12 | [place_or_version, { require: false }] 13 | end 14 | end 15 | 16 | ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments 17 | minor_version = ruby_version_segments[0..1].join('.') 18 | 19 | group :development do 20 | gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 21 | gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 22 | gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 2.8.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 23 | gem "puppet-module-posix-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 24 | gem "puppet-module-posix-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 25 | gem "puppet-module-win-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 26 | gem "puppet-module-win-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 27 | end 28 | group :system_tests do 29 | gem "puppet-module-posix-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] 30 | gem "puppet-module-win-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] 31 | end 32 | 33 | puppet_version = ENV['PUPPET_GEM_VERSION'] 34 | facter_version = ENV['FACTER_GEM_VERSION'] 35 | hiera_version = ENV['HIERA_GEM_VERSION'] 36 | 37 | gems = {} 38 | 39 | gems['puppet'] = location_for(puppet_version) 40 | 41 | # If facter or hiera versions have been specified via the environment 42 | # variables 43 | 44 | gems['facter'] = location_for(facter_version) if facter_version 45 | gems['hiera'] = location_for(hiera_version) if hiera_version 46 | 47 | gems.each do |gem_name, gem_params| 48 | gem gem_name, *gem_params 49 | end 50 | 51 | # Evaluate Gemfile.local and ~/.gemfile if they exist 52 | extra_gemfiles = [ 53 | "#{__FILE__}.local", 54 | File.join(Dir.home, '.gemfile'), 55 | ] 56 | 57 | extra_gemfiles.each do |gemfile| 58 | if File.file?(gemfile) && File.readable?(gemfile) 59 | eval(File.read(gemfile), binding) 60 | end 61 | end 62 | # vim: syntax=ruby 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "{}" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2018 Puppet, Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > **:warning: Project not maintained (we no longer can keep up with the changes and validate them, feel free to fork it)** 2 | 3 | ![PDK Test Unit](https://github.com/Telefonica/puppet-github-actions-runner/workflows/Run%20pdk%20test%20unit/badge.svg?branch=master) 4 | 5 | # GitHub Actions Runner 6 | 7 | Automatic configuration for running GitHub Actions as a service 8 | 9 | #### Table of Contents 10 | 11 | 1. [Description](#description) 12 | - [Hiera configuration examples](#hiera-configuration-examples) 13 | - [Github Enterprise examples](#github-enterprise-examples) 14 | 2. [Limitations - OS compatibility, etc.](#limitations) 15 | 3. [Development - Guide for contributing to the module](#development) 16 | 17 | ## Description 18 | 19 | This module will setup all of the files and configuration needed for GitHub Actions runner to work on Debian (Stretch and Buster) and CentOS7 hosts. 20 | 21 | ### hiera configuration examples 22 | 23 | This module supports configuration through hiera. 24 | 25 | #### Creating an organization level Actions runner 26 | 27 | ```yaml 28 | github_actions_runner::ensure: present 29 | github_actions_runner::base_dir_name: '/data/actions-runner' 30 | github_actions_runner::package_name: 'actions-runner-linux-x64' 31 | github_actions_runner::package_ensure: '2.277.1' 32 | github_actions_runner::repository_url: 'https://github.com/actions/runner/releases/download' 33 | github_actions_runner::org_name: 'my_github_organization' 34 | github_actions_runner::personal_access_token: 'PAT' 35 | github_actions_runner::user: 'root' 36 | github_actions_runner::group: 'root' 37 | github_actions_runner::instances: 38 | example_org_instance: 39 | labels: 40 | - self-hosted-custom 41 | ``` 42 | 43 | Note, your `personal_access_token` has to contain the `admin:org` permission. 44 | 45 | #### Creating an additional repository level Actions runner 46 | ```yaml 47 | github_actions_runner::instances: 48 | example_org_instance: 49 | labels: 50 | - self-hosted-custom1 51 | example_repo_instance: 52 | repo_name: myrepo 53 | labels: 54 | - self-hosted-custom2 55 | ``` 56 | 57 | Note, your `personal_access_token` has to contain the `repo` permission. 58 | 59 | #### Instance level overwrites 60 | ```yaml 61 | github_actions_runner::instances: 62 | example_org_instance: 63 | ensure: absent 64 | labels: 65 | - self-hosted-custom1 66 | example_repo_instance: 67 | org_name: overwritten_orgnization 68 | repo_name: myrepo 69 | labels: 70 | - self-hosted-custom2 71 | ``` 72 | 73 | #### Adding a global proxy and overwriting an instance level proxy 74 | ```yaml 75 | github_actions_runner::http_proxy: http://proxy.local 76 | github_actions_runner::https_proxy: http://proxy.local 77 | github_actions_runner::instances: 78 | example_org_instance: 79 | http_proxy: http://instance_specific_proxy.local 80 | https_proxy: http://instance_specific_proxy.local 81 | no_proxy: example.com 82 | labels: 83 | - self-hosted-custom1 84 | ``` 85 | 86 | ### Github Enterprise examples 87 | To use the module with Github Enterprise Server, you have to define these parameters: 88 | ```yaml 89 | github_actions_runner::github_domain: "https://git.example.com" 90 | github_actions_runner::github_api: "https://git.example.com/api/v3" 91 | ``` 92 | 93 | In addition to the runner configuration examples above, you can also configure runners 94 | on the enterprise level by setting a value for `enterprise_name`, for example: 95 | ```yaml 96 | github_actions_runner::ensure: present 97 | github_actions_runner::base_dir_name: '/data/actions-runner' 98 | github_actions_runner::package_name: 'actions-runner-linux-x64' 99 | github_actions_runner::package_ensure: '2.277.1' 100 | github_actions_runner::repository_url: 'https://github.com/actions/runner/releases/download' 101 | github_actions_runner::enterprise_name: 'enterprise_name' 102 | github_actions_runner::personal_access_token: 'PAT' 103 | github_actions_runner::user: 'root' 104 | github_actions_runner::group: 'root' 105 | github_actions_runner::instances: 106 | ``` 107 | 108 | Note, your `personal_access_token` has to contain the `admin:enterprise` permission. 109 | 110 | ### Update PATH used by Github Runners 111 | 112 | By default, puppet will not modify the values that the runner scripts create when 113 | the runner is set. 114 | 115 | In case you need to use another value of paths in the environment variable PATH, 116 | you can define through hiera. For example: 117 | 118 | - For all runners defined: 119 | ```yaml 120 | github_actions_runner::path: 121 | - /usr/local/bin 122 | - /usr/bin 123 | - /bin 124 | - /my/own/path 125 | ``` 126 | - For just a specific runner: 127 | ```yaml 128 | github_actions_runner::instances: 129 | example_org_instance: 130 | path: 131 | - /usr/local/bin 132 | - /usr/bin 133 | - /bin 134 | - /my/own/path 135 | labels: 136 | - self-hosted-custom 137 | ``` 138 | 139 | ## Adding environment variables to runner 140 | 141 | The runner uses environment variables to decide pre/post-run scripts: 142 | https://docs.github.com/en/actions/hosting-your-own-runners/running-scripts-before-or-after-a-job#triggering-the-scripts 143 | 144 | ```yaml 145 | github_actions_runner::env: 146 | ACTIONS_RUNNER_HOOK_JOB_STARTED: "/cleanup_script" 147 | FOO: "bar" 148 | ``` 149 | 150 | 151 | ## Limitations 152 | 153 | Tested on Debian 9 (stretch), Debian 10 (buster) and CentOS7 hosts. 154 | Full list of operating systems support and requirements are described in `metadata.json` file. 155 | 156 | ## Development 157 | 158 | There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. For more information, see Puppet Forge [module contribution guide](https://puppet.com/docs/puppet/7.1/modules_publishing.html). 159 | 160 | ## License 161 | 162 | *GitHub Actions Runner* is available under the Apache License, Version 2.0. See LICENSE file 163 | for more info. 164 | -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | ## Table of Contents 4 | 5 | **Classes** 6 | 7 | * [`github_actions_runner`](#github_actions_runner) 8 | 9 | **Defines** 10 | 11 | * [`github_actions_runner::instance`](#github_actions_runner_instance) 12 | 13 | ## Classes 14 | 15 | ### github_actions_runner 16 | 17 | Guides the basic setup and installation of GitHub actions runner on your system. 18 | 19 | You can read more about self-hosted actions runner [here](https://docs.github.com/en/free-pro-team@latest/actions/hosting-your-own-runners/about-self-hosted-runners) 20 | 21 | #### Parameters 22 | 23 | The following parameters are available in the `github_actions_runner` class. 24 | 25 | ##### `ensure` 26 | 27 | Data type: `Enum['present', 'absent']]` 28 | Enum, Determine if to add or remove the resource. 29 | 30 | ##### `base_dir_name` 31 | 32 | Data type: `Absolutepath` 33 | Location of the base directory for actions runner to be installed. 34 | 35 | ##### `org_name` 36 | 37 | Data type: `String` 38 | 39 | actions runner github organization name. 40 | 41 | ##### `enterprise_name` 42 | 43 | Data type: `String` 44 | 45 | enterprise name for global runners 46 | 47 | ##### `hostname` 48 | 49 | Data type: `String` 50 | 51 | actions runner name 52 | 53 | Default value: $::facts['hostname'] 54 | 55 | ##### `personal_access_token` 56 | 57 | Data type: `String` 58 | 59 | GitHub Personal Access Token with admin permission on the repositories or the organization. 60 | 61 | ##### `package_name` 62 | 63 | Data type: `String` 64 | 65 | GitHub Actions runner official package name. 66 | 67 | You can find the package names [here](https://github.com/actions/runner/releases) 68 | 69 | **Example**: 70 | 71 | ``` 72 | actions-runner-linux-x64 73 | ``` 74 | 75 | ##### `package_ensure` 76 | 77 | Data type: `String` 78 | 79 | GitHub Actions runner version to be used. 80 | 81 | You can find latest versions [here](https://github.com/actions/runner/releases) 82 | 83 | **Example**: 84 | 85 | ``` 86 | 2.292.0 87 | ``` 88 | 89 | ##### `repository_url` 90 | 91 | Data type: `String` 92 | 93 | A base URL to download GitHub actions runner. 94 | 95 | **Example**: 96 | 97 | ``` 98 | https://github.com/actions/runner/releases/download 99 | ``` 100 | 101 | ##### `user` 102 | 103 | Data type: `String` 104 | 105 | User to be used in Service and directories. 106 | 107 | ##### `group` 108 | 109 | Data type: `String` 110 | 111 | Group to be used in Service and directories. 112 | 113 | ## Defines 114 | 115 | ### github_actions_runner::instance 116 | 117 | #### Parameters 118 | 119 | ##### `ensure` 120 | 121 | Data type: `Enum` 122 | 123 | Determine if to add or remove the resource 124 | Default value: `undef` 125 | 126 | ##### `org_name` 127 | 128 | Data type: `String` 129 | 130 | actions runner github organization name. 131 | 132 | Default value: `undef` 133 | 134 | ##### `enterprise_name` 135 | 136 | Data type: `String` 137 | 138 | enterprise name for global runners 139 | 140 | Default value: `undef` 141 | 142 | ##### `personal_access_token` 143 | 144 | Data type: `String` 145 | 146 | GitHub Personal Access Token with admin permission on the repositories or the organization. 147 | 148 | Default value: `github_actions_runner::personal_access_token` 149 | 150 | ##### `user` 151 | 152 | Data type: `String` 153 | 154 | User to be used in Service and directories. 155 | 156 | Default value: `github_actions_runner::user` 157 | 158 | ##### `group` 159 | 160 | Data type: `String` 161 | 162 | Group to be used in Service and directories. 163 | 164 | Default value: `github_actions_runner::group` 165 | 166 | ##### `repo_name` 167 | 168 | Data type: `Optional[String]` 169 | 170 | actions runner github repository name to serve. 171 | Default value: `undef` 172 | 173 | ##### `labels` 174 | 175 | Data type: `Optional[Array[String]]` 176 | 177 | A list of costum lables to add to a actions runner host. 178 | 179 | Default value: `undef` 180 | 181 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any? 5 | require 'puppetlabs_spec_helper/rake_tasks' 6 | require 'puppet-syntax/tasks/puppet-syntax' 7 | require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? 8 | require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any? 9 | require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any? 10 | 11 | def changelog_user 12 | return unless Rake.application.top_level_tasks.include? "changelog" 13 | returnVal = nil || JSON.load(File.read('metadata.json'))['author'] 14 | raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil? 15 | puts "GitHubChangelogGenerator user:#{returnVal}" 16 | returnVal 17 | end 18 | 19 | def changelog_project 20 | return unless Rake.application.top_level_tasks.include? "changelog" 21 | 22 | returnVal = nil 23 | returnVal ||= begin 24 | metadata_source = JSON.load(File.read('metadata.json'))['source'] 25 | metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z}) 26 | 27 | metadata_source_match && metadata_source_match[1] 28 | end 29 | 30 | raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil? 31 | 32 | puts "GitHubChangelogGenerator project:#{returnVal}" 33 | returnVal 34 | end 35 | 36 | def changelog_future_release 37 | return unless Rake.application.top_level_tasks.include? "changelog" 38 | returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version'] 39 | raise "unable to find the future_release (version) in metadata.json" if returnVal.nil? 40 | puts "GitHubChangelogGenerator future_release:#{returnVal}" 41 | returnVal 42 | end 43 | 44 | PuppetLint.configuration.send('disable_relative') 45 | 46 | if Bundler.rubygems.find_name('github_changelog_generator').any? 47 | GitHubChangelogGenerator::RakeTask.new :changelog do |config| 48 | raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil? 49 | config.user = "#{changelog_user}" 50 | config.project = "#{changelog_project}" 51 | config.future_release = "#{changelog_future_release}" 52 | config.exclude_labels = ['maintenance'] 53 | config.header = "# Change log\n\nAll notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org)." 54 | config.add_pr_wo_labels = true 55 | config.issues = false 56 | config.merge_prefix = "### UNCATEGORIZED PRS; LABEL THEM ON GITHUB" 57 | config.configure_sections = { 58 | "Changed" => { 59 | "prefix" => "### Changed", 60 | "labels" => ["backwards-incompatible"], 61 | }, 62 | "Added" => { 63 | "prefix" => "### Added", 64 | "labels" => ["enhancement", "feature"], 65 | }, 66 | "Fixed" => { 67 | "prefix" => "### Fixed", 68 | "labels" => ["bug", "documentation", "bugfix"], 69 | }, 70 | } 71 | end 72 | else 73 | desc 'Generate a Changelog from GitHub' 74 | task :changelog do 75 | raise < 1.15' 84 | condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')" 85 | EOM 86 | end 87 | end 88 | 89 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.1.x.{build} 3 | branches: 4 | only: 5 | - master 6 | - release 7 | skip_commits: 8 | message: /^\(?doc\)?.*/ 9 | clone_depth: 10 10 | init: 11 | - SET 12 | - 'mkdir C:\ProgramData\PuppetLabs\code && exit 0' 13 | - 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0' 14 | - 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0' 15 | - 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0' 16 | environment: 17 | matrix: 18 | - 19 | RUBY_VERSION: 25-x64 20 | CHECK: syntax lint metadata_lint check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop 21 | - 22 | PUPPET_GEM_VERSION: ~> 6.0 23 | RUBY_VERSION: 25 24 | CHECK: parallel_spec 25 | - 26 | PUPPET_GEM_VERSION: ~> 6.0 27 | RUBY_VERSION: 25-x64 28 | CHECK: parallel_spec 29 | matrix: 30 | fast_finish: true 31 | install: 32 | - set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH% 33 | - bundle install --jobs 4 --retry 2 --without system_tests 34 | - type Gemfile.lock 35 | build: off 36 | test_script: 37 | - bundle exec puppet -V 38 | - ruby -v 39 | - gem -v 40 | - bundle -v 41 | - bundle exec rake %CHECK% 42 | notifications: 43 | - provider: Email 44 | to: 45 | - nobody@nowhere.com 46 | on_build_success: false 47 | on_build_failure: false 48 | on_build_status_changed: false 49 | -------------------------------------------------------------------------------- /data/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | github_actions_runner::ensure: present 3 | github_actions_runner::base_dir_name: '/some_dir/actions-runner' 4 | github_actions_runner::package_name: 'actions-runner-linux-x64' 5 | github_actions_runner::package_ensure: '2.292.0' 6 | github_actions_runner::repository_url: 'https://github.com/actions/runner/releases/download' 7 | github_actions_runner::personal_access_token: 'PAT' 8 | github_actions_runner::user: 'root' 9 | github_actions_runner::group: 'root' 10 | github_actions_runner::instances: {} 11 | github_actions_runner::github_domain: "https://github.com" 12 | github_actions_runner::github_api: "https://api.github.com" 13 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | defaults: 4 | datadir: data 5 | data_hash: yaml_data 6 | 7 | hierarchy: 8 | - name: "Common data" 9 | path: "common.yaml" 10 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # Class: github_actions_runner 2 | # =========================== 3 | # 4 | # Manages actions_runner service and configuration 5 | # All defaults can be viewed in the `modules/actions_runner/data/common.yaml` file. 6 | # 7 | # Parameters 8 | # ---------- 9 | # 10 | # * ensure 11 | # Enum, Determine if to add or remove the resource. 12 | # 13 | # * base_dir_name 14 | # Absolutepath, Location of the base directory for actions runner to be installed. 15 | # 16 | # * org_name 17 | # String, actions runner org name. 18 | # 19 | # * enterprise_name 20 | # String, enterprise name for global runners 21 | # 22 | # * personal_access_token 23 | # String, GitHub PAT with admin permission on the repositories or the origanization. 24 | # 25 | # * package_name 26 | # String, GitHub Actions runner offical package name. 27 | # 28 | # * package_ensure 29 | # String, GitHub Actions runner version to be used. 30 | # 31 | # * repository_url 32 | # String, URL to download GitHub actions runner. 33 | # 34 | # * user 35 | # String, User to be used in Service and directories. 36 | # 37 | # * group 38 | # String, Group to be used in Service and directories. 39 | # 40 | # * instances 41 | # Hash[String, Hash], Github Runner Instances to be managed. 42 | # 43 | # * github_domain 44 | # String, Base URL for Github Domain. 45 | # 46 | # * github_api 47 | # String, Base URL for Github API. 48 | # 49 | # * http_proxy 50 | # Optional[String], Proxy URL for HTTP traffic. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners. 51 | # 52 | # * https_proxy 53 | # Optional[String], Proxy URL for HTTPS traffic. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners 54 | # 55 | # * no_proxy 56 | # Optional[String], Comma separated list of hosts that should not use a proxy. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners 57 | # 58 | # * disable_update 59 | # Optional[Boolean], toggle for disabling automatic runner updates. 60 | # 61 | # * path 62 | # Optional[Array[String]], List of paths to be used as PATH env in the instance runner. 63 | # If not defined, file ".path" will be kept as created by the runner scripts. Default value: undef 64 | # 65 | # * env 66 | # Optional[Hash[String, String]], List of variables to be used as env variables in the instance runner. 67 | # If not defined, file ".env" will be kept as created 68 | # by the runner scripts. (Default: Value set by github_actions_runner Class) 69 | # 70 | class github_actions_runner ( 71 | Enum['present', 'absent'] $ensure, 72 | Stdlib::Absolutepath $base_dir_name, 73 | String[1] $personal_access_token, 74 | String[1] $package_name, 75 | String[1] $package_ensure, 76 | String[1] $repository_url, 77 | String[1] $user, 78 | String[1] $group, 79 | Hash[String[1], Hash] $instances, 80 | String[1] $github_domain, 81 | String[1] $github_api, 82 | Optional[String[1]] $enterprise_name = undef, 83 | Optional[String[1]] $org_name = undef, 84 | Optional[String[1]] $http_proxy = undef, 85 | Optional[String[1]] $https_proxy = undef, 86 | Optional[String[1]] $no_proxy = undef, 87 | Optional[Boolean] $disable_update = false, 88 | Optional[Array[String]] $path = undef, 89 | Optional[Hash[String, String]] $env = undef, 90 | ) { 91 | 92 | $root_dir = "${github_actions_runner::base_dir_name}-${github_actions_runner::package_ensure}" 93 | 94 | $ensure_directory = $github_actions_runner::ensure ? { 95 | 'present' => directory, 96 | 'absent' => absent, 97 | } 98 | 99 | file { $github_actions_runner::root_dir: 100 | ensure => $ensure_directory, 101 | mode => '0644', 102 | owner => $github_actions_runner::user, 103 | group => $github_actions_runner::group, 104 | force => true, 105 | } 106 | 107 | create_resources(github_actions_runner::instance, $github_actions_runner::instances) 108 | 109 | } 110 | -------------------------------------------------------------------------------- /manifests/instance.pp: -------------------------------------------------------------------------------- 1 | # == Define github_actions_runner::instance 2 | # 3 | # Configure and deploy actions runners instances 4 | # 5 | # * ensure 6 | # Enum, Determine if to add or remove the resource. 7 | # 8 | # * org_name 9 | # Optional[String], org name for organization level runners. (Default: Value set by github_actions_runner Class) 10 | # 11 | # * enterprise_name 12 | # Optional[String], enterprise name for global runners. (Default: Value set by github_actions_runner Class) 13 | # 14 | # * personal_access_token 15 | # String, GitHub PAT with admin permission on the repositories or the origanization.(Default: Value set by github_actions_runner Class) 16 | # 17 | # * user 18 | # String, User to be used in Service and directories.(Default: Value set by github_actions_runner Class) 19 | # 20 | # * group 21 | # String, Group to be used in Service and directories.(Default: Value set by github_actions_runner Class) 22 | # 23 | # * hostname 24 | # String, actions runner name. 25 | # 26 | # * instance_name 27 | # String, The instance name as part of the instances Hash. 28 | # 29 | # * http_proxy 30 | # Optional[String], Proxy URL for HTTP traffic. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners. 31 | # 32 | # * https_proxy 33 | # Optional[String], Proxy URL for HTTPS traffic. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners 34 | # 35 | # * no_proxy 36 | # Optional[String], Comma separated list of hosts that should not use a proxy. More information at https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners 37 | # 38 | # * disable_update 39 | # Optional[Boolean], toggle for disabling automatic runner updates. 40 | # 41 | # * repo_name 42 | # Optional[String], actions runner repository name. 43 | # 44 | # * labels 45 | # Optional[Array[String]], A list of costum lables to add to a runner. 46 | # 47 | # * path 48 | # Optional[Array[String]], List of paths to be used as PATH env in the instance runner. If not defined, file ".path" will be kept as created 49 | # by the runner scripts. (Default: Value set by github_actions_runner Class) 50 | # 51 | # * env 52 | # Optional[Hash[String, String]], List of variables to be used as env variables in the instance runner. 53 | # If not defined, file ".env" will be kept as created 54 | # by the runner scripts. (Default: Value set by github_actions_runner Class) 55 | # 56 | define github_actions_runner::instance ( 57 | Enum['present', 'absent'] $ensure = 'present', 58 | String[1] $personal_access_token = $github_actions_runner::personal_access_token, 59 | String[1] $user = $github_actions_runner::user, 60 | String[1] $group = $github_actions_runner::group, 61 | String[1] $hostname = $::facts['hostname'], 62 | String[1] $instance_name = $title, 63 | String[1] $github_domain = $github_actions_runner::github_domain, 64 | String[1] $github_api = $github_actions_runner::github_api, 65 | Optional[String[1]] $http_proxy = $github_actions_runner::http_proxy, 66 | Optional[String[1]] $https_proxy = $github_actions_runner::https_proxy, 67 | Optional[String[1]] $no_proxy = $github_actions_runner::no_proxy, 68 | Optional[Boolean] $disable_update = $github_actions_runner::disable_update, 69 | Optional[Array[String[1]]] $labels = undef, 70 | Optional[String[1]] $enterprise_name = $github_actions_runner::enterprise_name, 71 | Optional[String[1]] $org_name = $github_actions_runner::org_name, 72 | Optional[String[1]] $repo_name = undef, 73 | Optional[Array[String]] $path = $github_actions_runner::path, 74 | Optional[Hash[String, String]] $env = $github_actions_runner::env, 75 | ) { 76 | 77 | if $labels { 78 | $flattend_labels_list=join($labels, ',') 79 | $assured_labels="--labels ${flattend_labels_list}" 80 | } else { 81 | $assured_labels = '' 82 | } 83 | 84 | if $org_name { 85 | if $repo_name { 86 | $token_url = "${github_api}/repos/${org_name}/${repo_name}/actions/runners/registration-token" 87 | $url = "${github_domain}/${org_name}/${repo_name}" 88 | } else { 89 | $token_url = "${github_api}/orgs/${org_name}/actions/runners/registration-token" 90 | $url = "${github_domain}/${org_name}" 91 | } 92 | } elsif $enterprise_name { 93 | $token_url = "${github_api}/enterprises/${enterprise_name}/actions/runners/registration-token" 94 | $url = "${github_domain}/enterprises/${enterprise_name}" 95 | } else { 96 | fail("Either 'org_name' or 'enterprise_name' is required to create runner instances") 97 | } 98 | 99 | $archive_name = "${github_actions_runner::package_name}-${github_actions_runner::package_ensure}.tar.gz" 100 | $source = "${github_actions_runner::repository_url}/v${github_actions_runner::package_ensure}/${archive_name}" 101 | 102 | $ensure_instance_directory = $ensure ? { 103 | 'present' => directory, 104 | 'absent' => absent, 105 | } 106 | 107 | file { "${github_actions_runner::root_dir}/${instance_name}": 108 | ensure => $ensure_instance_directory, 109 | mode => '0644', 110 | owner => $user, 111 | group => $group, 112 | force => true, 113 | require => File[$github_actions_runner::root_dir], 114 | } 115 | 116 | archive { "${instance_name}-${archive_name}": 117 | ensure => $ensure, 118 | path => "/tmp/${instance_name}-${archive_name}", 119 | user => $user, 120 | group => $group, 121 | source => $source, 122 | extract => true, 123 | extract_path => "${github_actions_runner::root_dir}/${instance_name}", 124 | creates => "${github_actions_runner::root_dir}/${instance_name}/bin", 125 | cleanup => true, 126 | require => File["${github_actions_runner::root_dir}/${instance_name}"], 127 | } 128 | 129 | file { "${github_actions_runner::root_dir}/${name}/configure_install_runner.sh": 130 | ensure => $ensure, 131 | mode => '0755', 132 | owner => $user, 133 | group => $group, 134 | content => epp('github_actions_runner/configure_install_runner.sh.epp', { 135 | personal_access_token => $personal_access_token, 136 | token_url => $token_url, 137 | instance_name => $instance_name, 138 | root_dir => $github_actions_runner::root_dir, 139 | url => $url, 140 | hostname => $hostname, 141 | assured_labels => $assured_labels, 142 | disable_update => $disable_update, 143 | }), 144 | notify => Exec["${instance_name}-run_configure_install_runner.sh"], 145 | require => Archive["${instance_name}-${archive_name}"], 146 | } 147 | 148 | if $ensure == 'present' { 149 | exec { "${instance_name}-check-runner-configured": 150 | user => $user, 151 | cwd => '/srv', 152 | command => 'true', 153 | unless => "test -f ${github_actions_runner::root_dir}/${instance_name}/runsvc.sh", 154 | path => ['/bin', '/usr/bin'], 155 | notify => Exec["${instance_name}-run_configure_install_runner.sh"], 156 | } 157 | } 158 | 159 | exec { "${instance_name}-ownership": 160 | user => $user, 161 | cwd => $github_actions_runner::root_dir, 162 | command => "/bin/chown -R ${user}:${group} ${github_actions_runner::root_dir}/${instance_name}", 163 | refreshonly => true, 164 | path => ['/bin', '/usr/bin'], 165 | subscribe => Archive["${instance_name}-${archive_name}"], 166 | onlyif => "test -d ${github_actions_runner::root_dir}/${instance_name}" 167 | } 168 | 169 | exec { "${instance_name}-run_configure_install_runner.sh": 170 | user => $user, 171 | cwd => "${github_actions_runner::root_dir}/${instance_name}", 172 | command => "${github_actions_runner::root_dir}/${instance_name}/configure_install_runner.sh", 173 | refreshonly => true, 174 | path => ['/bin', '/usr/bin'], 175 | onlyif => "test -d ${github_actions_runner::root_dir}/${instance_name}" 176 | } 177 | 178 | $content_path = $path ? { 179 | undef => undef, 180 | default => epp('github_actions_runner/path.epp', { 181 | paths => $path, 182 | }) 183 | } 184 | 185 | file { "${github_actions_runner::root_dir}/${name}/.path": 186 | ensure => $ensure, 187 | mode => '0644', 188 | owner => $user, 189 | group => $group, 190 | content => $content_path, 191 | require => [Archive["${instance_name}-${archive_name}"], 192 | Exec["${instance_name}-run_configure_install_runner.sh"], 193 | ], 194 | notify => Systemd::Unit_file["github-actions-runner.${instance_name}.service"] 195 | } 196 | 197 | $content_env = $env ? { 198 | undef => undef, 199 | default => epp('github_actions_runner/env.epp', { 200 | envs => $env, 201 | }) 202 | } 203 | 204 | file { "${github_actions_runner::root_dir}/${name}/.env": 205 | ensure => $ensure, 206 | mode => '0644', 207 | owner => $user, 208 | group => $group, 209 | content => $content_env, 210 | require => [Archive["${instance_name}-${archive_name}"], 211 | Exec["${instance_name}-run_configure_install_runner.sh"], 212 | ], 213 | notify => Systemd::Unit_file["github-actions-runner.${instance_name}.service"] 214 | } 215 | 216 | $active_service = $ensure ? { 217 | 'present' => true, 218 | 'absent' => false, 219 | } 220 | 221 | $enable_service = $ensure ? { 222 | 'present' => true, 223 | 'absent' => false, 224 | } 225 | 226 | systemd::unit_file { "github-actions-runner.${instance_name}.service": 227 | ensure => $ensure, 228 | enable => $enable_service, 229 | active => $active_service, 230 | content => epp('github_actions_runner/github-actions-runner.service.epp', { 231 | instance_name => $instance_name, 232 | root_dir => $github_actions_runner::root_dir, 233 | user => $user, 234 | group => $group, 235 | http_proxy => $http_proxy, 236 | https_proxy => $https_proxy, 237 | no_proxy => $no_proxy, 238 | }), 239 | require => [File["${github_actions_runner::root_dir}/${instance_name}/configure_install_runner.sh"], 240 | File["${github_actions_runner::root_dir}/${instance_name}/.path"], 241 | Exec["${instance_name}-run_configure_install_runner.sh"]], 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telefonica-github_actions_runner", 3 | "version": "0.10.0", 4 | "author": "Shimon Ohayon", 5 | "summary": "Module to configure our GitHub Actions runner on Debian hosts", 6 | "license": "Apache-2.0", 7 | "source": "https://github.com/Telefonica/puppet-github-actions-runner", 8 | "project_page": "https://github.com/Telefonica/puppet-github-actions-runner", 9 | "issues_url": "https://github.com/Telefonica/puppet-github-actions-runner/issues", 10 | "dependencies": [ 11 | { 12 | "name": "puppetlabs-stdlib", 13 | "version_requirement": ">= 1.0.0 < 7.0.0" 14 | }, 15 | { 16 | "name": "camptocamp/systemd", 17 | "version_requirement": ">= 2.7.0 < 3.0.0" 18 | }, 19 | { 20 | "name": "puppet-archive", 21 | "version_requirement": ">= 1.1.2 < 5.0.0" 22 | } 23 | ], 24 | "data_provider": "hiera", 25 | "operatingsystem_support": [ 26 | { 27 | "operatingsystem": "Debian", 28 | "operatingsystemrelease": [ 29 | "9", 30 | "10" 31 | ] 32 | }, 33 | { 34 | "operatingsystem": "CentOS", 35 | "operatingsystemrelease": [ 36 | "7" 37 | ] 38 | }, 39 | { 40 | "operatingsystem": "Ubuntu", 41 | "operatingsystemrelease": [ 42 | "18.04" 43 | ] 44 | } 45 | ], 46 | "requirements": [ 47 | { 48 | "name": "puppet", 49 | "version_requirement": ">= 4.10.0 < 7.0.0" 50 | } 51 | ], 52 | "pdk-version": "2.1.1", 53 | "template-url": "pdk-default#2.1.1", 54 | "template-ref": "tags/2.1.1-0-g03daa92" 55 | } 56 | -------------------------------------------------------------------------------- /spec/classes/github_actions_runner_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'github_actions_runner' do 4 | on_supported_os.each do |os, os_facts| 5 | context "on #{os}" do 6 | let(:facts) { os_facts } 7 | let(:params) do 8 | { 9 | 'org_name' => 'github_org', 10 | 'instances' => { 11 | 'first_runner' => { 12 | 'labels' => ['test_label1', 'test_label2'], 13 | 'repo_name' => 'test_repo', 14 | }, 15 | }, 16 | } 17 | end 18 | 19 | context 'is expected compile' do 20 | it do 21 | is_expected.to compile.with_all_deps 22 | is_expected.to contain_class('github_actions_runner') 23 | end 24 | end 25 | 26 | context 'is expected compile and raise error when required values are undefined' do 27 | let(:params) do 28 | super().merge('org_name' => :undef, 'enterprise_name' => :undef) 29 | end 30 | 31 | it do 32 | is_expected.to compile.and_raise_error(%r{Either 'org_name' or 'enterprise_name' is required to create runner instances}) 33 | end 34 | end 35 | 36 | context 'is expected to create a github_actions_runner root directory' do 37 | it do 38 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0').with( 39 | 'ensure' => 'directory', 40 | 'owner' => 'root', 41 | 'group' => 'root', 42 | 'mode' => '0644', 43 | ) 44 | end 45 | end 46 | 47 | context 'is expected to create a github_actions_runner a new root directory' do 48 | let(:params) do 49 | super().merge('base_dir_name' => '/tmp/actions-runner') 50 | end 51 | 52 | it do 53 | is_expected.to contain_file('/tmp/actions-runner-2.292.0').with( 54 | 'ensure' => 'directory', 55 | 'owner' => 'root', 56 | 'group' => 'root', 57 | 'mode' => '0644', 58 | ) 59 | end 60 | end 61 | 62 | context 'is expected to create a github_actions_runner root directory with test user' do 63 | let(:params) do 64 | super().merge('user' => 'test_user', 65 | 'group' => 'test_group') 66 | end 67 | 68 | it do 69 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0').with( 70 | 'ensure' => 'directory', 71 | 'owner' => 'test_user', 72 | 'group' => 'test_group', 73 | 'mode' => '0644', 74 | ) 75 | end 76 | end 77 | 78 | context 'is expected to create a github_actions_runner instance directory' do 79 | it do 80 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner').with( 81 | 'ensure' => 'directory', 82 | 'owner' => 'root', 83 | 'group' => 'root', 84 | 'mode' => '0644', 85 | ) 86 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner').that_requires(['File[/some_dir/actions-runner-2.292.0]']) 87 | end 88 | end 89 | 90 | context 'is expected to create a github_actions_runner instance directory with test user' do 91 | let(:params) do 92 | super().merge('user' => 'test_user', 93 | 'group' => 'test_group') 94 | end 95 | 96 | it do 97 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner').with( 98 | 'ensure' => 'directory', 99 | 'owner' => 'test_user', 100 | 'group' => 'test_group', 101 | 'mode' => '0644', 102 | ) 103 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner').that_requires(['File[/some_dir/actions-runner-2.292.0]']) 104 | end 105 | end 106 | 107 | context 'is expected to contain archive' do 108 | it do 109 | is_expected.to contain_archive('first_runner-actions-runner-linux-x64-2.292.0.tar.gz').with( 110 | 'ensure' => 'present', 111 | 'user' => 'root', 112 | 'group' => 'root', 113 | ) 114 | is_expected.to contain_archive('first_runner-actions-runner-linux-x64-2.292.0.tar.gz').that_requires(['File[/some_dir/actions-runner-2.292.0/first_runner]']) 115 | end 116 | end 117 | 118 | context 'is expected to contain archive with test package and test url' do 119 | let(:params) do 120 | super().merge('package_name' => 'test_package', 121 | 'package_ensure' => '9.9.9', 122 | 'repository_url' => 'https://test_url') 123 | end 124 | 125 | it do 126 | is_expected.to contain_archive('first_runner-test_package-9.9.9.tar.gz').with( 127 | 'ensure' => 'present', 128 | 'user' => 'root', 129 | 'group' => 'root', 130 | 'source' => 'https://test_url/v9.9.9/test_package-9.9.9.tar.gz', 131 | ) 132 | is_expected.to contain_archive('first_runner-test_package-9.9.9.tar.gz').that_requires(['File[/some_dir/actions-runner-9.9.9/first_runner]']) 133 | end 134 | end 135 | 136 | context 'is expected to contain an ownership exec' do 137 | it do 138 | is_expected.to contain_exec('first_runner-ownership').with( 139 | 'user' => 'root', 140 | 'command' => '/bin/chown -R root:root /some_dir/actions-runner-2.292.0/first_runner', 141 | ) 142 | is_expected.to contain_exec('first_runner-ownership').that_subscribes_to('Archive[first_runner-actions-runner-linux-x64-2.292.0.tar.gz]') 143 | end 144 | end 145 | 146 | context 'is expected to contain a exec checking runner configured' do 147 | it do 148 | is_expected.to contain_exec('first_runner-check-runner-configured').with( 149 | 'user' => 'root', 150 | 'command' => 'true', 151 | 'unless' => 'test -f /some_dir/actions-runner-2.292.0/first_runner/runsvc.sh', 152 | 'path' => ['/bin', '/usr/bin'], 153 | ) 154 | is_expected.to contain_exec('first_runner-check-runner-configured').that_notifies('Exec[first_runner-run_configure_install_runner.sh]') 155 | end 156 | end 157 | 158 | context 'is expected to contain a Run exec' do 159 | it do 160 | is_expected.to contain_exec('first_runner-run_configure_install_runner.sh').with( 161 | 'user' => 'root', 162 | 'command' => '/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh', 163 | ) 164 | end 165 | end 166 | 167 | context 'installation scripts for different types of runners' do 168 | let(:params) do 169 | super().merge( 170 | 'org_name' => :undef, 171 | 'enterprise_name' => :undef, 172 | 'instances' => { 173 | 'first_runner' => { 174 | 'org_name' => 'github_org', 175 | 'repo_name' => 'test_repo', 176 | }, 177 | 'org_runner' => { 178 | 'org_name' => 'github_org', 179 | 'labels' => ['default'], 180 | }, 181 | 'enterprise_runner' => { 182 | 'org_name' => :undef, 183 | 'enterprise_name' => 'test_enterprise', 184 | 'labels' => ['default'], 185 | }, 186 | }, 187 | ) 188 | end 189 | 190 | it 'creates a repo specific runner script' do 191 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with( 192 | 'ensure' => 'present', 193 | 'owner' => 'root', 194 | 'group' => 'root', 195 | 'mode' => '0755', 196 | ) 197 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content( 198 | %r{https://api.github.com/repos/github_org/test_repo/actions/runners/registration-token}, 199 | ) 200 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--url https://github.com/github_org/test_repo }) 201 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--name foo-first_runner }) 202 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').that_requires('Archive[first_runner-actions-runner-linux-x64-2.292.0.tar.gz]') 203 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').that_notifies('Exec[first_runner-run_configure_install_runner.sh]') 204 | end 205 | 206 | it 'creates an org specific runner script' do 207 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').with( 208 | 'ensure' => 'present', 209 | 'owner' => 'root', 210 | 'group' => 'root', 211 | 'mode' => '0755', 212 | ) 213 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').with_content( 214 | %r{https://api.github.com/orgs/github_org/actions/runners/registration-token}, 215 | ) 216 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').with_content(%r{--url https://github.com/github_org }) 217 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').with_content(%r{--name foo-org_runner }) 218 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').that_requires('Archive[org_runner-actions-runner-linux-x64-2.292.0.tar.gz]') 219 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/org_runner/configure_install_runner.sh').that_notifies('Exec[org_runner-run_configure_install_runner.sh]') 220 | end 221 | 222 | it 'creates an enterprise specific runner script' do 223 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').with( 224 | 'ensure' => 'present', 225 | 'owner' => 'root', 226 | 'group' => 'root', 227 | 'mode' => '0755', 228 | ) 229 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').with_content( 230 | %r{https://api.github.com/enterprises/test_enterprise/actions/runners/registration-token}, 231 | ) 232 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').with_content(%r{--url https://github.com/enterprises/test_enterprise }) 233 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').with_content(%r{--name foo-enterprise_runner }) 234 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').that_requires( 235 | 'Archive[enterprise_runner-actions-runner-linux-x64-2.292.0.tar.gz]', 236 | ) 237 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/enterprise_runner/configure_install_runner.sh').that_notifies('Exec[enterprise_runner-run_configure_install_runner.sh]') 238 | end 239 | end 240 | 241 | context 'is expected to create a github_actions_runner installation script with test version' do 242 | let(:params) do 243 | super().merge('package_ensure' => '9.9.9') 244 | end 245 | 246 | it do 247 | is_expected.to contain_file('/some_dir/actions-runner-9.9.9/first_runner/configure_install_runner.sh').with( 248 | 'ensure' => 'present', 249 | 'owner' => 'root', 250 | 'group' => 'root', 251 | 'mode' => '0755', 252 | ) 253 | is_expected.to contain_file('/some_dir/actions-runner-9.9.9/first_runner/configure_install_runner.sh').that_requires('Archive[first_runner-actions-runner-linux-x64-9.9.9.tar.gz]') 254 | is_expected.to contain_file('/some_dir/actions-runner-9.9.9/first_runner/configure_install_runner.sh').that_notifies('Exec[first_runner-run_configure_install_runner.sh]') 255 | end 256 | end 257 | 258 | context 'is expected to create a github_actions_runner installation script with config in content' do 259 | it do 260 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{/some_dir/actions-runner-2.292.0/first_runner/config.sh}) 261 | end 262 | end 263 | 264 | context 'is expected to create a github_actions_runner installation script with github org in content' do 265 | it do 266 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://github.com/github_org/test_repo}) 267 | end 268 | end 269 | 270 | context 'is expected to create a github_actions_runner installation script with test_org in content ignoring enterprise_name' do 271 | let(:params) do 272 | super().merge('org_name' => 'test_org', 'enterprise_name' => 'test_enterprise') 273 | end 274 | 275 | it do 276 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://github.com/test_org/test_repo}) 277 | end 278 | end 279 | 280 | context 'is expected to create a github_actions_runner installation script with test_org in content' do 281 | let(:params) do 282 | super().merge('org_name' => 'test_org') 283 | end 284 | 285 | it do 286 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://github.com/test_org/test_repo}) 287 | end 288 | end 289 | 290 | context 'is expected to create a github_actions_runner installation script with test_enterprise in content' do 291 | let(:params) do 292 | super().merge('org_name' => :undef, 293 | 'enterprise_name' => 'test_enterprise') 294 | end 295 | 296 | it do 297 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://github.com/enterprises/test_enterprise}) 298 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--url https://github.com/enterprises/test_enterprise }) 299 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--name foo-first_runner }) 300 | end 301 | end 302 | 303 | context 'is expected to create a github_actions_runner installation script with labels in content' do 304 | it do 305 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{test_label1,test_label2}) 306 | end 307 | end 308 | 309 | context 'is expected to create a github_actions_runner installation script with PAT in content' do 310 | it do 311 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{authorization: token PAT}) 312 | end 313 | end 314 | 315 | context 'is expected to create a github_actions_runner installation script with test_PAT in content' do 316 | let(:params) do 317 | super().merge('personal_access_token' => 'test_PAT') 318 | end 319 | 320 | it do 321 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{authorization: token test_PAT}) 322 | end 323 | end 324 | 325 | context 'is expected to create a github_actions_runner installation script with disableupdate in content' do 326 | let(:params) do 327 | super().merge('disable_update' => true) 328 | end 329 | 330 | it do 331 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{disableupdate}) 332 | end 333 | end 334 | 335 | context 'is expected to create a github_actions_runner with service active and enabled' do 336 | let(:params) do 337 | super().merge( 338 | 'http_proxy' => 'http://proxy.local', 339 | 'https_proxy' => 'http://proxy.local', 340 | 'no_proxy' => 'example.com', 341 | 'instances' => { 342 | 'first_runner' => { 343 | 'labels' => ['test_label1'], 344 | 'repo_name' => 'test_repo', 345 | }, 346 | }, 347 | ) 348 | end 349 | 350 | it do 351 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with( 352 | 'ensure' => 'present', 353 | 'enable' => true, 354 | 'active' => true, 355 | ) 356 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').that_requires(['File[/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh]', 357 | 'File[/some_dir/actions-runner-2.292.0/first_runner/.path]', 358 | 'Exec[first_runner-run_configure_install_runner.sh]']) 359 | end 360 | end 361 | 362 | context 'is expected to create a .path file with a specific requires and notifies' do 363 | it do 364 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path') 365 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path').that_requires(['Archive[first_runner-actions-runner-linux-x64-2.292.0.tar.gz]', 366 | 'Exec[first_runner-run_configure_install_runner.sh]']) 367 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path').that_notifies('Systemd::Unit_file[github-actions-runner.first_runner.service]') 368 | end 369 | end 370 | 371 | context 'is expected to create a .path file in an instance with default path list' do 372 | it do 373 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path').with( 374 | 'ensure' => 'present', 375 | 'owner' => 'root', 376 | 'group' => 'root', 377 | 'mode' => '0644', 378 | 'content' => nil, 379 | ) 380 | end 381 | end 382 | 383 | context 'is expected to create a .path file in an instance, setting path at global level' do 384 | let(:params) do 385 | super().merge( 386 | 'path' => [ 387 | '/usr/bin', 388 | '/bin', 389 | ], 390 | ) 391 | end 392 | 393 | it do 394 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path').with( 395 | 'ensure' => 'present', 396 | 'owner' => 'root', 397 | 'group' => 'root', 398 | 'mode' => '0644', 399 | 'content' => "/usr/bin:/bin\n", 400 | ) 401 | end 402 | end 403 | 404 | context 'is expected to create a .path file in an instance, setting the path at instance level' do 405 | let(:params) do 406 | super().merge( 407 | 'path' => [ 408 | '/usr/bin', 409 | '/bin', 410 | ], 411 | 'instances' => { 412 | 'first_runner' => { 413 | 'path' => [ 414 | '/bin', 415 | '/other/path', 416 | ] 417 | }, 418 | }, 419 | ) 420 | end 421 | 422 | it do 423 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.path').with( 424 | 'ensure' => 'present', 425 | 'owner' => 'root', 426 | 'group' => 'root', 427 | 'mode' => '0644', 428 | 'content' => "/bin:/other/path\n", 429 | ) 430 | end 431 | end 432 | 433 | # .env 434 | context 'is expected to create a .env file with a specific requires and notifies' do 435 | it do 436 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env') 437 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env').that_requires(['Archive[first_runner-actions-runner-linux-x64-2.292.0.tar.gz]', 438 | 'Exec[first_runner-run_configure_install_runner.sh]']) 439 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env').that_notifies('Systemd::Unit_file[github-actions-runner.first_runner.service]') 440 | end 441 | end 442 | 443 | context 'is expected to create a .env file in an instance with default env hash (nil content)' do 444 | it do 445 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env').with( 446 | 'ensure' => 'present', 447 | 'owner' => 'root', 448 | 'group' => 'root', 449 | 'mode' => '0644', 450 | 'content' => nil, 451 | ) 452 | end 453 | end 454 | 455 | context 'is expected to create a .env file in an instance, setting env at global level' do 456 | let(:params) do 457 | super().merge( 458 | 'env' => { 459 | 'foo' => 'bar', 460 | 'key' => 'value', 461 | }, 462 | ) 463 | end 464 | 465 | it do 466 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env').with( 467 | 'ensure' => 'present', 468 | 'owner' => 'root', 469 | 'group' => 'root', 470 | 'mode' => '0644', 471 | 'content' => "foo=bar\nkey=value\n", 472 | ) 473 | end 474 | end 475 | 476 | context 'is expected to create a .env file in an instance, setting the env at instance level' do 477 | let(:params) do 478 | super().merge( 479 | 'env' => { 480 | 'foo' => 'bar', 481 | 'key' => 'value', 482 | }, 483 | 'instances' => { 484 | 'first_runner' => { 485 | 'env' => { 486 | 'other' => 'value', 487 | } 488 | }, 489 | }, 490 | ) 491 | end 492 | 493 | it do 494 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/.env').with( 495 | 'ensure' => 'present', 496 | 'owner' => 'root', 497 | 'group' => 'root', 498 | 'mode' => '0644', 499 | 'content' => "other=value\n", 500 | ) 501 | end 502 | end 503 | 504 | context 'is expected to remove github_actions_runner unit_file and other resources' do 505 | let(:params) do 506 | super().merge( 507 | 'http_proxy' => 'http://proxy.local', 508 | 'https_proxy' => 'http://proxy.local', 509 | 'no_proxy' => 'example.com', 510 | 'instances' => { 511 | 'first_runner' => { 512 | 'ensure' => 'absent', 513 | 'labels' => ['test_label1'], 514 | 'repo_name' => 'test_repo', 515 | }, 516 | }, 517 | ) 518 | end 519 | 520 | it do 521 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with( 522 | 'ensure' => 'absent', 523 | 'enable' => false, 524 | 'active' => false, 525 | ) 526 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner').with( 527 | 'ensure' => 'absent', 528 | ) 529 | is_expected.to contain_archive('first_runner-actions-runner-linux-x64-2.292.0.tar.gz').with( 530 | 'ensure' => 'absent', 531 | ) 532 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with( 533 | 'ensure' => 'absent', 534 | ) 535 | 536 | is_expected.not_to contain_exec('first_runner-check-runner-configured') 537 | is_expected.to contain_exec('first_runner-ownership') 538 | is_expected.to contain_exec('first_runner-run_configure_install_runner.sh') 539 | end 540 | end 541 | 542 | context 'is expected to create a github_actions_runner installation with proxy settings in systemd globally in init.pp' do 543 | let(:params) do 544 | super().merge( 545 | 'http_proxy' => 'http://proxy.local', 546 | 'https_proxy' => 'http://proxy.local', 547 | 'no_proxy' => 'example.com', 548 | 'instances' => { 549 | 'first_runner' => { 550 | 'labels' => ['test_label1'], 551 | 'repo_name' => 'test_repo', 552 | }, 553 | }, 554 | ) 555 | end 556 | 557 | it do 558 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="http_proxy=http://proxy.local"}) 559 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="https_proxy=http://proxy.local"}) 560 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="no_proxy=example.com"}) 561 | end 562 | end 563 | 564 | context 'is expected to create a github_actions_runner installation with proxy settings in systemd globally in init.pp overwriting in a instance' do 565 | let(:params) do 566 | super().merge( 567 | 'http_proxy' => 'http://proxy.local', 568 | 'https_proxy' => 'http://proxy.local', 569 | 'no_proxy' => 'example.com', 570 | 'instances' => { 571 | 'first_runner' => { 572 | 'labels' => ['test_label1'], 573 | 'repo_name' => 'test_repo', 574 | 'http_proxy' => 'http://newproxy.local', 575 | }, 576 | }, 577 | ) 578 | end 579 | 580 | it do 581 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="http_proxy=http://newproxy.local"}) 582 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="https_proxy=http://proxy.local"}) 583 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="no_proxy=example.com"}) 584 | end 585 | end 586 | 587 | context 'is expected to create a github_actions_runner installation with proxy settings in systemd' do 588 | let(:params) do 589 | super().merge( 590 | 'instances' => { 591 | 'first_runner' => { 592 | 'labels' => ['test_label1'], 593 | 'repo_name' => 'test_repo', 594 | 'http_proxy' => 'http://proxy.local', 595 | 'https_proxy' => 'http://proxy.local', 596 | 'no_proxy' => 'example.com', 597 | }, 598 | }, 599 | ) 600 | end 601 | 602 | it do 603 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="http_proxy=http://proxy.local"}) 604 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="https_proxy=http://proxy.local"}) 605 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').with_content(%r{Environment="no_proxy=example.com"}) 606 | end 607 | end 608 | 609 | context 'is expected to create a github_actions_runner installation without proxy settings in systemd' do 610 | let(:params) do 611 | super().merge( 612 | 'instances' => { 613 | 'first_runner' => { 614 | 'labels' => ['test_label1'], 615 | 'repo_name' => 'test_repo', 616 | }, 617 | }, 618 | ) 619 | end 620 | 621 | it do 622 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').without_content(%r{Environment="http_proxy=http://proxy.local"}) 623 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').without_content(%r{Environment="https_proxy=http://proxy.local"}) 624 | is_expected.to contain_systemd__unit_file('github-actions-runner.first_runner.service').without_content(%r{Environment="no_proxy=example.com"}) 625 | end 626 | end 627 | 628 | context 'is expected to create a github_actions_runner installation with another URLs for domain and API' do 629 | let(:params) do 630 | super().merge( 631 | 'github_domain' => 'https://git.example.com', 632 | 'github_api' => 'https://git.example.com/api/v3', 633 | 'instances' => { 634 | 'first_runner' => { 635 | 'labels' => ['test_label1'], 636 | 'repo_name' => 'test_repo', 637 | }, 638 | }, 639 | ) 640 | end 641 | 642 | it do 643 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--url https://git.example.com}) 644 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://git.example.com/api/v3.* \| jq -r .token}) 645 | end 646 | end 647 | 648 | context 'is expected to create a github_actions_runner installation with another URLs for domain and API per instance' do 649 | let(:params) do 650 | super().merge( 651 | 'instances' => { 652 | 'first_runner' => { 653 | 'labels' => ['test_label1'], 654 | 'repo_name' => 'test_repo', 655 | }, 656 | 'second_runner' => { 657 | 'labels' => ['test_label1'], 658 | 'repo_name' => 'test_repo', 659 | 'github_domain' => 'https://git.example.foo', 660 | 'github_api' => 'https://git.example.foo/api/v2', 661 | }, 662 | }, 663 | ) 664 | end 665 | 666 | it do 667 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{--url https://github.com}) 668 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/first_runner/configure_install_runner.sh').with_content(%r{https://api.github.com/.* \| jq -r .token}) 669 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/second_runner/configure_install_runner.sh').with_content(%r{--url https://git.example.foo}) 670 | is_expected.to contain_file('/some_dir/actions-runner-2.292.0/second_runner/configure_install_runner.sh').with_content(%r{https://git.example.foo/api/v2/.* \| jq -r .token}) 671 | end 672 | end 673 | end 674 | end 675 | end 676 | -------------------------------------------------------------------------------- /spec/default_facts.yml: -------------------------------------------------------------------------------- 1 | # Use default_module_facts.yml for module specific facts. 2 | # 3 | # Facts specified here will override the values provided by rspec-puppet-facts. 4 | --- 5 | ipaddress: "172.16.254.254" 6 | ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" 7 | is_pe: false 8 | macaddress: "AA:AA:AA:AA:AA:AA" 9 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |c| 4 | c.mock_with :rspec 5 | end 6 | 7 | require 'puppetlabs_spec_helper/module_spec_helper' 8 | require 'rspec-puppet-facts' 9 | 10 | require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) 11 | 12 | include RspecPuppetFacts 13 | 14 | default_facts = { 15 | puppetversion: Puppet.version, 16 | facterversion: Facter.version, 17 | } 18 | 19 | default_fact_files = [ 20 | File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), 21 | File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), 22 | ] 23 | 24 | default_fact_files.each do |f| 25 | next unless File.exist?(f) && File.readable?(f) && File.size?(f) 26 | 27 | begin 28 | default_facts.merge!(YAML.safe_load(File.read(f), [], [], true)) 29 | rescue => e 30 | RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" 31 | end 32 | end 33 | 34 | # read default_facts and merge them over what is provided by facterdb 35 | default_facts.each do |fact, value| 36 | add_custom_fact fact, value 37 | end 38 | 39 | RSpec.configure do |c| 40 | c.default_facts = default_facts 41 | c.before :each do 42 | # set to strictest setting for testing 43 | # by default Puppet runs at warning level 44 | Puppet.settings[:strict] = :warning 45 | Puppet.settings[:strict_variables] = true 46 | end 47 | c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] 48 | c.after(:suite) do 49 | end 50 | 51 | # Filter backtrace noise 52 | backtrace_exclusion_patterns = [ 53 | %r{spec_helper}, 54 | %r{gems}, 55 | ] 56 | 57 | if c.respond_to?(:backtrace_exclusion_patterns) 58 | c.backtrace_exclusion_patterns = backtrace_exclusion_patterns 59 | elsif c.respond_to?(:backtrace_clean_patterns) 60 | c.backtrace_clean_patterns = backtrace_exclusion_patterns 61 | end 62 | end 63 | 64 | # Ensures that a module is defined 65 | # @param module_name Name of the module 66 | def ensure_module_defined(module_name) 67 | module_name.split('::').reduce(Object) do |last_module, next_module| 68 | last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) 69 | last_module.const_get(next_module, false) 70 | end 71 | end 72 | 73 | # 'spec_overrides' from sync.yml will appear below this line 74 | -------------------------------------------------------------------------------- /templates/configure_install_runner.sh.epp: -------------------------------------------------------------------------------- 1 | <%- | String $personal_access_token, 2 | String $token_url, 3 | String $instance_name, 4 | Stdlib::Absolutepath $root_dir, 5 | String $url, 6 | String $hostname, 7 | String $assured_labels, 8 | Boolean $disable_update, 9 | | -%> 10 | #!/bin/bash 11 | # Configure the action runner after the package file has been downloaded. 12 | set -e 13 | 14 | # Get registration token. 15 | TOKEN=$(curl -s -XPOST -H "authorization: token <%= $personal_access_token %>" \ 16 | <%= $token_url %> | jq -r .token) 17 | 18 | # Allow root 19 | export RUNNER_ALLOW_RUNASROOT=true 20 | 21 | 22 | # (Optional) Remove previous config. 23 | <%= $root_dir %>/<%= $instance_name %>/config.sh remove \ 24 | --url <%= $url %> \ 25 | --token ${TOKEN} \ 26 | --name <%= $hostname %>-<%= $instance_name %> &>/dev/null 27 | 28 | 29 | # Configure the runner. 30 | <%= $root_dir %>/<%= $instance_name %>/config.sh \ 31 | --unattended \ 32 | --replace \ 33 | --name <%= $hostname %>-<%= $instance_name %> \ 34 | --url <%= $url %> \ 35 | --token ${TOKEN} \ 36 | <%- if $disable_update { -%> 37 | --disableupdate \ 38 | <%- } -%> 39 | <%= $assured_labels %> &>/dev/null 40 | 41 | # Copy service endpoint script. 42 | if [ ! -f <%= $root_dir %>/<%= $instance_name %>/runsvc.sh ]; then 43 | cp <%= $root_dir %>/<%= $instance_name %>/bin/runsvc.sh <%= $root_dir %>/<%= $instance_name %>/runsvc.sh 44 | chmod 755 <%= $root_dir %>/<%= $instance_name %>/runsvc.sh 45 | fi 46 | -------------------------------------------------------------------------------- /templates/env.epp: -------------------------------------------------------------------------------- 1 | <%- | Hash[String, String] $envs, 2 | | -%> 3 | <%- $envs.each |$key, $value| { -%> 4 | <%= $key %>=<%= $value %> 5 | <%- } -%> 6 | -------------------------------------------------------------------------------- /templates/github-actions-runner.service.epp: -------------------------------------------------------------------------------- 1 | <%- | String $instance_name, 2 | Stdlib::Absolutepath $root_dir, 3 | String $user, 4 | String $group, 5 | Optional[String] $http_proxy = undef, 6 | Optional[String] $https_proxy = undef, 7 | Optional[String] $no_proxy = undef 8 | | -%> 9 | [Unit] 10 | Description=github-actions-runner-<%= $instance_name %> 11 | After=network.target 12 | 13 | [Service] 14 | <% if $http_proxy { -%> 15 | Environment="http_proxy=<%= $http_proxy %>" 16 | <% } -%> 17 | <% if $https_proxy { -%> 18 | Environment="https_proxy=<%= $https_proxy %>" 19 | <% } -%> 20 | <% if $no_proxy { -%> 21 | Environment="no_proxy=<%= $no_proxy %>" 22 | <% } -%> 23 | ExecStart=<%= $root_dir %>/<%= $instance_name %>/runsvc.sh 24 | WorkingDirectory=<%= $root_dir %>/<%= $instance_name %> 25 | KillMode=process 26 | KillSignal=SIGTERM 27 | TimeoutStopSec=5min 28 | User=<%= $user %> 29 | Group=<%= $group %> 30 | 31 | Restart=on-failure 32 | RestartSec=5s 33 | 34 | [Install] 35 | WantedBy=multi-user.target 36 | -------------------------------------------------------------------------------- /templates/path.epp: -------------------------------------------------------------------------------- 1 | <%- | Array[String] $paths, 2 | | -%> 3 | <%= join($paths, ':') %> 4 | --------------------------------------------------------------------------------