This script automates the process of syncing ChromeOS device data from the Google Admin SDK into your Snipe-IT asset inventory.
It fetches device data using a Google service account with domain-wide delegation and pushes it to Snipe-IT. Duplicate devices are automatically updated. All activity is logged and a progress bar shows sync status.
- β Authenticates using a service account with domain-wide delegation
- β Fetches all ChromeOS devices with pagination support
- β Parses and formats relevant fields (MAC, IP, model, enrollment date, etc.)
- β Automatically creates models and categories using AI classification
- β Assigns fieldsets with custom fields to new models
- β Updates existing devices based on asset tag
- β Handles API rate limiting (429) with exponential backoff retry logic
- β Logs errors to file with configurable logging levels
- β
Displays live progress bar with
tqdm - β Development and Production deployment modes
- β SystemD timer for automated scheduled syncs
- β Centralized configuration management via environment variables
- Python 3.8+
- Snipe-IT API access
- Google Workspace Admin access with service account + delegation
- Internet connectivity for Google Admin SDK and Snipe-IT API calls
All dependencies are installed automatically by the setup script. See requirements.txt for details.
git clone https://github.com/Gunn1/Google2Snipe-IT.git
cd Google2Snipe-ITThe interactive setup script handles everything for you:
chmod +x setup.sh
./setup.shThis script will:
- β Check Python version (3.8+)
- β Create a Python virtual environment
- β Install all dependencies
- β Guide you through configuration (development or production)
- β
Create a
.envfile with your settings - β (Production only) Set up SystemD service and timer
- β Validate your configuration
Obtain your service account JSON key from Google Cloud Console:
- Create a service account with domain-wide delegation enabled
- Grant it the scope:
https://www.googleapis.com/auth/admin.directory.device.chromeos - Download the JSON key
- Save it as
service_account.jsonin the project directory
If you prefer to set up manually instead of using the setup script:
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activatepip install -r requirements.txtCopy the example configuration and customize it:
cp .env.example .envEdit .env with your settings. See Configuration section for details.
Save your Google service account JSON as service_account.json in the project directory.
python snipe-IT.pyConfiguration is managed via environment variables in the .env file. See .env.example for a complete example with documentation.
# Snipe-IT
API_TOKEN=your_snipeit_api_key
ENDPOINT_URL=https://your-snipeit-instance/api/v1
# Google Workspace
DELEGATED_ADMIN=[email protected]
GOOGLE_SERVICE_ACCOUNT_FILE=service_account.json
# Gemini AI
Gemini_APIKEY=your_gemini_api_keyMap Snipe-IT custom field IDs in your .env:
SNIPE_IT_FIELD_MAC_ADDRESS=_snipeit_mac_address_1
SNIPE_IT_FIELD_SYNC_DATE=_snipeit_sync_date_9
SNIPE_IT_FIELD_IP_ADDRESS=_snipeit_ip_address_3
SNIPE_IT_FIELD_USER=_snipeit_user_10Find your custom field IDs in Snipe-IT at: Settings β Custom Fields
# Defaults
SNIPE_IT_DEFAULT_MODEL_ID=87
SNIPE_IT_FIELDSET_ID=9
SNIPE_IT_DEFAULT_STATUS_ID=2
# Google API
GOOGLE_CHROMEOS_PAGE_SIZE=300
GOOGLE_CHROMEOS_PROJECTION=FULL
# Retry Logic
MAX_RETRIES=4
RETRY_DELAY_SECONDS=20
# Logging
LOG_FILE=snipeit_errors.log
LOG_LEVEL=WARNING
# Features
DEBUG=false
DRY_RUN=false
ENVIRONMENT=developmentFor testing and manual runs:
source venv/bin/activate
python snipe-IT.pyTo test without making changes (dry-run):
export DRY_RUN=true
python snipe-IT.pyAfter running ./setup.sh and selecting production, the sync runs automatically via SystemD timer.
# Run the sync immediately
systemctl start google2snipeit.service
# Check status
systemctl status google2snipeit.service
# View recent logs
journalctl -u google2snipeit.service -n 50 -f# Check timer status
systemctl status google2snipeit.timer
# View next scheduled run
systemctl list-timers google2snipeit.timer
# View all recent runs and logs
journalctl -u google2snipeit.service -n 100
# Follow logs in real-time
journalctl -u google2snipeit.service -fEdit the SystemD timer to change the schedule:
sudo systemctl edit google2snipeit.timerCommon schedule patterns:
# Every 15 minutes
OnUnitActiveSec=15min
# Every 30 minutes
OnUnitActiveSec=30min
# Every hour
OnUnitActiveSec=1h
# Every 4 hours
OnUnitActiveSec=4h
# Daily at 2 AM
OnCalendar=*-*-* 02:00:00
# Weekdays at 9 AM
OnCalendar=Mon-Fri *-*-* 09:00:00After editing:
sudo systemctl daemon-reload
sudo systemctl restart google2snipeit.timer1. Authenticate with Google Workspace using service account
β
2. Fetch all ChromeOS devices (with pagination)
β
3. For each device:
ββ Format MAC address (e.g., a81d166742f7 β a8:1d:16:67:42:f7)
ββ Check if device exists in Snipe-IT (by asset tag or serial)
β ββ If exists: Update with new data
β ββ If not: Create new device
ββ If model doesn't exist:
β ββ Use Gemini AI to classify into a category
β ββ Create model in Snipe-IT
β ββ Assign custom field fieldset
ββ Log any errors
β
4. Display progress and summary
The sync checks if a device already exists by matching:
- Asset tag (serial number from ChromeOS)
- Serial number
If found, the existing device is updated with new data instead of creating a duplicate.
Raw MAC addresses like a81d166742f7 are automatically converted to the standard format a8:1d:16:67:42:f7.
If a ChromeOS model doesn't exist in Snipe-IT:
- Google Gemini AI classifies it into a category (Chromebook, Desktop, Tablet, etc.)
- A new model is created with the category
- The configured fieldset is assigned to the model
If Gemini classification fails, the default model is used.
Data is stored in Snipe-IT custom fields:
- MAC Address: Network adapter MAC address
- Sync Date: When the device was enrolled (from ChromeOS)
- IP Address: Last known IP address
- User: Email of the device's last user
Errors and warnings are logged to snipeit_errors.log (or custom path via LOG_FILE env var).
Configure via LOG_LEVEL environment variable:
DEBUG: Verbose output, all function callsINFO: Informational messagesWARNING: Only warnings and errors (default)ERROR: Only errorsCRITICAL: Only critical failures
During sync, progress is displayed with:
- Live progress bar (total device count)
- Status messages for each operation
- Error messages for failed devices
- Summary statistics at completion
If you see configuration errors on startup, check:
# Validate your setup
python3 -c "from config import Config; is_valid, errors = Config.validate(); print('Valid' if is_valid else f'Errors: {errors}')"# Reinstall dependencies
source venv/bin/activate
pip install -r requirements.txt# Check service account file exists
ls -la service_account.json
# Verify it's valid JSON
python3 -m json.tool service_account.json- Verify
API_TOKENis a valid Snipe-IT API key - Verify
ENDPOINT_URLis correct (ends with/api/v1) - Verify
DELEGATED_ADMINemail has ChromeOS device access - Verify Gemini API key is valid
The script automatically retries with exponential backoff. If you still experience issues:
- Increase
MAX_RETRIESin.env - Increase
RETRY_DELAY_SECONDSin.env - Reduce
GOOGLE_CHROMEOS_PAGE_SIZEto fetch fewer devices per request
# Check if enabled
systemctl is-enabled google2snipeit.timer
# Enable if disabled
sudo systemctl enable google2snipeit.timer
# Check logs for errors
journalctl -u google2snipeit.service -p err
# Check timer status
systemctl status google2snipeit.timer- Verify custom field IDs in
.envmatch your Snipe-IT instance - Verify the fieldset contains those custom fields
- Verify
SNIPE_IT_FIELDSET_IDis assigned to the model
To find correct field IDs:
- In Snipe-IT, go to Settings β Custom Fields
- Click on a field to see its ID (e.g.,
_snipeit_mac_address_1) - Update your
.envfile
.env file contains API keys and tokens.
- Never commit
.envto version control (it's in.gitignore) - Restrict file permissions:
chmod 600 .env - Rotate API keys periodically
- Use strong, unique API keys
When deploying to production:
- Run
setup.shwith production mode selected - Ensure the service account has minimal required permissions
- Use a dedicated service account user (
_google2snipeit) created automatically - Monitor logs regularly:
journalctl -u google2snipeit.service -f - Set up log rotation for
snipeit_errors.logto prevent disk fill - Consider running behind a proxy or VPN if your Snipe-IT is internal
- Create a dedicated Snipe-IT admin account for this service
- Use the smallest permission set needed (asset creation/update)
- Regularly rotate the API token
- Monitor failed API authentication attempts in logs
New Features:
- β¨ Centralized configuration management via
config.py - β¨ Interactive setup script (
setup.sh) for easy deployment - β¨ Production-ready SystemD service and timer
- β¨ Support for dev and production environments
- β¨ Enhanced logging with configurable levels
- β¨ Configuration validation at startup
- β¨ Comprehensive documentation
Improvements:
- π§ Replaced hardcoded values with environment variables
- π§ Better error handling and logging
- π§ Virtual environment support
- π§ Dry-run mode for testing
- π§ Debug logging for troubleshooting
Breaking Changes:
- Configuration now uses
config.py- existing.envfiles should still work - Some hardcoded field IDs now require environment variables (see
.env.example)
- Basic ChromeOS to Snipe-IT sync
- Service account authentication
- Duplicate detection and update
- Basic error logging
To test the sync without making changes:
# Activate virtual environment
source venv/bin/activate
# Run in dry-run mode
export DRY_RUN=true
python snipe-IT.py
# View what would have been changed (check logs)
tail -f snipeit_errors.logMIT License - See LICENSE file for details
Contributions are welcome! Please feel free to open issues or PRs for:
- Bug fixes
- New features
- Documentation improvements
- Additional Snipe-IT field support
- Performance optimizations
Before submitting a PR, please:
- Test your changes with
python -m pytest tests/ - Ensure no sensitive data is committed
- Update documentation if needed
For issues, questions, or suggestions:
- Check the Troubleshooting section
- Review logs:
tail -f snipeit_errors.log - Open a GitHub issue with:
- Description of the problem
- Relevant log excerpts (no API keys!)
- Your configuration (no API keys!)
- Python version:
python3 --version