mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
add a puppet module to manage MDM features (#12032)
Related to #11185 this adds a Puppet module that provides: 1. A custom type named `fleetdm::profile` that can be used to define profiles to a device 2. A function named `fleetdm::release_device` that can be used to release a device from await device configuration. Instructions/usage can be found in the `README.md` file. --------- Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
This commit is contained in:
parent
46ee3af436
commit
c7488663f2
29 changed files with 1371 additions and 0 deletions
|
|
@ -9,6 +9,9 @@ go.mod @fleetdm/go
|
|||
# Compliance
|
||||
/ee/cis/ @sharon-fdm @lucasmrod @marcosd4h @rachelElysia
|
||||
|
||||
# MDM
|
||||
/ee/tools/puppet @roperzh @gillespi314 @mna @georgekarrv
|
||||
|
||||
# React engineers are automatically added as reviewers when changes are made to react files
|
||||
/frontend/ @fleetdm/frontend
|
||||
|
||||
|
|
|
|||
5
ee/tools/puppet/fleetdm/.gitattributes
vendored
Normal file
5
ee/tools/puppet/fleetdm/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
*.rb eol=lf
|
||||
*.erb eol=lf
|
||||
*.pp eol=lf
|
||||
*.sh eol=lf
|
||||
*.epp eol=lf
|
||||
28
ee/tools/puppet/fleetdm/.gitignore
vendored
Normal file
28
ee/tools/puppet/fleetdm/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
.git/
|
||||
.*.sw[op]
|
||||
.metadata
|
||||
.yardoc
|
||||
.yardwarns
|
||||
*.iml
|
||||
/.bundle/
|
||||
/.idea/
|
||||
/.vagrant/
|
||||
/coverage/
|
||||
/bin/
|
||||
/doc/
|
||||
/Gemfile.local
|
||||
/Gemfile.lock
|
||||
/junit/
|
||||
/log/
|
||||
/pkg/
|
||||
/spec/fixtures/manifests/
|
||||
/spec/fixtures/modules/
|
||||
/tmp/
|
||||
/vendor/
|
||||
/convert_report.txt
|
||||
/update_report.txt
|
||||
.DS_Store
|
||||
.project
|
||||
.envrc
|
||||
/inventory.yaml
|
||||
/spec/fixtures/litmus_inventory.yaml
|
||||
46
ee/tools/puppet/fleetdm/.pdkignore
Normal file
46
ee/tools/puppet/fleetdm/.pdkignore
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
.git/
|
||||
.*.sw[op]
|
||||
.metadata
|
||||
.yardoc
|
||||
.yardwarns
|
||||
*.iml
|
||||
/.bundle/
|
||||
/.idea/
|
||||
/.vagrant/
|
||||
/coverage/
|
||||
/bin/
|
||||
/doc/
|
||||
/Gemfile.local
|
||||
/Gemfile.lock
|
||||
/junit/
|
||||
/log/
|
||||
/pkg/
|
||||
/spec/fixtures/manifests/
|
||||
/spec/fixtures/modules/
|
||||
/tmp/
|
||||
/vendor/
|
||||
/convert_report.txt
|
||||
/update_report.txt
|
||||
.DS_Store
|
||||
.project
|
||||
.envrc
|
||||
/inventory.yaml
|
||||
/spec/fixtures/litmus_inventory.yaml
|
||||
/appveyor.yml
|
||||
/.editorconfig
|
||||
/.fixtures.yml
|
||||
/Gemfile
|
||||
/.gitattributes
|
||||
/.gitignore
|
||||
/.gitlab-ci.yml
|
||||
/.pdkignore
|
||||
/.puppet-lint.rc
|
||||
/Rakefile
|
||||
/rakelib/
|
||||
/.rspec
|
||||
/.rubocop.yml
|
||||
/.yardopts
|
||||
/spec/
|
||||
/.vscode/
|
||||
/.sync.yml
|
||||
/.devcontainer/
|
||||
1
ee/tools/puppet/fleetdm/.puppet-lint.rc
Normal file
1
ee/tools/puppet/fleetdm/.puppet-lint.rc
Normal file
|
|
@ -0,0 +1 @@
|
|||
--relative
|
||||
2
ee/tools/puppet/fleetdm/.rspec
Normal file
2
ee/tools/puppet/fleetdm/.rspec
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
--color
|
||||
--format documentation
|
||||
519
ee/tools/puppet/fleetdm/.rubocop.yml
Normal file
519
ee/tools/puppet/fleetdm/.rubocop.yml
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
---
|
||||
require:
|
||||
- rubocop-performance
|
||||
- rubocop-rspec
|
||||
AllCops:
|
||||
DisplayCopNames: true
|
||||
TargetRubyVersion: '2.5'
|
||||
Include:
|
||||
- "**/*.rb"
|
||||
Exclude:
|
||||
- bin/*
|
||||
- ".vendor/**/*"
|
||||
- "**/Gemfile"
|
||||
- "**/Rakefile"
|
||||
- pkg/**/*
|
||||
- spec/fixtures/**/*
|
||||
- vendor/**/*
|
||||
- "**/Puppetfile"
|
||||
- "**/Vagrantfile"
|
||||
- "**/Guardfile"
|
||||
Layout/LineLength:
|
||||
Description: People have wide screens, use them.
|
||||
Max: 200
|
||||
RSpec/BeforeAfterAll:
|
||||
Description: Beware of using after(:all) as it may cause state to leak between tests.
|
||||
A necessary evil in acceptance testing.
|
||||
Exclude:
|
||||
- spec/acceptance/**/*.rb
|
||||
RSpec/HookArgument:
|
||||
Description: Prefer explicit :each argument, matching existing module's style
|
||||
EnforcedStyle: each
|
||||
RSpec/DescribeSymbol:
|
||||
Exclude:
|
||||
- spec/unit/facter/**/*.rb
|
||||
Style/BlockDelimiters:
|
||||
Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to
|
||||
be consistent then.
|
||||
EnforcedStyle: braces_for_chaining
|
||||
Style/ClassAndModuleChildren:
|
||||
Description: Compact style reduces the required amount of indentation.
|
||||
EnforcedStyle: compact
|
||||
Style/EmptyElse:
|
||||
Description: Enforce against empty else clauses, but allow `nil` for clarity.
|
||||
EnforcedStyle: empty
|
||||
Style/FormatString:
|
||||
Description: Following the main puppet project's style, prefer the % format format.
|
||||
EnforcedStyle: percent
|
||||
Style/FormatStringToken:
|
||||
Description: Following the main puppet project's style, prefer the simpler template
|
||||
tokens over annotated ones.
|
||||
EnforcedStyle: template
|
||||
Style/Lambda:
|
||||
Description: Prefer the keyword for easier discoverability.
|
||||
EnforcedStyle: literal
|
||||
Style/RegexpLiteral:
|
||||
Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168
|
||||
EnforcedStyle: percent_r
|
||||
Style/TernaryParentheses:
|
||||
Description: Checks for use of parentheses around ternary conditions. Enforce parentheses
|
||||
on complex expressions for better readability, but seriously consider breaking
|
||||
it up.
|
||||
EnforcedStyle: require_parentheses_when_complex
|
||||
Style/TrailingCommaInArguments:
|
||||
Description: Prefer always trailing comma on multiline argument lists. This makes
|
||||
diffs, and re-ordering nicer.
|
||||
EnforcedStyleForMultiline: comma
|
||||
Style/TrailingCommaInArrayLiteral:
|
||||
Description: Prefer always trailing comma on multiline literals. This makes diffs,
|
||||
and re-ordering nicer.
|
||||
EnforcedStyleForMultiline: comma
|
||||
Style/SymbolArray:
|
||||
Description: Using percent style obscures symbolic intent of array's contents.
|
||||
EnforcedStyle: brackets
|
||||
RSpec/MessageSpies:
|
||||
EnforcedStyle: receive
|
||||
Style/Documentation:
|
||||
Exclude:
|
||||
- lib/puppet/parser/functions/**/*
|
||||
- spec/**/*
|
||||
Style/WordArray:
|
||||
EnforcedStyle: brackets
|
||||
Performance/AncestorsInclude:
|
||||
Enabled: true
|
||||
Performance/BigDecimalWithNumericArgument:
|
||||
Enabled: true
|
||||
Performance/BlockGivenWithExplicitBlock:
|
||||
Enabled: true
|
||||
Performance/CaseWhenSplat:
|
||||
Enabled: true
|
||||
Performance/ConstantRegexp:
|
||||
Enabled: true
|
||||
Performance/MethodObjectAsBlock:
|
||||
Enabled: true
|
||||
Performance/RedundantSortBlock:
|
||||
Enabled: true
|
||||
Performance/RedundantStringChars:
|
||||
Enabled: true
|
||||
Performance/ReverseFirst:
|
||||
Enabled: true
|
||||
Performance/SortReverse:
|
||||
Enabled: true
|
||||
Performance/Squeeze:
|
||||
Enabled: true
|
||||
Performance/StringInclude:
|
||||
Enabled: true
|
||||
Performance/Sum:
|
||||
Enabled: true
|
||||
Style/CollectionMethods:
|
||||
Enabled: true
|
||||
Style/MethodCalledOnDoEndBlock:
|
||||
Enabled: true
|
||||
Style/StringMethods:
|
||||
Enabled: true
|
||||
Bundler/InsecureProtocolSource:
|
||||
Enabled: false
|
||||
Gemspec/DuplicatedAssignment:
|
||||
Enabled: false
|
||||
Gemspec/OrderedDependencies:
|
||||
Enabled: false
|
||||
Gemspec/RequiredRubyVersion:
|
||||
Enabled: false
|
||||
Gemspec/RubyVersionGlobalsUsage:
|
||||
Enabled: false
|
||||
Layout/ArgumentAlignment:
|
||||
Enabled: false
|
||||
Layout/BeginEndAlignment:
|
||||
Enabled: false
|
||||
Layout/ClosingHeredocIndentation:
|
||||
Enabled: false
|
||||
Layout/EmptyComment:
|
||||
Enabled: false
|
||||
Layout/EmptyLineAfterGuardClause:
|
||||
Enabled: false
|
||||
Layout/EmptyLinesAroundArguments:
|
||||
Enabled: false
|
||||
Layout/EmptyLinesAroundAttributeAccessor:
|
||||
Enabled: false
|
||||
Layout/EndOfLine:
|
||||
Enabled: false
|
||||
Layout/FirstArgumentIndentation:
|
||||
Enabled: false
|
||||
Layout/HashAlignment:
|
||||
Enabled: false
|
||||
Layout/HeredocIndentation:
|
||||
Enabled: false
|
||||
Layout/LeadingEmptyLines:
|
||||
Enabled: false
|
||||
Layout/SpaceAroundMethodCallOperator:
|
||||
Enabled: false
|
||||
Layout/SpaceInsideArrayLiteralBrackets:
|
||||
Enabled: false
|
||||
Layout/SpaceInsideReferenceBrackets:
|
||||
Enabled: false
|
||||
Lint/BigDecimalNew:
|
||||
Enabled: false
|
||||
Lint/BooleanSymbol:
|
||||
Enabled: false
|
||||
Lint/ConstantDefinitionInBlock:
|
||||
Enabled: false
|
||||
Lint/DeprecatedOpenSSLConstant:
|
||||
Enabled: false
|
||||
Lint/DisjunctiveAssignmentInConstructor:
|
||||
Enabled: false
|
||||
Lint/DuplicateElsifCondition:
|
||||
Enabled: false
|
||||
Lint/DuplicateRequire:
|
||||
Enabled: false
|
||||
Lint/DuplicateRescueException:
|
||||
Enabled: false
|
||||
Lint/EmptyConditionalBody:
|
||||
Enabled: false
|
||||
Lint/EmptyFile:
|
||||
Enabled: false
|
||||
Lint/ErbNewArguments:
|
||||
Enabled: false
|
||||
Lint/FloatComparison:
|
||||
Enabled: false
|
||||
Lint/HashCompareByIdentity:
|
||||
Enabled: false
|
||||
Lint/IdentityComparison:
|
||||
Enabled: false
|
||||
Lint/InterpolationCheck:
|
||||
Enabled: false
|
||||
Lint/MissingCopEnableDirective:
|
||||
Enabled: false
|
||||
Lint/MixedRegexpCaptureTypes:
|
||||
Enabled: false
|
||||
Lint/NestedPercentLiteral:
|
||||
Enabled: false
|
||||
Lint/NonDeterministicRequireOrder:
|
||||
Enabled: false
|
||||
Lint/OrderedMagicComments:
|
||||
Enabled: false
|
||||
Lint/OutOfRangeRegexpRef:
|
||||
Enabled: false
|
||||
Lint/RaiseException:
|
||||
Enabled: false
|
||||
Lint/RedundantCopEnableDirective:
|
||||
Enabled: false
|
||||
Lint/RedundantRequireStatement:
|
||||
Enabled: false
|
||||
Lint/RedundantSafeNavigation:
|
||||
Enabled: false
|
||||
Lint/RedundantWithIndex:
|
||||
Enabled: false
|
||||
Lint/RedundantWithObject:
|
||||
Enabled: false
|
||||
Lint/RegexpAsCondition:
|
||||
Enabled: false
|
||||
Lint/ReturnInVoidContext:
|
||||
Enabled: false
|
||||
Lint/SafeNavigationConsistency:
|
||||
Enabled: false
|
||||
Lint/SafeNavigationWithEmpty:
|
||||
Enabled: false
|
||||
Lint/SelfAssignment:
|
||||
Enabled: false
|
||||
Lint/SendWithMixinArgument:
|
||||
Enabled: false
|
||||
Lint/ShadowedArgument:
|
||||
Enabled: false
|
||||
Lint/StructNewOverride:
|
||||
Enabled: false
|
||||
Lint/ToJSON:
|
||||
Enabled: false
|
||||
Lint/TopLevelReturnWithArgument:
|
||||
Enabled: false
|
||||
Lint/TrailingCommaInAttributeDeclaration:
|
||||
Enabled: false
|
||||
Lint/UnreachableLoop:
|
||||
Enabled: false
|
||||
Lint/UriEscapeUnescape:
|
||||
Enabled: false
|
||||
Lint/UriRegexp:
|
||||
Enabled: false
|
||||
Lint/UselessMethodDefinition:
|
||||
Enabled: false
|
||||
Lint/UselessTimes:
|
||||
Enabled: false
|
||||
Metrics/AbcSize:
|
||||
Enabled: false
|
||||
Metrics/BlockLength:
|
||||
Enabled: false
|
||||
Metrics/BlockNesting:
|
||||
Enabled: false
|
||||
Metrics/ClassLength:
|
||||
Enabled: false
|
||||
Metrics/CyclomaticComplexity:
|
||||
Enabled: false
|
||||
Metrics/MethodLength:
|
||||
Enabled: false
|
||||
Metrics/ModuleLength:
|
||||
Enabled: false
|
||||
Metrics/ParameterLists:
|
||||
Enabled: false
|
||||
Metrics/PerceivedComplexity:
|
||||
Enabled: false
|
||||
Migration/DepartmentName:
|
||||
Enabled: false
|
||||
Naming/AccessorMethodName:
|
||||
Enabled: false
|
||||
Naming/BlockParameterName:
|
||||
Enabled: false
|
||||
Naming/HeredocDelimiterCase:
|
||||
Enabled: false
|
||||
Naming/HeredocDelimiterNaming:
|
||||
Enabled: false
|
||||
Naming/MemoizedInstanceVariableName:
|
||||
Enabled: false
|
||||
Naming/MethodParameterName:
|
||||
Enabled: false
|
||||
Naming/RescuedExceptionsVariableName:
|
||||
Enabled: false
|
||||
Naming/VariableNumber:
|
||||
Enabled: false
|
||||
Performance/BindCall:
|
||||
Enabled: false
|
||||
Performance/DeletePrefix:
|
||||
Enabled: false
|
||||
Performance/DeleteSuffix:
|
||||
Enabled: false
|
||||
Performance/InefficientHashSearch:
|
||||
Enabled: false
|
||||
Performance/UnfreezeString:
|
||||
Enabled: false
|
||||
Performance/UriDefaultParser:
|
||||
Enabled: false
|
||||
RSpec/Be:
|
||||
Enabled: false
|
||||
RSpec/Capybara/CurrentPathExpectation:
|
||||
Enabled: false
|
||||
RSpec/Capybara/FeatureMethods:
|
||||
Enabled: false
|
||||
RSpec/Capybara/VisibilityMatcher:
|
||||
Enabled: false
|
||||
RSpec/ContextMethod:
|
||||
Enabled: false
|
||||
RSpec/ContextWording:
|
||||
Enabled: false
|
||||
RSpec/DescribeClass:
|
||||
Enabled: false
|
||||
RSpec/EmptyHook:
|
||||
Enabled: false
|
||||
RSpec/EmptyLineAfterExample:
|
||||
Enabled: false
|
||||
RSpec/EmptyLineAfterExampleGroup:
|
||||
Enabled: false
|
||||
RSpec/EmptyLineAfterHook:
|
||||
Enabled: false
|
||||
RSpec/ExampleLength:
|
||||
Enabled: false
|
||||
RSpec/ExampleWithoutDescription:
|
||||
Enabled: false
|
||||
RSpec/ExpectChange:
|
||||
Enabled: false
|
||||
RSpec/ExpectInHook:
|
||||
Enabled: false
|
||||
RSpec/FactoryBot/AttributeDefinedStatically:
|
||||
Enabled: false
|
||||
RSpec/FactoryBot/CreateList:
|
||||
Enabled: false
|
||||
RSpec/FactoryBot/FactoryClassName:
|
||||
Enabled: false
|
||||
RSpec/HooksBeforeExamples:
|
||||
Enabled: false
|
||||
RSpec/ImplicitBlockExpectation:
|
||||
Enabled: false
|
||||
RSpec/ImplicitSubject:
|
||||
Enabled: false
|
||||
RSpec/LeakyConstantDeclaration:
|
||||
Enabled: false
|
||||
RSpec/LetBeforeExamples:
|
||||
Enabled: false
|
||||
RSpec/MissingExampleGroupArgument:
|
||||
Enabled: false
|
||||
RSpec/MultipleExpectations:
|
||||
Enabled: false
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Enabled: false
|
||||
RSpec/MultipleSubjects:
|
||||
Enabled: false
|
||||
RSpec/NestedGroups:
|
||||
Enabled: false
|
||||
RSpec/PredicateMatcher:
|
||||
Enabled: false
|
||||
RSpec/ReceiveCounts:
|
||||
Enabled: false
|
||||
RSpec/ReceiveNever:
|
||||
Enabled: false
|
||||
RSpec/RepeatedExampleGroupBody:
|
||||
Enabled: false
|
||||
RSpec/RepeatedExampleGroupDescription:
|
||||
Enabled: false
|
||||
RSpec/RepeatedIncludeExample:
|
||||
Enabled: false
|
||||
RSpec/ReturnFromStub:
|
||||
Enabled: false
|
||||
RSpec/SharedExamples:
|
||||
Enabled: false
|
||||
RSpec/StubbedMock:
|
||||
Enabled: false
|
||||
RSpec/UnspecifiedException:
|
||||
Enabled: false
|
||||
RSpec/VariableDefinition:
|
||||
Enabled: false
|
||||
RSpec/VoidExpect:
|
||||
Enabled: false
|
||||
RSpec/Yield:
|
||||
Enabled: false
|
||||
Security/Open:
|
||||
Enabled: false
|
||||
Style/AccessModifierDeclarations:
|
||||
Enabled: false
|
||||
Style/AccessorGrouping:
|
||||
Enabled: false
|
||||
Style/AsciiComments:
|
||||
Enabled: false
|
||||
Style/BisectedAttrAccessor:
|
||||
Enabled: false
|
||||
Style/CaseLikeIf:
|
||||
Enabled: false
|
||||
Style/ClassEqualityComparison:
|
||||
Enabled: false
|
||||
Style/ColonMethodDefinition:
|
||||
Enabled: false
|
||||
Style/CombinableLoops:
|
||||
Enabled: false
|
||||
Style/CommentedKeyword:
|
||||
Enabled: false
|
||||
Style/Dir:
|
||||
Enabled: false
|
||||
Style/DoubleCopDisableDirective:
|
||||
Enabled: false
|
||||
Style/EmptyBlockParameter:
|
||||
Enabled: false
|
||||
Style/EmptyLambdaParameter:
|
||||
Enabled: false
|
||||
Style/Encoding:
|
||||
Enabled: false
|
||||
Style/EvalWithLocation:
|
||||
Enabled: false
|
||||
Style/ExpandPathArguments:
|
||||
Enabled: false
|
||||
Style/ExplicitBlockArgument:
|
||||
Enabled: false
|
||||
Style/ExponentialNotation:
|
||||
Enabled: false
|
||||
Style/FloatDivision:
|
||||
Enabled: false
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
Style/GlobalStdStream:
|
||||
Enabled: false
|
||||
Style/HashAsLastArrayItem:
|
||||
Enabled: false
|
||||
Style/HashLikeCase:
|
||||
Enabled: false
|
||||
Style/HashTransformKeys:
|
||||
Enabled: false
|
||||
Style/HashTransformValues:
|
||||
Enabled: false
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
Style/KeywordParametersOrder:
|
||||
Enabled: false
|
||||
Style/MinMax:
|
||||
Enabled: false
|
||||
Style/MixinUsage:
|
||||
Enabled: false
|
||||
Style/MultilineWhenThen:
|
||||
Enabled: false
|
||||
Style/NegatedUnless:
|
||||
Enabled: false
|
||||
Style/NumericPredicate:
|
||||
Enabled: false
|
||||
Style/OptionalBooleanParameter:
|
||||
Enabled: false
|
||||
Style/OrAssignment:
|
||||
Enabled: false
|
||||
Style/RandomWithOffset:
|
||||
Enabled: false
|
||||
Style/RedundantAssignment:
|
||||
Enabled: false
|
||||
Style/RedundantCondition:
|
||||
Enabled: false
|
||||
Style/RedundantConditional:
|
||||
Enabled: false
|
||||
Style/RedundantFetchBlock:
|
||||
Enabled: false
|
||||
Style/RedundantFileExtensionInRequire:
|
||||
Enabled: false
|
||||
Style/RedundantRegexpCharacterClass:
|
||||
Enabled: false
|
||||
Style/RedundantRegexpEscape:
|
||||
Enabled: false
|
||||
Style/RedundantSelfAssignment:
|
||||
Enabled: false
|
||||
Style/RedundantSort:
|
||||
Enabled: false
|
||||
Style/RescueStandardError:
|
||||
Enabled: false
|
||||
Style/SingleArgumentDig:
|
||||
Enabled: false
|
||||
Style/SlicingWithRange:
|
||||
Enabled: false
|
||||
Style/SoleNestedConditional:
|
||||
Enabled: false
|
||||
Style/StderrPuts:
|
||||
Enabled: false
|
||||
Style/StringConcatenation:
|
||||
Enabled: false
|
||||
Style/Strip:
|
||||
Enabled: false
|
||||
Style/SymbolProc:
|
||||
Enabled: false
|
||||
Style/TrailingBodyOnClass:
|
||||
Enabled: false
|
||||
Style/TrailingBodyOnMethodDefinition:
|
||||
Enabled: false
|
||||
Style/TrailingBodyOnModule:
|
||||
Enabled: false
|
||||
Style/TrailingCommaInHashLiteral:
|
||||
Enabled: false
|
||||
Style/TrailingMethodEndStatement:
|
||||
Enabled: false
|
||||
Style/UnpackFirst:
|
||||
Enabled: false
|
||||
Lint/DuplicateBranch:
|
||||
Enabled: false
|
||||
Lint/DuplicateRegexpCharacterClassElement:
|
||||
Enabled: false
|
||||
Lint/EmptyBlock:
|
||||
Enabled: false
|
||||
Lint/EmptyClass:
|
||||
Enabled: false
|
||||
Lint/NoReturnInBeginEndBlocks:
|
||||
Enabled: false
|
||||
Lint/ToEnumArguments:
|
||||
Enabled: false
|
||||
Lint/UnexpectedBlockArity:
|
||||
Enabled: false
|
||||
Lint/UnmodifiedReduceAccumulator:
|
||||
Enabled: false
|
||||
Performance/CollectionLiteralInLoop:
|
||||
Enabled: false
|
||||
Style/ArgumentsForwarding:
|
||||
Enabled: false
|
||||
Style/CollectionCompact:
|
||||
Enabled: false
|
||||
Style/DocumentDynamicEvalDefinition:
|
||||
Enabled: false
|
||||
Style/NegatedIfElseCondition:
|
||||
Enabled: false
|
||||
Style/NilLambda:
|
||||
Enabled: false
|
||||
Style/RedundantArgument:
|
||||
Enabled: false
|
||||
Style/SwapValues:
|
||||
Enabled: false
|
||||
1
ee/tools/puppet/fleetdm/.yardopts
Normal file
1
ee/tools/puppet/fleetdm/.yardopts
Normal file
|
|
@ -0,0 +1 @@
|
|||
--markup markdown
|
||||
11
ee/tools/puppet/fleetdm/CHANGELOG.md
Normal file
11
ee/tools/puppet/fleetdm/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## Release 0.0.0-beta.1
|
||||
|
||||
**Features**
|
||||
|
||||
- Ability to define profiles using the custom type `fleetdm::profile`.
|
||||
- Ability to release a device from await configuration using the custom function `fleetdm::release_device`.
|
||||
|
||||
72
ee/tools/puppet/fleetdm/Gemfile
Normal file
72
ee/tools/puppet/fleetdm/Gemfile
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
source ENV['GEM_SOURCE'] || 'https://rubygems.org'
|
||||
|
||||
def location_for(place_or_version, fake_version = nil)
|
||||
git_url_regex = %r{\A(?<url>(https?|git)[:@][^#]*)(#(?<branch>.*))?}
|
||||
file_url_regex = %r{\Afile:\/\/(?<path>.*)}
|
||||
|
||||
if place_or_version && (git_url = place_or_version.match(git_url_regex))
|
||||
[fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact
|
||||
elsif place_or_version && (file_url = place_or_version.match(file_url_regex))
|
||||
['>= 0', { path: File.expand_path(file_url[:path]), require: false }]
|
||||
else
|
||||
[place_or_version, { require: false }]
|
||||
end
|
||||
end
|
||||
|
||||
group :development do
|
||||
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))
|
||||
gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
|
||||
gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
|
||||
gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
|
||||
gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
|
||||
gem "voxpupuli-puppet-lint-plugins", '~> 4.0', require: false
|
||||
gem "facterdb", '~> 1.18', require: false
|
||||
gem "metadata-json-lint", '>= 2.0.2', '< 4.0.0', require: false
|
||||
gem "puppetlabs_spec_helper", '~> 5.0', require: false
|
||||
gem "rspec-puppet-facts", '~> 2.0', require: false
|
||||
gem "codecov", '~> 0.2', require: false
|
||||
gem "dependency_checker", '~> 0.2', require: false
|
||||
gem "parallel_tests", '= 3.12.1', require: false
|
||||
gem "pry", '~> 0.10', require: false
|
||||
gem "simplecov-console", '~> 0.5', require: false
|
||||
gem "puppet-debugger", '~> 1.0', require: false
|
||||
gem "rubocop", '= 1.6.1', require: false
|
||||
gem "rubocop-performance", '= 1.9.1', require: false
|
||||
gem "rubocop-rspec", '= 2.0.1', require: false
|
||||
gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw]
|
||||
end
|
||||
group :system_tests do
|
||||
gem "puppet_litmus", '< 1.0.0', require: false, platforms: [:ruby, :x64_mingw]
|
||||
gem "serverspec", '~> 2.41', require: false
|
||||
end
|
||||
|
||||
puppet_version = ENV['PUPPET_GEM_VERSION']
|
||||
facter_version = ENV['FACTER_GEM_VERSION']
|
||||
hiera_version = ENV['HIERA_GEM_VERSION']
|
||||
|
||||
gems = {}
|
||||
|
||||
gems['puppet'] = location_for(puppet_version)
|
||||
|
||||
# If facter or hiera versions have been specified via the environment
|
||||
# variables
|
||||
|
||||
gems['facter'] = location_for(facter_version) if facter_version
|
||||
gems['hiera'] = location_for(hiera_version) if hiera_version
|
||||
|
||||
gems.each do |gem_name, gem_params|
|
||||
gem gem_name, *gem_params
|
||||
end
|
||||
|
||||
# Evaluate Gemfile.local and ~/.gemfile if they exist
|
||||
extra_gemfiles = [
|
||||
"#{__FILE__}.local",
|
||||
File.join(Dir.home, '.gemfile'),
|
||||
]
|
||||
|
||||
extra_gemfiles.each do |gemfile|
|
||||
if File.file?(gemfile) && File.readable?(gemfile)
|
||||
eval(File.read(gemfile), binding)
|
||||
end
|
||||
end
|
||||
# vim: syntax=ruby
|
||||
96
ee/tools/puppet/fleetdm/README.md
Normal file
96
ee/tools/puppet/fleetdm/README.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# fleetdm
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Description](#description)
|
||||
1. [Setup - The basics of getting started with fleetdm](#setup)
|
||||
* [Setup requirements](#setup-requirements)
|
||||
* [Beginning with fleetdm](#beginning-with-fleetdm)
|
||||
1. [Usage - Configuration options and additional functionality](#usage)
|
||||
* [Defining profiles for a device](#defining-profiles-for-a-device)
|
||||
* [Releasing a device from await configuration](#releasing-a-device-from-await-configuration)
|
||||
3. [Limitations - OS compatibility, etc.](#limitations)
|
||||
4. [Development - Guide for contributing to the module](#development)
|
||||
|
||||
## Description
|
||||
|
||||
Manage MDM settings for macOS devices using [Fleet](https://fleetdm.com)
|
||||
|
||||
## Setup
|
||||
|
||||
### Setup Requirements
|
||||
|
||||
This module requires to add `fleetdm` as a reporter in your `report` settings,
|
||||
this helps Fleet understand when your Puppet run is finished and assign the
|
||||
device to a team with the necessary profiles.
|
||||
|
||||
For example, in your server configuration:
|
||||
|
||||
```
|
||||
reports = http,fleetdm
|
||||
```
|
||||
|
||||
To communicate with the Fleet server, you also need to provide your server URL
|
||||
and a token as Hiera values:
|
||||
|
||||
```yaml
|
||||
---
|
||||
fleetdm::host: https://example.com
|
||||
fleetdm::token: my_token
|
||||
```
|
||||
|
||||
Note: for the token, we recommend using an [API-only user][1], with a GitOps role.
|
||||
|
||||
### Beginning with fleetdm
|
||||
|
||||
## Usage
|
||||
|
||||
### Defining profiles for a device
|
||||
|
||||
The `examples/` folder in this repo contain some examples. Generally, you can
|
||||
define profiles using the custom resource type `fleetdm::profile`:
|
||||
|
||||
|
||||
```pp
|
||||
node default {
|
||||
fleetdm::profile { 'com.apple.universalaccess':
|
||||
template => 'xml template',
|
||||
group => 'workstations',
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Releasing a device from await configuration
|
||||
|
||||
If your DEP profile had `await_device_configured` set to `true`, you can use the `fleetdm::release_device` function to release the device:
|
||||
|
||||
```
|
||||
$host_uuid = $facts['system_profiler']['hardware_uuid']
|
||||
fleetdm::release_device($host_uuid)
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
At the moment, this module only works for macOS devices.
|
||||
|
||||
## Development
|
||||
|
||||
To trigger a puppet run locally:
|
||||
|
||||
```
|
||||
puppet apply --debug --test --modulepath="$(pwd)/.." --reports=fleetdm --hiera_config hiera.yaml examples/multiple-teams.pp
|
||||
```
|
||||
|
||||
To lint/fix Puppet (`.pp`) files, use:
|
||||
|
||||
```
|
||||
pdk bundle exec puppet-lint --fix .
|
||||
```
|
||||
|
||||
To lint/fix Ruby (`.rb`) files, use:
|
||||
|
||||
```
|
||||
pdk bundle exec rubocop -A
|
||||
```
|
||||
|
||||
[1]: https://fleetdm.com/docs/using-fleet/fleetctl-cli#using-fleetctl-with-an-api-only-user
|
||||
89
ee/tools/puppet/fleetdm/Rakefile
Normal file
89
ee/tools/puppet/fleetdm/Rakefile
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'bundler'
|
||||
require 'puppet_litmus/rake_tasks' if Bundler.rubygems.find_name('puppet_litmus').any?
|
||||
require 'puppetlabs_spec_helper/rake_tasks'
|
||||
require 'puppet-syntax/tasks/puppet-syntax'
|
||||
require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any?
|
||||
require 'github_changelog_generator/task' if Bundler.rubygems.find_name('github_changelog_generator').any?
|
||||
require 'puppet-strings/tasks' if Bundler.rubygems.find_name('puppet-strings').any?
|
||||
|
||||
def changelog_user
|
||||
return unless Rake.application.top_level_tasks.include? "changelog"
|
||||
returnVal = nil || JSON.load(File.read('metadata.json'))['author']
|
||||
raise "unable to find the changelog_user in .sync.yml, or the author in metadata.json" if returnVal.nil?
|
||||
puts "GitHubChangelogGenerator user:#{returnVal}"
|
||||
returnVal
|
||||
end
|
||||
|
||||
def changelog_project
|
||||
return unless Rake.application.top_level_tasks.include? "changelog"
|
||||
|
||||
returnVal = nil
|
||||
returnVal ||= begin
|
||||
metadata_source = JSON.load(File.read('metadata.json'))['source']
|
||||
metadata_source_match = metadata_source && metadata_source.match(%r{.*\/([^\/]*?)(?:\.git)?\Z})
|
||||
|
||||
metadata_source_match && metadata_source_match[1]
|
||||
end
|
||||
|
||||
raise "unable to find the changelog_project in .sync.yml or calculate it from the source in metadata.json" if returnVal.nil?
|
||||
|
||||
puts "GitHubChangelogGenerator project:#{returnVal}"
|
||||
returnVal
|
||||
end
|
||||
|
||||
def changelog_future_release
|
||||
return unless Rake.application.top_level_tasks.include? "changelog"
|
||||
returnVal = "v%s" % JSON.load(File.read('metadata.json'))['version']
|
||||
raise "unable to find the future_release (version) in metadata.json" if returnVal.nil?
|
||||
puts "GitHubChangelogGenerator future_release:#{returnVal}"
|
||||
returnVal
|
||||
end
|
||||
|
||||
PuppetLint.configuration.send('disable_relative')
|
||||
|
||||
|
||||
if Bundler.rubygems.find_name('github_changelog_generator').any?
|
||||
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
||||
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?
|
||||
config.user = "#{changelog_user}"
|
||||
config.project = "#{changelog_project}"
|
||||
config.future_release = "#{changelog_future_release}"
|
||||
config.exclude_labels = ['maintenance']
|
||||
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)."
|
||||
config.add_pr_wo_labels = true
|
||||
config.issues = false
|
||||
config.merge_prefix = "### UNCATEGORIZED PRS; LABEL THEM ON GITHUB"
|
||||
config.configure_sections = {
|
||||
"Changed" => {
|
||||
"prefix" => "### Changed",
|
||||
"labels" => ["backwards-incompatible"],
|
||||
},
|
||||
"Added" => {
|
||||
"prefix" => "### Added",
|
||||
"labels" => ["enhancement", "feature"],
|
||||
},
|
||||
"Fixed" => {
|
||||
"prefix" => "### Fixed",
|
||||
"labels" => ["bug", "documentation", "bugfix"],
|
||||
},
|
||||
}
|
||||
end
|
||||
else
|
||||
desc 'Generate a Changelog from GitHub'
|
||||
task :changelog do
|
||||
raise <<EOM
|
||||
The changelog tasks depends on recent features of the github_changelog_generator gem.
|
||||
Please manually add it to your .sync.yml for now, and run `pdk update`:
|
||||
---
|
||||
Gemfile:
|
||||
optional:
|
||||
':development':
|
||||
- gem: 'github_changelog_generator'
|
||||
version: '~> 1.15'
|
||||
condition: "Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0')"
|
||||
EOM
|
||||
end
|
||||
end
|
||||
|
||||
3
ee/tools/puppet/fleetdm/data/common.yaml
Normal file
3
ee/tools/puppet/fleetdm/data/common.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
fleetdm::host: https://example.com
|
||||
fleetdm::token: my_token
|
||||
10
ee/tools/puppet/fleetdm/examples/multiple-teams.pp
Normal file
10
ee/tools/puppet/fleetdm/examples/multiple-teams.pp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
node default {
|
||||
fleetdm::profile { 'com.apple.universalaccess':
|
||||
template => 'xml template',
|
||||
group => 'workstations',
|
||||
}
|
||||
|
||||
fleetdm::profile { 'com.apple.homescreenlayout':
|
||||
template => 'xml template',
|
||||
}
|
||||
}
|
||||
10
ee/tools/puppet/fleetdm/hiera.yaml
Normal file
10
ee/tools/puppet/fleetdm/hiera.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
version: 5
|
||||
|
||||
defaults:
|
||||
datadir: data
|
||||
data_hash: yaml_data
|
||||
|
||||
hierarchy:
|
||||
- name: 'common'
|
||||
path: 'common.yaml'
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'puppet/util/fleet_client'
|
||||
|
||||
Puppet::Functions.create_function(:"fleetdm::preassign_profile") do
|
||||
dispatch :preassign_profile do
|
||||
param 'String', :uuid
|
||||
param 'String', :template
|
||||
optional_param 'String', :group
|
||||
end
|
||||
|
||||
def preassign_profile(uuid, template, group = 'default')
|
||||
host = call_function('lookup', 'fleetdm::host')
|
||||
token = call_function('lookup', 'fleetdm::token')
|
||||
client = Puppet::Util::FleetClient.new(host, token)
|
||||
client.preassign_profile(uuid, template, group)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'puppet/util/fleet_client'
|
||||
|
||||
# fleetdm::release_device sends the [`DeviceConfigured`][1] MDM command to the
|
||||
# device with the provided UUID. This is useful to release DEP enrolled devices
|
||||
# during setup.
|
||||
#
|
||||
# [1]: https://developer.apple.com/documentation/devicemanagement/release_device_from_await_configuration
|
||||
Puppet::Functions.create_function(:"fleetdm::release_device") do
|
||||
dispatch :release_device do
|
||||
param 'String', :uuid
|
||||
end
|
||||
|
||||
def release_device(uuid)
|
||||
command_xml = <<~COMMAND_TEMPLATE
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Command</key>
|
||||
<dict>
|
||||
<key>RequestType</key>
|
||||
<string>DeviceConfigured</string>
|
||||
</dict>
|
||||
<key>CommandUUID</key>
|
||||
<string>#{SecureRandom.uuid}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
COMMAND_TEMPLATE
|
||||
|
||||
host = call_function('lookup', 'fleetdm::host')
|
||||
token = call_function('lookup', 'fleetdm::token')
|
||||
client = Puppet::Util::FleetClient.new(host, token)
|
||||
client.send_mdm_command(uuid, command_xml)
|
||||
end
|
||||
end
|
||||
24
ee/tools/puppet/fleetdm/lib/puppet/reports/fleetdm.rb
Normal file
24
ee/tools/puppet/fleetdm/lib/puppet/reports/fleetdm.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'puppet'
|
||||
require 'puppet/util/fleet_client'
|
||||
|
||||
Puppet::Reports.register_report(:fleetdm) do
|
||||
desc 'Used to signal the Fleet server that a Puppet run is done to match a device to a team for profile delivery'
|
||||
|
||||
def process
|
||||
return if noop
|
||||
node = Puppet::Node.new(Puppet[:node_name_value])
|
||||
compiler = Puppet::Parser::Compiler.new(node)
|
||||
scope = Puppet::Parser::Scope.new(compiler)
|
||||
lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, nil)
|
||||
host = Puppet::Pops::Lookup.lookup('fleetdm::host', nil, '', false, nil, lookup_invocation)
|
||||
token = Puppet::Pops::Lookup.lookup('fleetdm::token', nil, '', false, nil, lookup_invocation)
|
||||
|
||||
client = Puppet::Util::FleetClient.new(host, token)
|
||||
response = client.match_profiles
|
||||
|
||||
return unless response[:status] >= 400 && response[:status] < 600
|
||||
Puppet.err _('Unable to match profiles to Fleet [%{code}] %{message}') % { code: response[:status], message: response[:body] }
|
||||
end
|
||||
end
|
||||
99
ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb
Normal file
99
ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
require 'net/http'
|
||||
require 'uri'
|
||||
require 'json'
|
||||
require 'puppet'
|
||||
require 'hiera_puppet'
|
||||
|
||||
module Puppet::Util
|
||||
# FleetClient provides an interface for making HTTP requests to a Fleet server.
|
||||
class FleetClient
|
||||
def initialize(host, token)
|
||||
@host = host
|
||||
@token = token
|
||||
end
|
||||
|
||||
# Pre-assigns a profile to a host. Note that the profile assignment is not
|
||||
# effective until the sibling `match_profiles` method is called.
|
||||
#
|
||||
# @param uuid [String] The host uuid.
|
||||
# @param profile_xml [String] Raw XML with the configuration profile.
|
||||
# @param group [String] Used to construct a team name.
|
||||
# @return [Hash] The response status code, headers, and body.
|
||||
def preassign_profile(uuid, profile_xml, group)
|
||||
post(
|
||||
'/api/latest/fleet/mdm/apple/profiles/preassign',
|
||||
{
|
||||
'external_node_identifier' => Puppet[:node_name_value],
|
||||
'host_uuid' => uuid,
|
||||
'profile' => profile_xml,
|
||||
'group' => group,
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
# Matches the set of profiles preassigned to the host (via the sibling
|
||||
# `preassign_profile` method) with a team.
|
||||
#
|
||||
# It uses `Puppet[:node_name_value]` as the `external_node_identifier`,
|
||||
# which is unique per Puppet host.
|
||||
#
|
||||
# @return [Hash] The response status code, headers, and body.
|
||||
def match_profiles
|
||||
post('/api/latest/fleet/mdm/apple/profiles/match',
|
||||
{
|
||||
'external_node_identifier' => Puppet[:node_name_value],
|
||||
})
|
||||
end
|
||||
|
||||
# Sends an MDM command to the host with the specified UUID.
|
||||
#
|
||||
# @param uuid [String] The host uuid.
|
||||
# @param command_xml [String] Raw XML with the MDM command.
|
||||
# @return [Hash] The response status code, headers, and body.
|
||||
def send_mdm_command(uuid, command_xml)
|
||||
post('/api/latest/fleet/mdm/apple/enqueue',
|
||||
{
|
||||
'command' => command_xml,
|
||||
'device_ids' => [uuid],
|
||||
})
|
||||
end
|
||||
|
||||
# Sends an HTTP POST request to the specified path.
|
||||
#
|
||||
# @param path [String] The path of the resource to post to.
|
||||
# @param body [Object] (optional) The request body to send.
|
||||
# @param headers [Hash] (optional) Additional headers to include in the request.
|
||||
# @return [Hash] The response status code, headers, and body.
|
||||
def post(path, body = nil, headers = {})
|
||||
uri = URI.parse("#{@host}#{path}")
|
||||
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = true if uri.scheme == 'https'
|
||||
|
||||
request = Net::HTTP::Post.new(uri.request_uri)
|
||||
|
||||
headers['Authorization'] = "Bearer #{@token}"
|
||||
headers.each { |key, value| request[key] = value }
|
||||
request.body = body.to_json if body
|
||||
|
||||
response = http.request(request)
|
||||
parse_response(response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_response(response)
|
||||
{
|
||||
status: response.code.to_i,
|
||||
headers: response.to_hash,
|
||||
body: response.body ? JSON.parse(response.body) : nil,
|
||||
}
|
||||
rescue JSON::ParserError => e
|
||||
{
|
||||
status: response.code.to_i,
|
||||
headers: response.to_hash,
|
||||
error: "Failed to parse response body: #{e.message}"
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
41
ee/tools/puppet/fleetdm/manifests/profile.pp
Normal file
41
ee/tools/puppet/fleetdm/manifests/profile.pp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# @summary Add a configuration profile to the device.
|
||||
#
|
||||
# This resource ensures that the provided configuration
|
||||
# profile will be applied to the device using Fleet.
|
||||
#
|
||||
# Fleet keeps track of all the times this resource is
|
||||
# called for a device during a Puppet sync and at the
|
||||
# end of the sync tries to match the set of profiles
|
||||
# to an existing team and assign the device to the team.
|
||||
#
|
||||
# If a team doesn't exist, Fleet will automatically create one.
|
||||
#
|
||||
# @param template
|
||||
# XML with the profile definition.
|
||||
# @param group
|
||||
# Used to define the team name in Fleet.
|
||||
# Fleet keeps track of each time this resource is
|
||||
# declared with a group name, the final team name
|
||||
# will be a concatenation of all unique group names.
|
||||
#
|
||||
# @example
|
||||
# fleetdm::profile { 'identifier': }
|
||||
define fleetdm::profile (
|
||||
String $template,
|
||||
String $group = 'default',
|
||||
) {
|
||||
if $facts["clientnoop"] {
|
||||
notice('noop mode: skipping profile definition in the Fleet server')
|
||||
} else {
|
||||
unless $template =~ /^[[:print:]]+$/ {
|
||||
fail('invalid template')
|
||||
}
|
||||
|
||||
unless $group =~ /^[[:print:]]+$/ {
|
||||
fail('invalid group')
|
||||
}
|
||||
|
||||
$host_uuid = $facts['system_profiler']['hardware_uuid']
|
||||
fleetdm::preassign_profile($host_uuid, $template, $group)
|
||||
}
|
||||
}
|
||||
28
ee/tools/puppet/fleetdm/metadata.json
Normal file
28
ee/tools/puppet/fleetdm/metadata.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "root-fleetdm",
|
||||
"version": "0.1.0",
|
||||
"author": "Fleet Device Management Inc",
|
||||
"summary": "",
|
||||
"license": "proprietary",
|
||||
"source": "",
|
||||
"dependencies": [
|
||||
|
||||
],
|
||||
"operatingsystem_support": [
|
||||
{
|
||||
"operatingsystem": "Darwin",
|
||||
"operatingsystemrelease": [
|
||||
"16"
|
||||
]
|
||||
}
|
||||
],
|
||||
"requirements": [
|
||||
{
|
||||
"name": "puppet",
|
||||
"version_requirement": ">= 6.21.0 < 8.0.0"
|
||||
}
|
||||
],
|
||||
"pdk-version": "2.7.1",
|
||||
"template-url": "pdk-default#2.7.4",
|
||||
"template-ref": "tags/2.7.4-0-g58edf57"
|
||||
}
|
||||
8
ee/tools/puppet/fleetdm/spec/default_facts.yml
Normal file
8
ee/tools/puppet/fleetdm/spec/default_facts.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Use default_module_facts.yml for module specific facts.
|
||||
#
|
||||
# Facts specified here will override the values provided by rspec-puppet-facts.
|
||||
---
|
||||
ipaddress: "172.16.254.254"
|
||||
ipaddress6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA"
|
||||
is_pe: false
|
||||
macaddress: "AA:AA:AA:AA:AA:AA"
|
||||
68
ee/tools/puppet/fleetdm/spec/defines/profile_spec.rb
Normal file
68
ee/tools/puppet/fleetdm/spec/defines/profile_spec.rb
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'fleetdm::profile' do
|
||||
let(:fleet_client_mock) { instance_double('Puppet::Util::FleetClient') }
|
||||
let(:title) { 'namevar' }
|
||||
let(:template) { 'test-template' }
|
||||
let(:group) { 'group' }
|
||||
let(:node) { 'testhost.example.com' }
|
||||
let(:params) do
|
||||
{ 'template' => template, 'group' => group }
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
fleet_client_class = class_spy('Puppet::Util::FleetClient')
|
||||
stub_const('Puppet::Util::FleetClient', fleet_client_class)
|
||||
allow(fleet_client_class).to receive(:new).with('https://example.com', 'test_token') { fleet_client_mock }
|
||||
end
|
||||
|
||||
on_supported_os.each do |os, os_facts|
|
||||
context "on #{os}" do
|
||||
let(:facts) { os_facts }
|
||||
|
||||
it 'compiles' do
|
||||
uuid = os_facts[:system_profiler]['hardware_uuid']
|
||||
expect(fleet_client_mock).to receive(:preassign_profile).with(uuid, template, group)
|
||||
is_expected.to compile
|
||||
end
|
||||
|
||||
context 'noop' do
|
||||
let(:facts) { { 'clientnoop' => true } }
|
||||
|
||||
it 'does not send a request in noop mode' do
|
||||
is_expected.to compile
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid template' do
|
||||
let(:params) do
|
||||
{ 'template' => '', 'group' => group }
|
||||
end
|
||||
|
||||
it { is_expected.to compile.and_raise_error(%r{invalid template}) }
|
||||
end
|
||||
|
||||
context 'invalid group' do
|
||||
let(:params) do
|
||||
{ 'template' => template, 'group' => '' }
|
||||
end
|
||||
|
||||
it { is_expected.to compile.and_raise_error(%r{invalid group}) }
|
||||
end
|
||||
|
||||
context 'without group' do
|
||||
let(:params) do
|
||||
{ 'template' => template }
|
||||
end
|
||||
|
||||
it 'compiles' do
|
||||
uuid = os_facts[:system_profiler]['hardware_uuid']
|
||||
expect(fleet_client_mock).to receive(:preassign_profile).with(uuid, template, 'default')
|
||||
is_expected.to compile
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
8
ee/tools/puppet/fleetdm/spec/fixtures/hiera.yaml
vendored
Normal file
8
ee/tools/puppet/fleetdm/spec/fixtures/hiera.yaml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
version: 5
|
||||
defaults:
|
||||
datadir: hieradata
|
||||
data_hash: yaml_data
|
||||
|
||||
hierarchy:
|
||||
- name: "Common data"
|
||||
path: "common.yaml"
|
||||
3
ee/tools/puppet/fleetdm/spec/fixtures/hieradata/common.yaml
vendored
Normal file
3
ee/tools/puppet/fleetdm/spec/fixtures/hieradata/common.yaml
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
fleetdm::host: https://example.com
|
||||
fleetdm::token: test_token
|
||||
17
ee/tools/puppet/fleetdm/spec/functions/fleet_client_spec.rb
Normal file
17
ee/tools/puppet/fleetdm/spec/functions/fleet_client_spec.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'Puppet::Util::FleetClient' do
|
||||
let(:client) { Puppet::Util::FleetClient.new('https://example.com', 'token') }
|
||||
|
||||
it 'handles POST with 204 responses' do
|
||||
response = Net::HTTPSuccess.new(1.0, '204', 'OK')
|
||||
expect_any_instance_of(Net::HTTP).to receive(:request) { response }
|
||||
expect(response).to receive(:body) { nil }
|
||||
|
||||
result = client.post('/example')
|
||||
expect(result[:status]).to be(204)
|
||||
expect(result[:body]).to be(nil)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'fleetdm::preassign_profile' do
|
||||
let(:fleet_client_mock) { instance_double('Puppet::Util::FleetClient') }
|
||||
let(:device_uuid) { 'device-uuid' }
|
||||
let(:template) { 'template' }
|
||||
let(:group) { 'group' }
|
||||
|
||||
before(:each) do
|
||||
fleet_client_class = class_spy('Puppet::Util::FleetClient')
|
||||
stub_const('Puppet::Util::FleetClient', fleet_client_class)
|
||||
allow(fleet_client_class).to receive(:new).with('https://example.com', 'test_token') { fleet_client_mock }
|
||||
end
|
||||
|
||||
it { is_expected.to run.with_params(nil).and_raise_error(StandardError) }
|
||||
|
||||
it 'performs an API call to Fleet with the right parameters' do
|
||||
expect(fleet_client_mock).to receive(:preassign_profile).with(device_uuid, template, group)
|
||||
is_expected.to run.with_params(device_uuid, template, group)
|
||||
end
|
||||
|
||||
it 'has a default value if group is not provided' do
|
||||
expect(fleet_client_mock).to receive(:preassign_profile).with(device_uuid, template, 'default')
|
||||
is_expected.to run.with_params(device_uuid, template)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'puppet/util/fleet_client'
|
||||
|
||||
describe 'fleetdm::release_device' do
|
||||
let(:fleet_client_mock) { instance_double('Puppet::Util::FleetClient') }
|
||||
let(:device_uuid) { 'device-uuid' }
|
||||
|
||||
before(:each) do
|
||||
fleet_client_class = class_spy('Puppet::Util::FleetClient')
|
||||
stub_const('Puppet::Util::FleetClient', fleet_client_class)
|
||||
allow(fleet_client_class).to receive(:new).with('https://example.com', 'test_token') { fleet_client_mock }
|
||||
end
|
||||
|
||||
it { is_expected.to run.with_params(nil).and_raise_error(StandardError) }
|
||||
|
||||
it 'performs an API call to Fleet' do
|
||||
expect(fleet_client_mock).to receive(:send_mdm_command).with(device_uuid, %r{DeviceConfigured})
|
||||
is_expected.to run.with_params(device_uuid)
|
||||
end
|
||||
end
|
||||
74
ee/tools/puppet/fleetdm/spec/spec_helper.rb
Normal file
74
ee/tools/puppet/fleetdm/spec/spec_helper.rb
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.mock_with :rspec
|
||||
end
|
||||
|
||||
require 'puppetlabs_spec_helper/module_spec_helper'
|
||||
require 'rspec-puppet-facts'
|
||||
|
||||
require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb'))
|
||||
|
||||
include RspecPuppetFacts
|
||||
|
||||
default_facts = {
|
||||
puppetversion: Puppet.version,
|
||||
facterversion: Facter.version,
|
||||
}
|
||||
|
||||
default_fact_files = [
|
||||
File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')),
|
||||
File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')),
|
||||
]
|
||||
|
||||
default_fact_files.each do |f|
|
||||
next unless File.exist?(f) && File.readable?(f) && File.size?(f)
|
||||
|
||||
begin
|
||||
default_facts.merge!(YAML.safe_load(File.read(f), [], [], true))
|
||||
rescue => e
|
||||
RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}"
|
||||
end
|
||||
end
|
||||
|
||||
# read default_facts and merge them over what is provided by facterdb
|
||||
default_facts.each do |fact, value|
|
||||
add_custom_fact fact, value
|
||||
end
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.default_facts = default_facts
|
||||
c.hiera_config = 'spec/fixtures/hiera.yaml'
|
||||
c.before :each do
|
||||
# set to strictest setting for testing
|
||||
# by default Puppet runs at warning level
|
||||
Puppet.settings[:strict] = :warning
|
||||
Puppet.settings[:strict_variables] = true
|
||||
end
|
||||
c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT']
|
||||
c.after(:suite) do
|
||||
end
|
||||
|
||||
# Filter backtrace noise
|
||||
backtrace_exclusion_patterns = [
|
||||
%r{spec_helper},
|
||||
%r{gems},
|
||||
]
|
||||
|
||||
if c.respond_to?(:backtrace_exclusion_patterns)
|
||||
c.backtrace_exclusion_patterns = backtrace_exclusion_patterns
|
||||
elsif c.respond_to?(:backtrace_clean_patterns)
|
||||
c.backtrace_clean_patterns = backtrace_exclusion_patterns
|
||||
end
|
||||
end
|
||||
|
||||
# Ensures that a module is defined
|
||||
# @param module_name Name of the module
|
||||
def ensure_module_defined(module_name)
|
||||
module_name.split('::').reduce(Object) do |last_module, next_module|
|
||||
last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false)
|
||||
last_module.const_get(next_module, false)
|
||||
end
|
||||
end
|
||||
|
||||
# 'spec_overrides' from sync.yml will appear below this line
|
||||
Loading…
Reference in a new issue