Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check host network connectivity #128

Merged
merged 9 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion rootfs/usr/share/www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h2>This may take 20 minutes or more</h2>
</div>
</div>
</div>
<div class="state-error">
<div id="state-error" class="error">
<h1>Error installing Home Assistant</h1>
<div role="alert" class="alert">
<svg class="alert-icon" preserveAspectRatio="xMidYMid meet" focusable="false" role="img" aria-hidden="true"
Expand All @@ -42,6 +42,35 @@ <h1>Error installing Home Assistant</h1>
</div>
</div>
</div>
<div id="state-network-issue" class="warning">
<h1>Networking issue detected</h1>
<div role="alert" class="alert warning">
<svg class="alert-icon" preserveAspectRatio="xMidYMid meet" focusable="false" role="img" aria-hidden="true"
viewBox="0 0 24 24">
<g>
<path
d="M11,15H13V17H11V15M11,7H13V13H11V7M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20Z">
</path>
</g>
</svg>
<div class="alert-content">
<p>
Home Assistant OS detected a networking issue in your setup. As part of the initial
setup, Home Assistant OS downloads the latest version of Home Assistant Core. This
networking issue prevents this download. The network issue might be DNS related.
The currently used DNS service is: <span id="current_dns"></span>.
</p>
<p>
To resolve this, you can try a different DNS server. Select one of the options below.
Alternatively, change your router configuration to use your own custom DNS server.
</p>
</div>
</div>
<div class="actions">
<button id="use_cloudflare_dns" class="button">Use Cloudflare DNS</button>
<button id="use_google_dns" class="button">Use Google DNS</button>
</div>
</div>
<pre id="log"></pre>
<button id="show_logs">Show details</button>
</div>
Expand Down
110 changes: 107 additions & 3 deletions rootfs/usr/share/www/static/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function fetchLogs() {
res.text().then(function (text) {
var logElement = document.getElementById("log");
if (errorCheck.test(text)) {
document.body.classList.add("error");
document.body.classList.add("supervisor-error");
document.getElementById("show_logs").innerText = "Download raw logs";
logElement.showFull = true;
}
Expand All @@ -98,22 +98,60 @@ function fetchLogs() {
}
});
}
}, scheduleFetchLogs());
});
scheduleFetchLogs();
}

function scheduleTry() {
setTimeout(testAvailable, 5000);
}

var scheduleTimeout;
let scheduleTimeout;

function scheduleFetchLogs() {
clearTimeout(scheduleTimeout);
scheduleTimeout = setTimeout(fetchLogs, 5000);
}

function fetchSupervisorInfo() {
fetch("/supervisor/network/info").then(function (res) {
if (!res.ok)
return;
agners marked this conversation as resolved.
Show resolved Hide resolved

res.json().then(function (data) {
agners marked this conversation as resolved.
Show resolved Hide resolved
if (!data.data.host_internet) {
document.body.classList.add("network-issue");
}
agners marked this conversation as resolved.
Show resolved Hide resolved
else
{
document.body.classList.remove("network-issue");
}

if (document.body.classList.contains("network-issue")) {
const primaryInterface = data.data.interfaces.find(intf => intf.primary);
const dnsElement = document.getElementById("current_dns");
if (!primaryInterface) {
dnsElement.innerText = "(no primary interface)";
} else {
dnsElement.innerText = [...(primaryInterface.ipv4?.nameservers || []), ...(primaryInterface.ipv6?.nameservers || [])].join(', ');
}
}

});
});
scheduleFetchSupervisorInfo();
}

let scheduleSupervisorTimeout;

function scheduleFetchSupervisorInfo() {
clearTimeout(scheduleSupervisorTimeout);
scheduleSupervisorTimeout = setTimeout(fetchSupervisorInfo, 5000);
}

scheduleTry();
fetchLogs();
fetchSupervisorInfo();

document.getElementById("show_logs").addEventListener("click", toggleLogs);
function toggleLogs(event) {
Expand All @@ -139,6 +177,72 @@ function toggleLogs(event) {
}
}

document.getElementById("use_cloudflare_dns").addEventListener("click", function() {
setDns(["1.1.1.1", "1.0.0.1"], ["2606:4700:4700::1111", "2606:4700:4700::1001"]);
});

document.getElementById("use_google_dns").addEventListener("click", function() {
setDns(["8.8.8.8", "8.8.4.4"], ["2001:4860:4860::8888", "2001:4860:4860::8844"]);
});

function setDns(ipv4nameservers, ipv6nameservers) {
// Step 1: Fetch the primary network interface from the /network/info endpoint
fetch("/supervisor/network/info", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to fetch network info');
}
return response.json();
})
.then(data => {
// Step 2: Find the primary interface
const primaryInterface = data.data.interfaces.find(intf => intf.primary && intf.enabled);
if (!primaryInterface) {
throw new Error('No primary interface found');
}

// Step 3: Update the DNS settings for the primary interface
const payload = {
ipv4: {
method: "auto",
nameservers: ipv4nameservers
},
ipv6: {
method: "auto",
nameservers: ipv6nameservers
}
};

return fetch(`/supervisor/network/interface/${primaryInterface.interface}/update`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload)
});
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to update the interface');
}
fetchSupervisorInfo();
return response.json();
})
.then(data => {
console.log('Success:', data);
// Optionally handle the success case, e.g., updating the UI or showing a message
})
.catch((error) => {
console.error('Error:', error);
// Optionally handle the error case, e.g., showing an error message
});
}

var dialogs = document.querySelectorAll('dialog');
dialogs.forEach(dialog => {
dialogPolyfill.registerDialog(dialog);
Expand Down
34 changes: 31 additions & 3 deletions rootfs/usr/share/www/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ body {
white-space: nowrap;
}

.error .state-normal {
.supervisor-error .state-normal {
display: none;
}

.state-error {
#state-error {
display: none;
}

.error .state-error {
.supervisor-error #state-error {
display: block;
}

Expand All @@ -60,6 +60,9 @@ body {
pointer-events: none;
content: "";
border-radius: 4px;
}

.error .alert::after {
background-color: #db4437;
}

Expand All @@ -76,6 +79,31 @@ body {
margin-right: 0;
}

#state-network-issue {
display: none;
}

.network-issue #state-network-issue {
display: block;
}

.network-issue .state-normal {
display: none;
}

.warning .alert-icon {
fill: #ffa600;
}

.warning .alert::after {
background-color: #ffa600;
}

.warning .actions {
display: flex;
margin-bottom: 16px;
}

.header {
text-align: center;
margin-top: 32px;
Expand Down