@@ -79,8 +79,9 @@ use crate::db::{
79
79
} ,
80
80
pagination:: paginated,
81
81
pagination:: paginated_multicolumn,
82
- subnet_allocation:: AllocateIpQuery ,
83
82
subnet_allocation:: FilterConflictingVpcSubnetRangesQuery ,
83
+ subnet_allocation:: InsertNetworkInterfaceQuery ,
84
+ subnet_allocation:: NetworkInterfaceError ,
84
85
subnet_allocation:: SubnetError ,
85
86
update_and_check:: { UpdateAndCheck , UpdateStatus } ,
86
87
} ;
@@ -1698,109 +1699,153 @@ impl DataStore {
1698
1699
/*
1699
1700
* Network interfaces
1700
1701
*/
1701
-
1702
1702
pub async fn instance_create_network_interface (
1703
1703
& self ,
1704
1704
interface : IncompleteNetworkInterface ,
1705
- ) -> CreateResult < NetworkInterface > {
1705
+ ) -> Result < NetworkInterface , NetworkInterfaceError > {
1706
1706
use db:: schema:: network_interface:: dsl;
1707
+ let query = InsertNetworkInterfaceQuery {
1708
+ interface : interface. clone ( ) ,
1709
+ now : Utc :: now ( ) ,
1710
+ } ;
1711
+ diesel:: insert_into ( dsl:: network_interface)
1712
+ . values ( query)
1713
+ . returning ( NetworkInterface :: as_returning ( ) )
1714
+ . get_result_async ( self . pool ( ) )
1715
+ . await
1716
+ . map_err ( |e| NetworkInterfaceError :: from_pool ( e, & interface) )
1717
+ }
1707
1718
1708
- // TODO: Longer term, it would be nice to decouple the IP allocation
1709
- // (and MAC allocation) from the NetworkInterface table, so that
1710
- // retrying from parallel inserts doesn't need to happen here.
1711
-
1712
- let name = interface. identity . name . clone ( ) ;
1713
- match interface. ip {
1714
- // Attempt an insert with a requested IP address
1715
- Some ( ip) => {
1716
- interface. subnet . contains ( ip) ?;
1717
- let row = NetworkInterface {
1718
- identity : interface. identity ,
1719
- instance_id : interface. instance_id ,
1720
- vpc_id : interface. vpc_id ,
1721
- subnet_id : interface. subnet . id ( ) ,
1722
- mac : interface. mac ,
1723
- ip : ip. into ( ) ,
1724
- } ;
1725
- diesel:: insert_into ( dsl:: network_interface)
1726
- . values ( row)
1727
- . returning ( NetworkInterface :: as_returning ( ) )
1728
- . get_result_async ( self . pool ( ) )
1729
- . await
1730
- . map_err ( |e| {
1731
- public_error_from_diesel_pool (
1732
- e,
1733
- ErrorHandler :: Conflict (
1734
- ResourceType :: NetworkInterface ,
1735
- name. as_str ( ) ,
1736
- ) ,
1737
- )
1738
- } )
1739
- }
1740
- // Insert and allocate an IP address
1741
- None => {
1742
- let allocation_query = AllocateIpQuery {
1743
- block : ipnetwork:: IpNetwork :: V4 (
1744
- interface. subnet . ipv4_block . 0 . 0 ,
1719
+ /// Delete all network interfaces attached to the given instance.
1720
+ // NOTE: This is mostly useful in the context of sagas, but might be helpful
1721
+ // in other situations, such as moving an instance between VPC Subnets.
1722
+ pub async fn instance_delete_all_network_interfaces (
1723
+ & self ,
1724
+ instance_id : & Uuid ,
1725
+ ) -> DeleteResult {
1726
+ use db:: schema:: network_interface:: dsl;
1727
+ let now = Utc :: now ( ) ;
1728
+ diesel:: update ( dsl:: network_interface)
1729
+ . filter ( dsl:: instance_id. eq ( * instance_id) )
1730
+ . filter ( dsl:: time_deleted. is_null ( ) )
1731
+ . set ( dsl:: time_deleted. eq ( now) )
1732
+ . execute_async ( self . pool ( ) )
1733
+ . await
1734
+ . map_err ( |e| {
1735
+ public_error_from_diesel_pool (
1736
+ e,
1737
+ ErrorHandler :: NotFoundByLookup (
1738
+ ResourceType :: Instance ,
1739
+ LookupType :: ById ( * instance_id) ,
1745
1740
) ,
1746
- interface,
1747
- now : Utc :: now ( ) ,
1748
- } ;
1749
- diesel:: insert_into ( dsl:: network_interface)
1750
- . values ( allocation_query)
1751
- . returning ( NetworkInterface :: as_returning ( ) )
1752
- . get_result_async ( self . pool ( ) )
1753
- . await
1754
- . map_err ( |e| {
1755
- if let PoolError :: Connection ( ConnectionError :: Query (
1756
- diesel:: result:: Error :: NotFound ,
1757
- ) ) = e
1758
- {
1759
- Error :: InvalidRequest {
1760
- message : "no available IP addresses"
1761
- . to_string ( ) ,
1762
- }
1763
- } else {
1764
- public_error_from_diesel_pool (
1765
- e,
1766
- ErrorHandler :: Conflict (
1767
- ResourceType :: NetworkInterface ,
1768
- name. as_str ( ) ,
1769
- ) ,
1770
- )
1771
- }
1772
- } )
1773
- }
1774
- }
1741
+ )
1742
+ } ) ?;
1743
+ Ok ( ( ) )
1775
1744
}
1776
1745
1777
1746
pub async fn instance_delete_network_interface (
1778
1747
& self ,
1779
- network_interface_id : & Uuid ,
1748
+ interface_id : & Uuid ,
1780
1749
) -> DeleteResult {
1781
1750
use db:: schema:: network_interface:: dsl;
1751
+ let now = Utc :: now ( ) ;
1752
+ let result = diesel:: update ( dsl:: network_interface)
1753
+ . filter ( dsl:: id. eq ( * interface_id) )
1754
+ . filter ( dsl:: time_deleted. is_null ( ) )
1755
+ . set ( ( dsl:: time_deleted. eq ( now) , ) )
1756
+ . check_if_exists :: < db:: model:: NetworkInterface > ( * interface_id)
1757
+ . execute_and_check ( self . pool ( ) )
1758
+ . await
1759
+ . map_err ( |e| {
1760
+ public_error_from_diesel_pool (
1761
+ e,
1762
+ ErrorHandler :: NotFoundByLookup (
1763
+ ResourceType :: NetworkInterface ,
1764
+ LookupType :: ById ( * interface_id) ,
1765
+ ) ,
1766
+ )
1767
+ } ) ?;
1768
+ match result. status {
1769
+ UpdateStatus :: Updated => Ok ( ( ) ) ,
1770
+ UpdateStatus :: NotUpdatedButExists => {
1771
+ let interface = & result. found ;
1772
+ if interface. time_deleted ( ) . is_some ( ) {
1773
+ // Already deleted
1774
+ Ok ( ( ) )
1775
+ } else {
1776
+ Err ( Error :: internal_error ( & format ! (
1777
+ "failed to delete network interface: {}" ,
1778
+ interface_id
1779
+ ) ) )
1780
+ }
1781
+ }
1782
+ }
1783
+ }
1784
+
1785
+ pub async fn subnet_lookup_network_interface (
1786
+ & self ,
1787
+ subnet_id : & Uuid ,
1788
+ interface_name : & Name ,
1789
+ ) -> LookupResult < db:: model:: NetworkInterface > {
1790
+ use db:: schema:: network_interface:: dsl;
1791
+
1792
+ dsl:: network_interface
1793
+ . filter ( dsl:: subnet_id. eq ( * subnet_id) )
1794
+ . filter ( dsl:: time_deleted. is_null ( ) )
1795
+ . filter ( dsl:: name. eq ( interface_name. clone ( ) ) )
1796
+ . select ( db:: model:: NetworkInterface :: as_select ( ) )
1797
+ . get_result_async ( self . pool ( ) )
1798
+ . await
1799
+ . map_err ( |e| {
1800
+ public_error_from_diesel_pool (
1801
+ e,
1802
+ ErrorHandler :: NotFoundByLookup (
1803
+ ResourceType :: NetworkInterface ,
1804
+ LookupType :: ByName ( interface_name. to_string ( ) ) ,
1805
+ ) ,
1806
+ )
1807
+ } )
1808
+ }
1782
1809
1783
- // TODO-correctness: Do not allow deleting interfaces on running
1784
- // instances until we support hotplug
1810
+ /// List network interfaces associated with a given instance.
1811
+ pub async fn instance_list_network_interfaces (
1812
+ & self ,
1813
+ instance_id : & Uuid ,
1814
+ pagparams : & DataPageParams < ' _ , Name > ,
1815
+ ) -> ListResultVec < NetworkInterface > {
1816
+ use db:: schema:: network_interface:: dsl;
1817
+ paginated ( dsl:: network_interface, dsl:: name, & pagparams)
1818
+ . filter ( dsl:: time_deleted. is_null ( ) )
1819
+ . filter ( dsl:: instance_id. eq ( * instance_id) )
1820
+ . select ( NetworkInterface :: as_select ( ) )
1821
+ . load_async :: < NetworkInterface > ( self . pool ( ) )
1822
+ . await
1823
+ . map_err ( |e| public_error_from_diesel_pool ( e, ErrorHandler :: Server ) )
1824
+ }
1785
1825
1786
- let now = Utc :: now ( ) ;
1787
- diesel:: update ( dsl:: network_interface)
1826
+ /// Get a network interface by name attached to an instance
1827
+ pub async fn instance_lookup_network_interface (
1828
+ & self ,
1829
+ instance_id : & Uuid ,
1830
+ interface_name : & Name ,
1831
+ ) -> LookupResult < NetworkInterface > {
1832
+ use db:: schema:: network_interface:: dsl;
1833
+ dsl:: network_interface
1834
+ . filter ( dsl:: instance_id. eq ( * instance_id) )
1835
+ . filter ( dsl:: name. eq ( interface_name. clone ( ) ) )
1788
1836
. filter ( dsl:: time_deleted. is_null ( ) )
1789
- . filter ( dsl:: id. eq ( * network_interface_id) )
1790
- . set ( dsl:: time_deleted. eq ( now) )
1791
- . returning ( NetworkInterface :: as_returning ( ) )
1837
+ . select ( NetworkInterface :: as_select ( ) )
1792
1838
. get_result_async ( self . pool ( ) )
1793
1839
. await
1794
1840
. map_err ( |e| {
1795
1841
public_error_from_diesel_pool (
1796
1842
e,
1797
1843
ErrorHandler :: NotFoundByLookup (
1798
1844
ResourceType :: NetworkInterface ,
1799
- LookupType :: ById ( * network_interface_id ) ,
1845
+ LookupType :: ByName ( interface_name . to_string ( ) ) ,
1800
1846
) ,
1801
1847
)
1802
- } ) ?;
1803
- Ok ( ( ) )
1848
+ } )
1804
1849
}
1805
1850
1806
1851
// Create a record for a new Oximeter instance
0 commit comments